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