fa7fbf5de34be26327a856422e774012a944a412
[mono.git] / mcs / mcs / statement.cs
1 //
2 // statement.cs: Statement representation for the IL tree.
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //   Martin Baulig (martin@ximian.com)
7 //   Marek Safar (marek.safar@seznam.cz)
8 //
9 // Copyright 2001, 2002, 2003 Ximian, Inc.
10 // Copyright 2003, 2004 Novell, Inc.
11 //
12
13 using System;
14 using System.Text;
15 using System.Reflection;
16 using System.Reflection.Emit;
17 using System.Diagnostics;
18 using System.Collections;
19 using System.Collections.Specialized;
20
21 namespace Mono.CSharp {
22         
23         public abstract class Statement {
24                 public Location loc;
25                 
26                 /// <summary>
27                 ///   Resolves the statement, true means that all sub-statements
28                 ///   did resolve ok.
29                 //  </summary>
30                 public virtual bool Resolve (EmitContext ec)
31                 {
32                         return true;
33                 }
34
35                 /// <summary>
36                 ///   We already know that the statement is unreachable, but we still
37                 ///   need to resolve it to catch errors.
38                 /// </summary>
39                 public virtual bool ResolveUnreachable (EmitContext ec, bool warn)
40                 {
41                         //
42                         // This conflicts with csc's way of doing this, but IMHO it's
43                         // the right thing to do.
44                         //
45                         // If something is unreachable, we still check whether it's
46                         // correct.  This means that you cannot use unassigned variables
47                         // in unreachable code, for instance.
48                         //
49
50                         if (warn)
51                                 Report.Warning (162, 2, loc, "Unreachable code detected");
52
53                         ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc);
54                         bool ok = Resolve (ec);
55                         ec.KillFlowBranching ();
56
57                         return ok;
58                 }
59                                 
60                 /// <summary>
61                 ///   Return value indicates whether all code paths emitted return.
62                 /// </summary>
63                 protected abstract void DoEmit (EmitContext ec);
64
65                 /// <summary>
66                 ///   Utility wrapper routine for Error, just to beautify the code
67                 /// </summary>
68                 public void Error (int error, string format, params object[] args)
69                 {
70                         Error (error, String.Format (format, args));
71                 }
72
73                 public void Error (int error, string s)
74                 {
75                         if (!loc.IsNull)
76                                 Report.Error (error, loc, s);
77                         else
78                                 Report.Error (error, s);
79                 }
80
81                 /// <summary>
82                 ///   Return value indicates whether all code paths emitted return.
83                 /// </summary>
84                 public virtual void Emit (EmitContext ec)
85                 {
86                         ec.Mark (loc);
87                         DoEmit (ec);
88                 }
89
90                 //
91                 // This routine must be overrided in derived classes and make copies
92                 // of all the data that might be modified if resolved
93                 // 
94                 protected abstract void CloneTo (CloneContext clonectx, Statement target);
95
96                 public Statement Clone (CloneContext clonectx)
97                 {
98                         Statement s = (Statement) this.MemberwiseClone ();
99                         CloneTo (clonectx, s);
100                         return s;
101                 }
102
103                 public virtual Expression CreateExpressionTree (EmitContext ec)
104                 {
105                         Report.Error (834, loc, "A lambda expression with statement body cannot be converted to an expresion tree");
106                         return null;
107                 }
108
109                 public Statement PerformClone ()
110                 {
111                         CloneContext clonectx = new CloneContext ();
112
113                         return Clone (clonectx);
114                 }
115
116                 public abstract void MutateHoistedGenericType (AnonymousMethodStorey storey);
117         }
118
119         //
120         // This class is used during the Statement.Clone operation
121         // to remap objects that have been cloned.
122         //
123         // Since blocks are cloned by Block.Clone, we need a way for
124         // expressions that must reference the block to be cloned
125         // pointing to the new cloned block.
126         //
127         public class CloneContext {
128                 Hashtable block_map = new Hashtable ();
129                 Hashtable variable_map;
130                 
131                 public void AddBlockMap (Block from, Block to)
132                 {
133                         if (block_map.Contains (from))
134                                 return;
135                         block_map [from] = to;
136                 }
137                 
138                 public Block LookupBlock (Block from)
139                 {
140                         Block result = (Block) block_map [from];
141
142                         if (result == null){
143                                 result = (Block) from.Clone (this);
144                                 block_map [from] = result;
145                         }
146
147                         return result;
148                 }
149
150                 ///
151                 /// Remaps block to cloned copy if one exists.
152                 ///
153                 public Block RemapBlockCopy (Block from)
154                 {
155                         Block mapped_to = (Block)block_map[from];
156                         if (mapped_to == null)
157                                 return from;
158
159                         return mapped_to;
160                 }
161
162                 public void AddVariableMap (LocalInfo from, LocalInfo to)
163                 {
164                         if (variable_map == null)
165                                 variable_map = new Hashtable ();
166                         
167                         if (variable_map.Contains (from))
168                                 return;
169                         variable_map [from] = to;
170                 }
171                 
172                 public LocalInfo LookupVariable (LocalInfo from)
173                 {
174                         LocalInfo result = (LocalInfo) variable_map [from];
175
176                         if (result == null)
177                                 throw new Exception ("LookupVariable: looking up a variable that has not been registered yet");
178
179                         return result;
180                 }
181         }
182         
183         public sealed class EmptyStatement : Statement {
184                 
185                 private EmptyStatement () {}
186                 
187                 public static readonly EmptyStatement Value = new EmptyStatement ();
188                 
189                 public override bool Resolve (EmitContext ec)
190                 {
191                         return true;
192                 }
193
194                 public override bool ResolveUnreachable (EmitContext ec, bool warn)
195                 {
196                         return true;
197                 }
198
199                 protected override void DoEmit (EmitContext ec)
200                 {
201                 }
202
203                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
204                 {
205                 }
206
207                 protected override void CloneTo (CloneContext clonectx, Statement target)
208                 {
209                         // nothing needed.
210                 }
211         }
212         
213         public class If : Statement {
214                 Expression expr;
215                 public Statement TrueStatement;
216                 public Statement FalseStatement;
217
218                 bool is_true_ret;
219                 
220                 public If (Expression expr, Statement true_statement, Location l)
221                 {
222                         this.expr = expr;
223                         TrueStatement = true_statement;
224                         loc = l;
225                 }
226
227                 public If (Expression expr,
228                            Statement true_statement,
229                            Statement false_statement,
230                            Location l)
231                 {
232                         this.expr = expr;
233                         TrueStatement = true_statement;
234                         FalseStatement = false_statement;
235                         loc = l;
236                 }
237
238                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
239                 {
240                         expr.MutateHoistedGenericType (storey);
241                         TrueStatement.MutateHoistedGenericType (storey);
242                         if (FalseStatement != null)
243                                 FalseStatement.MutateHoistedGenericType (storey);
244                 }
245
246                 public override bool Resolve (EmitContext ec)
247                 {
248                         bool ok = true;
249
250                         Report.Debug (1, "START IF BLOCK", loc);
251
252                         expr = Expression.ResolveBoolean (ec, expr, loc);
253                         if (expr == null){
254                                 ok = false;
255                                 goto skip;
256                         }
257
258                         Assign ass = expr as Assign;
259                         if (ass != null && ass.Source is Constant) {
260                                 Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
261                         }
262
263                         //
264                         // Dead code elimination
265                         //
266                         if (expr is Constant){
267                                 bool take = !((Constant) expr).IsDefaultValue;
268
269                                 if (take){
270                                         if (!TrueStatement.Resolve (ec))
271                                                 return false;
272
273                                         if ((FalseStatement != null) &&
274                                             !FalseStatement.ResolveUnreachable (ec, true))
275                                                 return false;
276                                         FalseStatement = null;
277                                 } else {
278                                         if (!TrueStatement.ResolveUnreachable (ec, true))
279                                                 return false;
280                                         TrueStatement = null;
281
282                                         if ((FalseStatement != null) &&
283                                             !FalseStatement.Resolve (ec))
284                                                 return false;
285                                 }
286
287                                 return true;
288                         }
289                 skip:
290                         ec.StartFlowBranching (FlowBranching.BranchingType.Conditional, loc);
291                         
292                         ok &= TrueStatement.Resolve (ec);
293
294                         is_true_ret = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
295
296                         ec.CurrentBranching.CreateSibling ();
297
298                         if (FalseStatement != null)
299                                 ok &= FalseStatement.Resolve (ec);
300                                         
301                         ec.EndFlowBranching ();
302
303                         Report.Debug (1, "END IF BLOCK", loc);
304
305                         return ok;
306                 }
307                 
308                 protected override void DoEmit (EmitContext ec)
309                 {
310                         ILGenerator ig = ec.ig;
311                         Label false_target = ig.DefineLabel ();
312                         Label end;
313
314                         //
315                         // If we're a boolean constant, Resolve() already
316                         // eliminated dead code for us.
317                         //
318                         Constant c = expr as Constant;
319                         if (c != null){
320                                 c.EmitSideEffect (ec);
321
322                                 if (!c.IsDefaultValue)
323                                         TrueStatement.Emit (ec);
324                                 else if (FalseStatement != null)
325                                         FalseStatement.Emit (ec);
326
327                                 return;
328                         }                       
329                         
330                         expr.EmitBranchable (ec, false_target, false);
331                         
332                         TrueStatement.Emit (ec);
333
334                         if (FalseStatement != null){
335                                 bool branch_emitted = false;
336                                 
337                                 end = ig.DefineLabel ();
338                                 if (!is_true_ret){
339                                         ig.Emit (OpCodes.Br, end);
340                                         branch_emitted = true;
341                                 }
342
343                                 ig.MarkLabel (false_target);
344                                 FalseStatement.Emit (ec);
345
346                                 if (branch_emitted)
347                                         ig.MarkLabel (end);
348                         } else {
349                                 ig.MarkLabel (false_target);
350                         }
351                 }
352
353                 protected override void CloneTo (CloneContext clonectx, Statement t)
354                 {
355                         If target = (If) t;
356
357                         target.expr = expr.Clone (clonectx);
358                         target.TrueStatement = TrueStatement.Clone (clonectx);
359                         if (FalseStatement != null)
360                                 target.FalseStatement = FalseStatement.Clone (clonectx);
361                 }
362         }
363
364         public class Do : Statement {
365                 public Expression expr;
366                 public Statement  EmbeddedStatement;
367                 
368                 public Do (Statement statement, Expression bool_expr, Location l)
369                 {
370                         expr = bool_expr;
371                         EmbeddedStatement = statement;
372                         loc = l;
373                 }
374
375                 public override bool Resolve (EmitContext ec)
376                 {
377                         bool ok = true;
378
379                         ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
380
381                         bool was_unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
382
383                         ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc);
384                         if (!EmbeddedStatement.Resolve (ec))
385                                 ok = false;
386                         ec.EndFlowBranching ();
387
388                         if (ec.CurrentBranching.CurrentUsageVector.IsUnreachable && !was_unreachable)
389                                 Report.Warning (162, 2, expr.Location, "Unreachable code detected");
390
391                         expr = Expression.ResolveBoolean (ec, expr, loc);
392                         if (expr == null)
393                                 ok = false;
394                         else if (expr is Constant){
395                                 bool infinite = !((Constant) expr).IsDefaultValue;
396                                 if (infinite)
397                                         ec.CurrentBranching.CurrentUsageVector.Goto ();
398                         }
399
400                         ec.EndFlowBranching ();
401
402                         return ok;
403                 }
404                 
405                 protected override void DoEmit (EmitContext ec)
406                 {
407                         ILGenerator ig = ec.ig;
408                         Label loop = ig.DefineLabel ();
409                         Label old_begin = ec.LoopBegin;
410                         Label old_end = ec.LoopEnd;
411                         
412                         ec.LoopBegin = ig.DefineLabel ();
413                         ec.LoopEnd = ig.DefineLabel ();
414                                 
415                         ig.MarkLabel (loop);
416                         EmbeddedStatement.Emit (ec);
417                         ig.MarkLabel (ec.LoopBegin);
418
419                         //
420                         // Dead code elimination
421                         //
422                         if (expr is Constant){
423                                 bool res = !((Constant) expr).IsDefaultValue;
424
425                                 expr.EmitSideEffect (ec);
426                                 if (res)
427                                         ec.ig.Emit (OpCodes.Br, loop); 
428                         } else
429                                 expr.EmitBranchable (ec, loop, true);
430                         
431                         ig.MarkLabel (ec.LoopEnd);
432
433                         ec.LoopBegin = old_begin;
434                         ec.LoopEnd = old_end;
435                 }
436
437                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
438                 {
439                         expr.MutateHoistedGenericType (storey);
440                         EmbeddedStatement.MutateHoistedGenericType (storey);
441                 }
442
443                 protected override void CloneTo (CloneContext clonectx, Statement t)
444                 {
445                         Do target = (Do) t;
446
447                         target.EmbeddedStatement = EmbeddedStatement.Clone (clonectx);
448                         target.expr = expr.Clone (clonectx);
449                 }
450         }
451
452         public class While : Statement {
453                 public Expression expr;
454                 public Statement Statement;
455                 bool infinite, empty;
456                 
457                 public While (Expression bool_expr, Statement statement, Location l)
458                 {
459                         this.expr = bool_expr;
460                         Statement = statement;
461                         loc = l;
462                 }
463
464                 public override bool Resolve (EmitContext ec)
465                 {
466                         bool ok = true;
467
468                         expr = Expression.ResolveBoolean (ec, expr, loc);
469                         if (expr == null)
470                                 return false;
471
472                         //
473                         // Inform whether we are infinite or not
474                         //
475                         if (expr is Constant){
476                                 bool value = !((Constant) expr).IsDefaultValue;
477
478                                 if (value == false){
479                                         if (!Statement.ResolveUnreachable (ec, true))
480                                                 return false;
481                                         empty = true;
482                                         return true;
483                                 } else
484                                         infinite = true;
485                         }
486
487                         ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
488                         if (!infinite)
489                                 ec.CurrentBranching.CreateSibling ();
490
491                         ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc);
492                         if (!Statement.Resolve (ec))
493                                 ok = false;
494                         ec.EndFlowBranching ();
495
496                         // There's no direct control flow from the end of the embedded statement to the end of the loop
497                         ec.CurrentBranching.CurrentUsageVector.Goto ();
498
499                         ec.EndFlowBranching ();
500
501                         return ok;
502                 }
503                 
504                 protected override void DoEmit (EmitContext ec)
505                 {
506                         if (empty) {
507                                 expr.EmitSideEffect (ec);
508                                 return;
509                         }
510
511                         ILGenerator ig = ec.ig;
512                         Label old_begin = ec.LoopBegin;
513                         Label old_end = ec.LoopEnd;
514                         
515                         ec.LoopBegin = ig.DefineLabel ();
516                         ec.LoopEnd = ig.DefineLabel ();
517
518                         //
519                         // Inform whether we are infinite or not
520                         //
521                         if (expr is Constant){
522                                 // expr is 'true', since the 'empty' case above handles the 'false' case
523                                 ig.MarkLabel (ec.LoopBegin);
524                                 expr.EmitSideEffect (ec);
525                                 Statement.Emit (ec);
526                                 ig.Emit (OpCodes.Br, ec.LoopBegin);
527                                         
528                                 //
529                                 // Inform that we are infinite (ie, `we return'), only
530                                 // if we do not `break' inside the code.
531                                 //
532                                 ig.MarkLabel (ec.LoopEnd);
533                         } else {
534                                 Label while_loop = ig.DefineLabel ();
535
536                                 ig.Emit (OpCodes.Br, ec.LoopBegin);
537                                 ig.MarkLabel (while_loop);
538
539                                 Statement.Emit (ec);
540                         
541                                 ig.MarkLabel (ec.LoopBegin);
542                                 ec.Mark (loc);
543
544                                 expr.EmitBranchable (ec, while_loop, true);
545                                 
546                                 ig.MarkLabel (ec.LoopEnd);
547                         }       
548
549                         ec.LoopBegin = old_begin;
550                         ec.LoopEnd = old_end;
551                 }
552
553                 public override void Emit (EmitContext ec)
554                 {
555                         DoEmit (ec);
556                 }
557
558                 protected override void CloneTo (CloneContext clonectx, Statement t)
559                 {
560                         While target = (While) t;
561
562                         target.expr = expr.Clone (clonectx);
563                         target.Statement = Statement.Clone (clonectx);
564                 }
565
566                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
567                 {
568                         expr.MutateHoistedGenericType (storey);
569                         Statement.MutateHoistedGenericType (storey);
570                 }
571         }
572
573         public class For : Statement {
574                 Expression Test;
575                 Statement InitStatement;
576                 Statement Increment;
577                 public Statement Statement;
578                 bool infinite, empty;
579                 
580                 public For (Statement init_statement,
581                             Expression test,
582                             Statement increment,
583                             Statement statement,
584                             Location l)
585                 {
586                         InitStatement = init_statement;
587                         Test = test;
588                         Increment = increment;
589                         Statement = statement;
590                         loc = l;
591                 }
592
593                 public override bool Resolve (EmitContext ec)
594                 {
595                         bool ok = true;
596
597                         if (InitStatement != null){
598                                 if (!InitStatement.Resolve (ec))
599                                         ok = false;
600                         }
601
602                         if (Test != null){
603                                 Test = Expression.ResolveBoolean (ec, Test, loc);
604                                 if (Test == null)
605                                         ok = false;
606                                 else if (Test is Constant){
607                                         bool value = !((Constant) Test).IsDefaultValue;
608
609                                         if (value == false){
610                                                 if (!Statement.ResolveUnreachable (ec, true))
611                                                         return false;
612                                                 if ((Increment != null) &&
613                                                     !Increment.ResolveUnreachable (ec, false))
614                                                         return false;
615                                                 empty = true;
616                                                 return true;
617                                         } else
618                                                 infinite = true;
619                                 }
620                         } else
621                                 infinite = true;
622
623                         ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
624                         if (!infinite)
625                                 ec.CurrentBranching.CreateSibling ();
626
627                         bool was_unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
628
629                         ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc);
630                         if (!Statement.Resolve (ec))
631                                 ok = false;
632                         ec.EndFlowBranching ();
633
634                         if (Increment != null){
635                                 if (ec.CurrentBranching.CurrentUsageVector.IsUnreachable) {
636                                         if (!Increment.ResolveUnreachable (ec, !was_unreachable))
637                                                 ok = false;
638                                 } else {
639                                         if (!Increment.Resolve (ec))
640                                                 ok = false;
641                                 }
642                         }
643
644                         // There's no direct control flow from the end of the embedded statement to the end of the loop
645                         ec.CurrentBranching.CurrentUsageVector.Goto ();
646
647                         ec.EndFlowBranching ();
648
649                         return ok;
650                 }
651
652                 protected override void DoEmit (EmitContext ec)
653                 {
654                         if (InitStatement != null && InitStatement != EmptyStatement.Value)
655                                 InitStatement.Emit (ec);
656
657                         if (empty) {
658                                 Test.EmitSideEffect (ec);
659                                 return;
660                         }
661
662                         ILGenerator ig = ec.ig;
663                         Label old_begin = ec.LoopBegin;
664                         Label old_end = ec.LoopEnd;
665                         Label loop = ig.DefineLabel ();
666                         Label test = ig.DefineLabel ();
667
668                         ec.LoopBegin = ig.DefineLabel ();
669                         ec.LoopEnd = ig.DefineLabel ();
670
671                         ig.Emit (OpCodes.Br, test);
672                         ig.MarkLabel (loop);
673                         Statement.Emit (ec);
674
675                         ig.MarkLabel (ec.LoopBegin);
676                         if (Increment != EmptyStatement.Value)
677                                 Increment.Emit (ec);
678
679                         ig.MarkLabel (test);
680                         //
681                         // If test is null, there is no test, and we are just
682                         // an infinite loop
683                         //
684                         if (Test != null){
685                                 //
686                                 // The Resolve code already catches the case for
687                                 // Test == Constant (false) so we know that
688                                 // this is true
689                                 //
690                                 if (Test is Constant) {
691                                         Test.EmitSideEffect (ec);
692                                         ig.Emit (OpCodes.Br, loop);
693                                 } else {
694                                         Test.EmitBranchable (ec, loop, true);
695                                 }
696                                 
697                         } else
698                                 ig.Emit (OpCodes.Br, loop);
699                         ig.MarkLabel (ec.LoopEnd);
700
701                         ec.LoopBegin = old_begin;
702                         ec.LoopEnd = old_end;
703                 }
704
705                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
706                 {
707                         if (InitStatement != null)
708                                 InitStatement.MutateHoistedGenericType (storey);
709                         if (Test != null)
710                                 Test.MutateHoistedGenericType (storey);
711                         if (Increment != null)
712                                 Increment.MutateHoistedGenericType (storey);
713
714                         Statement.MutateHoistedGenericType (storey);
715                 }
716
717                 protected override void CloneTo (CloneContext clonectx, Statement t)
718                 {
719                         For target = (For) t;
720
721                         if (InitStatement != null)
722                                 target.InitStatement = InitStatement.Clone (clonectx);
723                         if (Test != null)
724                                 target.Test = Test.Clone (clonectx);
725                         if (Increment != null)
726                                 target.Increment = Increment.Clone (clonectx);
727                         target.Statement = Statement.Clone (clonectx);
728                 }
729         }
730         
731         public class StatementExpression : Statement {
732                 ExpressionStatement expr;
733                 
734                 public StatementExpression (ExpressionStatement expr)
735                 {
736                         this.expr = expr;
737                         loc = expr.Location;
738                 }
739
740                 public override bool Resolve (EmitContext ec)
741                 {
742                         if (expr != null)
743                                 expr = expr.ResolveStatement (ec);
744                         return expr != null;
745                 }
746                 
747                 protected override void DoEmit (EmitContext ec)
748                 {
749                         expr.EmitStatement (ec);
750                 }
751
752                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
753                 {
754                         expr.MutateHoistedGenericType (storey);
755                 }
756
757                 public override string ToString ()
758                 {
759                         return "StatementExpression (" + expr + ")";
760                 }
761
762                 protected override void CloneTo (CloneContext clonectx, Statement t)
763                 {
764                         StatementExpression target = (StatementExpression) t;
765
766                         target.expr = (ExpressionStatement) expr.Clone (clonectx);
767                 }
768         }
769
770         // A 'return' or a 'yield break'
771         public abstract class ExitStatement : Statement
772         {
773                 protected bool unwind_protect;
774                 protected abstract bool DoResolve (EmitContext ec);
775
776                 public virtual void Error_FinallyClause ()
777                 {
778                         Report.Error (157, loc, "Control cannot leave the body of a finally clause");
779                 }
780
781                 public sealed override bool Resolve (EmitContext ec)
782                 {
783                         if (!DoResolve (ec))
784                                 return false;
785
786                         unwind_protect = ec.CurrentBranching.AddReturnOrigin (ec.CurrentBranching.CurrentUsageVector, this);
787                         if (unwind_protect)
788                                 ec.NeedReturnLabel ();
789                         ec.CurrentBranching.CurrentUsageVector.Goto ();
790                         return true;
791                 }
792         }
793
794         /// <summary>
795         ///   Implements the return statement
796         /// </summary>
797         public class Return : ExitStatement {
798                 protected Expression Expr;
799                 public Return (Expression expr, Location l)
800                 {
801                         Expr = expr;
802                         loc = l;
803                 }
804                 
805                 protected override bool DoResolve (EmitContext ec)
806                 {
807                         if (Expr == null) {
808                                 if (ec.ReturnType == TypeManager.void_type)
809                                         return true;
810                                 
811                                 Error (126, "An object of a type convertible to `{0}' is required " +
812                                            "for the return statement",
813                                            TypeManager.CSharpName (ec.ReturnType));
814                                 return false;
815                         }
816
817                         if (ec.CurrentBlock.Toplevel.IsIterator) {
818                                 Report.Error (1622, loc, "Cannot return a value from iterators. Use the yield return " +
819                                                   "statement to return a value, or yield break to end the iteration");
820                         }
821
822                         AnonymousExpression am = ec.CurrentAnonymousMethod;
823                         if (am == null && ec.ReturnType == TypeManager.void_type) {
824                                 MemberCore mc = ec.ResolveContext as MemberCore;
825                                 Report.Error (127, loc, "`{0}': A return keyword must not be followed by any expression when method returns void",
826                                         mc.GetSignatureForError ());
827                         }
828
829                         Expr = Expr.Resolve (ec);
830                         if (Expr == null)
831                                 return false;
832
833                         if (Expr.Type != ec.ReturnType) {
834                                 if (ec.InferReturnType) {
835                                         //
836                                         // void cannot be used in contextual return
837                                         //
838                                         if (Expr.Type == TypeManager.void_type)
839                                                 return false;
840
841                                         ec.ReturnType = Expr.Type;
842                                 } else {
843                                         Expr = Convert.ImplicitConversionRequired (
844                                                 ec, Expr, ec.ReturnType, loc);
845
846                                         if (Expr == null) {
847                                                 if (am != null) {
848                                                         Report.Error (1662, loc,
849                                                                 "Cannot convert `{0}' to delegate type `{1}' because some of the return types in the block are not implicitly convertible to the delegate return type",
850                                                                 am.ContainerType, am.GetSignatureForError ());
851                                                 }
852                                                 return false;
853                                         }
854                                 }
855                         }
856
857                         return true;                    
858                 }
859                 
860                 protected override void DoEmit (EmitContext ec)
861                 {
862                         if (Expr != null) {
863                                 Expr.Emit (ec);
864
865                                 if (unwind_protect)
866                                         ec.ig.Emit (OpCodes.Stloc, ec.TemporaryReturn ());
867                         }
868
869                         if (unwind_protect)
870                                 ec.ig.Emit (OpCodes.Leave, ec.ReturnLabel);
871                         else
872                                 ec.ig.Emit (OpCodes.Ret);
873                 }
874
875                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
876                 {
877                         if (Expr != null)
878                                 Expr.MutateHoistedGenericType (storey);
879                 }
880
881                 protected override void CloneTo (CloneContext clonectx, Statement t)
882                 {
883                         Return target = (Return) t;
884                         // It's null for simple return;
885                         if (Expr != null)
886                                 target.Expr = Expr.Clone (clonectx);
887                 }
888         }
889
890         public class Goto : Statement {
891                 string target;
892                 LabeledStatement label;
893                 bool unwind_protect;
894                 
895                 public override bool Resolve (EmitContext ec)
896                 {
897                         int errors = Report.Errors;
898                         unwind_protect = ec.CurrentBranching.AddGotoOrigin (ec.CurrentBranching.CurrentUsageVector, this);
899                         ec.CurrentBranching.CurrentUsageVector.Goto ();
900                         return errors == Report.Errors;
901                 }
902                 
903                 public Goto (string label, Location l)
904                 {
905                         loc = l;
906                         target = label;
907                 }
908
909                 public string Target {
910                         get { return target; }
911                 }
912
913                 public void SetResolvedTarget (LabeledStatement label)
914                 {
915                         this.label = label;
916                         label.AddReference ();
917                 }
918
919                 protected override void CloneTo (CloneContext clonectx, Statement target)
920                 {
921                         // Nothing to clone
922                 }
923
924                 protected override void DoEmit (EmitContext ec)
925                 {
926                         if (label == null)
927                                 throw new InternalErrorException ("goto emitted before target resolved");
928                         Label l = label.LabelTarget (ec);
929                         ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, l);
930                 }
931
932                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
933                 {
934                 }
935         }
936
937         public class LabeledStatement : Statement {
938                 string name;
939                 bool defined;
940                 bool referenced;
941                 Label label;
942                 ILGenerator ig;
943
944                 FlowBranching.UsageVector vectors;
945                 
946                 public LabeledStatement (string name, Location l)
947                 {
948                         this.name = name;
949                         this.loc = l;
950                 }
951
952                 public Label LabelTarget (EmitContext ec)
953                 {
954                         if (defined)
955                                 return label;
956                         ig = ec.ig;
957                         label = ec.ig.DefineLabel ();
958                         defined = true;
959
960                         return label;
961                 }
962
963                 public string Name {
964                         get { return name; }
965                 }
966
967                 public bool IsDefined {
968                         get { return defined; }
969                 }
970
971                 public bool HasBeenReferenced {
972                         get { return referenced; }
973                 }
974
975                 public FlowBranching.UsageVector JumpOrigins {
976                         get { return vectors; }
977                 }
978
979                 public void AddUsageVector (FlowBranching.UsageVector vector)
980                 {
981                         vector = vector.Clone ();
982                         vector.Next = vectors;
983                         vectors = vector;
984                 }
985
986                 protected override void CloneTo (CloneContext clonectx, Statement target)
987                 {
988                         // nothing to clone
989                 }
990
991                 public override bool Resolve (EmitContext ec)
992                 {
993                         // this flow-branching will be terminated when the surrounding block ends
994                         ec.StartFlowBranching (this);
995                         return true;
996                 }
997
998                 protected override void DoEmit (EmitContext ec)
999                 {
1000                         if (ig != null && ig != ec.ig)
1001                                 throw new InternalErrorException ("cannot happen");
1002                         LabelTarget (ec);
1003                         ec.ig.MarkLabel (label);
1004                 }
1005
1006                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1007                 {
1008                 }
1009
1010                 public void AddReference ()
1011                 {
1012                         referenced = true;
1013                 }
1014         }
1015         
1016
1017         /// <summary>
1018         ///   `goto default' statement
1019         /// </summary>
1020         public class GotoDefault : Statement {
1021                 
1022                 public GotoDefault (Location l)
1023                 {
1024                         loc = l;
1025                 }
1026
1027                 protected override void CloneTo (CloneContext clonectx, Statement target)
1028                 {
1029                         // nothing to clone
1030                 }
1031
1032                 public override bool Resolve (EmitContext ec)
1033                 {
1034                         ec.CurrentBranching.CurrentUsageVector.Goto ();
1035                         return true;
1036                 }
1037
1038                 protected override void DoEmit (EmitContext ec)
1039                 {
1040                         if (ec.Switch == null){
1041                                 Report.Error (153, loc, "A goto case is only valid inside a switch statement");
1042                                 return;
1043                         }
1044
1045                         if (!ec.Switch.GotDefault){
1046                                 FlowBranchingBlock.Error_UnknownLabel (loc, "default");
1047                                 return;
1048                         }
1049                         ec.ig.Emit (OpCodes.Br, ec.Switch.DefaultTarget);
1050                 }
1051
1052                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1053                 {
1054                 }
1055         }
1056
1057         /// <summary>
1058         ///   `goto case' statement
1059         /// </summary>
1060         public class GotoCase : Statement {
1061                 Expression expr;
1062                 SwitchLabel sl;
1063                 
1064                 public GotoCase (Expression e, Location l)
1065                 {
1066                         expr = e;
1067                         loc = l;
1068                 }
1069
1070                 public override bool Resolve (EmitContext ec)
1071                 {
1072                         if (ec.Switch == null){
1073                                 Report.Error (153, loc, "A goto case is only valid inside a switch statement");
1074                                 return false;
1075                         }
1076
1077                         expr = expr.Resolve (ec);
1078                         if (expr == null)
1079                                 return false;
1080
1081                         Constant c = expr as Constant;
1082                         if (c == null) {
1083                                 Error (150, "A constant value is expected");
1084                                 return false;
1085                         }
1086
1087                         Type type = ec.Switch.SwitchType;
1088                         if (!Convert.ImplicitStandardConversionExists (c, type))
1089                                 Report.Warning (469, 2, loc, "The `goto case' value is not implicitly " +
1090                                                 "convertible to type `{0}'", TypeManager.CSharpName (type));
1091
1092                         bool fail = false;
1093                         object val = c.GetValue ();
1094                         if ((val != null) && (c.Type != type) && (c.Type != TypeManager.object_type))
1095                                 val = TypeManager.ChangeType (val, type, out fail);
1096
1097                         if (fail) {
1098                                 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
1099                                               c.GetSignatureForError (), TypeManager.CSharpName (type));
1100                                 return false;
1101                         }
1102
1103                         if (val == null)
1104                                 val = SwitchLabel.NullStringCase;
1105                                         
1106                         sl = (SwitchLabel) ec.Switch.Elements [val];
1107
1108                         if (sl == null){
1109                                 FlowBranchingBlock.Error_UnknownLabel (loc, "case " + 
1110                                         (c.GetValue () == null ? "null" : val.ToString ()));
1111                                 return false;
1112                         }
1113
1114                         ec.CurrentBranching.CurrentUsageVector.Goto ();
1115                         return true;
1116                 }
1117
1118                 protected override void DoEmit (EmitContext ec)
1119                 {
1120                         ec.ig.Emit (OpCodes.Br, sl.GetILLabelCode (ec));
1121                 }
1122
1123                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1124                 {
1125                         expr.MutateHoistedGenericType (storey);
1126                 }
1127
1128                 protected override void CloneTo (CloneContext clonectx, Statement t)
1129                 {
1130                         GotoCase target = (GotoCase) t;
1131
1132                         target.expr = expr.Clone (clonectx);
1133                 }
1134         }
1135         
1136         public class Throw : Statement {
1137                 Expression expr;
1138                 
1139                 public Throw (Expression expr, Location l)
1140                 {
1141                         this.expr = expr;
1142                         loc = l;
1143                 }
1144
1145                 public override bool Resolve (EmitContext ec)
1146                 {
1147                         if (expr == null) {
1148                                 ec.CurrentBranching.CurrentUsageVector.Goto ();
1149                                 return ec.CurrentBranching.CheckRethrow (loc);
1150                         }
1151
1152                         expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
1153                         ec.CurrentBranching.CurrentUsageVector.Goto ();
1154
1155                         if (expr == null)
1156                                 return false;
1157
1158                         Type t = expr.Type;
1159
1160                         if ((t != TypeManager.exception_type) &&
1161                             !TypeManager.IsSubclassOf (t, TypeManager.exception_type) &&
1162                             !(expr is NullLiteral)) {
1163                                 Error (155, "The type caught or thrown must be derived from System.Exception");
1164                                 return false;
1165                         }
1166                         return true;
1167                 }
1168                         
1169                 protected override void DoEmit (EmitContext ec)
1170                 {
1171                         if (expr == null)
1172                                 ec.ig.Emit (OpCodes.Rethrow);
1173                         else {
1174                                 expr.Emit (ec);
1175
1176                                 ec.ig.Emit (OpCodes.Throw);
1177                         }
1178                 }
1179
1180                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1181                 {
1182                         if (expr != null)
1183                                 expr.MutateHoistedGenericType (storey);
1184                 }
1185
1186                 protected override void CloneTo (CloneContext clonectx, Statement t)
1187                 {
1188                         Throw target = (Throw) t;
1189
1190                         if (expr != null)
1191                                 target.expr = expr.Clone (clonectx);
1192                 }
1193         }
1194
1195         public class Break : Statement {
1196                 
1197                 public Break (Location l)
1198                 {
1199                         loc = l;
1200                 }
1201
1202                 bool unwind_protect;
1203
1204                 public override bool Resolve (EmitContext ec)
1205                 {
1206                         int errors = Report.Errors;
1207                         unwind_protect = ec.CurrentBranching.AddBreakOrigin (ec.CurrentBranching.CurrentUsageVector, loc);
1208                         ec.CurrentBranching.CurrentUsageVector.Goto ();
1209                         return errors == Report.Errors;
1210                 }
1211
1212                 protected override void DoEmit (EmitContext ec)
1213                 {
1214                         ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopEnd);
1215                 }
1216
1217                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1218                 {
1219                 }
1220                 
1221                 protected override void CloneTo (CloneContext clonectx, Statement t)
1222                 {
1223                         // nothing needed
1224                 }
1225         }
1226
1227         public class Continue : Statement {
1228                 
1229                 public Continue (Location l)
1230                 {
1231                         loc = l;
1232                 }
1233
1234                 bool unwind_protect;
1235
1236                 public override bool Resolve (EmitContext ec)
1237                 {
1238                         int errors = Report.Errors;
1239                         unwind_protect = ec.CurrentBranching.AddContinueOrigin (ec.CurrentBranching.CurrentUsageVector, loc);
1240                         ec.CurrentBranching.CurrentUsageVector.Goto ();
1241                         return errors == Report.Errors;
1242                 }
1243
1244                 protected override void DoEmit (EmitContext ec)
1245                 {
1246                         ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopBegin);
1247                 }
1248
1249                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1250                 {
1251                 }
1252
1253                 protected override void CloneTo (CloneContext clonectx, Statement t)
1254                 {
1255                         // nothing needed.
1256                 }
1257         }
1258
1259         public interface ILocalVariable
1260         {
1261                 void Emit (EmitContext ec);
1262                 void EmitAssign (EmitContext ec);
1263                 void EmitAddressOf (EmitContext ec);
1264         }
1265
1266         public interface IKnownVariable {
1267                 Block Block { get; }
1268                 Location Location { get; }
1269         }
1270
1271         //
1272         // The information about a user-perceived local variable
1273         //
1274         public class LocalInfo : IKnownVariable, ILocalVariable {
1275                 public readonly Expression Type;
1276
1277                 public Type VariableType;
1278                 public readonly string Name;
1279                 public readonly Location Location;
1280                 public readonly Block Block;
1281
1282                 public VariableInfo VariableInfo;
1283                 public HoistedVariable HoistedVariableReference;
1284
1285                 [Flags]
1286                 enum Flags : byte {
1287                         Used = 1,
1288                         ReadOnly = 2,
1289                         Pinned = 4,
1290                         IsThis = 8,
1291                         AddressTaken = 32,
1292                         CompilerGenerated = 64,
1293                         IsConstant = 128
1294                 }
1295
1296                 public enum ReadOnlyContext: byte {
1297                         Using,
1298                         Foreach,
1299                         Fixed
1300                 }
1301
1302                 Flags flags;
1303                 ReadOnlyContext ro_context;
1304                 LocalBuilder builder;
1305                 
1306                 public LocalInfo (Expression type, string name, Block block, Location l)
1307                 {
1308                         Type = type;
1309                         Name = name;
1310                         Block = block;
1311                         Location = l;
1312                 }
1313
1314                 public LocalInfo (DeclSpace ds, Block block, Location l)
1315                 {
1316                         VariableType = ds.IsGeneric ? ds.CurrentType : ds.TypeBuilder;
1317                         Block = block;
1318                         Location = l;
1319                 }
1320
1321                 public void ResolveVariable (EmitContext ec)
1322                 {
1323                         if (HoistedVariableReference != null)
1324                                 return;
1325
1326                         if (builder == null) {
1327                                 if (Pinned)
1328                                         //
1329                                         // This is needed to compile on both .NET 1.x and .NET 2.x
1330                                         // the later introduced `DeclareLocal (Type t, bool pinned)'
1331                                         //
1332                                         builder = TypeManager.DeclareLocalPinned (ec.ig, VariableType);
1333                                 else
1334                                         builder = ec.ig.DeclareLocal (VariableType);
1335                         }
1336                 }
1337
1338                 public void Emit (EmitContext ec)
1339                 {
1340                         ec.ig.Emit (OpCodes.Ldloc, builder);
1341                 }
1342
1343                 public void EmitAssign (EmitContext ec)
1344                 {
1345                         ec.ig.Emit (OpCodes.Stloc, builder);
1346                 }
1347
1348                 public void EmitAddressOf (EmitContext ec)
1349                 {
1350                         ec.ig.Emit (OpCodes.Ldloca, builder);
1351                 }
1352
1353                 public void EmitSymbolInfo (EmitContext ec)
1354                 {
1355                         if (builder != null)
1356                                 ec.DefineLocalVariable (Name, builder);
1357                 }
1358
1359                 public bool IsThisAssigned (EmitContext ec)
1360                 {
1361                         if (VariableInfo == null)
1362                                 throw new Exception ();
1363
1364                         if (!ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (VariableInfo))
1365                                 return true;
1366
1367                         return VariableInfo.TypeInfo.IsFullyInitialized (ec.CurrentBranching, VariableInfo, ec.loc);
1368                 }
1369
1370                 public bool IsAssigned (EmitContext ec)
1371                 {
1372                         if (VariableInfo == null)
1373                                 throw new Exception ();
1374
1375                         return !ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (VariableInfo);
1376                 }
1377
1378                 public bool Resolve (EmitContext ec)
1379                 {
1380                         if (VariableType != null)
1381                                 return true;
1382
1383                         TypeExpr texpr = Type.ResolveAsContextualType (ec, false);
1384                         if (texpr == null)
1385                                 return false;
1386                                 
1387                         VariableType = texpr.Type;
1388
1389                         if (TypeManager.IsGenericParameter (VariableType))
1390                                 return true;
1391
1392                         if (VariableType == TypeManager.void_type) {
1393                                 Expression.Error_VoidInvalidInTheContext (Location);
1394                                 return false;
1395                         }
1396
1397                         if (VariableType.IsAbstract && VariableType.IsSealed) {
1398                                 FieldBase.Error_VariableOfStaticClass (Location, Name, VariableType);
1399                                 return false;
1400                         }
1401
1402                         if (VariableType.IsPointer && !ec.InUnsafe)
1403                                 Expression.UnsafeError (Location);
1404
1405                         return true;
1406                 }
1407
1408                 public bool IsConstant {
1409                         get { return (flags & Flags.IsConstant) != 0; }
1410                         set { flags |= Flags.IsConstant; }
1411                 }
1412
1413                 public bool AddressTaken {
1414                         get { return (flags & Flags.AddressTaken) != 0; }
1415                         set { flags |= Flags.AddressTaken; }
1416                 }
1417
1418                 public bool CompilerGenerated {
1419                         get { return (flags & Flags.CompilerGenerated) != 0; }
1420                         set { flags |= Flags.CompilerGenerated; }
1421                 }
1422
1423                 public override string ToString ()
1424                 {
1425                         return String.Format ("LocalInfo ({0},{1},{2},{3})",
1426                                               Name, Type, VariableInfo, Location);
1427                 }
1428
1429                 public bool Used {
1430                         get { return (flags & Flags.Used) != 0; }
1431                         set { flags = value ? (flags | Flags.Used) : (unchecked (flags & ~Flags.Used)); }
1432                 }
1433
1434                 public bool ReadOnly {
1435                         get { return (flags & Flags.ReadOnly) != 0; }
1436                 }
1437
1438                 public void SetReadOnlyContext (ReadOnlyContext context)
1439                 {
1440                         flags |= Flags.ReadOnly;
1441                         ro_context = context;
1442                 }
1443
1444                 public string GetReadOnlyContext ()
1445                 {
1446                         if (!ReadOnly)
1447                                 throw new InternalErrorException ("Variable is not readonly");
1448
1449                         switch (ro_context) {
1450                                 case ReadOnlyContext.Fixed:
1451                                         return "fixed variable";
1452                                 case ReadOnlyContext.Foreach:
1453                                         return "foreach iteration variable";
1454                                 case ReadOnlyContext.Using:
1455                                         return "using variable";
1456                         }
1457                         throw new NotImplementedException ();
1458                 }
1459
1460                 //
1461                 // Whether the variable is pinned, if Pinned the variable has been 
1462                 // allocated in a pinned slot with DeclareLocal.
1463                 //
1464                 public bool Pinned {
1465                         get { return (flags & Flags.Pinned) != 0; }
1466                         set { flags = value ? (flags | Flags.Pinned) : (flags & ~Flags.Pinned); }
1467                 }
1468
1469                 public bool IsThis {
1470                         get { return (flags & Flags.IsThis) != 0; }
1471                         set { flags = value ? (flags | Flags.IsThis) : (flags & ~Flags.IsThis); }
1472                 }
1473
1474                 Block IKnownVariable.Block {
1475                         get { return Block; }
1476                 }
1477
1478                 Location IKnownVariable.Location {
1479                         get { return Location; }
1480                 }
1481
1482                 public LocalInfo Clone (CloneContext clonectx)
1483                 {
1484                         //
1485                         // Variables in anonymous block are not resolved yet
1486                         //
1487                         if (VariableType == null)
1488                                 return new LocalInfo (Type.Clone (clonectx), Name, clonectx.LookupBlock (Block), Location);
1489
1490                         //
1491                         // Variables in method block are resolved
1492                         //
1493                         LocalInfo li = new LocalInfo (null, Name, clonectx.LookupBlock (Block), Location);
1494                         li.VariableType = VariableType;
1495                         return li;                      
1496                 }
1497         }
1498
1499         /// <summary>
1500         ///   Block represents a C# block.
1501         /// </summary>
1502         ///
1503         /// <remarks>
1504         ///   This class is used in a number of places: either to represent
1505         ///   explicit blocks that the programmer places or implicit blocks.
1506         ///
1507         ///   Implicit blocks are used as labels or to introduce variable
1508         ///   declarations.
1509         ///
1510         ///   Top-level blocks derive from Block, and they are called ToplevelBlock
1511         ///   they contain extra information that is not necessary on normal blocks.
1512         /// </remarks>
1513         public class Block : Statement {
1514                 public Block    Parent;
1515                 public readonly Location  StartLocation;
1516                 public Location EndLocation = Location.Null;
1517
1518                 public ExplicitBlock Explicit;
1519                 public ToplevelBlock Toplevel; // TODO: Use Explicit
1520
1521                 [Flags]
1522                 public enum Flags : byte {
1523                         Unchecked = 1,
1524                         BlockUsed = 2,
1525                         VariablesInitialized = 4,
1526                         HasRet = 8,
1527                         IsDestructor = 16,
1528                         Unsafe = 32,
1529                         IsIterator = 64,
1530                         HasStoreyAccess = 128
1531                 }
1532                 protected Flags flags;
1533
1534                 public bool Unchecked {
1535                         get { return (flags & Flags.Unchecked) != 0; }
1536                         set { flags = value ? flags | Flags.Unchecked : flags & ~Flags.Unchecked; }
1537                 }
1538
1539                 public bool Unsafe {
1540                         get { return (flags & Flags.Unsafe) != 0; }
1541                         set { flags |= Flags.Unsafe; }
1542                 }
1543
1544                 //
1545                 // The statements in this block
1546                 //
1547                 protected ArrayList statements;
1548
1549                 //
1550                 // An array of Blocks.  We keep track of children just
1551                 // to generate the local variable declarations.
1552                 //
1553                 // Statements and child statements are handled through the
1554                 // statements.
1555                 //
1556                 ArrayList children;
1557
1558                 //
1559                 // Labels.  (label, block) pairs.
1560                 //
1561                 protected HybridDictionary labels;
1562
1563                 //
1564                 // Keeps track of (name, type) pairs
1565                 //
1566                 IDictionary variables;
1567                 protected IDictionary range_variables;
1568
1569                 //
1570                 // Keeps track of constants
1571                 HybridDictionary constants;
1572
1573                 //
1574                 // Temporary variables.
1575                 //
1576                 ArrayList temporary_variables;
1577                 
1578                 //
1579                 // If this is a switch section, the enclosing switch block.
1580                 //
1581                 Block switch_block;
1582
1583                 ArrayList scope_initializers;
1584
1585                 ArrayList anonymous_children;
1586
1587                 protected static int id;
1588
1589                 int this_id;
1590
1591                 int assignable_slots;
1592                 bool unreachable_shown;
1593                 bool unreachable;
1594                 
1595                 public Block (Block parent)
1596                         : this (parent, (Flags) 0, Location.Null, Location.Null)
1597                 { }
1598
1599                 public Block (Block parent, Flags flags)
1600                         : this (parent, flags, Location.Null, Location.Null)
1601                 { }
1602
1603                 public Block (Block parent, Location start, Location end)
1604                         : this (parent, (Flags) 0, start, end)
1605                 { }
1606
1607                 public Block (Block parent, Flags flags, Location start, Location end)
1608                 {
1609                         if (parent != null) {
1610                                 parent.AddChild (this);
1611
1612                                 // the appropriate constructors will fixup these fields
1613                                 Toplevel = parent.Toplevel;
1614                                 Explicit = parent.Explicit;
1615                         }
1616                         
1617                         this.Parent = parent;
1618                         this.flags = flags;
1619                         this.StartLocation = start;
1620                         this.EndLocation = end;
1621                         this.loc = start;
1622                         this_id = id++;
1623                         statements = new ArrayList (4);
1624                 }
1625
1626                 public Block CreateSwitchBlock (Location start)
1627                 {
1628                         // FIXME: should this be implicit?
1629                         Block new_block = new ExplicitBlock (this, start, start);
1630                         new_block.switch_block = this;
1631                         return new_block;
1632                 }
1633
1634                 public int ID {
1635                         get { return this_id; }
1636                 }
1637
1638                 public IDictionary Variables {
1639                         get {
1640                                 if (variables == null)
1641                                         variables = new ListDictionary ();
1642                                 return variables;
1643                         }
1644                 }
1645
1646                 void AddChild (Block b)
1647                 {
1648                         if (children == null)
1649                                 children = new ArrayList (1);
1650                         
1651                         children.Add (b);
1652                 }
1653
1654                 public void SetEndLocation (Location loc)
1655                 {
1656                         EndLocation = loc;
1657                 }
1658
1659                 protected static void Error_158 (string name, Location loc)
1660                 {
1661                         Report.Error (158, loc, "The label `{0}' shadows another label " +
1662                                       "by the same name in a contained scope", name);
1663                 }
1664
1665                 /// <summary>
1666                 ///   Adds a label to the current block. 
1667                 /// </summary>
1668                 ///
1669                 /// <returns>
1670                 ///   false if the name already exists in this block. true
1671                 ///   otherwise.
1672                 /// </returns>
1673                 ///
1674                 public bool AddLabel (LabeledStatement target)
1675                 {
1676                         if (switch_block != null)
1677                                 return switch_block.AddLabel (target);
1678
1679                         string name = target.Name;
1680
1681                         Block cur = this;
1682                         while (cur != null) {
1683                                 LabeledStatement s = cur.DoLookupLabel (name);
1684                                 if (s != null) {
1685                                         Report.SymbolRelatedToPreviousError (s.loc, s.Name);
1686                                         Report.Error (140, target.loc, "The label `{0}' is a duplicate", name);
1687                                         return false;
1688                                 }
1689
1690                                 if (this == Explicit)
1691                                         break;
1692
1693                                 cur = cur.Parent;
1694                         }
1695
1696                         while (cur != null) {
1697                                 if (cur.DoLookupLabel (name) != null) {
1698                                         Error_158 (name, target.loc);
1699                                         return false;
1700                                 }
1701
1702                                 if (children != null) {
1703                                         foreach (Block b in children) {
1704                                                 LabeledStatement s = b.DoLookupLabel (name);
1705                                                 if (s == null)
1706                                                         continue;
1707
1708                                                 Report.SymbolRelatedToPreviousError (s.loc, s.Name);
1709                                                 Error_158 (name, target.loc);
1710                                                 return false;
1711                                         }
1712                                 }
1713
1714                                 cur = cur.Parent;
1715                         }
1716
1717                         Toplevel.CheckError158 (name, target.loc);
1718
1719                         if (labels == null)
1720                                 labels = new HybridDictionary();
1721
1722                         labels.Add (name, target);
1723                         return true;
1724                 }
1725
1726                 public LabeledStatement LookupLabel (string name)
1727                 {
1728                         LabeledStatement s = DoLookupLabel (name);
1729                         if (s != null)
1730                                 return s;
1731
1732                         if (children == null)
1733                                 return null;
1734
1735                         foreach (Block child in children) {
1736                                 if (Explicit != child.Explicit)
1737                                         continue;
1738
1739                                 s = child.LookupLabel (name);
1740                                 if (s != null)
1741                                         return s;
1742                         }
1743
1744                         return null;
1745                 }
1746
1747                 LabeledStatement DoLookupLabel (string name)
1748                 {
1749                         if (switch_block != null)
1750                                 return switch_block.LookupLabel (name);
1751
1752                         if (labels != null)
1753                                 if (labels.Contains (name))
1754                                         return ((LabeledStatement) labels [name]);
1755
1756                         return null;
1757                 }
1758
1759                 public bool CheckInvariantMeaningInBlock (string name, Expression e, Location loc)
1760                 {
1761                         Block b = this;
1762                         IKnownVariable kvi = b.Explicit.GetKnownVariable (name);
1763                         while (kvi == null) {
1764                                 b = b.Explicit.Parent;
1765                                 if (b == null)
1766                                         return true;
1767                                 kvi = b.Explicit.GetKnownVariable (name);
1768                         }
1769
1770                         if (kvi.Block == b)
1771                                 return true;
1772
1773                         // Is kvi.Block nested inside 'b'
1774                         if (b.Explicit != kvi.Block.Explicit) {
1775                                 //
1776                                 // If a variable by the same name it defined in a nested block of this
1777                                 // block, we violate the invariant meaning in a block.
1778                                 //
1779                                 if (b == this) {
1780                                         Report.SymbolRelatedToPreviousError (kvi.Location, name);
1781                                         Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", name);
1782                                         return false;
1783                                 }
1784
1785                                 //
1786                                 // It's ok if the definition is in a nested subblock of b, but not
1787                                 // nested inside this block -- a definition in a sibling block
1788                                 // should not affect us.
1789                                 //
1790                                 return true;
1791                         }
1792
1793                         //
1794                         // Block 'b' and kvi.Block are the same textual block.
1795                         // However, different variables are extant.
1796                         //
1797                         // Check if the variable is in scope in both blocks.  We use
1798                         // an indirect check that depends on AddVariable doing its
1799                         // part in maintaining the invariant-meaning-in-block property.
1800                         //
1801                         if (e is VariableReference || (e is Constant && b.GetLocalInfo (name) != null))
1802                                 return true;
1803
1804                         if (this is ToplevelBlock) {
1805                                 Report.SymbolRelatedToPreviousError (kvi.Location, name);
1806                                 e.Error_VariableIsUsedBeforeItIsDeclared (name);
1807                                 return false;
1808                         }
1809
1810                         //
1811                         // Even though we detected the error when the name is used, we
1812                         // treat it as if the variable declaration was in error.
1813                         //
1814                         Report.SymbolRelatedToPreviousError (loc, name);
1815                         Error_AlreadyDeclared (kvi.Location, name, "parent or current");
1816                         return false;
1817                 }
1818
1819                 public LocalInfo AddVariable (Expression type, string name, Location l)
1820                 {
1821                         LocalInfo vi = GetLocalInfo (name);
1822                         if (vi != null) {
1823                                 Report.SymbolRelatedToPreviousError (vi.Location, name);
1824                                 if (Explicit == vi.Block.Explicit) {
1825                                         if (type == Linq.ImplicitQueryParameter.ImplicitType.Instance && type == vi.Type)
1826                                                 Error_AlreadyDeclared (l, name);
1827                                         else
1828                                                 Error_AlreadyDeclared (l, name, null);
1829                                 } else {
1830                                         Error_AlreadyDeclared (l, name, "parent");
1831                                 }
1832                                 return null;
1833                         }
1834
1835                         ToplevelParameterInfo pi = Toplevel.GetParameterInfo (name);
1836                         if (pi != null) {
1837                                 Report.SymbolRelatedToPreviousError (pi.Location, name);
1838                                 Error_AlreadyDeclared (loc, name,
1839                                         pi.Block == Toplevel ? "method argument" : "parent or current");
1840                                 return null;
1841                         }
1842                         
1843                         if (Toplevel.GenericMethod != null) {
1844                                 foreach (TypeParameter tp in Toplevel.GenericMethod.CurrentTypeParameters) {
1845                                         if (tp.Name == name) {
1846                                                 Report.SymbolRelatedToPreviousError (tp);
1847                                                 Error_AlreadyDeclaredTypeParameter (loc, name);
1848                                                 return null;
1849                                         }
1850                                 }
1851                         }                       
1852
1853                         IKnownVariable kvi = Explicit.GetKnownVariable (name);
1854                         if (kvi != null) {
1855                                 Report.SymbolRelatedToPreviousError (kvi.Location, name);
1856                                 Error_AlreadyDeclared (l, name, "child");
1857                                 return null;
1858                         }
1859
1860                         vi = new LocalInfo (type, name, this, l);
1861                         AddVariable (vi);
1862
1863                         if ((flags & Flags.VariablesInitialized) != 0)
1864                                 throw new InternalErrorException ("block has already been resolved");
1865
1866                         return vi;
1867                 }
1868                 
1869                 protected virtual void AddVariable (LocalInfo li)
1870                 {
1871                         Variables.Add (li.Name, li);
1872                         Explicit.AddKnownVariable (li.Name, li);
1873                 }
1874
1875                 protected virtual void Error_AlreadyDeclared (Location loc, string var, string reason)
1876                 {
1877                         if (reason == null) {
1878                                 Error_AlreadyDeclared (loc, var);
1879                                 return;
1880                         }
1881                         
1882                         Report.Error (136, loc, "A local variable named `{0}' cannot be declared " +
1883                                       "in this scope because it would give a different meaning " +
1884                                       "to `{0}', which is already used in a `{1}' scope " +
1885                                       "to denote something else", var, reason);
1886                 }
1887
1888                 protected virtual void Error_AlreadyDeclared (Location loc, string name)
1889                 {
1890                         Report.Error (128, loc,
1891                                 "A local variable named `{0}' is already defined in this scope", name);
1892                 }
1893                                         
1894                 protected virtual void Error_AlreadyDeclaredTypeParameter (Location loc, string name)
1895                 {
1896                         GenericMethod.Error_ParameterNameCollision (loc, name, "local variable");
1897                 }                                       
1898
1899                 public bool AddConstant (Expression type, string name, Expression value, Location l)
1900                 {
1901                         if (AddVariable (type, name, l) == null)
1902                                 return false;
1903                         
1904                         if (constants == null)
1905                                 constants = new HybridDictionary();
1906
1907                         constants.Add (name, value);
1908
1909                         // A block is considered used if we perform an initialization in a local declaration, even if it is constant.
1910                         Use ();
1911                         return true;
1912                 }
1913
1914                 static int next_temp_id = 0;
1915
1916                 public LocalInfo AddTemporaryVariable (TypeExpr te, Location loc)
1917                 {
1918                         Report.Debug (64, "ADD TEMPORARY", this, Toplevel, loc);
1919
1920                         if (temporary_variables == null)
1921                                 temporary_variables = new ArrayList ();
1922
1923                         int id = ++next_temp_id;
1924                         string name = "$s_" + id.ToString ();
1925
1926                         LocalInfo li = new LocalInfo (te, name, this, loc);
1927                         li.CompilerGenerated = true;
1928                         temporary_variables.Add (li);
1929                         return li;
1930                 }
1931
1932                 public LocalInfo GetLocalInfo (string name)
1933                 {
1934                         LocalInfo ret;
1935                         for (Block b = this; b != null; b = b.Parent) {
1936                                 if (b.variables != null) {
1937                                         ret = (LocalInfo) b.variables [name];
1938                                         if (ret != null)
1939                                                 return ret;
1940                                 }
1941
1942                                 if (b.range_variables != null) {
1943                                         ret = (LocalInfo) b.range_variables [name];
1944                                         if (ret != null)
1945                                                 return ret;
1946                                 }
1947                         }
1948
1949                         return null;
1950                 }
1951
1952                 public Expression GetVariableType (string name)
1953                 {
1954                         LocalInfo vi = GetLocalInfo (name);
1955                         return vi == null ? null : vi.Type;
1956                 }
1957
1958                 public Expression GetConstantExpression (string name)
1959                 {
1960                         for (Block b = this; b != null; b = b.Parent) {
1961                                 if (b.constants != null) {
1962                                         Expression ret = b.constants [name] as Expression;
1963                                         if (ret != null)
1964                                                 return ret;
1965                                 }
1966                         }
1967                         return null;
1968                 }
1969
1970                 //
1971                 // It should be used by expressions which require to
1972                 // register a statement during resolve process.
1973                 //
1974                 public void AddScopeStatement (StatementExpression s)
1975                 {
1976                         if (scope_initializers == null)
1977                                 scope_initializers = new ArrayList ();
1978
1979                         scope_initializers.Add (s);
1980                 }
1981                 
1982                 public void AddStatement (Statement s)
1983                 {
1984                         statements.Add (s);
1985                         flags |= Flags.BlockUsed;
1986                 }
1987
1988                 public bool Used {
1989                         get { return (flags & Flags.BlockUsed) != 0; }
1990                 }
1991
1992                 public void Use ()
1993                 {
1994                         flags |= Flags.BlockUsed;
1995                 }
1996
1997                 public bool HasRet {
1998                         get { return (flags & Flags.HasRet) != 0; }
1999                 }
2000
2001                 public bool IsDestructor {
2002                         get { return (flags & Flags.IsDestructor) != 0; }
2003                 }
2004
2005                 public void SetDestructor ()
2006                 {
2007                         flags |= Flags.IsDestructor;
2008                 }
2009
2010                 public int AssignableSlots {
2011                         get {
2012 // TODO: Re-enable                      
2013 //                              if ((flags & Flags.VariablesInitialized) == 0)
2014 //                                      throw new Exception ("Variables have not been initialized yet");
2015                                 return assignable_slots;
2016                         }
2017                 }
2018
2019                 public ArrayList AnonymousChildren {
2020                         get { return anonymous_children; }
2021                 }
2022
2023                 public void AddAnonymousChild (ToplevelBlock b)
2024                 {
2025                         if (anonymous_children == null)
2026                                 anonymous_children = new ArrayList ();
2027
2028                         anonymous_children.Add (b);
2029                 }
2030
2031                 void DoResolveConstants (EmitContext ec)
2032                 {
2033                         if (constants == null)
2034                                 return;
2035
2036                         if (variables == null)
2037                                 throw new InternalErrorException ("cannot happen");
2038
2039                         foreach (DictionaryEntry de in variables) {
2040                                 string name = (string) de.Key;
2041                                 LocalInfo vi = (LocalInfo) de.Value;
2042                                 Type variable_type = vi.VariableType;
2043
2044                                 if (variable_type == null) {
2045                                         if (vi.Type is VarExpr)
2046                                                 Report.Error (822, vi.Type.Location, "An implicitly typed local variable cannot be a constant");
2047
2048                                         continue;
2049                                 }
2050
2051                                 Expression cv = (Expression) constants [name];
2052                                 if (cv == null)
2053                                         continue;
2054
2055                                 // Don't let 'const int Foo = Foo;' succeed.
2056                                 // Removing the name from 'constants' ensures that we get a LocalVariableReference below,
2057                                 // which in turn causes the 'must be constant' error to be triggered.
2058                                 constants.Remove (name);
2059
2060                                 if (!Const.IsConstantTypeValid (variable_type)) {
2061                                         Const.Error_InvalidConstantType (variable_type, loc);
2062                                         continue;
2063                                 }
2064
2065                                 ec.CurrentBlock = this;
2066                                 Expression e;
2067                                 using (ec.With (EmitContext.Flags.ConstantCheckState, (flags & Flags.Unchecked) == 0)) {
2068                                         e = cv.Resolve (ec);
2069                                 }
2070                                 if (e == null)
2071                                         continue;
2072
2073                                 Constant ce = e as Constant;
2074                                 if (ce == null) {
2075                                         Const.Error_ExpressionMustBeConstant (vi.Location, name);
2076                                         continue;
2077                                 }
2078
2079                                 e = ce.ConvertImplicitly (variable_type);
2080                                 if (e == null) {
2081                                         if (TypeManager.IsReferenceType (variable_type))
2082                                                 Const.Error_ConstantCanBeInitializedWithNullOnly (vi.Location, vi.Name);
2083                                         else
2084                                                 ce.Error_ValueCannotBeConverted (ec, vi.Location, variable_type, false);
2085                                         continue;
2086                                 }
2087
2088                                 constants.Add (name, e);
2089                                 vi.IsConstant = true;
2090                         }
2091                 }
2092
2093                 protected void ResolveMeta (EmitContext ec, int offset)
2094                 {
2095                         Report.Debug (64, "BLOCK RESOLVE META", this, Parent);
2096
2097                         // If some parent block was unsafe, we remain unsafe even if this block
2098                         // isn't explicitly marked as such.
2099                         using (ec.With (EmitContext.Flags.InUnsafe, ec.InUnsafe | Unsafe)) {
2100                                 flags |= Flags.VariablesInitialized;
2101
2102                                 if (variables != null) {
2103                                         foreach (LocalInfo li in variables.Values) {
2104                                                 if (!li.Resolve (ec))
2105                                                         continue;
2106                                                 li.VariableInfo = new VariableInfo (li, offset);
2107                                                 offset += li.VariableInfo.Length;
2108                                         }
2109                                 }
2110                                 assignable_slots = offset;
2111
2112                                 DoResolveConstants (ec);
2113
2114                                 if (children == null)
2115                                         return;
2116                                 foreach (Block b in children)
2117                                         b.ResolveMeta (ec, offset);
2118                         }
2119                 }
2120
2121                 //
2122                 // Emits the local variable declarations for a block
2123                 //
2124                 public virtual void EmitMeta (EmitContext ec)
2125                 {
2126                         if (variables != null){
2127                                 foreach (LocalInfo vi in variables.Values)
2128                                         vi.ResolveVariable (ec);
2129                         }
2130
2131                         if (temporary_variables != null) {
2132                                 for (int i = 0; i < temporary_variables.Count; i++)
2133                                         ((LocalInfo)temporary_variables[i]).ResolveVariable(ec);
2134                         }
2135
2136                         if (children != null) {
2137                                 for (int i = 0; i < children.Count; i++)
2138                                         ((Block)children[i]).EmitMeta(ec);
2139                         }
2140                 }
2141
2142                 void UsageWarning ()
2143                 {
2144                         if (variables == null || Report.WarningLevel < 3)
2145                                 return;
2146
2147                         foreach (DictionaryEntry de in variables) {
2148                                 LocalInfo vi = (LocalInfo) de.Value;
2149
2150                                 if (!vi.Used) {
2151                                         string name = (string) de.Key;
2152
2153                                         // vi.VariableInfo can be null for 'catch' variables
2154                                         if (vi.VariableInfo != null && vi.VariableInfo.IsEverAssigned)
2155                                                 Report.Warning (219, 3, vi.Location, "The variable `{0}' is assigned but its value is never used", name);
2156                                         else
2157                                                 Report.Warning (168, 3, vi.Location, "The variable `{0}' is declared but never used", name);
2158                                 }
2159                         }
2160                 }
2161
2162                 static void CheckPossibleMistakenEmptyStatement (Statement s)
2163                 {
2164                         Statement body;
2165
2166                         // Some statements are wrapped by a Block. Since
2167                         // others' internal could be changed, here I treat
2168                         // them as possibly wrapped by Block equally.
2169                         Block b = s as Block;
2170                         if (b != null && b.statements.Count == 1)
2171                                 s = (Statement) b.statements [0];
2172
2173                         if (s is Lock)
2174                                 body = ((Lock) s).Statement;
2175                         else if (s is For)
2176                                 body = ((For) s).Statement;
2177                         else if (s is Foreach)
2178                                 body = ((Foreach) s).Statement;
2179                         else if (s is While)
2180                                 body = ((While) s).Statement;
2181                         else if (s is Fixed)
2182                                 body = ((Fixed) s).Statement;
2183                         else if (s is Using)
2184                                 body = ((Using) s).EmbeddedStatement;
2185                         else if (s is UsingTemporary)
2186                                 body = ((UsingTemporary) s).Statement;
2187                         else
2188                                 return;
2189
2190                         if (body == null || body is EmptyStatement)
2191                                 Report.Warning (642, 3, s.loc, "Possible mistaken empty statement");
2192                 }
2193
2194                 public override bool Resolve (EmitContext ec)
2195                 {
2196                         Block prev_block = ec.CurrentBlock;
2197                         bool ok = true;
2198
2199                         int errors = Report.Errors;
2200
2201                         ec.CurrentBlock = this;
2202                         ec.StartFlowBranching (this);
2203
2204                         Report.Debug (4, "RESOLVE BLOCK", StartLocation, ec.CurrentBranching);
2205
2206                         //
2207                         // This flag is used to notate nested statements as unreachable from the beginning of this block.
2208                         // For the purposes of this resolution, it doesn't matter that the whole block is unreachable 
2209                         // from the beginning of the function.  The outer Resolve() that detected the unreachability is
2210                         // responsible for handling the situation.
2211                         //
2212                         int statement_count = statements.Count;
2213                         for (int ix = 0; ix < statement_count; ix++){
2214                                 Statement s = (Statement) statements [ix];
2215                                 // Check possible empty statement (CS0642)
2216                                 if (Report.WarningLevel >= 3 &&
2217                                         ix + 1 < statement_count &&
2218                                                 statements [ix + 1] is Block)
2219                                         CheckPossibleMistakenEmptyStatement (s);
2220
2221                                 //
2222                                 // Warn if we detect unreachable code.
2223                                 //
2224                                 if (unreachable) {
2225                                         if (s is EmptyStatement)
2226                                                 continue;
2227
2228                                         if (!unreachable_shown && !(s is LabeledStatement)) {
2229                                                 Report.Warning (162, 2, s.loc, "Unreachable code detected");
2230                                                 unreachable_shown = true;
2231                                         }
2232
2233                                         Block c_block = s as Block;
2234                                         if (c_block != null)
2235                                                 c_block.unreachable = c_block.unreachable_shown = true;
2236                                 }
2237
2238                                 //
2239                                 // Note that we're not using ResolveUnreachable() for unreachable
2240                                 // statements here.  ResolveUnreachable() creates a temporary
2241                                 // flow branching and kills it afterwards.  This leads to problems
2242                                 // if you have two unreachable statements where the first one
2243                                 // assigns a variable and the second one tries to access it.
2244                                 //
2245
2246                                 if (!s.Resolve (ec)) {
2247                                         ok = false;
2248                                         if (ec.IsInProbingMode)
2249                                                 break;
2250
2251                                         statements [ix] = EmptyStatement.Value;
2252                                         continue;
2253                                 }
2254
2255                                 if (unreachable && !(s is LabeledStatement) && !(s is Block))
2256                                         statements [ix] = EmptyStatement.Value;
2257
2258                                 unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
2259                                 if (unreachable && s is LabeledStatement)
2260                                         throw new InternalErrorException ("should not happen");
2261                         }
2262
2263                         Report.Debug (4, "RESOLVE BLOCK DONE", StartLocation,
2264                                       ec.CurrentBranching, statement_count);
2265
2266                         while (ec.CurrentBranching is FlowBranchingLabeled)
2267                                 ec.EndFlowBranching ();
2268
2269                         bool flow_unreachable = ec.EndFlowBranching ();
2270
2271                         ec.CurrentBlock = prev_block;
2272
2273                         if (flow_unreachable)
2274                                 flags |= Flags.HasRet;
2275
2276                         // If we're a non-static `struct' constructor which doesn't have an
2277                         // initializer, then we must initialize all of the struct's fields.
2278                         if (this == Toplevel && !Toplevel.IsThisAssigned (ec) && !flow_unreachable)
2279                                 ok = false;
2280
2281                         if ((labels != null) && (Report.WarningLevel >= 2)) {
2282                                 foreach (LabeledStatement label in labels.Values)
2283                                         if (!label.HasBeenReferenced)
2284                                                 Report.Warning (164, 2, label.loc, "This label has not been referenced");
2285                         }
2286
2287                         if (ok && errors == Report.Errors)
2288                                 UsageWarning ();
2289
2290                         return ok;
2291                 }
2292
2293                 public override bool ResolveUnreachable (EmitContext ec, bool warn)
2294                 {
2295                         unreachable_shown = true;
2296                         unreachable = true;
2297
2298                         if (warn)
2299                                 Report.Warning (162, 2, loc, "Unreachable code detected");
2300
2301                         ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc);
2302                         bool ok = Resolve (ec);
2303                         ec.KillFlowBranching ();
2304
2305                         return ok;
2306                 }
2307                 
2308                 protected override void DoEmit (EmitContext ec)
2309                 {
2310                         for (int ix = 0; ix < statements.Count; ix++){
2311                                 Statement s = (Statement) statements [ix];
2312                                 s.Emit (ec);
2313                         }
2314                 }
2315
2316                 public override void Emit (EmitContext ec)
2317                 {
2318                         Block prev_block = ec.CurrentBlock;
2319                         ec.CurrentBlock = this;
2320
2321                         if (scope_initializers != null) {
2322                                 SymbolWriter.OpenCompilerGeneratedBlock (ec.ig);
2323
2324                                 bool omit_debug_info = ec.OmitDebuggingInfo;
2325                                 ec.OmitDebuggingInfo = true;
2326                                 foreach (StatementExpression s in scope_initializers)
2327                                         s.Emit (ec);
2328                                 ec.OmitDebuggingInfo = omit_debug_info;
2329
2330                                 SymbolWriter.CloseCompilerGeneratedBlock (ec.ig);
2331                         }
2332
2333                         ec.Mark (StartLocation);
2334                         DoEmit (ec);
2335
2336                         if (SymbolWriter.HasSymbolWriter)
2337                                 EmitSymbolInfo (ec);
2338
2339                         ec.CurrentBlock = prev_block;
2340                 }
2341
2342                 protected virtual void EmitSymbolInfo (EmitContext ec)
2343                 {
2344                         if (variables != null) {
2345                                 foreach (LocalInfo vi in variables.Values) {
2346                                         vi.EmitSymbolInfo (ec);
2347                                 }
2348                         }
2349                 }
2350
2351                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2352                 {
2353                         MutateVariables (storey);
2354
2355                         foreach (Statement s in statements)
2356                                 s.MutateHoistedGenericType (storey);
2357                 }
2358
2359                 void MutateVariables (AnonymousMethodStorey storey)
2360                 {
2361                         if (variables != null) {
2362                                 foreach (LocalInfo vi in variables.Values) {
2363                                         vi.VariableType = storey.MutateType (vi.VariableType);
2364                                 }
2365                         }
2366
2367                         if (temporary_variables != null) {
2368                                 foreach (LocalInfo vi in temporary_variables)
2369                                         vi.VariableType = storey.MutateType (vi.VariableType);
2370                         }
2371                 }
2372
2373                 public override string ToString ()
2374                 {
2375                         return String.Format ("{0} ({1}:{2})", GetType (),ID, StartLocation);
2376                 }
2377
2378                 protected override void CloneTo (CloneContext clonectx, Statement t)
2379                 {
2380                         Block target = (Block) t;
2381
2382                         clonectx.AddBlockMap (this, target);
2383
2384                         //target.Toplevel = (ToplevelBlock) clonectx.LookupBlock (Toplevel);
2385                         target.Explicit = (ExplicitBlock) clonectx.LookupBlock (Explicit);
2386                         if (Parent != null)
2387                                 target.Parent = clonectx.RemapBlockCopy (Parent);
2388
2389                         if (variables != null){
2390                                 target.variables = new Hashtable ();
2391
2392                                 foreach (DictionaryEntry de in variables){
2393                                         LocalInfo newlocal = ((LocalInfo) de.Value).Clone (clonectx);
2394                                         target.variables [de.Key] = newlocal;
2395                                         clonectx.AddVariableMap ((LocalInfo) de.Value, newlocal);
2396                                 }
2397                         }
2398
2399                         target.statements = new ArrayList (statements.Count);
2400                         foreach (Statement s in statements)
2401                                 target.statements.Add (s.Clone (clonectx));
2402
2403                         if (target.children != null){
2404                                 target.children = new ArrayList (children.Count);
2405                                 foreach (Block b in children){
2406                                         target.children.Add (clonectx.LookupBlock (b));
2407                                 }
2408                         }
2409
2410                         //
2411                         // TODO: labels, switch_block, constants (?), anonymous_children
2412                         //
2413                 }
2414         }
2415
2416         public class ExplicitBlock : Block {
2417                 HybridDictionary known_variables;
2418                 protected AnonymousMethodStorey am_storey;
2419
2420                 public ExplicitBlock (Block parent, Location start, Location end)
2421                         : this (parent, (Flags) 0, start, end)
2422                 {
2423                 }
2424
2425                 public ExplicitBlock (Block parent, Flags flags, Location start, Location end)
2426                         : base (parent, flags, start, end)
2427                 {
2428                         this.Explicit = this;
2429                 }
2430
2431                 // <summary>
2432                 //   Marks a variable with name @name as being used in this or a child block.
2433                 //   If a variable name has been used in a child block, it's illegal to
2434                 //   declare a variable with the same name in the current block.
2435                 // </summary>
2436                 internal void AddKnownVariable (string name, IKnownVariable info)
2437                 {
2438                         if (known_variables == null)
2439                                 known_variables = new HybridDictionary();
2440
2441                         known_variables [name] = info;
2442
2443                         if (Parent != null)
2444                                 Parent.Explicit.AddKnownVariable (name, info);
2445                 }
2446
2447                 public AnonymousMethodStorey AnonymousMethodStorey {
2448                         get { return am_storey; }
2449                 }
2450
2451                 //
2452                 // Creates anonymous method storey in current block
2453                 //
2454                 public AnonymousMethodStorey CreateAnonymousMethodStorey (EmitContext ec)
2455                 {
2456                         //
2457                         // When referencing a variable in iterator storey from children anonymous method
2458                         //
2459                         if (Toplevel.am_storey is IteratorStorey) {
2460                                 ec.CurrentAnonymousMethod.AddStoreyReference (Toplevel.am_storey);
2461                                 return Toplevel.am_storey;
2462                         }
2463
2464                         //
2465                         // An iterator has only 1 storey block
2466                         //
2467                         if (ec.CurrentIterator != null)
2468                             return ec.CurrentIterator.Storey;
2469
2470                         if (am_storey == null) {
2471                                 MemberBase mc = ec.ResolveContext as MemberBase;
2472                                 GenericMethod gm = mc == null ? null : mc.GenericMethod;
2473
2474                                 //
2475                                 // Create anonymous method storey for this block
2476                                 //
2477                                 am_storey = new AnonymousMethodStorey (this, ec.TypeContainer, mc, gm, "AnonStorey");
2478                         }
2479
2480                         //
2481                         // Creates a link between this block and the anonymous method
2482                         //
2483                         // An anonymous method can reference variables from any outer block, but they are
2484                         // hoisted in their own ExplicitBlock. When more than one block is referenced we
2485                         // need to create another link between those variable storeys
2486                         //
2487                         ec.CurrentAnonymousMethod.AddStoreyReference (am_storey);
2488                         return am_storey;
2489                 }
2490
2491                 public override void Emit (EmitContext ec)
2492                 {
2493                         if (am_storey != null)
2494                                 am_storey.EmitHoistedVariables (ec);
2495
2496                         bool emit_debug_info = SymbolWriter.HasSymbolWriter && Parent != null && !(am_storey is IteratorStorey);
2497                         if (emit_debug_info)
2498                                 ec.BeginScope ();
2499
2500                         base.Emit (ec);
2501
2502                         if (emit_debug_info)
2503                                 ec.EndScope ();
2504                 }
2505
2506                 public override void EmitMeta (EmitContext ec)
2507                 {
2508                         //
2509                         // Creates anonymous method storey
2510                         //
2511                         if (am_storey != null) {
2512                                 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.Storey != null) {
2513                                         am_storey.ChangeParentStorey (ec.CurrentAnonymousMethod.Storey);
2514                                 }
2515
2516                                 am_storey.DefineType ();
2517                                 am_storey.ResolveType ();                               
2518                                 am_storey.DefineMembers ();
2519                                 am_storey.Parent.PartialContainer.AddCompilerGeneratedClass (am_storey);
2520                         }
2521
2522                         base.EmitMeta (ec);
2523                 }
2524
2525                 internal IKnownVariable GetKnownVariable (string name)
2526                 {
2527                         return known_variables == null ? null : (IKnownVariable) known_variables [name];
2528                 }
2529
2530                 public void PropagateStoreyReference (AnonymousMethodStorey s)
2531                 {
2532                         if (Parent != null && am_storey != s) {
2533                                 if (am_storey != null)
2534                                         am_storey.AddParentStoreyReference (s);
2535
2536                                 Parent.Explicit.PropagateStoreyReference (s);
2537                         }
2538                 }
2539
2540                 public override bool Resolve (EmitContext ec)
2541                 {
2542                         bool ok = base.Resolve (ec);
2543
2544                         //
2545                         // Discard an anonymous method storey when this block has no hoisted variables
2546                         //
2547                         if (am_storey != null && !am_storey.HasHoistedVariables) {
2548                                 am_storey.Undo ();
2549                                 am_storey = null;
2550                         }
2551
2552                         return ok;
2553                 }
2554
2555                 protected override void CloneTo (CloneContext clonectx, Statement t)
2556                 {
2557                         ExplicitBlock target = (ExplicitBlock) t;
2558                         target.known_variables = null;
2559                         base.CloneTo (clonectx, t);
2560                 }
2561         }
2562
2563         public class ToplevelParameterInfo : IKnownVariable {
2564                 public readonly ToplevelBlock Block;
2565                 public readonly int Index;
2566                 public VariableInfo VariableInfo;
2567
2568                 Block IKnownVariable.Block {
2569                         get { return Block; }
2570                 }
2571                 public Parameter Parameter {
2572                         get { return Block.Parameters [Index]; }
2573                 }
2574
2575                 public Type ParameterType {
2576                         get { return Block.Parameters.Types [Index]; }
2577                 }
2578
2579                 public Location Location {
2580                         get { return Parameter.Location; }
2581                 }
2582
2583                 public ToplevelParameterInfo (ToplevelBlock block, int idx)
2584                 {
2585                         this.Block = block;
2586                         this.Index = idx;
2587                 }
2588         }
2589
2590         //
2591         // A toplevel block contains extra information, the split is done
2592         // only to separate information that would otherwise bloat the more
2593         // lightweight Block.
2594         //
2595         // In particular, this was introduced when the support for Anonymous
2596         // Methods was implemented. 
2597         // 
2598         public class ToplevelBlock : ExplicitBlock {
2599                 GenericMethod generic;
2600                 FlowBranchingToplevel top_level_branching;
2601                 Parameters parameters;
2602                 ToplevelParameterInfo[] parameter_info;
2603                 LocalInfo this_variable;
2604
2605                 public HoistedVariable HoistedThisVariable;
2606
2607                 //
2608                 // The parameters for the block.
2609                 //
2610                 public Parameters Parameters {
2611                         get { return parameters; }
2612                 }
2613
2614                 public GenericMethod GenericMethod {
2615                         get { return generic; }
2616                 }
2617
2618                 public bool HasStoreyAccess {
2619                         set { flags = value ? flags | Flags.HasStoreyAccess : flags & ~Flags.HasStoreyAccess; }
2620                         get { return (flags & Flags.HasStoreyAccess) != 0;  }
2621                 }
2622
2623                 public ToplevelBlock Container {
2624                         get { return Parent == null ? null : Parent.Toplevel; }
2625                 }
2626
2627                 public ToplevelBlock (Block parent, Parameters parameters, Location start) :
2628                         this (parent, (Flags) 0, parameters, start)
2629                 {
2630                 }
2631
2632                 public ToplevelBlock (Block parent, Parameters parameters, GenericMethod generic, Location start) :
2633                         this (parent, parameters, start)
2634                 {
2635                         this.generic = generic;
2636                 }
2637                 
2638                 public ToplevelBlock (Parameters parameters, Location start) :
2639                         this (null, (Flags) 0, parameters, start)
2640                 {
2641                 }
2642
2643                 ToplevelBlock (Flags flags, Parameters parameters, Location start) :
2644                         this (null, flags, parameters, start)
2645                 {
2646                 }
2647
2648                 // We use 'Parent' to hook up to the containing block, but don't want to register the current block as a child.
2649                 // So, we use a two-stage setup -- first pass a null parent to the base constructor, and then override 'Parent'.
2650                 public ToplevelBlock (Block parent, Flags flags, Parameters parameters, Location start) :
2651                         base (null, flags, start, Location.Null)
2652                 {
2653                         this.Toplevel = this;
2654
2655                         this.parameters = parameters == null ? Parameters.EmptyReadOnlyParameters : parameters;
2656                         this.Parent = parent;
2657                         if (parent != null)
2658                                 parent.AddAnonymousChild (this);
2659
2660                         if (!this.parameters.IsEmpty)
2661                                 ProcessParameters ();
2662                 }
2663
2664                 public ToplevelBlock (Location loc) : this (null, (Flags) 0, null, loc)
2665                 {
2666                 }
2667
2668                 protected override void CloneTo (CloneContext clonectx, Statement t)
2669                 {
2670                         ToplevelBlock target = (ToplevelBlock) t;
2671                         base.CloneTo (clonectx, t);
2672
2673                         if (parameters.Count != 0)
2674                                 target.parameter_info = new ToplevelParameterInfo [parameters.Count];
2675                         for (int i = 0; i < parameters.Count; ++i)
2676                                 target.parameter_info [i] = new ToplevelParameterInfo (target, i);
2677                 }
2678
2679                 public bool CheckError158 (string name, Location loc)
2680                 {
2681                         if (AnonymousChildren != null) {
2682                                 foreach (ToplevelBlock child in AnonymousChildren) {
2683                                         if (!child.CheckError158 (name, loc))
2684                                                 return false;
2685                                 }
2686                         }
2687
2688                         for (ToplevelBlock c = Container; c != null; c = c.Container) {
2689                                 if (!c.DoCheckError158 (name, loc))
2690                                         return false;
2691                         }
2692
2693                         return true;
2694                 }
2695
2696                 public virtual Expression GetTransparentIdentifier (string name)
2697                 {
2698                         return null;
2699                 }
2700
2701                 void ProcessParameters ()
2702                 {
2703                         int n = parameters.Count;
2704                         parameter_info = new ToplevelParameterInfo [n];
2705                         for (int i = 0; i < n; ++i) {
2706                                 parameter_info [i] = new ToplevelParameterInfo (this, i);
2707
2708                                 Parameter p = parameters [i];
2709                                 if (p == null)
2710                                         continue;
2711
2712                                 string name = p.Name;
2713                                 LocalInfo vi = GetLocalInfo (name);
2714                                 if (vi != null) {
2715                                         Report.SymbolRelatedToPreviousError (vi.Location, name);
2716                                         Error_AlreadyDeclared (loc, name, "parent or current");
2717                                         continue;
2718                                 }
2719
2720                                 ToplevelParameterInfo pi = Parent == null ? null : Parent.Toplevel.GetParameterInfo (name);
2721                                 if (pi != null) {
2722                                         Report.SymbolRelatedToPreviousError (pi.Location, name);
2723                                         Error_AlreadyDeclared (loc, name, "parent or current");
2724                                         continue;
2725                                 }
2726
2727                                 AddKnownVariable (name, parameter_info [i]);
2728                         }
2729
2730                         // mark this block as "used" so that we create local declarations in a sub-block
2731                         // FIXME: This appears to uncover a lot of bugs
2732                         //this.Use ();
2733                 }
2734
2735                 bool DoCheckError158 (string name, Location loc)
2736                 {
2737                         LabeledStatement s = LookupLabel (name);
2738                         if (s != null) {
2739                                 Report.SymbolRelatedToPreviousError (s.loc, s.Name);
2740                                 Error_158 (name, loc);
2741                                 return false;
2742                         }
2743
2744                         return true;
2745                 }
2746
2747                 public override Expression CreateExpressionTree (EmitContext ec)
2748                 {
2749                         if (statements.Count == 1)
2750                                 return ((Statement) statements [0]).CreateExpressionTree (ec);
2751
2752                         return base.CreateExpressionTree (ec);
2753                 }
2754
2755                 //
2756                 // Reformats this block to be top-level iterator block
2757                 //
2758                 public IteratorStorey ChangeToIterator (Iterator iterator, ToplevelBlock source)
2759                 {
2760                         // Create block with original statements
2761                         ExplicitBlock iter_block = new ExplicitBlock (this, flags, StartLocation, EndLocation);
2762                         IsIterator = true;
2763
2764                         // TODO: Change to iter_block.statements = statements;
2765                         foreach (Statement stmt in source.statements)
2766                                 iter_block.AddStatement (stmt);
2767                         labels = source.labels;
2768                         
2769                         AddStatement (new IteratorStatement (iterator, iter_block));
2770
2771                         source.statements = new ArrayList (1);
2772                         source.AddStatement (new Return (iterator, iterator.Location));
2773                         source.IsIterator = false;
2774
2775                         IteratorStorey iterator_storey = new IteratorStorey (iterator);
2776                         source.am_storey = iterator_storey;
2777                         return iterator_storey;
2778                 }
2779
2780                 public FlowBranchingToplevel TopLevelBranching {
2781                         get { return top_level_branching; }
2782                 }
2783
2784                 //
2785                 // Returns a `ParameterReference' for the given name, or null if there
2786                 // is no such parameter
2787                 //
2788                 public ParameterReference GetParameterReference (string name, Location loc)
2789                 {
2790                         ToplevelParameterInfo p = GetParameterInfo (name);
2791                         return p == null ? null : new ParameterReference (this, p, loc);
2792                 }
2793
2794                 public ToplevelParameterInfo GetParameterInfo (string name)
2795                 {
2796                         int idx;
2797                         for (ToplevelBlock t = this; t != null; t = t.Container) {
2798                                 Parameter par = t.Parameters.GetParameterByName (name, out idx);
2799                                 if (par != null)
2800                                         return t.parameter_info [idx];
2801                         }
2802                         return null;
2803                 }
2804
2805                 // <summary>
2806                 //   Returns the "this" instance variable of this block.
2807                 //   See AddThisVariable() for more information.
2808                 // </summary>
2809                 public LocalInfo ThisVariable {
2810                         get { return this_variable; }
2811                 }
2812
2813                 // <summary>
2814                 //   This is used by non-static `struct' constructors which do not have an
2815                 //   initializer - in this case, the constructor must initialize all of the
2816                 //   struct's fields.  To do this, we add a "this" variable and use the flow
2817                 //   analysis code to ensure that it's been fully initialized before control
2818                 //   leaves the constructor.
2819                 // </summary>
2820                 public LocalInfo AddThisVariable (DeclSpace ds, Location l)
2821                 {
2822                         if (this_variable == null) {
2823                                 this_variable = new LocalInfo (ds, this, l);
2824                                 this_variable.Used = true;
2825                                 this_variable.IsThis = true;
2826
2827                                 Variables.Add ("this", this_variable);
2828                         }
2829
2830                         return this_variable;
2831                 }
2832
2833                 public bool IsIterator {
2834                         get { return (flags & Flags.IsIterator) != 0; }
2835                         set { flags = value ? flags | Flags.IsIterator : flags & ~Flags.IsIterator; }
2836                 }
2837
2838                 public bool IsThisAssigned (EmitContext ec)
2839                 {
2840                         return this_variable == null || this_variable.IsThisAssigned (ec);
2841                 }
2842
2843                 public bool ResolveMeta (EmitContext ec, Parameters ip)
2844                 {
2845                         int errors = Report.Errors;
2846                         int orig_count = parameters.Count;
2847
2848                         if (top_level_branching != null)
2849                                 return true;
2850
2851                         if (ip != null)
2852                                 parameters = ip;
2853
2854                         // Assert: orig_count != parameter.Count => orig_count == 0
2855                         if (orig_count != 0 && orig_count != parameters.Count)
2856                                 throw new InternalErrorException ("parameter information mismatch");
2857
2858                         int offset = Parent == null ? 0 : Parent.AssignableSlots;
2859
2860                         for (int i = 0; i < orig_count; ++i) {
2861                                 Parameter.Modifier mod = parameters.FixedParameters [i].ModFlags;
2862
2863                                 if ((mod & Parameter.Modifier.OUT) != Parameter.Modifier.OUT)
2864                                         continue;
2865
2866                                 VariableInfo vi = new VariableInfo (ip, i, offset);
2867                                 parameter_info [i].VariableInfo = vi;
2868                                 offset += vi.Length;
2869                         }
2870
2871                         ResolveMeta (ec, offset);
2872
2873                         top_level_branching = ec.StartFlowBranching (this);
2874
2875                         return Report.Errors == errors;
2876                 }
2877
2878                 // <summary>
2879                 //   Check whether all `out' parameters have been assigned.
2880                 // </summary>
2881                 public void CheckOutParameters (FlowBranching.UsageVector vector, Location loc)
2882                 {
2883                         if (vector.IsUnreachable)
2884                                 return;
2885
2886                         int n = parameter_info == null ? 0 : parameter_info.Length;
2887
2888                         for (int i = 0; i < n; i++) {
2889                                 VariableInfo var = parameter_info [i].VariableInfo;
2890
2891                                 if (var == null)
2892                                         continue;
2893
2894                                 if (vector.IsAssigned (var, false))
2895                                         continue;
2896
2897                                 Report.Error (177, loc, "The out parameter `{0}' must be assigned to before control leaves the current method",
2898                                         var.Name);
2899                         }
2900                 }
2901
2902                 public override void EmitMeta (EmitContext ec)
2903                 {
2904                         parameters.ResolveVariable ();
2905
2906                         // Avoid declaring an IL variable for this_variable since it is not accessed
2907                         // from the generated IL
2908                         if (this_variable != null)
2909                                 Variables.Remove ("this");
2910                         base.EmitMeta (ec);
2911                 }
2912
2913                 protected override void EmitSymbolInfo (EmitContext ec)
2914                 {
2915                         AnonymousExpression ae = ec.CurrentAnonymousMethod;
2916                         if ((ae != null) && (ae.Storey != null))
2917                                 SymbolWriter.DefineScopeVariable (ae.Storey.ID);
2918
2919                         base.EmitSymbolInfo (ec);
2920                 }
2921
2922                 public override void Emit (EmitContext ec)
2923                 {
2924                         base.Emit (ec);
2925                         ec.Mark (EndLocation);
2926                 }
2927         }
2928         
2929         public class SwitchLabel {
2930                 Expression label;
2931                 object converted;
2932                 Location loc;
2933
2934                 Label il_label;
2935                 bool  il_label_set;
2936                 Label il_label_code;
2937                 bool  il_label_code_set;
2938
2939                 public static readonly object NullStringCase = new object ();
2940
2941                 //
2942                 // if expr == null, then it is the default case.
2943                 //
2944                 public SwitchLabel (Expression expr, Location l)
2945                 {
2946                         label = expr;
2947                         loc = l;
2948                 }
2949
2950                 public Expression Label {
2951                         get {
2952                                 return label;
2953                         }
2954                 }
2955
2956                 public Location Location {
2957                         get { return loc; }
2958                 }
2959
2960                 public object Converted {
2961                         get {
2962                                 return converted;
2963                         }
2964                 }
2965
2966                 public Label GetILLabel (EmitContext ec)
2967                 {
2968                         if (!il_label_set){
2969                                 il_label = ec.ig.DefineLabel ();
2970                                 il_label_set = true;
2971                         }
2972                         return il_label;
2973                 }
2974
2975                 public Label GetILLabelCode (EmitContext ec)
2976                 {
2977                         if (!il_label_code_set){
2978                                 il_label_code = ec.ig.DefineLabel ();
2979                                 il_label_code_set = true;
2980                         }
2981                         return il_label_code;
2982                 }                               
2983                 
2984                 //
2985                 // Resolves the expression, reduces it to a literal if possible
2986                 // and then converts it to the requested type.
2987                 //
2988                 public bool ResolveAndReduce (EmitContext ec, Type required_type, bool allow_nullable)
2989                 {       
2990                         Expression e = label.Resolve (ec);
2991
2992                         if (e == null)
2993                                 return false;
2994
2995                         Constant c = e as Constant;
2996                         if (c == null){
2997                                 Report.Error (150, loc, "A constant value is expected");
2998                                 return false;
2999                         }
3000
3001                         if (required_type == TypeManager.string_type && c.GetValue () == null) {
3002                                 converted = NullStringCase;
3003                                 return true;
3004                         }
3005
3006                         if (allow_nullable && c.GetValue () == null) {
3007                                 converted = NullStringCase;
3008                                 return true;
3009                         }
3010                         
3011                         c = c.ImplicitConversionRequired (ec, required_type, loc);
3012                         if (c == null)
3013                                 return false;
3014
3015                         converted = c.GetValue ();
3016                         return true;
3017                 }
3018
3019                 public void Error_AlreadyOccurs (Type switch_type, SwitchLabel collision_with)
3020                 {
3021                         string label;
3022                         if (converted == null)
3023                                 label = "default";
3024                         else if (converted == NullStringCase)
3025                                 label = "null";
3026                         else
3027                                 label = converted.ToString ();
3028                         
3029                         Report.SymbolRelatedToPreviousError (collision_with.loc, null);
3030                         Report.Error (152, loc, "The label `case {0}:' already occurs in this switch statement", label);
3031                 }
3032
3033                 public SwitchLabel Clone (CloneContext clonectx)
3034                 {
3035                         return new SwitchLabel (label.Clone (clonectx), loc);
3036                 }
3037         }
3038
3039         public class SwitchSection {
3040                 // An array of SwitchLabels.
3041                 public readonly ArrayList Labels;
3042                 public readonly Block Block;
3043                 
3044                 public SwitchSection (ArrayList labels, Block block)
3045                 {
3046                         Labels = labels;
3047                         Block = block;
3048                 }
3049
3050                 public SwitchSection Clone (CloneContext clonectx)
3051                 {
3052                         ArrayList cloned_labels = new ArrayList ();
3053
3054                         foreach (SwitchLabel sl in cloned_labels)
3055                                 cloned_labels.Add (sl.Clone (clonectx));
3056                         
3057                         return new SwitchSection (cloned_labels, clonectx.LookupBlock (Block));
3058                 }
3059         }
3060         
3061         public class Switch : Statement {
3062                 public ArrayList Sections;
3063                 public Expression Expr;
3064
3065                 /// <summary>
3066                 ///   Maps constants whose type type SwitchType to their  SwitchLabels.
3067                 /// </summary>
3068                 public IDictionary Elements;
3069
3070                 /// <summary>
3071                 ///   The governing switch type
3072                 /// </summary>
3073                 public Type SwitchType;
3074
3075                 //
3076                 // Computed
3077                 //
3078                 Label default_target;
3079                 Label null_target;
3080                 Expression new_expr;
3081                 bool is_constant;
3082                 bool has_null_case;
3083                 SwitchSection constant_section;
3084                 SwitchSection default_section;
3085
3086                 ExpressionStatement string_dictionary;
3087                 FieldExpr switch_cache_field;
3088                 static int unique_counter;
3089
3090 #if GMCS_SOURCE
3091                 //
3092                 // Nullable Types support for GMCS.
3093                 //
3094                 Nullable.Unwrap unwrap;
3095
3096                 protected bool HaveUnwrap {
3097                         get { return unwrap != null; }
3098                 }
3099 #else
3100                 protected bool HaveUnwrap {
3101                         get { return false; }
3102                 }
3103 #endif
3104
3105                 //
3106                 // The types allowed to be implicitly cast from
3107                 // on the governing type
3108                 //
3109                 static Type [] allowed_types;
3110                 
3111                 public Switch (Expression e, ArrayList sects, Location l)
3112                 {
3113                         Expr = e;
3114                         Sections = sects;
3115                         loc = l;
3116                 }
3117
3118                 public bool GotDefault {
3119                         get {
3120                                 return default_section != null;
3121                         }
3122                 }
3123
3124                 public Label DefaultTarget {
3125                         get {
3126                                 return default_target;
3127                         }
3128                 }
3129
3130                 //
3131                 // Determines the governing type for a switch.  The returned
3132                 // expression might be the expression from the switch, or an
3133                 // expression that includes any potential conversions to the
3134                 // integral types or to string.
3135                 //
3136                 Expression SwitchGoverningType (EmitContext ec, Expression expr)
3137                 {
3138                         Type t = expr.Type;
3139
3140                         if (t == TypeManager.byte_type ||
3141                             t == TypeManager.sbyte_type ||
3142                             t == TypeManager.ushort_type ||
3143                             t == TypeManager.short_type ||
3144                             t == TypeManager.uint32_type ||
3145                             t == TypeManager.int32_type ||
3146                             t == TypeManager.uint64_type ||
3147                             t == TypeManager.int64_type ||
3148                             t == TypeManager.char_type ||
3149                             t == TypeManager.string_type ||
3150                             t == TypeManager.bool_type ||
3151                             TypeManager.IsEnumType (t))
3152                                 return expr;
3153
3154                         if (allowed_types == null){
3155                                 allowed_types = new Type [] {
3156                                         TypeManager.sbyte_type,
3157                                         TypeManager.byte_type,
3158                                         TypeManager.short_type,
3159                                         TypeManager.ushort_type,
3160                                         TypeManager.int32_type,
3161                                         TypeManager.uint32_type,
3162                                         TypeManager.int64_type,
3163                                         TypeManager.uint64_type,
3164                                         TypeManager.char_type,
3165                                         TypeManager.string_type
3166                                 };
3167                         }
3168
3169                         //
3170                         // Try to find a *user* defined implicit conversion.
3171                         //
3172                         // If there is no implicit conversion, or if there are multiple
3173                         // conversions, we have to report an error
3174                         //
3175                         Expression converted = null;
3176                         foreach (Type tt in allowed_types){
3177                                 Expression e;
3178                                 
3179                                 e = Convert.ImplicitUserConversion (ec, expr, tt, loc);
3180                                 if (e == null)
3181                                         continue;
3182
3183                                 //
3184                                 // Ignore over-worked ImplicitUserConversions that do
3185                                 // an implicit conversion in addition to the user conversion.
3186                                 // 
3187                                 if (!(e is UserCast))
3188                                         continue;
3189
3190                                 if (converted != null){
3191                                         Report.ExtraInformation (loc, "(Ambiguous implicit user defined conversion in previous ");
3192                                         return null;
3193                                 }
3194
3195                                 converted = e;
3196                         }
3197                         return converted;
3198                 }
3199
3200                 //
3201                 // Performs the basic sanity checks on the switch statement
3202                 // (looks for duplicate keys and non-constant expressions).
3203                 //
3204                 // It also returns a hashtable with the keys that we will later
3205                 // use to compute the switch tables
3206                 //
3207                 bool CheckSwitch (EmitContext ec)
3208                 {
3209                         bool error = false;
3210                         Elements = Sections.Count > 10 ? 
3211                                 (IDictionary)new Hashtable () : 
3212                                 (IDictionary)new ListDictionary ();
3213                                 
3214                         foreach (SwitchSection ss in Sections){
3215                                 foreach (SwitchLabel sl in ss.Labels){
3216                                         if (sl.Label == null){
3217                                                 if (default_section != null){
3218                                                         sl.Error_AlreadyOccurs (SwitchType, (SwitchLabel)default_section.Labels [0]);
3219                                                         error = true;
3220                                                 }
3221                                                 default_section = ss;
3222                                                 continue;
3223                                         }
3224
3225                                         if (!sl.ResolveAndReduce (ec, SwitchType, HaveUnwrap)) {
3226                                                 error = true;
3227                                                 continue;
3228                                         }
3229                                         
3230                                         object key = sl.Converted;
3231                                         if (key == SwitchLabel.NullStringCase)
3232                                                 has_null_case = true;
3233
3234                                         try {
3235                                                 Elements.Add (key, sl);
3236                                         } catch (ArgumentException) {
3237                                                 sl.Error_AlreadyOccurs (SwitchType, (SwitchLabel)Elements [key]);
3238                                                 error = true;
3239                                         }
3240                                 }
3241                         }
3242                         return !error;
3243                 }
3244
3245                 void EmitObjectInteger (ILGenerator ig, object k)
3246                 {
3247                         if (k is int)
3248                                 IntConstant.EmitInt (ig, (int) k);
3249                         else if (k is Constant) {
3250                                 EmitObjectInteger (ig, ((Constant) k).GetValue ());
3251                         } 
3252                         else if (k is uint)
3253                                 IntConstant.EmitInt (ig, unchecked ((int) (uint) k));
3254                         else if (k is long)
3255                         {
3256                                 if ((long) k >= int.MinValue && (long) k <= int.MaxValue)
3257                                 {
3258                                         IntConstant.EmitInt (ig, (int) (long) k);
3259                                         ig.Emit (OpCodes.Conv_I8);
3260                                 }
3261                                 else
3262                                         LongConstant.EmitLong (ig, (long) k);
3263                         }
3264                         else if (k is ulong)
3265                         {
3266                                 ulong ul = (ulong) k;
3267                                 if (ul < (1L<<32))
3268                                 {
3269                                         IntConstant.EmitInt (ig, unchecked ((int) ul));
3270                                         ig.Emit (OpCodes.Conv_U8);
3271                                 }
3272                                 else
3273                                 {
3274                                         LongConstant.EmitLong (ig, unchecked ((long) ul));
3275                                 }
3276                         }
3277                         else if (k is char)
3278                                 IntConstant.EmitInt (ig, (int) ((char) k));
3279                         else if (k is sbyte)
3280                                 IntConstant.EmitInt (ig, (int) ((sbyte) k));
3281                         else if (k is byte)
3282                                 IntConstant.EmitInt (ig, (int) ((byte) k));
3283                         else if (k is short)
3284                                 IntConstant.EmitInt (ig, (int) ((short) k));
3285                         else if (k is ushort)
3286                                 IntConstant.EmitInt (ig, (int) ((ushort) k));
3287                         else if (k is bool)
3288                                 IntConstant.EmitInt (ig, ((bool) k) ? 1 : 0);
3289                         else
3290                                 throw new Exception ("Unhandled case");
3291                 }
3292                 
3293                 // structure used to hold blocks of keys while calculating table switch
3294                 class KeyBlock : IComparable
3295                 {
3296                         public KeyBlock (long _first)
3297                         {
3298                                 first = last = _first;
3299                         }
3300                         public long first;
3301                         public long last;
3302                         public ArrayList element_keys = null;
3303                         // how many items are in the bucket
3304                         public int Size = 1;
3305                         public int Length
3306                         {
3307                                 get { return (int) (last - first + 1); }
3308                         }
3309                         public static long TotalLength (KeyBlock kb_first, KeyBlock kb_last)
3310                         {
3311                                 return kb_last.last - kb_first.first + 1;
3312                         }
3313                         public int CompareTo (object obj)
3314                         {
3315                                 KeyBlock kb = (KeyBlock) obj;
3316                                 int nLength = Length;
3317                                 int nLengthOther = kb.Length;
3318                                 if (nLengthOther == nLength)
3319                                         return (int) (kb.first - first);
3320                                 return nLength - nLengthOther;
3321                         }
3322                 }
3323
3324                 /// <summary>
3325                 /// This method emits code for a lookup-based switch statement (non-string)
3326                 /// Basically it groups the cases into blocks that are at least half full,
3327                 /// and then spits out individual lookup opcodes for each block.
3328                 /// It emits the longest blocks first, and short blocks are just
3329                 /// handled with direct compares.
3330                 /// </summary>
3331                 /// <param name="ec"></param>
3332                 /// <param name="val"></param>
3333                 /// <returns></returns>
3334                 void TableSwitchEmit (EmitContext ec, Expression val)
3335                 {
3336                         int element_count = Elements.Count;
3337                         object [] element_keys = new object [element_count];
3338                         Elements.Keys.CopyTo (element_keys, 0);
3339                         Array.Sort (element_keys);
3340
3341                         // initialize the block list with one element per key
3342                         ArrayList key_blocks = new ArrayList (element_count);
3343                         foreach (object key in element_keys)
3344                                 key_blocks.Add (new KeyBlock (System.Convert.ToInt64 (key)));
3345
3346                         KeyBlock current_kb;
3347                         // iteratively merge the blocks while they are at least half full
3348                         // there's probably a really cool way to do this with a tree...
3349                         while (key_blocks.Count > 1)
3350                         {
3351                                 ArrayList key_blocks_new = new ArrayList ();
3352                                 current_kb = (KeyBlock) key_blocks [0];
3353                                 for (int ikb = 1; ikb < key_blocks.Count; ikb++)
3354                                 {
3355                                         KeyBlock kb = (KeyBlock) key_blocks [ikb];
3356                                         if ((current_kb.Size + kb.Size) * 2 >=  KeyBlock.TotalLength (current_kb, kb))
3357                                         {
3358                                                 // merge blocks
3359                                                 current_kb.last = kb.last;
3360                                                 current_kb.Size += kb.Size;
3361                                         }
3362                                         else
3363                                         {
3364                                                 // start a new block
3365                                                 key_blocks_new.Add (current_kb);
3366                                                 current_kb = kb;
3367                                         }
3368                                 }
3369                                 key_blocks_new.Add (current_kb);
3370                                 if (key_blocks.Count == key_blocks_new.Count)
3371                                         break;
3372                                 key_blocks = key_blocks_new;
3373                         }
3374
3375                         // initialize the key lists
3376                         foreach (KeyBlock kb in key_blocks)
3377                                 kb.element_keys = new ArrayList ();
3378
3379                         // fill the key lists
3380                         int iBlockCurr = 0;
3381                         if (key_blocks.Count > 0) {
3382                                 current_kb = (KeyBlock) key_blocks [0];
3383                                 foreach (object key in element_keys)
3384                                 {
3385                                         bool next_block = (key is UInt64) ? (ulong) key > (ulong) current_kb.last :
3386                                                 System.Convert.ToInt64 (key) > current_kb.last;
3387                                         if (next_block)
3388                                                 current_kb = (KeyBlock) key_blocks [++iBlockCurr];
3389                                         current_kb.element_keys.Add (key);
3390                                 }
3391                         }
3392
3393                         // sort the blocks so we can tackle the largest ones first
3394                         key_blocks.Sort ();
3395
3396                         // okay now we can start...
3397                         ILGenerator ig = ec.ig;
3398                         Label lbl_end = ig.DefineLabel ();      // at the end ;-)
3399                         Label lbl_default = default_target;
3400
3401                         Type type_keys = null;
3402                         if (element_keys.Length > 0)
3403                                 type_keys = element_keys [0].GetType ();        // used for conversions
3404
3405                         Type compare_type;
3406                         
3407                         if (TypeManager.IsEnumType (SwitchType))
3408                                 compare_type = TypeManager.GetEnumUnderlyingType (SwitchType);
3409                         else
3410                                 compare_type = SwitchType;
3411                         
3412                         for (int iBlock = key_blocks.Count - 1; iBlock >= 0; --iBlock)
3413                         {
3414                                 KeyBlock kb = ((KeyBlock) key_blocks [iBlock]);
3415                                 lbl_default = (iBlock == 0) ? default_target : ig.DefineLabel ();
3416                                 if (kb.Length <= 2)
3417                                 {
3418                                         foreach (object key in kb.element_keys) {
3419                                                 SwitchLabel sl = (SwitchLabel) Elements [key];
3420                                                 if (key is int && (int) key == 0) {
3421                                                         val.EmitBranchable (ec, sl.GetILLabel (ec), false);
3422                                                 } else {
3423                                                         val.Emit (ec);
3424                                                         EmitObjectInteger (ig, key);
3425                                                         ig.Emit (OpCodes.Beq, sl.GetILLabel (ec));
3426                                                 }
3427                                         }
3428                                 }
3429                                 else
3430                                 {
3431                                         // TODO: if all the keys in the block are the same and there are
3432                                         //       no gaps/defaults then just use a range-check.
3433                                         if (compare_type == TypeManager.int64_type ||
3434                                                 compare_type == TypeManager.uint64_type)
3435                                         {
3436                                                 // TODO: optimize constant/I4 cases
3437
3438                                                 // check block range (could be > 2^31)
3439                                                 val.Emit (ec);
3440                                                 EmitObjectInteger (ig, System.Convert.ChangeType (kb.first, type_keys));
3441                                                 ig.Emit (OpCodes.Blt, lbl_default);
3442                                                 val.Emit (ec);
3443                                                 EmitObjectInteger (ig, System.Convert.ChangeType (kb.last, type_keys));
3444                                                 ig.Emit (OpCodes.Bgt, lbl_default);
3445
3446                                                 // normalize range
3447                                                 val.Emit (ec);
3448                                                 if (kb.first != 0)
3449                                                 {
3450                                                         EmitObjectInteger (ig, System.Convert.ChangeType (kb.first, type_keys));
3451                                                         ig.Emit (OpCodes.Sub);
3452                                                 }
3453                                                 ig.Emit (OpCodes.Conv_I4);      // assumes < 2^31 labels!
3454                                         }
3455                                         else
3456                                         {
3457                                                 // normalize range
3458                                                 val.Emit (ec);
3459                                                 int first = (int) kb.first;
3460                                                 if (first > 0)
3461                                                 {
3462                                                         IntConstant.EmitInt (ig, first);
3463                                                         ig.Emit (OpCodes.Sub);
3464                                                 }
3465                                                 else if (first < 0)
3466                                                 {
3467                                                         IntConstant.EmitInt (ig, -first);
3468                                                         ig.Emit (OpCodes.Add);
3469                                                 }
3470                                         }
3471
3472                                         // first, build the list of labels for the switch
3473                                         int iKey = 0;
3474                                         int cJumps = kb.Length;
3475                                         Label [] switch_labels = new Label [cJumps];
3476                                         for (int iJump = 0; iJump < cJumps; iJump++)
3477                                         {
3478                                                 object key = kb.element_keys [iKey];
3479                                                 if (System.Convert.ToInt64 (key) == kb.first + iJump)
3480                                                 {
3481                                                         SwitchLabel sl = (SwitchLabel) Elements [key];
3482                                                         switch_labels [iJump] = sl.GetILLabel (ec);
3483                                                         iKey++;
3484                                                 }
3485                                                 else
3486                                                         switch_labels [iJump] = lbl_default;
3487                                         }
3488                                         // emit the switch opcode
3489                                         ig.Emit (OpCodes.Switch, switch_labels);
3490                                 }
3491
3492                                 // mark the default for this block
3493                                 if (iBlock != 0)
3494                                         ig.MarkLabel (lbl_default);
3495                         }
3496
3497                         // TODO: find the default case and emit it here,
3498                         //       to prevent having to do the following jump.
3499                         //       make sure to mark other labels in the default section
3500
3501                         // the last default just goes to the end
3502                         if (element_keys.Length > 0)
3503                                 ig.Emit (OpCodes.Br, lbl_default);
3504
3505                         // now emit the code for the sections
3506                         bool found_default = false;
3507
3508                         foreach (SwitchSection ss in Sections) {
3509                                 foreach (SwitchLabel sl in ss.Labels) {
3510                                         if (sl.Converted == SwitchLabel.NullStringCase) {
3511                                                 ig.MarkLabel (null_target);
3512                                         } else if (sl.Label == null) {
3513                                                 ig.MarkLabel (lbl_default);
3514                                                 found_default = true;
3515                                                 if (!has_null_case)
3516                                                         ig.MarkLabel (null_target);
3517                                         }
3518                                         ig.MarkLabel (sl.GetILLabel (ec));
3519                                         ig.MarkLabel (sl.GetILLabelCode (ec));
3520                                 }
3521                                 ss.Block.Emit (ec);
3522                         }
3523                         
3524                         if (!found_default) {
3525                                 ig.MarkLabel (lbl_default);
3526                                 if (!has_null_case) {
3527                                         ig.MarkLabel (null_target);
3528                                 }
3529                         }
3530                         
3531                         ig.MarkLabel (lbl_end);
3532                 }
3533
3534                 SwitchSection FindSection (SwitchLabel label)
3535                 {
3536                         foreach (SwitchSection ss in Sections){
3537                                 foreach (SwitchLabel sl in ss.Labels){
3538                                         if (label == sl)
3539                                                 return ss;
3540                                 }
3541                         }
3542
3543                         return null;
3544                 }
3545
3546                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3547                 {
3548                         foreach (SwitchSection ss in Sections)
3549                                 ss.Block.MutateHoistedGenericType (storey);
3550                 }
3551
3552                 public static void Reset ()
3553                 {
3554                         unique_counter = 0;
3555                 }
3556
3557                 public override bool Resolve (EmitContext ec)
3558                 {
3559                         Expr = Expr.Resolve (ec);
3560                         if (Expr == null)
3561                                 return false;
3562
3563                         new_expr = SwitchGoverningType (ec, Expr);
3564
3565 #if GMCS_SOURCE
3566                         if ((new_expr == null) && TypeManager.IsNullableType (Expr.Type)) {
3567                                 unwrap = Nullable.Unwrap.Create (Expr, ec);
3568                                 if (unwrap == null)
3569                                         return false;
3570
3571                                 new_expr = SwitchGoverningType (ec, unwrap);
3572                         }
3573 #endif
3574
3575                         if (new_expr == null){
3576                                 Report.Error (151, loc, "A value of an integral type or string expected for switch");
3577                                 return false;
3578                         }
3579
3580                         // Validate switch.
3581                         SwitchType = new_expr.Type;
3582
3583                         if (RootContext.Version == LanguageVersion.ISO_1 && SwitchType == TypeManager.bool_type) {
3584                                 Report.FeatureIsNotAvailable (loc, "switch expression of boolean type");
3585                                 return false;
3586                         }
3587
3588                         if (!CheckSwitch (ec))
3589                                 return false;
3590
3591                         if (HaveUnwrap)
3592                                 Elements.Remove (SwitchLabel.NullStringCase);
3593
3594                         Switch old_switch = ec.Switch;
3595                         ec.Switch = this;
3596                         ec.Switch.SwitchType = SwitchType;
3597
3598                         Report.Debug (1, "START OF SWITCH BLOCK", loc, ec.CurrentBranching);
3599                         ec.StartFlowBranching (FlowBranching.BranchingType.Switch, loc);
3600
3601                         is_constant = new_expr is Constant;
3602                         if (is_constant) {
3603                                 object key = ((Constant) new_expr).GetValue ();
3604                                 SwitchLabel label = (SwitchLabel) Elements [key];
3605
3606                                 constant_section = FindSection (label);
3607                                 if (constant_section == null)
3608                                         constant_section = default_section;
3609                         }
3610
3611                         bool first = true;
3612                         bool ok = true;
3613                         foreach (SwitchSection ss in Sections){
3614                                 if (!first)
3615                                         ec.CurrentBranching.CreateSibling (
3616                                                 null, FlowBranching.SiblingType.SwitchSection);
3617                                 else
3618                                         first = false;
3619
3620                                 if (is_constant && (ss != constant_section)) {
3621                                         // If we're a constant switch, we're only emitting
3622                                         // one single section - mark all the others as
3623                                         // unreachable.
3624                                         ec.CurrentBranching.CurrentUsageVector.Goto ();
3625                                         if (!ss.Block.ResolveUnreachable (ec, true)) {
3626                                                 ok = false;
3627                                         }
3628                                 } else {
3629                                         if (!ss.Block.Resolve (ec))
3630                                                 ok = false;
3631                                 }
3632                         }
3633
3634                         if (default_section == null)
3635                                 ec.CurrentBranching.CreateSibling (
3636                                         null, FlowBranching.SiblingType.SwitchSection);
3637
3638                         ec.EndFlowBranching ();
3639                         ec.Switch = old_switch;
3640
3641                         Report.Debug (1, "END OF SWITCH BLOCK", loc, ec.CurrentBranching);
3642
3643                         if (!ok)
3644                                 return false;
3645
3646                         if (SwitchType == TypeManager.string_type && !is_constant) {
3647                                 // TODO: Optimize single case, and single+default case
3648                                 ResolveStringSwitchMap (ec);
3649                         }
3650
3651                         return true;
3652                 }
3653
3654                 void ResolveStringSwitchMap (EmitContext ec)
3655                 {
3656                         FullNamedExpression string_dictionary_type;
3657 #if GMCS_SOURCE
3658                         MemberAccess system_collections_generic = new MemberAccess (new MemberAccess (
3659                                 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc), "Generic", loc);
3660
3661                         string_dictionary_type = new MemberAccess (system_collections_generic, "Dictionary",
3662                                 new TypeArguments (loc,
3663                                         new TypeExpression (TypeManager.string_type, loc),
3664                                         new TypeExpression (TypeManager.int32_type, loc)), loc);
3665 #else
3666                         MemberAccess system_collections_generic = new MemberAccess (
3667                                 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc);
3668
3669                         string_dictionary_type = new MemberAccess (system_collections_generic, "Hashtable", loc);
3670 #endif
3671                         Field field = new Field (ec.TypeContainer, string_dictionary_type,
3672                                 Modifiers.STATIC | Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED,
3673                                 CompilerGeneratedClass.MakeName (null, "f", "switch$map", unique_counter++), null, loc);
3674                         if (!field.Define ())
3675                                 return;
3676                         ec.TypeContainer.PartialContainer.AddField (field);
3677
3678                         ArrayList init = new ArrayList ();
3679                         int counter = 0;
3680                         Elements.Clear ();
3681                         string value = null;
3682                         foreach (SwitchSection section in Sections) {
3683                                 foreach (SwitchLabel sl in section.Labels) {
3684                                         if (sl.Label == null || sl.Converted == SwitchLabel.NullStringCase) {
3685                                                 value = null;
3686                                                 continue;
3687                                         }
3688
3689                                         value = (string) sl.Converted;
3690                                         ArrayList init_args = new ArrayList (2);
3691                                         init_args.Add (new StringLiteral (value, sl.Location));
3692                                         init_args.Add (new IntConstant (counter, loc));
3693                                         init.Add (new CollectionElementInitializer (init_args, loc));
3694                                 }
3695
3696                                 if (value == null)
3697                                         continue;
3698
3699                                 Elements.Add (counter, section.Labels [0]);
3700                                 ++counter;
3701                         }
3702
3703                         ArrayList args = new ArrayList (1);
3704                         args.Add (new Argument (new IntConstant (Sections.Count, loc)));
3705                         Expression initializer = new NewInitialize (string_dictionary_type, args,
3706                                 new CollectionOrObjectInitializers (init, loc), loc);
3707
3708                         switch_cache_field = new FieldExpr (field.FieldBuilder, loc);
3709                         string_dictionary = new SimpleAssign (switch_cache_field, initializer.Resolve (ec));
3710                 }
3711
3712                 void DoEmitStringSwitch (LocalTemporary value, EmitContext ec)
3713                 {
3714                         ILGenerator ig = ec.ig;
3715                         Label l_initialized = ig.DefineLabel ();
3716
3717                         //
3718                         // Skip initialization when value is null
3719                         //
3720                         value.EmitBranchable (ec, null_target, false);
3721
3722                         //
3723                         // Check if string dictionary is initialized and initialize
3724                         //
3725                         switch_cache_field.EmitBranchable (ec, l_initialized, true);
3726                         string_dictionary.EmitStatement (ec);
3727                         ig.MarkLabel (l_initialized);
3728
3729                         LocalTemporary string_switch_variable = new LocalTemporary (TypeManager.int32_type);
3730
3731 #if GMCS_SOURCE
3732                         ArrayList get_value_args = new ArrayList (2);
3733                         get_value_args.Add (new Argument (value));
3734                         get_value_args.Add (new Argument (string_switch_variable, Argument.AType.Out));
3735                         Expression get_item = new Invocation (new MemberAccess (switch_cache_field, "TryGetValue", loc), get_value_args).Resolve (ec);
3736                         if (get_item == null)
3737                                 return;
3738
3739                         //
3740                         // A value was not found, go to default case
3741                         //
3742                         get_item.EmitBranchable (ec, default_target, false);
3743 #else
3744                         ArrayList get_value_args = new ArrayList (1);
3745                         get_value_args.Add (value);
3746
3747                         Expression get_item = new IndexerAccess (new ElementAccess (switch_cache_field, get_value_args), loc).Resolve (ec);
3748                         if (get_item == null)
3749                                 return;
3750
3751                         LocalTemporary get_item_object = new LocalTemporary (TypeManager.object_type);
3752                         get_item_object.EmitAssign (ec, get_item, true, false);
3753                         ec.ig.Emit (OpCodes.Brfalse, default_target);
3754
3755                         ExpressionStatement get_item_int = (ExpressionStatement) new SimpleAssign (string_switch_variable,
3756                                 new Cast (new TypeExpression (TypeManager.int32_type, loc), get_item_object, loc)).Resolve (ec);
3757
3758                         get_item_int.EmitStatement (ec);
3759                         get_item_object.Release (ec);
3760 #endif
3761                         TableSwitchEmit (ec, string_switch_variable);
3762                         string_switch_variable.Release (ec);
3763                 }
3764                 
3765                 protected override void DoEmit (EmitContext ec)
3766                 {
3767                         ILGenerator ig = ec.ig;
3768
3769                         default_target = ig.DefineLabel ();
3770                         null_target = ig.DefineLabel ();
3771
3772                         // Store variable for comparission purposes
3773                         // TODO: Don't duplicate non-captured VariableReference
3774                         LocalTemporary value;
3775                         if (HaveUnwrap) {
3776                                 value = new LocalTemporary (SwitchType);
3777 #if GMCS_SOURCE
3778                                 unwrap.EmitCheck (ec);
3779                                 ig.Emit (OpCodes.Brfalse, null_target);
3780                                 new_expr.Emit (ec);
3781                                 value.Store (ec);
3782 #endif
3783                         } else if (!is_constant) {
3784                                 value = new LocalTemporary (SwitchType);
3785                                 new_expr.Emit (ec);
3786                                 value.Store (ec);
3787                         } else
3788                                 value = null;
3789
3790                         //
3791                         // Setup the codegen context
3792                         //
3793                         Label old_end = ec.LoopEnd;
3794                         Switch old_switch = ec.Switch;
3795                         
3796                         ec.LoopEnd = ig.DefineLabel ();
3797                         ec.Switch = this;
3798
3799                         // Emit Code.
3800                         if (is_constant) {
3801                                 if (constant_section != null)
3802                                         constant_section.Block.Emit (ec);
3803                         } else if (string_dictionary != null) {
3804                                 DoEmitStringSwitch (value, ec);
3805                         } else {
3806                                 TableSwitchEmit (ec, value);
3807                         }
3808
3809                         if (value != null)
3810                                 value.Release (ec);
3811
3812                         // Restore context state. 
3813                         ig.MarkLabel (ec.LoopEnd);
3814
3815                         //
3816                         // Restore the previous context
3817                         //
3818                         ec.LoopEnd = old_end;
3819                         ec.Switch = old_switch;
3820                 }
3821
3822                 protected override void CloneTo (CloneContext clonectx, Statement t)
3823                 {
3824                         Switch target = (Switch) t;
3825
3826                         target.Expr = Expr.Clone (clonectx);
3827                         target.Sections = new ArrayList ();
3828                         foreach (SwitchSection ss in Sections){
3829                                 target.Sections.Add (ss.Clone (clonectx));
3830                         }
3831                 }
3832         }
3833
3834         // A place where execution can restart in an iterator
3835         public abstract class ResumableStatement : Statement
3836         {
3837                 bool prepared;
3838                 protected Label resume_point;
3839
3840                 public Label PrepareForEmit (EmitContext ec)
3841                 {
3842                         if (!prepared) {
3843                                 prepared = true;
3844                                 resume_point = ec.ig.DefineLabel ();
3845                         }
3846                         return resume_point;
3847                 }
3848
3849                 public virtual Label PrepareForDispose (EmitContext ec, Label end)
3850                 {
3851                         return end;
3852                 }
3853                 public virtual void EmitForDispose (EmitContext ec, Iterator iterator, Label end, bool have_dispatcher)
3854                 {
3855                 }
3856         }
3857
3858         // Base class for statements that are implemented in terms of try...finally
3859         public abstract class ExceptionStatement : ResumableStatement
3860         {
3861                 bool code_follows;
3862
3863                 protected abstract void EmitPreTryBody (EmitContext ec);
3864                 protected abstract void EmitTryBody (EmitContext ec);
3865                 protected abstract void EmitFinallyBody (EmitContext ec);
3866
3867                 protected sealed override void DoEmit (EmitContext ec)
3868                 {
3869                         ILGenerator ig = ec.ig;
3870
3871                         EmitPreTryBody (ec);
3872
3873                         if (resume_points != null) {
3874                                 IntConstant.EmitInt (ig, (int) Iterator.State.Running);
3875                                 ig.Emit (OpCodes.Stloc, ec.CurrentIterator.CurrentPC);
3876                         }
3877
3878                         ig.BeginExceptionBlock ();
3879
3880                         if (resume_points != null) {
3881                                 ig.MarkLabel (resume_point);
3882
3883                                 // For normal control flow, we want to fall-through the Switch
3884                                 // So, we use CurrentPC rather than the $PC field, and initialize it to an outside value above
3885                                 ig.Emit (OpCodes.Ldloc, ec.CurrentIterator.CurrentPC);
3886                                 IntConstant.EmitInt (ig, first_resume_pc);
3887                                 ig.Emit (OpCodes.Sub);
3888
3889                                 Label [] labels = new Label [resume_points.Count];
3890                                 for (int i = 0; i < resume_points.Count; ++i)
3891                                         labels [i] = ((ResumableStatement) resume_points [i]).PrepareForEmit (ec);
3892                                 ig.Emit (OpCodes.Switch, labels);
3893                         }
3894
3895                         EmitTryBody (ec);
3896
3897                         ig.BeginFinallyBlock ();
3898
3899                         Label start_finally = ec.ig.DefineLabel ();
3900                         if (resume_points != null) {
3901                                 ig.Emit (OpCodes.Ldloc, ec.CurrentIterator.SkipFinally);
3902                                 ig.Emit (OpCodes.Brfalse_S, start_finally);
3903                                 ig.Emit (OpCodes.Endfinally);
3904                         }
3905
3906                         ig.MarkLabel (start_finally);
3907                         EmitFinallyBody (ec);
3908
3909                         ig.EndExceptionBlock ();
3910                 }
3911
3912                 public void SomeCodeFollows ()
3913                 {
3914                         code_follows = true;
3915                 }
3916
3917                 protected void ResolveReachability (EmitContext ec)
3918                 {
3919                         // System.Reflection.Emit automatically emits a 'leave' at the end of a try clause
3920                         // So, ensure there's some IL code after this statement.
3921                         if (!code_follows && resume_points == null && ec.CurrentBranching.CurrentUsageVector.IsUnreachable)
3922                                 ec.NeedReturnLabel ();
3923
3924                 }
3925
3926                 ArrayList resume_points;
3927                 int first_resume_pc;
3928                 public void AddResumePoint (ResumableStatement stmt, int pc)
3929                 {
3930                         if (resume_points == null) {
3931                                 resume_points = new ArrayList ();
3932                                 first_resume_pc = pc;
3933                         }
3934
3935                         if (pc != first_resume_pc + resume_points.Count)
3936                                 throw new InternalErrorException ("missed an intervening AddResumePoint?");
3937
3938                         resume_points.Add (stmt);
3939                 }
3940
3941                 Label dispose_try_block;
3942                 bool prepared_for_dispose, emitted_dispose;
3943                 public override Label PrepareForDispose (EmitContext ec, Label end)
3944                 {
3945                         if (!prepared_for_dispose) {
3946                                 prepared_for_dispose = true;
3947                                 dispose_try_block = ec.ig.DefineLabel ();
3948                         }
3949                         return dispose_try_block;
3950                 }
3951
3952                 public override void EmitForDispose (EmitContext ec, Iterator iterator, Label end, bool have_dispatcher)
3953                 {
3954                         if (emitted_dispose)
3955                                 return;
3956
3957                         emitted_dispose = true;
3958
3959                         ILGenerator ig = ec.ig;
3960
3961                         Label end_of_try = ig.DefineLabel ();
3962
3963                         // Ensure that the only way we can get into this code is through a dispatcher
3964                         if (have_dispatcher)
3965                                 ig.Emit (OpCodes.Br, end);
3966
3967                         ig.BeginExceptionBlock ();
3968
3969                         ig.MarkLabel (dispose_try_block);
3970
3971                         Label [] labels = null;
3972                         for (int i = 0; i < resume_points.Count; ++i) {
3973                                 ResumableStatement s = (ResumableStatement) resume_points [i];
3974                                 Label ret = s.PrepareForDispose (ec, end_of_try);
3975                                 if (ret.Equals (end_of_try) && labels == null)
3976                                         continue;
3977                                 if (labels == null) {
3978                                         labels = new Label [resume_points.Count];
3979                                         for (int j = 0; j < i; ++j)
3980                                                 labels [j] = end_of_try;
3981                                 }
3982                                 labels [i] = ret;
3983                         }
3984
3985                         if (labels != null) {
3986                                 int j;
3987                                 for (j = 1; j < labels.Length; ++j)
3988                                         if (!labels [0].Equals (labels [j]))
3989                                                 break;
3990                                 bool emit_dispatcher = j < labels.Length;
3991
3992                                 if (emit_dispatcher) {
3993                                         //SymbolWriter.StartIteratorDispatcher (ec.ig);
3994                                         ig.Emit (OpCodes.Ldloc, iterator.CurrentPC);
3995                                         IntConstant.EmitInt (ig, first_resume_pc);
3996                                         ig.Emit (OpCodes.Sub);
3997                                         ig.Emit (OpCodes.Switch, labels);
3998                                         //SymbolWriter.EndIteratorDispatcher (ec.ig);
3999                                 }
4000
4001                                 foreach (ResumableStatement s in resume_points)
4002                                         s.EmitForDispose (ec, iterator, end_of_try, emit_dispatcher);
4003                         }
4004
4005                         ig.MarkLabel (end_of_try);
4006
4007                         ig.BeginFinallyBlock ();
4008
4009                         EmitFinallyBody (ec);
4010
4011                         ig.EndExceptionBlock ();
4012                 }
4013         }
4014
4015         public class Lock : ExceptionStatement {
4016                 Expression expr;
4017                 public Statement Statement;
4018                 TemporaryVariable temp;
4019                         
4020                 public Lock (Expression expr, Statement stmt, Location l)
4021                 {
4022                         this.expr = expr;
4023                         Statement = stmt;
4024                         loc = l;
4025                 }
4026
4027                 public override bool Resolve (EmitContext ec)
4028                 {
4029                         expr = expr.Resolve (ec);
4030                         if (expr == null)
4031                                 return false;
4032
4033                         if (expr.Type.IsValueType){
4034                                 Report.Error (185, loc,
4035                                               "`{0}' is not a reference type as required by the lock statement",
4036                                               TypeManager.CSharpName (expr.Type));
4037                                 return false;
4038                         }
4039
4040                         ec.StartFlowBranching (this);
4041                         bool ok = Statement.Resolve (ec);
4042                         ec.EndFlowBranching ();
4043
4044                         ResolveReachability (ec);
4045
4046                         // Avoid creating libraries that reference the internal
4047                         // mcs NullType:
4048                         Type t = expr.Type;
4049                         if (t == TypeManager.null_type)
4050                                 t = TypeManager.object_type;
4051                         
4052                         temp = new TemporaryVariable (t, loc);
4053                         temp.Resolve (ec);
4054
4055                         if (TypeManager.void_monitor_enter_object == null || TypeManager.void_monitor_exit_object == null) {
4056                                 Type monitor_type = TypeManager.CoreLookupType ("System.Threading", "Monitor", Kind.Class, true);
4057                                 TypeManager.void_monitor_enter_object = TypeManager.GetPredefinedMethod (
4058                                         monitor_type, "Enter", loc, TypeManager.object_type);
4059                                 TypeManager.void_monitor_exit_object = TypeManager.GetPredefinedMethod (
4060                                         monitor_type, "Exit", loc, TypeManager.object_type);
4061                         }
4062                         
4063                         return ok;
4064                 }
4065                 
4066                 protected override void EmitPreTryBody (EmitContext ec)
4067                 {
4068                         ILGenerator ig = ec.ig;
4069
4070                         temp.EmitAssign (ec, expr);
4071                         temp.Emit (ec);
4072                         ig.Emit (OpCodes.Call, TypeManager.void_monitor_enter_object);
4073                 }
4074
4075                 protected override void EmitTryBody (EmitContext ec)
4076                 {
4077                         Statement.Emit (ec);
4078                 }
4079
4080                 protected override void EmitFinallyBody (EmitContext ec)
4081                 {
4082                         temp.Emit (ec);
4083                         ec.ig.Emit (OpCodes.Call, TypeManager.void_monitor_exit_object);
4084                 }
4085
4086                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4087                 {
4088                         expr.MutateHoistedGenericType (storey);
4089                         temp.MutateHoistedGenericType (storey);
4090                         Statement.MutateHoistedGenericType (storey);
4091                 }
4092                 
4093                 protected override void CloneTo (CloneContext clonectx, Statement t)
4094                 {
4095                         Lock target = (Lock) t;
4096
4097                         target.expr = expr.Clone (clonectx);
4098                         target.Statement = Statement.Clone (clonectx);
4099                 }
4100         }
4101
4102         public class Unchecked : Statement {
4103                 public Block Block;
4104                 
4105                 public Unchecked (Block b)
4106                 {
4107                         Block = b;
4108                         b.Unchecked = true;
4109                 }
4110
4111                 public override bool Resolve (EmitContext ec)
4112                 {
4113                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
4114                                 return Block.Resolve (ec);
4115                 }
4116                 
4117                 protected override void DoEmit (EmitContext ec)
4118                 {
4119                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
4120                                 Block.Emit (ec);
4121                 }
4122
4123                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4124                 {
4125                         Block.MutateHoistedGenericType (storey);
4126                 }
4127
4128                 protected override void CloneTo (CloneContext clonectx, Statement t)
4129                 {
4130                         Unchecked target = (Unchecked) t;
4131
4132                         target.Block = clonectx.LookupBlock (Block);
4133                 }
4134         }
4135
4136         public class Checked : Statement {
4137                 public Block Block;
4138                 
4139                 public Checked (Block b)
4140                 {
4141                         Block = b;
4142                         b.Unchecked = false;
4143                 }
4144
4145                 public override bool Resolve (EmitContext ec)
4146                 {
4147                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
4148                                 return Block.Resolve (ec);
4149                 }
4150
4151                 protected override void DoEmit (EmitContext ec)
4152                 {
4153                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
4154                                 Block.Emit (ec);
4155                 }
4156
4157                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4158                 {
4159                         Block.MutateHoistedGenericType (storey);
4160                 }
4161
4162                 protected override void CloneTo (CloneContext clonectx, Statement t)
4163                 {
4164                         Checked target = (Checked) t;
4165
4166                         target.Block = clonectx.LookupBlock (Block);
4167                 }
4168         }
4169
4170         public class Unsafe : Statement {
4171                 public Block Block;
4172
4173                 public Unsafe (Block b)
4174                 {
4175                         Block = b;
4176                         Block.Unsafe = true;
4177                 }
4178
4179                 public override bool Resolve (EmitContext ec)
4180                 {
4181                         using (ec.With (EmitContext.Flags.InUnsafe, true))
4182                                 return Block.Resolve (ec);
4183                 }
4184                 
4185                 protected override void DoEmit (EmitContext ec)
4186                 {
4187                         using (ec.With (EmitContext.Flags.InUnsafe, true))
4188                                 Block.Emit (ec);
4189                 }
4190
4191                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4192                 {
4193                         Block.MutateHoistedGenericType (storey);
4194                 }
4195
4196                 protected override void CloneTo (CloneContext clonectx, Statement t)
4197                 {
4198                         Unsafe target = (Unsafe) t;
4199
4200                         target.Block = clonectx.LookupBlock (Block);
4201                 }
4202         }
4203
4204         // 
4205         // Fixed statement
4206         //
4207         public class Fixed : Statement {
4208                 Expression type;
4209                 ArrayList declarators;
4210                 Statement statement;
4211                 Type expr_type;
4212                 Emitter[] data;
4213                 bool has_ret;
4214
4215                 abstract class Emitter
4216                 {
4217                         protected LocalInfo vi;
4218                         protected Expression converted;
4219
4220                         protected Emitter (Expression expr, LocalInfo li)
4221                         {
4222                                 converted = expr;
4223                                 vi = li;
4224                         }
4225
4226                         public abstract void Emit (EmitContext ec);
4227                         public abstract void EmitExit (EmitContext ec);
4228                 }
4229
4230                 class ExpressionEmitter : Emitter {
4231                         public ExpressionEmitter (Expression converted, LocalInfo li) :
4232                                 base (converted, li)
4233                         {
4234                         }
4235
4236                         public override void Emit (EmitContext ec) {
4237                                 //
4238                                 // Store pointer in pinned location
4239                                 //
4240                                 converted.Emit (ec);
4241                                 vi.EmitAssign (ec);
4242                         }
4243
4244                         public override void EmitExit (EmitContext ec)
4245                         {
4246                                 ec.ig.Emit (OpCodes.Ldc_I4_0);
4247                                 ec.ig.Emit (OpCodes.Conv_U);
4248                                 vi.EmitAssign (ec);
4249                         }
4250                 }
4251
4252                 class StringEmitter : Emitter {
4253                         class StringPtr : Expression
4254                         {
4255                                 LocalBuilder b;
4256
4257                                 public StringPtr (LocalBuilder b, Location l)
4258                                 {
4259                                         this.b = b;
4260                                         eclass = ExprClass.Value;
4261                                         type = TypeManager.char_ptr_type;
4262                                         loc = l;
4263                                 }
4264
4265                                 public override Expression CreateExpressionTree (EmitContext ec)
4266                                 {
4267                                         throw new NotSupportedException ("ET");
4268                                 }
4269
4270                                 public override Expression DoResolve (EmitContext ec)
4271                                 {
4272                                         // This should never be invoked, we are born in fully
4273                                         // initialized state.
4274
4275                                         return this;
4276                                 }
4277
4278                                 public override void Emit (EmitContext ec)
4279                                 {
4280                                         if (TypeManager.int_get_offset_to_string_data == null) {
4281                                                 // TODO: Move to resolve !!
4282                                                 TypeManager.int_get_offset_to_string_data = TypeManager.GetPredefinedMethod (
4283                                                         TypeManager.runtime_helpers_type, "get_OffsetToStringData", loc, Type.EmptyTypes);
4284                                         }
4285
4286                                         ILGenerator ig = ec.ig;
4287
4288                                         ig.Emit (OpCodes.Ldloc, b);
4289                                         ig.Emit (OpCodes.Conv_I);
4290                                         ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
4291                                         ig.Emit (OpCodes.Add);
4292                                 }
4293                         }
4294
4295                         LocalBuilder pinned_string;
4296                         Location loc;
4297
4298                         public StringEmitter (Expression expr, LocalInfo li, Location loc):
4299                                 base (expr, li)
4300                         {
4301                                 this.loc = loc;
4302                         }
4303
4304                         public override void Emit (EmitContext ec)
4305                         {
4306                                 ILGenerator ig = ec.ig;
4307                                 pinned_string = TypeManager.DeclareLocalPinned (ig, TypeManager.string_type);
4308                                         
4309                                 converted.Emit (ec);
4310                                 ig.Emit (OpCodes.Stloc, pinned_string);
4311
4312                                 Expression sptr = new StringPtr (pinned_string, loc);
4313                                 converted = Convert.ImplicitConversionRequired (
4314                                         ec, sptr, vi.VariableType, loc);
4315                                         
4316                                 if (converted == null)
4317                                         return;
4318
4319                                 converted.Emit (ec);
4320                                 vi.EmitAssign (ec);
4321                         }
4322
4323                         public override void EmitExit (EmitContext ec)
4324                         {
4325                                 ec.ig.Emit (OpCodes.Ldnull);
4326                                 ec.ig.Emit (OpCodes.Stloc, pinned_string);
4327                         }
4328                 }
4329
4330                 public Fixed (Expression type, ArrayList decls, Statement stmt, Location l)
4331                 {
4332                         this.type = type;
4333                         declarators = decls;
4334                         statement = stmt;
4335                         loc = l;
4336                 }
4337
4338                 public Statement Statement {
4339                         get { return statement; }
4340                 }
4341
4342                 public override bool Resolve (EmitContext ec)
4343                 {
4344                         if (!ec.InUnsafe){
4345                                 Expression.UnsafeError (loc);
4346                                 return false;
4347                         }
4348                         
4349                         TypeExpr texpr = type.ResolveAsContextualType (ec, false);
4350                         if (texpr == null) {
4351                                 if (type is VarExpr)
4352                                         Report.Error (821, type.Location, "A fixed statement cannot use an implicitly typed local variable");
4353
4354                                 return false;
4355                         }
4356
4357                         expr_type = texpr.Type;
4358
4359                         data = new Emitter [declarators.Count];
4360
4361                         if (!expr_type.IsPointer){
4362                                 Report.Error (209, loc, "The type of locals declared in a fixed statement must be a pointer type");
4363                                 return false;
4364                         }
4365                         
4366                         int i = 0;
4367                         foreach (Pair p in declarators){
4368                                 LocalInfo vi = (LocalInfo) p.First;
4369                                 Expression e = (Expression) p.Second;
4370                                 
4371                                 vi.VariableInfo.SetAssigned (ec);
4372                                 vi.SetReadOnlyContext (LocalInfo.ReadOnlyContext.Fixed);
4373
4374                                 //
4375                                 // The rules for the possible declarators are pretty wise,
4376                                 // but the production on the grammar is more concise.
4377                                 //
4378                                 // So we have to enforce these rules here.
4379                                 //
4380                                 // We do not resolve before doing the case 1 test,
4381                                 // because the grammar is explicit in that the token &
4382                                 // is present, so we need to test for this particular case.
4383                                 //
4384
4385                                 if (e is Cast){
4386                                         Report.Error (254, loc, "The right hand side of a fixed statement assignment may not be a cast expression");
4387                                         return false;
4388                                 }
4389
4390                                 ec.InFixedInitializer = true;
4391                                 e = e.Resolve (ec);
4392                                 ec.InFixedInitializer = false;
4393                                 if (e == null)
4394                                         return false;
4395
4396                                 //
4397                                 // Case 2: Array
4398                                 //
4399                                 if (e.Type.IsArray){
4400                                         Type array_type = TypeManager.GetElementType (e.Type);
4401                                         
4402                                         //
4403                                         // Provided that array_type is unmanaged,
4404                                         //
4405                                         if (!TypeManager.VerifyUnManaged (array_type, loc))
4406                                                 return false;
4407
4408                                         //
4409                                         // and T* is implicitly convertible to the
4410                                         // pointer type given in the fixed statement.
4411                                         //
4412                                         ArrayPtr array_ptr = new ArrayPtr (e, array_type, loc);
4413                                         
4414                                         Expression converted = Convert.ImplicitConversionRequired (
4415                                                 ec, array_ptr, vi.VariableType, loc);
4416                                         if (converted == null)
4417                                                 return false;
4418                                         
4419                                         //
4420                                         // fixed (T* e_ptr = (e == null || e.Length == 0) ? null : converted [0])
4421                                         //
4422                                         converted = new Conditional (new Binary (Binary.Operator.LogicalOr,
4423                                                 new Binary (Binary.Operator.Equality, e, new NullLiteral (loc)),
4424                                                 new Binary (Binary.Operator.Equality, new MemberAccess (e, "Length"), new IntConstant (0, loc))),
4425                                                         new NullPointer (loc),
4426                                                         converted);
4427
4428                                         converted = converted.Resolve (ec);                                     
4429
4430                                         data [i] = new ExpressionEmitter (converted, vi);
4431                                         i++;
4432
4433                                         continue;
4434                                 }
4435
4436                                 //
4437                                 // Case 3: string
4438                                 //
4439                                 if (e.Type == TypeManager.string_type){
4440                                         data [i] = new StringEmitter (e, vi, loc);
4441                                         i++;
4442                                         continue;
4443                                 }
4444
4445                                 // Case 4: fixed buffer
4446                                 if (e is FixedBufferPtr) {
4447                                         data [i++] = new ExpressionEmitter (e, vi);
4448                                         continue;
4449                                 }
4450
4451                                 //
4452                                 // Case 1: & object.
4453                                 //
4454                                 Unary u = e as Unary;
4455                                 if (u != null && u.Oper == Unary.Operator.AddressOf) {
4456                                         IVariableReference vr = u.Expr as IVariableReference;
4457                                         if (vr == null || !vr.IsFixedVariable) {
4458                                                 data [i] = new ExpressionEmitter (e, vi);
4459                                         }
4460                                 }
4461
4462                                 if (data [i++] == null)
4463                                         Report.Error (213, vi.Location, "You cannot use the fixed statement to take the address of an already fixed expression");
4464
4465                                 e = Convert.ImplicitConversionRequired (ec, e, expr_type, loc);
4466                         }
4467
4468                         ec.StartFlowBranching (FlowBranching.BranchingType.Conditional, loc);
4469                         bool ok = statement.Resolve (ec);
4470                         bool flow_unreachable = ec.EndFlowBranching ();
4471                         has_ret = flow_unreachable;
4472
4473                         return ok;
4474                 }
4475                 
4476                 protected override void DoEmit (EmitContext ec)
4477                 {
4478                         for (int i = 0; i < data.Length; i++) {
4479                                 data [i].Emit (ec);
4480                         }
4481
4482                         statement.Emit (ec);
4483
4484                         if (has_ret)
4485                                 return;
4486
4487                         //
4488                         // Clear the pinned variable
4489                         //
4490                         for (int i = 0; i < data.Length; i++) {
4491                                 data [i].EmitExit (ec);
4492                         }
4493                 }
4494
4495                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4496                 {
4497                         // Fixed statement cannot be used inside anonymous methods or lambdas
4498                         throw new NotSupportedException ();
4499                 }
4500
4501                 protected override void CloneTo (CloneContext clonectx, Statement t)
4502                 {
4503                         Fixed target = (Fixed) t;
4504
4505                         target.type = type.Clone (clonectx);
4506                         target.declarators = new ArrayList (declarators.Count);
4507                         foreach (Pair p in declarators) {
4508                                 LocalInfo vi = (LocalInfo) p.First;
4509                                 Expression e = (Expression) p.Second;
4510
4511                                 target.declarators.Add (
4512                                         new Pair (clonectx.LookupVariable (vi), e.Clone (clonectx)));                           
4513                         }
4514                         
4515                         target.statement = statement.Clone (clonectx);
4516                 }
4517         }
4518         
4519         public class Catch : Statement {
4520                 public readonly string Name;
4521                 public Block  Block;
4522                 public Block  VarBlock;
4523
4524                 Expression type_expr;
4525                 Type type;
4526                 
4527                 public Catch (Expression type, string name, Block block, Block var_block, Location l)
4528                 {
4529                         type_expr = type;
4530                         Name = name;
4531                         Block = block;
4532                         VarBlock = var_block;
4533                         loc = l;
4534                 }
4535
4536                 public Type CatchType {
4537                         get {
4538                                 return type;
4539                         }
4540                 }
4541
4542                 public bool IsGeneral {
4543                         get {
4544                                 return type_expr == null;
4545                         }
4546                 }
4547
4548                 protected override void DoEmit (EmitContext ec)
4549                 {
4550                         ILGenerator ig = ec.ig;
4551
4552                         if (CatchType != null)
4553                                 ig.BeginCatchBlock (CatchType);
4554                         else
4555                                 ig.BeginCatchBlock (TypeManager.object_type);
4556
4557                         if (VarBlock != null)
4558                                 VarBlock.Emit (ec);
4559
4560                         if (Name != null) {
4561                                 // TODO: Move to resolve
4562                                 LocalVariableReference lvr = new LocalVariableReference (Block, Name, loc);
4563                                 lvr.Resolve (ec);
4564
4565                                 Expression source;
4566                                 if (lvr.IsHoisted) {
4567                                         LocalTemporary lt = new LocalTemporary (lvr.Type);
4568                                         lt.Store (ec);
4569                                         source = lt;
4570                                 } else {
4571                                         // Variable is at the top of the stack
4572                                         source = EmptyExpression.Null;
4573                                 }
4574
4575                                 lvr.EmitAssign (ec, source, false, false);
4576                         } else
4577                                 ig.Emit (OpCodes.Pop);
4578
4579                         Block.Emit (ec);
4580                 }
4581
4582                 public override bool Resolve (EmitContext ec)
4583                 {
4584                         using (ec.With (EmitContext.Flags.InCatch, true)) {
4585                                 if (type_expr != null) {
4586                                         TypeExpr te = type_expr.ResolveAsTypeTerminal (ec, false);
4587                                         if (te == null)
4588                                                 return false;
4589
4590                                         type = te.Type;
4591
4592                                         if (type != TypeManager.exception_type && !TypeManager.IsSubclassOf (type, TypeManager.exception_type)){
4593                                                 Error (155, "The type caught or thrown must be derived from System.Exception");
4594                                                 return false;
4595                                         }
4596                                 } else
4597                                         type = null;
4598
4599                                 if (!Block.Resolve (ec))
4600                                         return false;
4601
4602                                 // Even though VarBlock surrounds 'Block' we resolve it later, so that we can correctly
4603                                 // emit the "unused variable" warnings.
4604                                 if (VarBlock != null)
4605                                         return VarBlock.Resolve (ec);
4606
4607                                 return true;
4608                         }
4609                 }
4610
4611                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4612                 {
4613                         if (type != null)
4614                                 type = storey.MutateType (type);
4615                         if (VarBlock != null)
4616                                 VarBlock.MutateHoistedGenericType (storey);
4617                         Block.MutateHoistedGenericType (storey);
4618                 }
4619
4620                 protected override void CloneTo (CloneContext clonectx, Statement t)
4621                 {
4622                         Catch target = (Catch) t;
4623
4624                         if (type_expr != null)
4625                                 target.type_expr = type_expr.Clone (clonectx);
4626                         if (VarBlock != null)
4627                                 target.VarBlock = clonectx.LookupBlock (VarBlock);                      
4628                         target.Block = clonectx.LookupBlock (Block);
4629                 }
4630         }
4631
4632         public class TryFinally : ExceptionStatement {
4633                 Statement stmt;
4634                 Block fini;
4635
4636                 public TryFinally (Statement stmt, Block fini, Location l)
4637                 {
4638                         this.stmt = stmt;
4639                         this.fini = fini;
4640                         loc = l;
4641                 }
4642
4643                 public override bool Resolve (EmitContext ec)
4644                 {
4645                         bool ok = true;
4646
4647                         ec.StartFlowBranching (this);
4648
4649                         if (!stmt.Resolve (ec))
4650                                 ok = false;
4651
4652                         if (ok)
4653                                 ec.CurrentBranching.CreateSibling (fini, FlowBranching.SiblingType.Finally);
4654                         using (ec.With (EmitContext.Flags.InFinally, true)) {
4655                                 if (!fini.Resolve (ec))
4656                                         ok = false;
4657                         }
4658
4659                         ec.EndFlowBranching ();
4660
4661                         ResolveReachability (ec);
4662
4663                         return ok;
4664                 }
4665
4666                 protected override void EmitPreTryBody (EmitContext ec)
4667                 {
4668                 }
4669
4670                 protected override void EmitTryBody (EmitContext ec)
4671                 {
4672                         stmt.Emit (ec);
4673                 }
4674
4675                 protected override void EmitFinallyBody (EmitContext ec)
4676                 {
4677                         fini.Emit (ec);
4678                 }
4679
4680                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4681                 {
4682                         stmt.MutateHoistedGenericType (storey);
4683                         fini.MutateHoistedGenericType (storey);
4684                 }
4685
4686                 protected override void CloneTo (CloneContext clonectx, Statement t)
4687                 {
4688                         TryFinally target = (TryFinally) t;
4689
4690                         target.stmt = (Statement) stmt.Clone (clonectx);
4691                         if (fini != null)
4692                                 target.fini = clonectx.LookupBlock (fini);
4693                 }
4694         }
4695
4696         public class TryCatch : Statement {
4697                 public Block Block;
4698                 public ArrayList Specific;
4699                 public Catch General;
4700                 bool inside_try_finally, code_follows;
4701
4702                 public TryCatch (Block block, ArrayList catch_clauses, Location l, bool inside_try_finally)
4703                 {
4704                         this.Block = block;
4705                         this.Specific = catch_clauses;
4706                         this.General = null;
4707                         this.inside_try_finally = inside_try_finally;
4708
4709                         for (int i = 0; i < catch_clauses.Count; ++i) {
4710                                 Catch c = (Catch) catch_clauses [i];
4711                                 if (c.IsGeneral) {
4712                                         if (i != catch_clauses.Count - 1)
4713                                                 Report.Error (1017, c.loc, "Try statement already has an empty catch block");
4714                                         this.General = c;
4715                                         catch_clauses.RemoveAt (i);
4716                                         i--;
4717                                 }
4718                         }
4719
4720                         loc = l;
4721                 }
4722
4723                 public override bool Resolve (EmitContext ec)
4724                 {
4725                         bool ok = true;
4726
4727                         ec.StartFlowBranching (this);
4728
4729                         if (!Block.Resolve (ec))
4730                                 ok = false;
4731
4732                         Type[] prev_catches = new Type [Specific.Count];
4733                         int last_index = 0;
4734                         foreach (Catch c in Specific){
4735                                 ec.CurrentBranching.CreateSibling (c.Block, FlowBranching.SiblingType.Catch);
4736
4737                                 if (c.Name != null) {
4738                                         LocalInfo vi = c.Block.GetLocalInfo (c.Name);
4739                                         if (vi == null)
4740                                                 throw new Exception ();
4741
4742                                         vi.VariableInfo = null;
4743                                 }
4744
4745                                 if (!c.Resolve (ec))
4746                                         ok = false;
4747
4748                                 Type resolved_type = c.CatchType;
4749                                 for (int ii = 0; ii < last_index; ++ii) {
4750                                         if (resolved_type == prev_catches [ii] || TypeManager.IsSubclassOf (resolved_type, prev_catches [ii])) {
4751                                                 Report.Error (160, c.loc, "A previous catch clause already catches all exceptions of this or a super type `{0}'", prev_catches [ii].FullName);
4752                                                 ok = false;
4753                                         }
4754                                 }
4755
4756                                 prev_catches [last_index++] = resolved_type;
4757                         }
4758
4759                         if (General != null) {
4760                                 if (CodeGen.Assembly.WrapNonExceptionThrows) {
4761                                         foreach (Catch c in Specific){
4762                                                 if (c.CatchType == TypeManager.exception_type) {
4763                                                         Report.Warning (1058, 1, c.loc, "A previous catch clause already catches all exceptions. All non-exceptions thrown will be wrapped in a `System.Runtime.CompilerServices.RuntimeWrappedException'");
4764                                                 }
4765                                         }
4766                                 }
4767
4768                                 ec.CurrentBranching.CreateSibling (General.Block, FlowBranching.SiblingType.Catch);
4769
4770                                 if (!General.Resolve (ec))
4771                                         ok = false;
4772                         }
4773
4774                         ec.EndFlowBranching ();
4775
4776                         // System.Reflection.Emit automatically emits a 'leave' at the end of a try/catch clause
4777                         // So, ensure there's some IL code after this statement
4778                         if (!inside_try_finally && !code_follows && ec.CurrentBranching.CurrentUsageVector.IsUnreachable)
4779                                 ec.NeedReturnLabel ();
4780
4781                         return ok;
4782                 }
4783
4784                 public void SomeCodeFollows ()
4785                 {
4786                         code_follows = true;
4787                 }
4788                 
4789                 protected override void DoEmit (EmitContext ec)
4790                 {
4791                         ILGenerator ig = ec.ig;
4792
4793                         if (!inside_try_finally)
4794                                 ig.BeginExceptionBlock ();
4795
4796                         Block.Emit (ec);
4797
4798                         foreach (Catch c in Specific)
4799                                 c.Emit (ec);
4800
4801                         if (General != null)
4802                                 General.Emit (ec);
4803
4804                         if (!inside_try_finally)
4805                                 ig.EndExceptionBlock ();
4806                 }
4807
4808                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4809                 {
4810                         Block.MutateHoistedGenericType (storey);
4811
4812                         if (General != null)
4813                                 General.MutateHoistedGenericType (storey);
4814                         if (Specific != null) {
4815                                 foreach (Catch c in Specific)
4816                                         c.MutateHoistedGenericType (storey);
4817                         }
4818                 }
4819
4820                 protected override void CloneTo (CloneContext clonectx, Statement t)
4821                 {
4822                         TryCatch target = (TryCatch) t;
4823
4824                         target.Block = clonectx.LookupBlock (Block);
4825                         if (General != null)
4826                                 target.General = (Catch) General.Clone (clonectx);
4827                         if (Specific != null){
4828                                 target.Specific = new ArrayList ();
4829                                 foreach (Catch c in Specific)
4830                                         target.Specific.Add (c.Clone (clonectx));
4831                         }
4832                 }
4833         }
4834
4835         public class UsingTemporary : ExceptionStatement {
4836                 TemporaryVariable local_copy;
4837                 public Statement Statement;
4838                 Expression expr;
4839                 Type expr_type;
4840
4841                 public UsingTemporary (Expression expr, Statement stmt, Location l)
4842                 {
4843                         this.expr = expr;
4844                         Statement = stmt;
4845                         loc = l;
4846                 }
4847
4848                 public override bool Resolve (EmitContext ec)
4849                 {
4850                         expr = expr.Resolve (ec);
4851                         if (expr == null)
4852                                 return false;
4853
4854                         expr_type = expr.Type;
4855
4856                         if (!TypeManager.ImplementsInterface (expr_type, TypeManager.idisposable_type)) {
4857                                 if (Convert.ImplicitConversion (ec, expr, TypeManager.idisposable_type, loc) == null) {
4858                                         Using.Error_IsNotConvertibleToIDisposable (expr);
4859                                         return false;
4860                                 }
4861                         }
4862
4863                         local_copy = new TemporaryVariable (expr_type, loc);
4864                         local_copy.Resolve (ec);
4865
4866                         ec.StartFlowBranching (this);
4867
4868                         bool ok = Statement.Resolve (ec);
4869
4870                         ec.EndFlowBranching ();
4871
4872                         ResolveReachability (ec);
4873
4874                         if (TypeManager.void_dispose_void == null) {
4875                                 TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
4876                                         TypeManager.idisposable_type, "Dispose", loc, Type.EmptyTypes);
4877                         }
4878
4879                         return ok;
4880                 }
4881
4882                 protected override void EmitPreTryBody (EmitContext ec)
4883                 {
4884                         local_copy.EmitAssign (ec, expr);
4885                 }
4886
4887                 protected override void EmitTryBody (EmitContext ec)
4888                 {
4889                         Statement.Emit (ec);
4890                 }
4891
4892                 protected override void EmitFinallyBody (EmitContext ec)
4893                 {
4894                         ILGenerator ig = ec.ig;
4895                         if (!expr_type.IsValueType) {
4896                                 Label skip = ig.DefineLabel ();
4897                                 local_copy.Emit (ec);
4898                                 ig.Emit (OpCodes.Brfalse, skip);
4899                                 local_copy.Emit (ec);
4900                                 ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
4901                                 ig.MarkLabel (skip);
4902                                 return;
4903                         }
4904
4905                         Expression ml = Expression.MemberLookup (
4906                                 ec.ContainerType, TypeManager.idisposable_type, expr_type,
4907                                 "Dispose", Location.Null);
4908
4909                         if (!(ml is MethodGroupExpr)) {
4910                                 local_copy.Emit (ec);
4911                                 ig.Emit (OpCodes.Box, expr_type);
4912                                 ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
4913                                 return;
4914                         }
4915
4916                         MethodInfo mi = null;
4917
4918                         foreach (MethodInfo mk in ((MethodGroupExpr) ml).Methods) {
4919                                 if (TypeManager.GetParameterData (mk).Count == 0) {
4920                                         mi = mk;
4921                                         break;
4922                                 }
4923                         }
4924
4925                         if (mi == null) {
4926                                 Report.Error(-100, Mono.CSharp.Location.Null, "Internal error: No Dispose method which takes 0 parameters.");
4927                                 return;
4928                         }
4929
4930                         local_copy.AddressOf (ec, AddressOp.Load);
4931                         ig.Emit (OpCodes.Call, mi);
4932                 }
4933
4934                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4935                 {
4936                         expr_type = storey.MutateType (expr_type);
4937                         local_copy.MutateHoistedGenericType (storey);
4938                         Statement.MutateHoistedGenericType (storey);
4939                 }
4940
4941                 protected override void CloneTo (CloneContext clonectx, Statement t)
4942                 {
4943                         UsingTemporary target = (UsingTemporary) t;
4944
4945                         target.expr = expr.Clone (clonectx);
4946                         target.Statement = Statement.Clone (clonectx);
4947                 }
4948         }
4949
4950         public class Using : ExceptionStatement {
4951                 Statement stmt;
4952                 public Statement EmbeddedStatement {
4953                         get { return stmt is Using ? ((Using) stmt).EmbeddedStatement : stmt; }
4954                 }
4955
4956                 Expression var;
4957                 Expression init;
4958
4959                 Expression converted_var;
4960                 ExpressionStatement assign;
4961
4962                 public Using (Expression var, Expression init, Statement stmt, Location l)
4963                 {
4964                         this.var = var;
4965                         this.init = init;
4966                         this.stmt = stmt;
4967                         loc = l;
4968                 }
4969
4970                 bool ResolveVariable (EmitContext ec)
4971                 {
4972                         ExpressionStatement a = new SimpleAssign (var, init, loc);
4973                         a = a.ResolveStatement (ec);
4974                         if (a == null)
4975                                 return false;
4976
4977                         assign = a;
4978
4979                         if (TypeManager.ImplementsInterface (a.Type, TypeManager.idisposable_type)) {
4980                                 converted_var = var;
4981                                 return true;
4982                         }
4983
4984                         Expression e = Convert.ImplicitConversionStandard (ec, a, TypeManager.idisposable_type, var.Location);
4985                         if (e == null) {
4986                                 Error_IsNotConvertibleToIDisposable (var);
4987                                 return false;
4988                         }
4989
4990                         converted_var = e;
4991
4992                         return true;
4993                 }
4994
4995                 static public void Error_IsNotConvertibleToIDisposable (Expression expr)
4996                 {
4997                         Report.SymbolRelatedToPreviousError (expr.Type);
4998                         Report.Error (1674, expr.Location, "`{0}': type used in a using statement must be implicitly convertible to `System.IDisposable'",
4999                                 expr.GetSignatureForError ());
5000                 }
5001
5002                 protected override void EmitPreTryBody (EmitContext ec)
5003                 {
5004                         assign.EmitStatement (ec);
5005                 }
5006
5007                 protected override void EmitTryBody (EmitContext ec)
5008                 {
5009                         stmt.Emit (ec);
5010                 }
5011
5012                 protected override void EmitFinallyBody (EmitContext ec)
5013                 {
5014                         ILGenerator ig = ec.ig;
5015
5016                         if (!var.Type.IsValueType) {
5017                                 Label skip = ig.DefineLabel ();
5018                                 var.Emit (ec);
5019                                 ig.Emit (OpCodes.Brfalse, skip);
5020                                 converted_var.Emit (ec);
5021                                 ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
5022                                 ig.MarkLabel (skip);
5023                         } else {
5024                                 Expression ml = Expression.MemberLookup(ec.ContainerType, TypeManager.idisposable_type, var.Type, "Dispose", Mono.CSharp.Location.Null);
5025
5026                                 if (!(ml is MethodGroupExpr)) {
5027                                         var.Emit (ec);
5028                                         ig.Emit (OpCodes.Box, var.Type);
5029                                         ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
5030                                 } else {
5031                                         MethodInfo mi = null;
5032
5033                                         foreach (MethodInfo mk in ((MethodGroupExpr) ml).Methods) {
5034                                                 if (TypeManager.GetParameterData (mk).Count == 0) {
5035                                                         mi = mk;
5036                                                         break;
5037                                                 }
5038                                         }
5039
5040                                         if (mi == null) {
5041                                                 Report.Error(-100, Mono.CSharp.Location.Null, "Internal error: No Dispose method which takes 0 parameters.");
5042                                                 return;
5043                                         }
5044
5045                                         IMemoryLocation mloc = (IMemoryLocation) var;
5046
5047                                         mloc.AddressOf (ec, AddressOp.Load);
5048                                         ig.Emit (OpCodes.Call, mi);
5049                                 }
5050                         }
5051                 }
5052
5053                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5054                 {
5055                         assign.MutateHoistedGenericType (storey);
5056                         var.MutateHoistedGenericType (storey);
5057                         stmt.MutateHoistedGenericType (storey);
5058                 }
5059
5060                 public override bool Resolve (EmitContext ec)
5061                 {
5062                         if (!ResolveVariable (ec))
5063                                 return false;
5064
5065                         ec.StartFlowBranching (this);
5066
5067                         bool ok = stmt.Resolve (ec);
5068
5069                         ec.EndFlowBranching ();
5070
5071                         ResolveReachability (ec);
5072
5073                         if (TypeManager.void_dispose_void == null) {
5074                                 TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
5075                                         TypeManager.idisposable_type, "Dispose", loc, Type.EmptyTypes);
5076                         }
5077
5078                         return ok;
5079                 }
5080
5081                 protected override void CloneTo (CloneContext clonectx, Statement t)
5082                 {
5083                         Using target = (Using) t;
5084
5085                         target.var = var.Clone (clonectx);
5086                         target.init = init.Clone (clonectx);
5087                         target.stmt = stmt.Clone (clonectx);
5088                 }
5089         }
5090
5091         /// <summary>
5092         ///   Implementation of the foreach C# statement
5093         /// </summary>
5094         public class Foreach : Statement {
5095                 Expression type;
5096                 Expression variable;
5097                 Expression expr;
5098                 Statement statement;
5099                 
5100                 public Foreach (Expression type, LocalVariableReference var, Expression expr,
5101                                 Statement stmt, Location l)
5102                 {
5103                         this.type = type;
5104                         this.variable = var;
5105                         this.expr = expr;
5106                         statement = stmt;
5107                         loc = l;
5108                 }
5109
5110                 public Statement Statement {
5111                         get { return statement; }
5112                 }
5113
5114                 public override bool Resolve (EmitContext ec)
5115                 {
5116                         expr = expr.Resolve (ec);
5117                         if (expr == null)
5118                                 return false;
5119
5120                         if (expr.IsNull) {
5121                                 Report.Error (186, loc, "Use of null is not valid in this context");
5122                                 return false;
5123                         }
5124
5125                         if (expr.eclass == ExprClass.MethodGroup || expr is AnonymousMethodExpression) {
5126                                 Report.Error (446, expr.Location, "Foreach statement cannot operate on a `{0}'",
5127                                         expr.ExprClassName);
5128                                 return false;
5129                         }
5130
5131                         if (expr.Type.IsArray) {
5132                                 statement = new ArrayForeach (type, variable, expr, statement, loc);
5133                         } else {
5134                                 statement = new CollectionForeach (type, variable, expr, statement, loc);
5135                         }
5136                         
5137                         return statement.Resolve (ec);
5138                 }
5139
5140                 protected override void DoEmit (EmitContext ec)
5141                 {
5142                         ILGenerator ig = ec.ig;
5143                         
5144                         Label old_begin = ec.LoopBegin, old_end = ec.LoopEnd;
5145                         ec.LoopBegin = ig.DefineLabel ();
5146                         ec.LoopEnd = ig.DefineLabel ();
5147
5148                         statement.Emit (ec);
5149                         
5150                         ec.LoopBegin = old_begin;
5151                         ec.LoopEnd = old_end;
5152                 }
5153
5154                 protected class ArrayCounter : TemporaryVariable
5155                 {
5156                         StatementExpression increment;
5157
5158                         public ArrayCounter (Location loc)
5159                                 : base (TypeManager.int32_type, loc)
5160                         {
5161                         }
5162
5163                         public void ResolveIncrement (EmitContext ec)
5164                         {
5165                                 increment = new StatementExpression (new UnaryMutator (UnaryMutator.Mode.PostIncrement, this, loc));
5166                                 increment.Resolve (ec);
5167                         }
5168
5169                         public void EmitIncrement (EmitContext ec)
5170                         {
5171                                 increment.Emit (ec);
5172                         }
5173                 }
5174
5175                 protected class ArrayForeach : Statement
5176                 {
5177                         Expression variable, expr, conv;
5178                         Statement statement;
5179                         Type array_type;
5180                         Expression var_type;
5181                         TemporaryVariable[] lengths;
5182                         ArrayCounter[] counter;
5183                         int rank;
5184
5185                         TemporaryVariable copy;
5186                         Expression access;
5187                         Expression[] length_exprs;
5188
5189                         public ArrayForeach (Expression var_type, Expression var,
5190                                              Expression expr, Statement stmt, Location l)
5191                         {
5192                                 this.var_type = var_type;
5193                                 this.variable = var;
5194                                 this.expr = expr;
5195                                 statement = stmt;
5196                                 loc = l;
5197                         }
5198
5199                         protected override void CloneTo (CloneContext clonectx, Statement target)
5200                         {
5201                                 throw new NotImplementedException ();
5202                         }
5203
5204                         public override bool Resolve (EmitContext ec)
5205                         {
5206                                 array_type = expr.Type;
5207                                 rank = array_type.GetArrayRank ();
5208
5209                                 copy = new TemporaryVariable (array_type, loc);
5210                                 copy.Resolve (ec);
5211
5212                                 counter = new ArrayCounter [rank];
5213                                 lengths = new TemporaryVariable [rank];
5214                                 length_exprs = new Expression [rank];
5215
5216                                 ArrayList list = new ArrayList (rank);
5217                                 for (int i = 0; i < rank; i++) {
5218                                         counter [i] = new ArrayCounter (loc);
5219                                         counter [i].ResolveIncrement (ec);                                      
5220
5221                                         lengths [i] = new TemporaryVariable (TypeManager.int32_type, loc);
5222                                         lengths [i].Resolve (ec);
5223
5224                                         if (rank == 1) {
5225                                                 length_exprs [i] = new MemberAccess (copy, "Length").Resolve (ec);
5226                                         } else {
5227                                                 ArrayList args = new ArrayList (1);
5228                                                 args.Add (new Argument (new IntConstant (i, loc)));
5229                                                 length_exprs [i] = new Invocation (new MemberAccess (copy, "GetLength"), args).Resolve (ec);
5230                                         }
5231
5232                                         list.Add (counter [i]);
5233                                 }
5234
5235                                 access = new ElementAccess (copy, list).Resolve (ec);
5236                                 if (access == null)
5237                                         return false;
5238
5239                                 VarExpr ve = var_type as VarExpr;
5240                                 if (ve != null) {
5241                                         // Infer implicitly typed local variable from foreach array type
5242                                         var_type = new TypeExpression (access.Type, ve.Location);
5243                                 }
5244
5245                                 var_type = var_type.ResolveAsTypeTerminal (ec, false);
5246                                 if (var_type == null)
5247                                         return false;
5248
5249                                 conv = Convert.ExplicitConversion (ec, access, var_type.Type, loc);
5250                                 if (conv == null)
5251                                         return false;
5252
5253                                 bool ok = true;
5254
5255                                 ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
5256                                 ec.CurrentBranching.CreateSibling ();
5257
5258                                 variable = variable.ResolveLValue (ec, conv, loc);
5259                                 if (variable == null)
5260                                         ok = false;
5261
5262                                 ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc);
5263                                 if (!statement.Resolve (ec))
5264                                         ok = false;
5265                                 ec.EndFlowBranching ();
5266
5267                                 // There's no direct control flow from the end of the embedded statement to the end of the loop
5268                                 ec.CurrentBranching.CurrentUsageVector.Goto ();
5269
5270                                 ec.EndFlowBranching ();
5271
5272                                 return ok;
5273                         }
5274
5275                         protected override void DoEmit (EmitContext ec)
5276                         {
5277                                 ILGenerator ig = ec.ig;
5278
5279                                 copy.EmitAssign (ec, expr);
5280
5281                                 Label[] test = new Label [rank];
5282                                 Label[] loop = new Label [rank];
5283
5284                                 for (int i = 0; i < rank; i++) {
5285                                         test [i] = ig.DefineLabel ();
5286                                         loop [i] = ig.DefineLabel ();
5287
5288                                         lengths [i].EmitAssign (ec, length_exprs [i]);
5289                                 }
5290
5291                                 IntConstant zero = new IntConstant (0, loc);
5292                                 for (int i = 0; i < rank; i++) {
5293                                         counter [i].EmitAssign (ec, zero);
5294
5295                                         ig.Emit (OpCodes.Br, test [i]);
5296                                         ig.MarkLabel (loop [i]);
5297                                 }
5298
5299                                 ((IAssignMethod) variable).EmitAssign (ec, conv, false, false);
5300
5301                                 statement.Emit (ec);
5302
5303                                 ig.MarkLabel (ec.LoopBegin);
5304
5305                                 for (int i = rank - 1; i >= 0; i--){
5306                                         counter [i].EmitIncrement (ec);
5307
5308                                         ig.MarkLabel (test [i]);
5309                                         counter [i].Emit (ec);
5310                                         lengths [i].Emit (ec);
5311                                         ig.Emit (OpCodes.Blt, loop [i]);
5312                                 }
5313
5314                                 ig.MarkLabel (ec.LoopEnd);
5315                         }
5316
5317                         public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5318                         {
5319                                 copy.MutateHoistedGenericType (storey);
5320                                 conv.MutateHoistedGenericType (storey);
5321                                 variable.MutateHoistedGenericType (storey);
5322                                 statement.MutateHoistedGenericType (storey);
5323
5324                                 for (int i = 0; i < rank; i++) {
5325                                         counter [i].MutateHoistedGenericType (storey);
5326                                         lengths [i].MutateHoistedGenericType (storey);
5327                                 }
5328                         }
5329                 }
5330
5331                 protected class CollectionForeach : Statement
5332                 {
5333                         Expression variable, expr;
5334                         Statement statement;
5335
5336                         TemporaryVariable enumerator;
5337                         Expression init;
5338                         Statement loop;
5339                         Statement wrapper;
5340
5341                         MethodGroupExpr get_enumerator;
5342                         PropertyExpr get_current;
5343                         MethodInfo move_next;
5344                         Expression var_type;
5345                         Type enumerator_type;
5346                         bool enumerator_found;
5347
5348                         public CollectionForeach (Expression var_type, Expression var,
5349                                                   Expression expr, Statement stmt, Location l)
5350                         {
5351                                 this.var_type = var_type;
5352                                 this.variable = var;
5353                                 this.expr = expr;
5354                                 statement = stmt;
5355                                 loc = l;
5356                         }
5357
5358                         protected override void CloneTo (CloneContext clonectx, Statement target)
5359                         {
5360                                 throw new NotImplementedException ();
5361                         }
5362
5363                         bool GetEnumeratorFilter (EmitContext ec, MethodInfo mi)
5364                         {
5365                                 Type return_type = mi.ReturnType;
5366
5367                                 if ((return_type == TypeManager.ienumerator_type) && (mi.DeclaringType == TypeManager.string_type))
5368                                         //
5369                                         // Apply the same optimization as MS: skip the GetEnumerator
5370                                         // returning an IEnumerator, and use the one returning a 
5371                                         // CharEnumerator instead. This allows us to avoid the 
5372                                         // try-finally block and the boxing.
5373                                         //
5374                                         return false;
5375
5376                                 //
5377                                 // Ok, we can access it, now make sure that we can do something
5378                                 // with this `GetEnumerator'
5379                                 //
5380
5381                                 if (return_type == TypeManager.ienumerator_type ||
5382                                     TypeManager.ienumerator_type.IsAssignableFrom (return_type) ||
5383                                     (!RootContext.StdLib && TypeManager.ImplementsInterface (return_type, TypeManager.ienumerator_type))) {
5384                                         //
5385                                         // If it is not an interface, lets try to find the methods ourselves.
5386                                         // For example, if we have:
5387                                         // public class Foo : IEnumerator { public bool MoveNext () {} public int Current { get {}}}
5388                                         // We can avoid the iface call. This is a runtime perf boost.
5389                                         // even bigger if we have a ValueType, because we avoid the cost
5390                                         // of boxing.
5391                                         //
5392                                         // We have to make sure that both methods exist for us to take
5393                                         // this path. If one of the methods does not exist, we will just
5394                                         // use the interface. Sadly, this complex if statement is the only
5395                                         // way I could do this without a goto
5396                                         //
5397
5398                                         if (TypeManager.bool_movenext_void == null) {
5399                                                 TypeManager.bool_movenext_void = TypeManager.GetPredefinedMethod (
5400                                                         TypeManager.ienumerator_type, "MoveNext", loc, Type.EmptyTypes);
5401                                         }
5402
5403                                         if (TypeManager.ienumerator_getcurrent == null) {
5404                                                 TypeManager.ienumerator_getcurrent = TypeManager.GetPredefinedProperty (
5405                                                         TypeManager.ienumerator_type, "Current", loc, TypeManager.object_type);
5406                                         }
5407
5408 #if GMCS_SOURCE
5409                                         //
5410                                         // Prefer a generic enumerator over a non-generic one.
5411                                         //
5412                                         if (return_type.IsInterface && return_type.IsGenericType) {
5413                                                 enumerator_type = return_type;
5414                                                 if (!FetchGetCurrent (ec, return_type))
5415                                                         get_current = new PropertyExpr (
5416                                                                 ec.ContainerType, TypeManager.ienumerator_getcurrent, loc);
5417                                                 if (!FetchMoveNext (return_type))
5418                                                         move_next = TypeManager.bool_movenext_void;
5419                                                 return true;
5420                                         }
5421 #endif
5422
5423                                         if (return_type.IsInterface ||
5424                                             !FetchMoveNext (return_type) ||
5425                                             !FetchGetCurrent (ec, return_type)) {
5426                                                 enumerator_type = return_type;
5427                                                 move_next = TypeManager.bool_movenext_void;
5428                                                 get_current = new PropertyExpr (
5429                                                         ec.ContainerType, TypeManager.ienumerator_getcurrent, loc);
5430                                                 return true;
5431                                         }
5432                                 } else {
5433                                         //
5434                                         // Ok, so they dont return an IEnumerable, we will have to
5435                                         // find if they support the GetEnumerator pattern.
5436                                         //
5437
5438                                         if (TypeManager.HasElementType (return_type) || !FetchMoveNext (return_type) || !FetchGetCurrent (ec, return_type)) {
5439                                                 Report.Error (202, loc, "foreach statement requires that the return type `{0}' of `{1}' must have a suitable public MoveNext method and public Current property",
5440                                                         TypeManager.CSharpName (return_type), TypeManager.CSharpSignature (mi));
5441                                                 return false;
5442                                         }
5443                                 }
5444
5445                                 enumerator_type = return_type;
5446
5447                                 return true;
5448                         }
5449
5450                         //
5451                         // Retrieves a `public bool MoveNext ()' method from the Type `t'
5452                         //
5453                         bool FetchMoveNext (Type t)
5454                         {
5455                                 MemberList move_next_list;
5456
5457                                 move_next_list = TypeContainer.FindMembers (
5458                                         t, MemberTypes.Method,
5459                                         BindingFlags.Public | BindingFlags.Instance,
5460                                         Type.FilterName, "MoveNext");
5461                                 if (move_next_list.Count == 0)
5462                                         return false;
5463
5464                                 foreach (MemberInfo m in move_next_list){
5465                                         MethodInfo mi = (MethodInfo) m;
5466                                 
5467                                         if ((TypeManager.GetParameterData (mi).Count == 0) &&
5468                                             TypeManager.TypeToCoreType (mi.ReturnType) == TypeManager.bool_type) {
5469                                                 move_next = mi;
5470                                                 return true;
5471                                         }
5472                                 }
5473
5474                                 return false;
5475                         }
5476                 
5477                         //
5478                         // Retrieves a `public T get_Current ()' method from the Type `t'
5479                         //
5480                         bool FetchGetCurrent (EmitContext ec, Type t)
5481                         {
5482                                 PropertyExpr pe = Expression.MemberLookup (
5483                                         ec.ContainerType, t, "Current", MemberTypes.Property,
5484                                         Expression.AllBindingFlags, loc) as PropertyExpr;
5485                                 if (pe == null)
5486                                         return false;
5487
5488                                 get_current = pe;
5489                                 return true;
5490                         }
5491
5492                         // 
5493                         // Retrieves a `public void Dispose ()' method from the Type `t'
5494                         //
5495                         static MethodInfo FetchMethodDispose (Type t)
5496                         {
5497                                 MemberList dispose_list;
5498
5499                                 dispose_list = TypeContainer.FindMembers (
5500                                         t, MemberTypes.Method,
5501                                         BindingFlags.Public | BindingFlags.Instance,
5502                                         Type.FilterName, "Dispose");
5503                                 if (dispose_list.Count == 0)
5504                                         return null;
5505
5506                                 foreach (MemberInfo m in dispose_list){
5507                                         MethodInfo mi = (MethodInfo) m;
5508
5509                                         if (TypeManager.GetParameterData (mi).Count == 0){
5510                                                 if (mi.ReturnType == TypeManager.void_type)
5511                                                         return mi;
5512                                         }
5513                                 }
5514                                 return null;
5515                         }
5516
5517                         void Error_Enumerator ()
5518                         {
5519                                 if (enumerator_found) {
5520                                         return;
5521                                 }
5522
5523                             Report.Error (1579, loc,
5524                                         "foreach statement cannot operate on variables of type `{0}' because it does not contain a definition for `GetEnumerator' or is not accessible",
5525                                         TypeManager.CSharpName (expr.Type));
5526                         }
5527
5528                         bool IsOverride (MethodInfo m)
5529                         {
5530                                 m = (MethodInfo) TypeManager.DropGenericMethodArguments (m);
5531
5532                                 if (!m.IsVirtual || ((m.Attributes & MethodAttributes.NewSlot) != 0))
5533                                         return false;
5534                                 if (m is MethodBuilder)
5535                                         return true;
5536
5537                                 MethodInfo base_method = m.GetBaseDefinition ();
5538                                 return base_method != m;
5539                         }
5540
5541                         bool TryType (EmitContext ec, Type t)
5542                         {
5543                                 MethodGroupExpr mg = Expression.MemberLookup (
5544                                         ec.ContainerType, t, "GetEnumerator", MemberTypes.Method,
5545                                         Expression.AllBindingFlags, loc) as MethodGroupExpr;
5546                                 if (mg == null)
5547                                         return false;
5548
5549                                 MethodInfo result = null;
5550                                 MethodInfo tmp_move_next = null;
5551                                 PropertyExpr tmp_get_cur = null;
5552                                 Type tmp_enumerator_type = enumerator_type;
5553                                 foreach (MethodInfo mi in mg.Methods) {
5554                                         if (TypeManager.GetParameterData (mi).Count != 0)
5555                                                 continue;
5556                         
5557                                         // Check whether GetEnumerator is public
5558                                         if ((mi.Attributes & MethodAttributes.Public) != MethodAttributes.Public)
5559                                                 continue;
5560
5561                                         if (IsOverride (mi))
5562                                                 continue;
5563
5564                                         enumerator_found = true;
5565
5566                                         if (!GetEnumeratorFilter (ec, mi))
5567                                                 continue;
5568
5569                                         if (result != null) {
5570                                                 if (TypeManager.IsGenericType (result.ReturnType)) {
5571                                                         if (!TypeManager.IsGenericType (mi.ReturnType))
5572                                                                 continue;
5573
5574                                                         MethodBase mb = TypeManager.DropGenericMethodArguments (mi);
5575                                                         Report.SymbolRelatedToPreviousError (t);
5576                                                         Report.Error(1640, loc, "foreach statement cannot operate on variables of type `{0}' " +
5577                                                                      "because it contains multiple implementation of `{1}'. Try casting to a specific implementation",
5578                                                                      TypeManager.CSharpName (t), TypeManager.CSharpSignature (mb));
5579                                                         return false;
5580                                                 }
5581
5582                                                 // Always prefer generics enumerators
5583                                                 if (!TypeManager.IsGenericType (mi.ReturnType)) {
5584                                                         if (TypeManager.ImplementsInterface (mi.DeclaringType, result.DeclaringType) ||
5585                                                             TypeManager.ImplementsInterface (result.DeclaringType, mi.DeclaringType))
5586                                                                 continue;
5587
5588                                                         Report.SymbolRelatedToPreviousError (result);
5589                                                         Report.SymbolRelatedToPreviousError (mi);
5590                                                         Report.Warning (278, 2, loc, "`{0}' contains ambiguous implementation of `{1}' pattern. Method `{2}' is ambiguous with method `{3}'",
5591                                                                         TypeManager.CSharpName (t), "enumerable", TypeManager.CSharpSignature (result), TypeManager.CSharpSignature (mi));
5592                                                         return false;
5593                                                 }
5594                                         }
5595                                         result = mi;
5596                                         tmp_move_next = move_next;
5597                                         tmp_get_cur = get_current;
5598                                         tmp_enumerator_type = enumerator_type;
5599                                         if (mi.DeclaringType == t)
5600                                                 break;
5601                                 }
5602
5603                                 if (result != null) {
5604                                         move_next = tmp_move_next;
5605                                         get_current = tmp_get_cur;
5606                                         enumerator_type = tmp_enumerator_type;
5607                                         MethodInfo[] mi = new MethodInfo[] { (MethodInfo) result };
5608                                         get_enumerator = new MethodGroupExpr (mi, enumerator_type, loc);
5609
5610                                         if (t != expr.Type) {
5611                                                 expr = Convert.ExplicitConversion (
5612                                                         ec, expr, t, loc);
5613                                                 if (expr == null)
5614                                                         throw new InternalErrorException ();
5615                                         }
5616
5617                                         get_enumerator.InstanceExpression = expr;
5618                                         get_enumerator.IsBase = t != expr.Type;
5619
5620                                         return true;
5621                                 }
5622
5623                                 return false;
5624                         }               
5625
5626                         bool ProbeCollectionType (EmitContext ec, Type t)
5627                         {
5628                                 int errors = Report.Errors;
5629                                 for (Type tt = t; tt != null && tt != TypeManager.object_type;){
5630                                         if (TryType (ec, tt))
5631                                                 return true;
5632                                         tt = tt.BaseType;
5633                                 }
5634
5635                                 if (Report.Errors > errors)
5636                                         return false;
5637
5638                                 //
5639                                 // Now try to find the method in the interfaces
5640                                 //
5641                                 Type [] ifaces = TypeManager.GetInterfaces (t);
5642                                 foreach (Type i in ifaces){
5643                                         if (TryType (ec, i))
5644                                                 return true;
5645                                 }
5646
5647                                 return false;
5648                         }
5649
5650                         public override bool Resolve (EmitContext ec)
5651                         {
5652                                 enumerator_type = TypeManager.ienumerator_type;
5653
5654                                 if (!ProbeCollectionType (ec, expr.Type)) {
5655                                         Error_Enumerator ();
5656                                         return false;
5657                                 }
5658
5659                                 bool is_disposable = !enumerator_type.IsSealed ||
5660                                         TypeManager.ImplementsInterface (enumerator_type, TypeManager.idisposable_type);
5661
5662                                 VarExpr ve = var_type as VarExpr;
5663                                 if (ve != null) {
5664                                         // Infer implicitly typed local variable from foreach enumerable type
5665                                         var_type = new TypeExpression (get_current.PropertyInfo.PropertyType, var_type.Location);
5666                                 }
5667
5668                                 var_type = var_type.ResolveAsTypeTerminal (ec, false);
5669                                 if (var_type == null)
5670                                         return false;
5671                                                                 
5672                                 enumerator = new TemporaryVariable (enumerator_type, loc);
5673                                 enumerator.Resolve (ec);
5674
5675                                 init = new Invocation (get_enumerator, null);
5676                                 init = init.Resolve (ec);
5677                                 if (init == null)
5678                                         return false;
5679
5680                                 Expression move_next_expr;
5681                                 {
5682                                         MemberInfo[] mi = new MemberInfo[] { move_next };
5683                                         MethodGroupExpr mg = new MethodGroupExpr (mi, var_type.Type, loc);
5684                                         mg.InstanceExpression = enumerator;
5685
5686                                         move_next_expr = new Invocation (mg, null);
5687                                 }
5688
5689                                 get_current.InstanceExpression = enumerator;
5690
5691                                 Statement block = new CollectionForeachStatement (
5692                                         var_type.Type, variable, get_current, statement, loc);
5693
5694                                 loop = new While (move_next_expr, block, loc);
5695
5696                                 wrapper = is_disposable ?
5697                                         (Statement) new DisposableWrapper (this) :
5698                                         (Statement) new NonDisposableWrapper (this);
5699                                 return wrapper.Resolve (ec);
5700                         }
5701
5702                         protected override void DoEmit (EmitContext ec)
5703                         {
5704                                 wrapper.Emit (ec);
5705                         }
5706
5707                         class NonDisposableWrapper : Statement {
5708                                 CollectionForeach parent;
5709
5710                                 internal NonDisposableWrapper (CollectionForeach parent)
5711                                 {
5712                                         this.parent = parent;
5713                                 }
5714
5715                                 protected override void CloneTo (CloneContext clonectx, Statement target)
5716                                 {
5717                                         throw new NotSupportedException ();
5718                                 }
5719
5720                                 public override bool Resolve (EmitContext ec)
5721                                 {
5722                                         return parent.ResolveLoop (ec);
5723                                 }
5724
5725                                 protected override void DoEmit (EmitContext ec)
5726                                 {
5727                                         parent.EmitLoopInit (ec);
5728                                         parent.EmitLoopBody (ec);
5729                                 }
5730
5731                                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5732                                 {
5733                                         throw new NotSupportedException ();
5734                                 }
5735                         }
5736
5737                         class DisposableWrapper : ExceptionStatement {
5738                                 CollectionForeach parent;
5739
5740                                 internal DisposableWrapper (CollectionForeach parent)
5741                                 {
5742                                         this.parent = parent;
5743                                 }
5744
5745                                 protected override void CloneTo (CloneContext clonectx, Statement target)
5746                                 {
5747                                         throw new NotSupportedException ();
5748                                 }
5749
5750                                 public override bool Resolve (EmitContext ec)
5751                                 {
5752                                         bool ok = true;
5753
5754                                         ec.StartFlowBranching (this);
5755
5756                                         if (!parent.ResolveLoop (ec))
5757                                                 ok = false;
5758
5759                                         ec.EndFlowBranching ();
5760
5761                                         ResolveReachability (ec);
5762
5763                                         if (TypeManager.void_dispose_void == null) {
5764                                                 TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
5765                                                         TypeManager.idisposable_type, "Dispose", loc, Type.EmptyTypes);
5766                                         }
5767                                         return ok;
5768                                 }
5769
5770                                 protected override void EmitPreTryBody (EmitContext ec)
5771                                 {
5772                                         parent.EmitLoopInit (ec);
5773                                 }
5774
5775                                 protected override void EmitTryBody (EmitContext ec)
5776                                 {
5777                                         parent.EmitLoopBody (ec);
5778                                 }
5779
5780                                 protected override void EmitFinallyBody (EmitContext ec)
5781                                 {
5782                                         parent.EmitFinallyBody (ec);
5783                                 }
5784
5785                                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5786                                 {
5787                                         throw new NotSupportedException ();
5788                                 }
5789                         }
5790
5791                         bool ResolveLoop (EmitContext ec)
5792                         {
5793                                 return loop.Resolve (ec);
5794                         }
5795
5796                         void EmitLoopInit (EmitContext ec)
5797                         {
5798                                 enumerator.EmitAssign (ec, init);
5799                         }
5800
5801                         void EmitLoopBody (EmitContext ec)
5802                         {
5803                                 loop.Emit (ec);
5804                         }
5805
5806                         void EmitFinallyBody (EmitContext ec)
5807                         {
5808                                 ILGenerator ig = ec.ig;
5809
5810                                 if (enumerator_type.IsValueType) {
5811                                         MethodInfo mi = FetchMethodDispose (enumerator_type);
5812                                         if (mi != null) {
5813                                                 enumerator.AddressOf (ec, AddressOp.Load);
5814                                                 ig.Emit (OpCodes.Call, mi);
5815                                         } else {
5816                                                 enumerator.Emit (ec);
5817                                                 ig.Emit (OpCodes.Box, enumerator_type);
5818                                                 ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
5819                                         }
5820                                 } else {
5821                                         Label call_dispose = ig.DefineLabel ();
5822
5823                                         enumerator.Emit (ec);
5824                                         ig.Emit (OpCodes.Isinst, TypeManager.idisposable_type);
5825                                         ig.Emit (OpCodes.Dup);
5826                                         ig.Emit (OpCodes.Brtrue_S, call_dispose);
5827
5828                                         // 'endfinally' empties the evaluation stack, and can appear anywhere inside a finally block
5829                                         // (Partition III, Section 3.35)
5830                                         ig.Emit (OpCodes.Endfinally);
5831
5832                                         ig.MarkLabel (call_dispose);
5833                                         ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
5834                                 }
5835                         }
5836
5837                         public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5838                         {
5839                                 enumerator_type = storey.MutateType (enumerator_type);
5840                                 init.MutateHoistedGenericType (storey);
5841                                 loop.MutateHoistedGenericType (storey);
5842                         }
5843                 }
5844
5845                 protected class CollectionForeachStatement : Statement
5846                 {
5847                         Type type;
5848                         Expression variable, current, conv;
5849                         Statement statement;
5850                         Assign assign;
5851
5852                         public CollectionForeachStatement (Type type, Expression variable,
5853                                                            Expression current, Statement statement,
5854                                                            Location loc)
5855                         {
5856                                 this.type = type;
5857                                 this.variable = variable;
5858                                 this.current = current;
5859                                 this.statement = statement;
5860                                 this.loc = loc;
5861                         }
5862
5863                         protected override void CloneTo (CloneContext clonectx, Statement target)
5864                         {
5865                                 throw new NotImplementedException ();
5866                         }
5867
5868                         public override bool Resolve (EmitContext ec)
5869                         {
5870                                 current = current.Resolve (ec);
5871                                 if (current == null)
5872                                         return false;
5873
5874                                 conv = Convert.ExplicitConversion (ec, current, type, loc);
5875                                 if (conv == null)
5876                                         return false;
5877
5878                                 assign = new SimpleAssign (variable, conv, loc);
5879                                 if (assign.Resolve (ec) == null)
5880                                         return false;
5881
5882                                 if (!statement.Resolve (ec))
5883                                         return false;
5884
5885                                 return true;
5886                         }
5887
5888                         protected override void DoEmit (EmitContext ec)
5889                         {
5890                                 assign.EmitStatement (ec);
5891                                 statement.Emit (ec);
5892                         }
5893
5894                         public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5895                         {
5896                                 assign.MutateHoistedGenericType (storey);
5897                                 statement.MutateHoistedGenericType (storey);
5898                         }
5899                 }
5900
5901                 protected override void CloneTo (CloneContext clonectx, Statement t)
5902                 {
5903                         Foreach target = (Foreach) t;
5904
5905                         target.type = type.Clone (clonectx);
5906                         target.variable = variable.Clone (clonectx);
5907                         target.expr = expr.Clone (clonectx);
5908                         target.statement = statement.Clone (clonectx);
5909                 }
5910
5911                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5912                 {
5913                         statement.MutateHoistedGenericType (storey);
5914                 }
5915         }
5916 }