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