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