Don't recreate top-level destructor block, it carries precious stuff
[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                 static void CheckPossibleMistakenEmptyStatement (BlockContext ec, Statement s)
2019                 {
2020                         Statement body;
2021
2022                         // Some statements are wrapped by a Block. Since
2023                         // others' internal could be changed, here I treat
2024                         // them as possibly wrapped by Block equally.
2025                         Block b = s as Block;
2026                         if (b != null && b.statements.Count == 1)
2027                                 s = b.statements [0];
2028
2029                         if (s is Lock)
2030                                 body = ((Lock) s).Statement;
2031                         else if (s is For)
2032                                 body = ((For) s).Statement;
2033                         else if (s is Foreach)
2034                                 body = ((Foreach) s).Statement;
2035                         else if (s is While)
2036                                 body = ((While) s).Statement;
2037                         else if (s is Fixed)
2038                                 body = ((Fixed) s).Statement;
2039                         else if (s is Using)
2040                                 body = ((Using) s).Statement;
2041                         else if (s is UsingTemporary)
2042                                 body = ((UsingTemporary) s).Statement;
2043                         else
2044                                 return;
2045
2046                         if (body == null || body is EmptyStatement)
2047                                 ec.Report.Warning (642, 3, s.loc, "Possible mistaken empty statement");
2048                 }
2049
2050                 public override bool Resolve (BlockContext ec)
2051                 {
2052                         Block prev_block = ec.CurrentBlock;
2053                         bool ok = true;
2054
2055                         ec.CurrentBlock = this;
2056                         ec.StartFlowBranching (this);
2057
2058                         Report.Debug (4, "RESOLVE BLOCK", StartLocation, ec.CurrentBranching);
2059
2060                         //
2061                         // Compiler generated scope statements
2062                         //
2063                         if (scope_initializers != null) {
2064                                 for (resolving_init_idx = 0; resolving_init_idx < scope_initializers.Count; ++resolving_init_idx) {
2065                                         scope_initializers[resolving_init_idx.Value].Resolve (ec);
2066                                 }
2067
2068                                 resolving_init_idx = null;
2069                         }
2070
2071                         //
2072                         // This flag is used to notate nested statements as unreachable from the beginning of this block.
2073                         // For the purposes of this resolution, it doesn't matter that the whole block is unreachable 
2074                         // from the beginning of the function.  The outer Resolve() that detected the unreachability is
2075                         // responsible for handling the situation.
2076                         //
2077                         int statement_count = statements.Count;
2078                         for (int ix = 0; ix < statement_count; ix++){
2079                                 Statement s = statements [ix];
2080                                 // Check possible empty statement (CS0642)
2081                                 if (ix + 1 < statement_count && ec.Report.WarningLevel >= 3 &&
2082                                         statements [ix + 1] is ExplicitBlock)
2083                                         CheckPossibleMistakenEmptyStatement (ec, s);
2084
2085                                 //
2086                                 // Warn if we detect unreachable code.
2087                                 //
2088                                 if (unreachable) {
2089                                         if (s is EmptyStatement)
2090                                                 continue;
2091
2092                                         if (!unreachable_shown && !(s is LabeledStatement)) {
2093                                                 ec.Report.Warning (162, 2, s.loc, "Unreachable code detected");
2094                                                 unreachable_shown = true;
2095                                         }
2096
2097                                         Block c_block = s as Block;
2098                                         if (c_block != null)
2099                                                 c_block.unreachable = c_block.unreachable_shown = true;
2100                                 }
2101
2102                                 //
2103                                 // Note that we're not using ResolveUnreachable() for unreachable
2104                                 // statements here.  ResolveUnreachable() creates a temporary
2105                                 // flow branching and kills it afterwards.  This leads to problems
2106                                 // if you have two unreachable statements where the first one
2107                                 // assigns a variable and the second one tries to access it.
2108                                 //
2109
2110                                 if (!s.Resolve (ec)) {
2111                                         ok = false;
2112                                         if (ec.IsInProbingMode)
2113                                                 break;
2114
2115                                         statements [ix] = new EmptyStatement (s.loc);
2116                                         continue;
2117                                 }
2118
2119                                 if (unreachable && !(s is LabeledStatement) && !(s is Block))
2120                                         statements [ix] = new EmptyStatement (s.loc);
2121
2122                                 unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
2123                                 if (unreachable && s is LabeledStatement)
2124                                         throw new InternalErrorException ("should not happen");
2125                         }
2126
2127                         Report.Debug (4, "RESOLVE BLOCK DONE", StartLocation,
2128                                       ec.CurrentBranching, statement_count);
2129
2130                         while (ec.CurrentBranching is FlowBranchingLabeled)
2131                                 ec.EndFlowBranching ();
2132
2133                         bool flow_unreachable = ec.EndFlowBranching ();
2134
2135                         ec.CurrentBlock = prev_block;
2136
2137                         if (flow_unreachable)
2138                                 flags |= Flags.HasRet;
2139
2140                         // If we're a non-static `struct' constructor which doesn't have an
2141                         // initializer, then we must initialize all of the struct's fields.
2142                         if (this == ParametersBlock.TopBlock && !ParametersBlock.TopBlock.IsThisAssigned (ec) && !flow_unreachable)
2143                                 ok = false;
2144
2145                         if ((labels != null) && (ec.Report.WarningLevel >= 2)) {
2146                                 foreach (LabeledStatement label in labels.Values)
2147                                         if (!label.HasBeenReferenced)
2148                                                 ec.Report.Warning (164, 2, label.loc, "This label has not been referenced");
2149                         }
2150
2151                         return ok;
2152                 }
2153
2154                 public override bool ResolveUnreachable (BlockContext ec, bool warn)
2155                 {
2156                         unreachable_shown = true;
2157                         unreachable = true;
2158
2159                         if (warn)
2160                                 ec.Report.Warning (162, 2, loc, "Unreachable code detected");
2161
2162                         ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc);
2163                         bool ok = Resolve (ec);
2164                         ec.KillFlowBranching ();
2165
2166                         return ok;
2167                 }
2168                 
2169                 protected override void DoEmit (EmitContext ec)
2170                 {
2171                         for (int ix = 0; ix < statements.Count; ix++){
2172                                 statements [ix].Emit (ec);
2173                         }
2174                 }
2175
2176                 public override void Emit (EmitContext ec)
2177                 {
2178                         if (scope_initializers != null)
2179                                 EmitScopeInitializers (ec);
2180
2181                         ec.Mark (StartLocation);
2182                         DoEmit (ec);
2183
2184                         if (SymbolWriter.HasSymbolWriter)
2185                                 EmitSymbolInfo (ec);
2186                 }
2187
2188                 protected void EmitScopeInitializers (EmitContext ec)
2189                 {
2190                         SymbolWriter.OpenCompilerGeneratedBlock (ec);
2191
2192                         using (ec.With (EmitContext.Options.OmitDebugInfo, true)) {
2193                                 foreach (Statement s in scope_initializers)
2194                                         s.Emit (ec);
2195                         }
2196
2197                         SymbolWriter.CloseCompilerGeneratedBlock (ec);
2198                 }
2199
2200                 protected virtual void EmitSymbolInfo (EmitContext ec)
2201                 {
2202                 }
2203
2204 #if DEBUG
2205                 public override string ToString ()
2206                 {
2207                         return String.Format ("{0} ({1}:{2})", GetType (), ID, StartLocation);
2208                 }
2209 #endif
2210
2211                 protected override void CloneTo (CloneContext clonectx, Statement t)
2212                 {
2213                         Block target = (Block) t;
2214 #if DEBUG
2215                         target.clone_id = clone_id_counter++;
2216 #endif
2217
2218                         clonectx.AddBlockMap (this, target);
2219
2220                         target.ParametersBlock = (ParametersBlock) (ParametersBlock == this ? target : clonectx.RemapBlockCopy (ParametersBlock));
2221                         target.Explicit = (ExplicitBlock) (Explicit == this ? target : clonectx.LookupBlock (Explicit));
2222
2223                         if (Parent != null)
2224                                 target.Parent = clonectx.RemapBlockCopy (Parent);
2225
2226                         target.statements = new List<Statement> (statements.Count);
2227                         foreach (Statement s in statements)
2228                                 target.statements.Add (s.Clone (clonectx));
2229                 }
2230         }
2231
2232         public class ExplicitBlock : Block
2233         {
2234                 protected AnonymousMethodStorey am_storey;
2235
2236                 public ExplicitBlock (Block parent, Location start, Location end)
2237                         : this (parent, (Flags) 0, start, end)
2238                 {
2239                 }
2240
2241                 public ExplicitBlock (Block parent, Flags flags, Location start, Location end)
2242                         : base (parent, flags, start, end)
2243                 {
2244                         this.Explicit = this;
2245                 }
2246
2247                 #region Properties
2248
2249                 public AnonymousMethodStorey AnonymousMethodStorey {
2250                         get {
2251                                 return am_storey;
2252                         }
2253                 }
2254
2255                 public bool HasCapturedThis {
2256                         set { flags = value ? flags | Flags.HasCapturedThis : flags & ~Flags.HasCapturedThis; }
2257                         get {
2258                                 return (flags & Flags.HasCapturedThis) != 0;
2259                         }
2260                 }
2261
2262                 public bool HasCapturedVariable {
2263                         set { flags = value ? flags | Flags.HasCapturedVariable : flags & ~Flags.HasCapturedVariable; }
2264                         get {
2265                                 return (flags & Flags.HasCapturedVariable) != 0;
2266                         }
2267                 }
2268
2269                 #endregion
2270
2271                 //
2272                 // Creates anonymous method storey in current block
2273                 //
2274                 public AnonymousMethodStorey CreateAnonymousMethodStorey (ResolveContext ec)
2275                 {
2276                         //
2277                         // An iterator has only 1 storey block
2278                         //
2279                         if (ec.CurrentIterator != null)
2280                             return ec.CurrentIterator.Storey;
2281
2282                         //
2283                         // When referencing a variable in iterator storey from children anonymous method
2284                         //
2285                         if (ParametersBlock.am_storey is IteratorStorey) {
2286                                 return ParametersBlock.am_storey;
2287                         }
2288
2289                         //
2290                         // Switch block does not follow sequential flow and we cannot emit
2291                         // storey initialization inside the block because it can be jumped over
2292                         // for all non-first cases. Instead we push it up to the parent block to be
2293                         // always initialized
2294                         //
2295                         if (switch_block != null)
2296                                 return switch_block.CreateAnonymousMethodStorey (ec);
2297
2298                         if (am_storey == null) {
2299                                 MemberBase mc = ec.MemberContext as MemberBase;
2300
2301                                 //
2302                                 // Creates anonymous method storey for this block
2303                                 //
2304                                 am_storey = new AnonymousMethodStorey (this, ec.CurrentMemberDefinition.Parent.PartialContainer, mc, ec.CurrentTypeParameters, "AnonStorey");
2305                         }
2306
2307                         return am_storey;
2308                 }
2309
2310                 public override void Emit (EmitContext ec)
2311                 {
2312                         if (am_storey != null) {
2313                                 DefineAnonymousStorey (ec);
2314                                 am_storey.EmitStoreyInstantiation (ec);
2315                         }
2316
2317                         bool emit_debug_info = SymbolWriter.HasSymbolWriter && Parent != null && !(am_storey is IteratorStorey);
2318                         if (emit_debug_info)
2319                                 ec.BeginScope ();
2320
2321                         base.Emit (ec);
2322
2323                         if (emit_debug_info)
2324                                 ec.EndScope ();
2325                 }
2326
2327                 void DefineAnonymousStorey (EmitContext ec)
2328                 {
2329                         //
2330                         // Creates anonymous method storey
2331                         //
2332                         if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.Storey != null) {
2333                                 //
2334                                 // Creates parent storey reference when hoisted this is accessible
2335                                 //
2336                                 if (am_storey.OriginalSourceBlock.Explicit.HasCapturedThis) {
2337                                         ExplicitBlock parent = am_storey.OriginalSourceBlock.Explicit.Parent.Explicit;
2338
2339                                         //
2340                                         // Hoisted this exists in top-level parent storey only
2341                                         //
2342                                         while (parent.am_storey == null || parent.am_storey.Parent is AnonymousMethodStorey)
2343                                                 parent = parent.Parent.Explicit;
2344
2345                                         am_storey.AddParentStoreyReference (ec, parent.am_storey);
2346                                 }
2347
2348                                 am_storey.SetNestedStoryParent (ec.CurrentAnonymousMethod.Storey);
2349
2350                                 // TODO MemberCache: Review
2351                                 am_storey.Mutator = ec.CurrentAnonymousMethod.Storey.Mutator;
2352                         }
2353
2354                         am_storey.CreateType ();
2355                         if (am_storey.Mutator == null && ec.CurrentTypeParameters != null)
2356                                 am_storey.Mutator = new TypeParameterMutator (ec.CurrentTypeParameters, am_storey.CurrentTypeParameters);
2357
2358                         am_storey.DefineType ();
2359                         am_storey.ResolveTypeParameters ();
2360
2361                         var ref_blocks = am_storey.ReferencesFromChildrenBlock;
2362                         if (ref_blocks != null) {
2363                                 foreach (ExplicitBlock ref_block in ref_blocks) {
2364                                         for (ExplicitBlock b = ref_block.Explicit; b.am_storey != am_storey; b = b.Parent.Explicit) {
2365                                                 if (b.am_storey != null) {
2366                                                         b.am_storey.AddParentStoreyReference (ec, am_storey);
2367
2368                                                         // Stop propagation inside same top block
2369                                                         if (b.ParametersBlock.am_storey == ParametersBlock.am_storey)
2370                                                                 break;
2371
2372                                                         b = b.ParametersBlock;
2373                                                 }
2374
2375                                                 b.HasCapturedVariable = true;
2376                                         }
2377                                 }
2378                         }
2379
2380                         am_storey.Define ();
2381                         am_storey.Parent.PartialContainer.AddCompilerGeneratedClass (am_storey);
2382                 }
2383
2384
2385                 public void WrapIntoDestructor (TryFinally tf, ExplicitBlock tryBlock)
2386                 {
2387                         tryBlock.statements = statements;
2388                         statements = new List<Statement> (1);
2389                         statements.Add (tf);
2390                 }
2391         }
2392
2393         //
2394         // ParametersBlock was introduced to support anonymous methods
2395         // and lambda expressions
2396         // 
2397         public class ParametersBlock : ExplicitBlock
2398         {
2399                 public class ParameterInfo : INamedBlockVariable
2400                 {
2401                         readonly ParametersBlock block;
2402                         readonly int index;
2403                         public VariableInfo VariableInfo;
2404
2405                         public ParameterInfo (ParametersBlock block, int index)
2406                         {
2407                                 this.block = block;
2408                                 this.index = index;
2409                         }
2410
2411                         #region Properties
2412
2413                         public Block Block {
2414                                 get {
2415                                         return block;
2416                                 }
2417                         }
2418
2419                         public bool IsDeclared {
2420                                 get {
2421                                         return true;
2422                                 }
2423                         }
2424
2425                         public Location Location {
2426                                 get {
2427                                         return Parameter.Location;
2428                                 }
2429                         }
2430
2431                         public Parameter Parameter {
2432                                 get {
2433                                         return block.Parameters [index];
2434                                 }
2435                         }
2436
2437                         public TypeSpec ParameterType {
2438                                 get {
2439                                         return Parameter.Type;
2440                                 }
2441                         }
2442
2443                         #endregion
2444
2445                         public Expression CreateReferenceExpression (ResolveContext rc, Location loc)
2446                         {
2447                                 return new ParameterReference (this, loc);
2448                         }
2449                 }
2450
2451                 // 
2452                 // Block is converted to an expression
2453                 //
2454                 sealed class BlockScopeExpression : Expression
2455                 {
2456                         Expression child;
2457                         readonly ParametersBlock block;
2458
2459                         public BlockScopeExpression (Expression child, ParametersBlock block)
2460                         {
2461                                 this.child = child;
2462                                 this.block = block;
2463                         }
2464
2465                         public override Expression CreateExpressionTree (ResolveContext ec)
2466                         {
2467                                 throw new NotSupportedException ();
2468                         }
2469
2470                         protected override Expression DoResolve (ResolveContext ec)
2471                         {
2472                                 if (child == null)
2473                                         return null;
2474
2475                                 child = child.Resolve (ec);
2476                                 if (child == null)
2477                                         return null;
2478
2479                                 eclass = child.eclass;
2480                                 type = child.Type;
2481                                 return this;
2482                         }
2483
2484                         public override void Emit (EmitContext ec)
2485                         {
2486                                 block.EmitScopeInitializers (ec);
2487                                 child.Emit (ec);
2488                         }
2489                 }
2490
2491                 protected ParametersCompiled parameters;
2492                 protected ParameterInfo[] parameter_info;
2493                 bool resolved;
2494                 protected bool unreachable;
2495                 protected ToplevelBlock top_block;
2496
2497                 public ParametersBlock (Block parent, ParametersCompiled parameters, Location start)
2498                         : base (parent, 0, start, start)
2499                 {
2500                         if (parameters == null)
2501                                 throw new ArgumentNullException ("parameters");
2502
2503                         this.parameters = parameters;
2504                         ParametersBlock = this;
2505
2506                         this.top_block = parent.ParametersBlock.top_block;
2507                         ProcessParameters ();
2508                 }
2509
2510                 protected ParametersBlock (ParametersCompiled parameters, Location start)
2511                         : base (null, 0, start, start)
2512                 {
2513                         if (parameters == null)
2514                                 throw new ArgumentNullException ("parameters");
2515
2516                         this.parameters = parameters;
2517                         ParametersBlock = this;
2518                 }
2519
2520                 protected ParametersBlock (ParametersBlock source, ParametersCompiled parameters)
2521                         : base (null, 0, source.StartLocation, source.EndLocation)
2522                 {
2523                         this.parameters = parameters;
2524                         this.statements = source.statements;
2525                         this.scope_initializers = source.scope_initializers;
2526                         this.switch_block = source.switch_block;
2527
2528                         this.resolved = true;
2529                         this.unreachable = source.unreachable;
2530                         this.am_storey = source.am_storey;
2531
2532                         ParametersBlock = this;
2533                 }
2534
2535                 #region Properties
2536
2537                 //
2538                 // Block has been converted to expression tree
2539                 //
2540                 public bool IsExpressionTree {
2541                         get {
2542                                 return (flags & Flags.IsExpressionTree) != 0;
2543                         }
2544                 }
2545
2546                 //
2547                 // The parameters for the block.
2548                 //
2549                 public ParametersCompiled Parameters {
2550                         get {
2551                                 return parameters;
2552                         }
2553                 }
2554
2555                 public ToplevelBlock TopBlock {
2556                         get {
2557                                 return top_block;
2558                         }
2559                 }
2560
2561                 public bool Resolved {
2562                         get {
2563                                 return resolved;
2564                         }
2565                 }
2566
2567                 #endregion
2568
2569                 // <summary>
2570                 //   Check whether all `out' parameters have been assigned.
2571                 // </summary>
2572                 public void CheckOutParameters (FlowBranching.UsageVector vector, Location loc)
2573                 {
2574                         if (vector.IsUnreachable)
2575                                 return;
2576
2577                         int n = parameter_info == null ? 0 : parameter_info.Length;
2578
2579                         for (int i = 0; i < n; i++) {
2580                                 VariableInfo var = parameter_info[i].VariableInfo;
2581
2582                                 if (var == null)
2583                                         continue;
2584
2585                                 if (vector.IsAssigned (var, false))
2586                                         continue;
2587
2588                                 TopBlock.Report.Error (177, loc, "The out parameter `{0}' must be assigned to before control leaves the current method",
2589                                         var.Name);
2590                         }
2591                 }
2592
2593                 public override Expression CreateExpressionTree (ResolveContext ec)
2594                 {
2595                         if (statements.Count == 1) {
2596                                 Expression expr = ((Statement) statements[0]).CreateExpressionTree (ec);
2597                                 if (scope_initializers != null)
2598                                         expr = new BlockScopeExpression (expr, this);
2599
2600                                 return expr;
2601                         }
2602
2603                         return base.CreateExpressionTree (ec);
2604                 }
2605
2606                 public ParameterInfo GetParameterInfo (Parameter p)
2607                 {
2608                         for (int i = 0; i < parameters.Count; ++i) {
2609                                 if (parameters[i] == p)
2610                                         return parameter_info[i];
2611                         }
2612
2613                         throw new ArgumentException ("Invalid parameter");
2614                 }
2615
2616                 public Expression GetParameterReference (int index, Location loc)
2617                 {
2618                         return new ParameterReference (parameter_info[index], loc);
2619                 }
2620
2621                 protected void ProcessParameters ()
2622                 {
2623                         if (parameters.Count == 0)
2624                                 return;
2625
2626                         parameter_info = new ParameterInfo[parameters.Count];
2627                         for (int i = 0; i < parameter_info.Length; ++i) {
2628                                 var p = parameters.FixedParameters[i];
2629                                 if (p == null)
2630                                         continue;
2631
2632                                 // TODO: Should use Parameter only and more block there
2633                                 parameter_info[i] = new ParameterInfo (this, i);
2634                                 AddLocalName (p.Name, parameter_info[i]);
2635                         }
2636                 }
2637
2638                 public bool Resolve (FlowBranching parent, BlockContext rc, IMethodData md)
2639                 {
2640                         if (resolved)
2641                                 return true;
2642
2643                         resolved = true;
2644
2645                         if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
2646                                 flags |= Flags.IsExpressionTree;
2647
2648                         try {
2649                                 ResolveMeta (rc);
2650
2651                                 using (rc.With (ResolveContext.Options.DoFlowAnalysis, true)) {
2652                                         FlowBranchingToplevel top_level = rc.StartFlowBranching (this, parent);
2653
2654                                         if (!Resolve (rc))
2655                                                 return false;
2656
2657                                         unreachable = top_level.End ();
2658                                 }
2659                         } catch (Exception e) {
2660                                 if (e is CompletionResult || rc.Report.IsDisabled)
2661                                         throw;
2662
2663                                 if (rc.CurrentBlock != null) {
2664                                         rc.Report.Error (584, rc.CurrentBlock.StartLocation, "Internal compiler error: {0}", e.Message);
2665                                 } else {
2666                                         rc.Report.Error (587, "Internal compiler error: {0}", e.Message);
2667                                 }
2668
2669                                 if (Report.DebugFlags > 0)
2670                                         throw;
2671                         }
2672
2673                         if (rc.ReturnType != TypeManager.void_type && !unreachable) {
2674                                 if (rc.CurrentAnonymousMethod == null) {
2675                                         // FIXME: Missing FlowAnalysis for generated iterator MoveNext method
2676                                         if (md is IteratorMethod) {
2677                                                 unreachable = true;
2678                                         } else {
2679                                                 rc.Report.Error (161, md.Location, "`{0}': not all code paths return a value", md.GetSignatureForError ());
2680                                                 return false;
2681                                         }
2682                                 } else {
2683                                         rc.Report.Error (1643, rc.CurrentAnonymousMethod.Location, "Not all code paths return a value in anonymous method of type `{0}'",
2684                                                           rc.CurrentAnonymousMethod.GetSignatureForError ());
2685                                         return false;
2686                                 }
2687                         }
2688
2689                         return true;
2690                 }
2691
2692                 void ResolveMeta (BlockContext ec)
2693                 {
2694                         int orig_count = parameters.Count;
2695
2696                         for (int i = 0; i < orig_count; ++i) {
2697                                 Parameter.Modifier mod = parameters.FixedParameters[i].ModFlags;
2698
2699                                 if ((mod & Parameter.Modifier.OUT) != Parameter.Modifier.OUT)
2700                                         continue;
2701
2702                                 VariableInfo vi = new VariableInfo (parameters, i, ec.FlowOffset);
2703                                 parameter_info[i].VariableInfo = vi;
2704                                 ec.FlowOffset += vi.Length;
2705                         }
2706                 }
2707
2708                 public void WrapIntoIterator (IMethodData method, TypeContainer host, TypeSpec iterator_type, bool is_enumerable)
2709                 {
2710                         ParametersBlock pb = new ParametersBlock (this, ParametersCompiled.EmptyReadOnlyParameters, StartLocation);
2711                         pb.EndLocation = EndLocation;
2712                         pb.statements = statements;
2713
2714                         var iterator = new Iterator (pb, method, host, iterator_type, is_enumerable);
2715                         am_storey = new IteratorStorey (iterator);
2716
2717                         statements = new List<Statement> (1);
2718                         AddStatement (new Return (iterator, iterator.Location));
2719                 }
2720         }
2721
2722         //
2723         //
2724         //
2725         public class ToplevelBlock : ParametersBlock
2726         {
2727                 LocalVariable this_variable;
2728                 CompilerContext compiler;
2729                 Dictionary<string, object> names;
2730
2731                 public HoistedVariable HoistedThisVariable;
2732
2733                 public Report Report {
2734                         get { return compiler.Report; }
2735                 }
2736
2737                 public ToplevelBlock (CompilerContext ctx, Location loc)
2738                         : this (ctx, ParametersCompiled.EmptyReadOnlyParameters, loc)
2739                 {
2740                 }
2741
2742                 public ToplevelBlock (CompilerContext ctx, ParametersCompiled parameters, Location start)
2743                         : base (parameters, start)
2744                 {
2745                         this.compiler = ctx;
2746                         top_block = this;
2747
2748                         ProcessParameters ();
2749                 }
2750
2751                 //
2752                 // Recreates a top level block from parameters block. Used for
2753                 // compiler generated methods where the original block comes from
2754                 // explicit child block. This works for already resolved blocks
2755                 // only to ensure we resolve them in the correct flow order
2756                 //
2757                 public ToplevelBlock (ParametersBlock source, ParametersCompiled parameters)
2758                         : base (source, parameters)
2759                 {
2760                         this.compiler = source.TopBlock.compiler;
2761                         top_block = this;
2762                 }
2763
2764                 public override void AddLocalName (string name, INamedBlockVariable li)
2765                 {
2766                         if (names == null)
2767                                 names = new Dictionary<string, object> ();
2768
2769                         object value;
2770                         if (!names.TryGetValue (name, out value)) {
2771                                 names.Add (name, li);
2772                                 return;
2773                         }
2774
2775                         INamedBlockVariable existing = value as INamedBlockVariable;
2776                         List<INamedBlockVariable> existing_list;
2777                         if (existing != null) {
2778                                 existing_list = new List<INamedBlockVariable> ();
2779                                 existing_list.Add (existing);
2780                                 names[name] = existing_list;
2781                         } else {
2782                                 existing_list = (List<INamedBlockVariable>) value;
2783                         }
2784
2785                         //
2786                         // A collision checking between local names
2787                         //
2788                         for (int i = 0; i < existing_list.Count; ++i) {
2789                                 existing = existing_list[i];
2790                                 Block b = existing.Block;
2791
2792                                 // Collision at same level
2793                                 if (li.Block == b) {
2794                                         li.Block.Error_AlreadyDeclared (name, li);
2795                                         break;
2796                                 }
2797
2798                                 // Collision with parent
2799                                 b = li.Block;
2800                                 while ((b = b.Parent) != null) {
2801                                         if (existing.Block == b) {
2802                                                 li.Block.Error_AlreadyDeclared (name, li, "parent or current");
2803                                                 i = existing_list.Count;
2804                                                 break;
2805                                         }
2806                                 }
2807
2808                                 // Collision with with children
2809                                 b = existing.Block;
2810                                 while ((b = b.Parent) != null) {
2811                                         if (li.Block == b) {
2812                                                 li.Block.Error_AlreadyDeclared (name, li, "child");
2813                                                 i = existing_list.Count;
2814                                                 break;
2815                                         }
2816                                 }
2817                         }
2818
2819                         existing_list.Add (li);
2820                 }
2821
2822                 public bool CheckError158 (string name, Location loc)
2823                 {
2824 /*
2825                         if (AnonymousChildren != null) {
2826                                 foreach (ToplevelBlock child in AnonymousChildren) {
2827                                         if (!child.CheckError158 (name, loc))
2828                                                 return false;
2829                                 }
2830                         }
2831
2832                         for (ToplevelBlock c = Container; c != null; c = c.Container) {
2833                                 if (!c.DoCheckError158 (name, loc))
2834                                         return false;
2835                         }
2836 */
2837                         return true;
2838                 }
2839
2840                 bool DoCheckError158 (string name, Location loc)
2841                 {
2842                         LabeledStatement s = LookupLabel (name);
2843                         if (s != null) {
2844                                 Report.SymbolRelatedToPreviousError (s.loc, s.Name);
2845                                 Error_158 (name, loc);
2846                                 return false;
2847                         }
2848
2849                         return true;
2850                 }
2851
2852                 //
2853                 // Creates an arguments set from all parameters, useful for method proxy calls
2854                 //
2855                 public Arguments GetAllParametersArguments ()
2856                 {
2857                         int count = parameters.Count;
2858                         Arguments args = new Arguments (count);
2859                         for (int i = 0; i < count; ++i) {
2860                                 var arg_expr = GetParameterReference (i, parameter_info[i].Location);
2861                                 args.Add (new Argument (arg_expr));
2862                         }
2863
2864                         return args;
2865                 }
2866
2867                 //
2868                 // Lookup inside a block, the returned value can represent 3 states
2869                 //
2870                 // true+variable: A local name was found and it's valid
2871                 // false+variable: A local name was found in a child block only
2872                 // false+null: No local name was found
2873                 //
2874                 public bool GetLocalName (string name, Block block, ref INamedBlockVariable variable)
2875                 {
2876                         if (names == null)
2877                                 return false;
2878
2879                         object value;
2880                         if (!names.TryGetValue (name, out value))
2881                                 return false;
2882
2883                         variable = value as INamedBlockVariable;
2884                         Block b = block;
2885                         if (variable != null) {
2886                                 do {
2887                                         if (variable.Block == b)
2888                                                 return true;
2889
2890                                         b = b.Parent;
2891                                 } while (b != null);
2892
2893                                 b = variable.Block;
2894                                 do {
2895                                         if (block == b)
2896                                                 return false;
2897
2898                                         b = b.Parent;
2899                                 } while (b != null);
2900                         } else {
2901                                 List<INamedBlockVariable> list = (List<INamedBlockVariable>) value;
2902                                 for (int i = 0; i < list.Count; ++i) {
2903                                         variable = list[i];
2904                                         do {
2905                                                 if (variable.Block == b)
2906                                                         return true;
2907
2908                                                 b = b.Parent;
2909                                         } while (b != null);
2910
2911                                         b = variable.Block;
2912                                         do {
2913                                                 if (block == b)
2914                                                         return false;
2915
2916                                                 b = b.Parent;
2917                                         } while (b != null);
2918
2919                                         b = block;
2920                                 }
2921                         }
2922
2923                         variable = null;
2924                         return false;
2925                 }
2926
2927                 // <summary>
2928                 //   Returns the "this" instance variable of this block.
2929                 //   See AddThisVariable() for more information.
2930                 // </summary>
2931                 public LocalVariable ThisVariable {
2932                         get { return this_variable; }
2933                 }
2934
2935                 // <summary>
2936                 //   This is used by non-static `struct' constructors which do not have an
2937                 //   initializer - in this case, the constructor must initialize all of the
2938                 //   struct's fields.  To do this, we add a "this" variable and use the flow
2939                 //   analysis code to ensure that it's been fully initialized before control
2940                 //   leaves the constructor.
2941                 // </summary>
2942                 public LocalVariable AddThisVariable (BlockContext bc, TypeContainer ds, Location l)
2943                 {
2944                         if (this_variable == null) {
2945                                 this_variable = new LocalVariable (this, "this", LocalVariable.Flags.IsThis | LocalVariable.Flags.Used, l);
2946                                 this_variable.Type = ds.CurrentType;
2947                                 this_variable.PrepareForFlowAnalysis (bc);
2948                         }
2949
2950                         return this_variable;
2951                 }
2952
2953                 public bool IsIterator {
2954                         get { return (flags & Flags.IsIterator) != 0; }
2955                         set { flags = value ? flags | Flags.IsIterator : flags & ~Flags.IsIterator; }
2956                 }
2957
2958                 public bool IsThisAssigned (BlockContext ec)
2959                 {
2960                         return this_variable == null || this_variable.IsThisAssigned (ec, this);
2961                 }
2962
2963                 public override void Emit (EmitContext ec)
2964                 {
2965                         if (Report.Errors > 0)
2966                                 return;
2967
2968 #if PRODUCTION
2969                         try {
2970 #endif
2971                         if (ec.HasReturnLabel)
2972                                 ec.ReturnLabel = ec.DefineLabel ();
2973
2974                         base.Emit (ec);
2975
2976                         ec.Mark (EndLocation);
2977
2978                         if (ec.HasReturnLabel)
2979                                 ec.MarkLabel (ec.ReturnLabel);
2980
2981                         if (ec.return_value != null) {
2982                                 ec.Emit (OpCodes.Ldloc, ec.return_value);
2983                                 ec.Emit (OpCodes.Ret);
2984                         } else {
2985                                 //
2986                                 // If `HasReturnLabel' is set, then we already emitted a
2987                                 // jump to the end of the method, so we must emit a `ret'
2988                                 // there.
2989                                 //
2990                                 // Unfortunately, System.Reflection.Emit automatically emits
2991                                 // a leave to the end of a finally block.  This is a problem
2992                                 // if no code is following the try/finally block since we may
2993                                 // jump to a point after the end of the method.
2994                                 // As a workaround, we're always creating a return label in
2995                                 // this case.
2996                                 //
2997
2998                                 if (ec.HasReturnLabel || !unreachable) {
2999                                         if (ec.ReturnType != TypeManager.void_type)
3000                                                 ec.Emit (OpCodes.Ldloc, ec.TemporaryReturn ());
3001                                         ec.Emit (OpCodes.Ret);
3002                                 }
3003                         }
3004
3005 #if PRODUCTION
3006                         } catch (Exception e){
3007                                 Console.WriteLine ("Exception caught by the compiler while emitting:");
3008                                 Console.WriteLine ("   Block that caused the problem begin at: " + block.loc);
3009                                         
3010                                 Console.WriteLine (e.GetType ().FullName + ": " + e.Message);
3011                                 throw;
3012                         }
3013 #endif
3014                 }
3015
3016                 protected override void EmitSymbolInfo (EmitContext ec)
3017                 {
3018                         AnonymousExpression ae = ec.CurrentAnonymousMethod;
3019                         if ((ae != null) && (ae.Storey != null))
3020                                 SymbolWriter.DefineScopeVariable (ae.Storey.ID);
3021
3022                         base.EmitSymbolInfo (ec);
3023                 }
3024         }
3025         
3026         public class SwitchLabel {
3027                 Expression label;
3028                 object converted;
3029                 Location loc;
3030
3031                 Label il_label;
3032                 bool  il_label_set;
3033                 Label il_label_code;
3034                 bool  il_label_code_set;
3035
3036                 public static readonly object NullStringCase = new object ();
3037
3038                 //
3039                 // if expr == null, then it is the default case.
3040                 //
3041                 public SwitchLabel (Expression expr, Location l)
3042                 {
3043                         label = expr;
3044                         loc = l;
3045                 }
3046
3047                 public Expression Label {
3048                         get {
3049                                 return label;
3050                         }
3051                 }
3052
3053                 public Location Location {
3054                         get { return loc; }
3055                 }
3056
3057                 public object Converted {
3058                         get {
3059                                 return converted;
3060                         }
3061                 }
3062
3063                 public Label GetILLabel (EmitContext ec)
3064                 {
3065                         if (!il_label_set){
3066                                 il_label = ec.DefineLabel ();
3067                                 il_label_set = true;
3068                         }
3069                         return il_label;
3070                 }
3071
3072                 public Label GetILLabelCode (EmitContext ec)
3073                 {
3074                         if (!il_label_code_set){
3075                                 il_label_code = ec.DefineLabel ();
3076                                 il_label_code_set = true;
3077                         }
3078                         return il_label_code;
3079                 }                               
3080                 
3081                 //
3082                 // Resolves the expression, reduces it to a literal if possible
3083                 // and then converts it to the requested type.
3084                 //
3085                 public bool ResolveAndReduce (ResolveContext ec, TypeSpec required_type, bool allow_nullable)
3086                 {       
3087                         Expression e = label.Resolve (ec);
3088
3089                         if (e == null)
3090                                 return false;
3091
3092                         Constant c = e as Constant;
3093                         if (c == null){
3094                                 ec.Report.Error (150, loc, "A constant value is expected");
3095                                 return false;
3096                         }
3097
3098                         if (required_type == TypeManager.string_type && c.GetValue () == null) {
3099                                 converted = NullStringCase;
3100                                 return true;
3101                         }
3102
3103                         if (allow_nullable && c.GetValue () == null) {
3104                                 converted = NullStringCase;
3105                                 return true;
3106                         }
3107                         
3108                         c = c.ImplicitConversionRequired (ec, required_type, loc);
3109                         if (c == null)
3110                                 return false;
3111
3112                         converted = c.GetValue ();
3113                         return true;
3114                 }
3115
3116                 public void Error_AlreadyOccurs (ResolveContext ec, TypeSpec switch_type, SwitchLabel collision_with)
3117                 {
3118                         string label;
3119                         if (converted == null)
3120                                 label = "default";
3121                         else if (converted == NullStringCase)
3122                                 label = "null";
3123                         else
3124                                 label = converted.ToString ();
3125                         
3126                         ec.Report.SymbolRelatedToPreviousError (collision_with.loc, null);
3127                         ec.Report.Error (152, loc, "The label `case {0}:' already occurs in this switch statement", label);
3128                 }
3129
3130                 public SwitchLabel Clone (CloneContext clonectx)
3131                 {
3132                         return new SwitchLabel (label.Clone (clonectx), loc);
3133                 }
3134         }
3135
3136         public class SwitchSection {
3137                 // An array of SwitchLabels.
3138                 public readonly List<SwitchLabel> Labels;
3139                 public readonly Block Block;
3140                 
3141                 public SwitchSection (List<SwitchLabel> labels, Block block)
3142                 {
3143                         Labels = labels;
3144                         Block = block;
3145                 }
3146
3147                 public SwitchSection Clone (CloneContext clonectx)
3148                 {
3149                         var cloned_labels = new List<SwitchLabel> ();
3150
3151                         foreach (SwitchLabel sl in cloned_labels)
3152                                 cloned_labels.Add (sl.Clone (clonectx));
3153                         
3154                         return new SwitchSection (cloned_labels, clonectx.LookupBlock (Block));
3155                 }
3156         }
3157         
3158         public class Switch : Statement {
3159                 public List<SwitchSection> Sections;
3160                 public Expression Expr;
3161
3162                 /// <summary>
3163                 ///   Maps constants whose type type SwitchType to their  SwitchLabels.
3164                 /// </summary>
3165                 public IDictionary<object, SwitchLabel> Elements;
3166
3167                 /// <summary>
3168                 ///   The governing switch type
3169                 /// </summary>
3170                 public TypeSpec SwitchType;
3171
3172                 //
3173                 // Computed
3174                 //
3175                 Label default_target;
3176                 Label null_target;
3177                 Expression new_expr;
3178                 bool is_constant;
3179                 bool has_null_case;
3180                 SwitchSection constant_section;
3181                 SwitchSection default_section;
3182
3183                 ExpressionStatement string_dictionary;
3184                 FieldExpr switch_cache_field;
3185                 static int unique_counter;
3186
3187                 //
3188                 // Nullable Types support
3189                 //
3190                 Nullable.Unwrap unwrap;
3191
3192                 protected bool HaveUnwrap {
3193                         get { return unwrap != null; }
3194                 }
3195
3196                 //
3197                 // The types allowed to be implicitly cast from
3198                 // on the governing type
3199                 //
3200                 static TypeSpec [] allowed_types;
3201
3202                 public Switch (Expression e, List<SwitchSection> sects, Location l)
3203                 {
3204                         Expr = e;
3205                         Sections = sects;
3206                         loc = l;
3207                 }
3208
3209                 public bool GotDefault {
3210                         get {
3211                                 return default_section != null;
3212                         }
3213                 }
3214
3215                 public Label DefaultTarget {
3216                         get {
3217                                 return default_target;
3218                         }
3219                 }
3220
3221                 //
3222                 // Determines the governing type for a switch.  The returned
3223                 // expression might be the expression from the switch, or an
3224                 // expression that includes any potential conversions to the
3225                 // integral types or to string.
3226                 //
3227                 Expression SwitchGoverningType (ResolveContext ec, Expression expr)
3228                 {
3229                         TypeSpec t = expr.Type;
3230
3231                         if (t == TypeManager.byte_type ||
3232                             t == TypeManager.sbyte_type ||
3233                             t == TypeManager.ushort_type ||
3234                             t == TypeManager.short_type ||
3235                             t == TypeManager.uint32_type ||
3236                             t == TypeManager.int32_type ||
3237                             t == TypeManager.uint64_type ||
3238                             t == TypeManager.int64_type ||
3239                             t == TypeManager.char_type ||
3240                             t == TypeManager.string_type ||
3241                             t == TypeManager.bool_type ||
3242                             TypeManager.IsEnumType (t))
3243                                 return expr;
3244
3245                         if (allowed_types == null){
3246                                 allowed_types = new TypeSpec [] {
3247                                         TypeManager.sbyte_type,
3248                                         TypeManager.byte_type,
3249                                         TypeManager.short_type,
3250                                         TypeManager.ushort_type,
3251                                         TypeManager.int32_type,
3252                                         TypeManager.uint32_type,
3253                                         TypeManager.int64_type,
3254                                         TypeManager.uint64_type,
3255                                         TypeManager.char_type,
3256                                         TypeManager.string_type
3257                                 };
3258                         }
3259
3260                         //
3261                         // Try to find a *user* defined implicit conversion.
3262                         //
3263                         // If there is no implicit conversion, or if there are multiple
3264                         // conversions, we have to report an error
3265                         //
3266                         Expression converted = null;
3267                         foreach (TypeSpec tt in allowed_types){
3268                                 Expression e;
3269                                 
3270                                 e = Convert.ImplicitUserConversion (ec, expr, tt, loc);
3271                                 if (e == null)
3272                                         continue;
3273
3274                                 //
3275                                 // Ignore over-worked ImplicitUserConversions that do
3276                                 // an implicit conversion in addition to the user conversion.
3277                                 // 
3278                                 if (!(e is UserCast))
3279                                         continue;
3280
3281                                 if (converted != null){
3282                                         ec.Report.ExtraInformation (loc, "(Ambiguous implicit user defined conversion in previous ");
3283                                         return null;
3284                                 }
3285
3286                                 converted = e;
3287                         }
3288                         return converted;
3289                 }
3290
3291                 //
3292                 // Performs the basic sanity checks on the switch statement
3293                 // (looks for duplicate keys and non-constant expressions).
3294                 //
3295                 // It also returns a hashtable with the keys that we will later
3296                 // use to compute the switch tables
3297                 //
3298                 bool CheckSwitch (ResolveContext ec)
3299                 {
3300                         bool error = false;
3301                         Elements = new Dictionary<object, SwitchLabel> ();
3302                                 
3303                         foreach (SwitchSection ss in Sections){
3304                                 foreach (SwitchLabel sl in ss.Labels){
3305                                         if (sl.Label == null){
3306                                                 if (default_section != null){
3307                                                         sl.Error_AlreadyOccurs (ec, SwitchType, (SwitchLabel)default_section.Labels [0]);
3308                                                         error = true;
3309                                                 }
3310                                                 default_section = ss;
3311                                                 continue;
3312                                         }
3313
3314                                         if (!sl.ResolveAndReduce (ec, SwitchType, HaveUnwrap)) {
3315                                                 error = true;
3316                                                 continue;
3317                                         }
3318                                         
3319                                         object key = sl.Converted;
3320                                         if (key == SwitchLabel.NullStringCase)
3321                                                 has_null_case = true;
3322
3323                                         try {
3324                                                 Elements.Add (key, sl);
3325                                         } catch (ArgumentException) {
3326                                                 sl.Error_AlreadyOccurs (ec, SwitchType, Elements [key]);
3327                                                 error = true;
3328                                         }
3329                                 }
3330                         }
3331                         return !error;
3332                 }
3333
3334                 void EmitObjectInteger (EmitContext ec, object k)
3335                 {
3336                         if (k is int)
3337                                 ec.EmitInt ((int) k);
3338                         else if (k is Constant) {
3339                                 EmitObjectInteger (ec, ((Constant) k).GetValue ());
3340                         } 
3341                         else if (k is uint)
3342                                 ec.EmitInt (unchecked ((int) (uint) k));
3343                         else if (k is long)
3344                         {
3345                                 if ((long) k >= int.MinValue && (long) k <= int.MaxValue)
3346                                 {
3347                                         ec.EmitInt ((int) (long) k);
3348                                         ec.Emit (OpCodes.Conv_I8);
3349                                 }
3350                                 else
3351                                         ec.EmitLong ((long) k);
3352                         }
3353                         else if (k is ulong)
3354                         {
3355                                 ulong ul = (ulong) k;
3356                                 if (ul < (1L<<32))
3357                                 {
3358                                         ec.EmitInt (unchecked ((int) ul));
3359                                         ec.Emit (OpCodes.Conv_U8);
3360                                 }
3361                                 else
3362                                 {
3363                                         ec.EmitLong (unchecked ((long) ul));
3364                                 }
3365                         }
3366                         else if (k is char)
3367                                 ec.EmitInt ((int) ((char) k));
3368                         else if (k is sbyte)
3369                                 ec.EmitInt ((int) ((sbyte) k));
3370                         else if (k is byte)
3371                                 ec.EmitInt ((int) ((byte) k));
3372                         else if (k is short)
3373                                 ec.EmitInt ((int) ((short) k));
3374                         else if (k is ushort)
3375                                 ec.EmitInt ((int) ((ushort) k));
3376                         else if (k is bool)
3377                                 ec.EmitInt (((bool) k) ? 1 : 0);
3378                         else
3379                                 throw new Exception ("Unhandled case");
3380                 }
3381                 
3382                 // structure used to hold blocks of keys while calculating table switch
3383                 class KeyBlock : IComparable
3384                 {
3385                         public KeyBlock (long _first)
3386                         {
3387                                 first = last = _first;
3388                         }
3389                         public long first;
3390                         public long last;
3391                         public List<object> element_keys;
3392                         // how many items are in the bucket
3393                         public int Size = 1;
3394                         public int Length
3395                         {
3396                                 get { return (int) (last - first + 1); }
3397                         }
3398                         public static long TotalLength (KeyBlock kb_first, KeyBlock kb_last)
3399                         {
3400                                 return kb_last.last - kb_first.first + 1;
3401                         }
3402                         public int CompareTo (object obj)
3403                         {
3404                                 KeyBlock kb = (KeyBlock) obj;
3405                                 int nLength = Length;
3406                                 int nLengthOther = kb.Length;
3407                                 if (nLengthOther == nLength)
3408                                         return (int) (kb.first - first);
3409                                 return nLength - nLengthOther;
3410                         }
3411                 }
3412
3413                 /// <summary>
3414                 /// This method emits code for a lookup-based switch statement (non-string)
3415                 /// Basically it groups the cases into blocks that are at least half full,
3416                 /// and then spits out individual lookup opcodes for each block.
3417                 /// It emits the longest blocks first, and short blocks are just
3418                 /// handled with direct compares.
3419                 /// </summary>
3420                 /// <param name="ec"></param>
3421                 /// <param name="val"></param>
3422                 /// <returns></returns>
3423                 void TableSwitchEmit (EmitContext ec, Expression val)
3424                 {
3425                         int element_count = Elements.Count;
3426                         object [] element_keys = new object [element_count];
3427                         Elements.Keys.CopyTo (element_keys, 0);
3428                         Array.Sort (element_keys);
3429
3430                         // initialize the block list with one element per key
3431                         var key_blocks = new List<KeyBlock> (element_count);
3432                         foreach (object key in element_keys)
3433                                 key_blocks.Add (new KeyBlock (System.Convert.ToInt64 (key)));
3434
3435                         KeyBlock current_kb;
3436                         // iteratively merge the blocks while they are at least half full
3437                         // there's probably a really cool way to do this with a tree...
3438                         while (key_blocks.Count > 1)
3439                         {
3440                                 var key_blocks_new = new List<KeyBlock> ();
3441                                 current_kb = (KeyBlock) key_blocks [0];
3442                                 for (int ikb = 1; ikb < key_blocks.Count; ikb++)
3443                                 {
3444                                         KeyBlock kb = (KeyBlock) key_blocks [ikb];
3445                                         if ((current_kb.Size + kb.Size) * 2 >=  KeyBlock.TotalLength (current_kb, kb))
3446                                         {
3447                                                 // merge blocks
3448                                                 current_kb.last = kb.last;
3449                                                 current_kb.Size += kb.Size;
3450                                         }
3451                                         else
3452                                         {
3453                                                 // start a new block
3454                                                 key_blocks_new.Add (current_kb);
3455                                                 current_kb = kb;
3456                                         }
3457                                 }
3458                                 key_blocks_new.Add (current_kb);
3459                                 if (key_blocks.Count == key_blocks_new.Count)
3460                                         break;
3461                                 key_blocks = key_blocks_new;
3462                         }
3463
3464                         // initialize the key lists
3465                         foreach (KeyBlock kb in key_blocks)
3466                                 kb.element_keys = new List<object> ();
3467
3468                         // fill the key lists
3469                         int iBlockCurr = 0;
3470                         if (key_blocks.Count > 0) {
3471                                 current_kb = (KeyBlock) key_blocks [0];
3472                                 foreach (object key in element_keys)
3473                                 {
3474                                         bool next_block = (key is UInt64) ? (ulong) key > (ulong) current_kb.last :
3475                                                 System.Convert.ToInt64 (key) > current_kb.last;
3476                                         if (next_block)
3477                                                 current_kb = (KeyBlock) key_blocks [++iBlockCurr];
3478                                         current_kb.element_keys.Add (key);
3479                                 }
3480                         }
3481
3482                         // sort the blocks so we can tackle the largest ones first
3483                         key_blocks.Sort ();
3484
3485                         // okay now we can start...
3486                         Label lbl_end = ec.DefineLabel ();      // at the end ;-)
3487                         Label lbl_default = default_target;
3488
3489                         Type type_keys = null;
3490                         if (element_keys.Length > 0)
3491                                 type_keys = element_keys [0].GetType ();        // used for conversions
3492
3493                         TypeSpec compare_type;
3494                         
3495                         if (TypeManager.IsEnumType (SwitchType))
3496                                 compare_type = EnumSpec.GetUnderlyingType (SwitchType);
3497                         else
3498                                 compare_type = SwitchType;
3499                         
3500                         for (int iBlock = key_blocks.Count - 1; iBlock >= 0; --iBlock)
3501                         {
3502                                 KeyBlock kb = ((KeyBlock) key_blocks [iBlock]);
3503                                 lbl_default = (iBlock == 0) ? default_target : ec.DefineLabel ();
3504                                 if (kb.Length <= 2)
3505                                 {
3506                                         foreach (object key in kb.element_keys) {
3507                                                 SwitchLabel sl = (SwitchLabel) Elements [key];
3508                                                 if (key is int && (int) key == 0) {
3509                                                         val.EmitBranchable (ec, sl.GetILLabel (ec), false);
3510                                                 } else {
3511                                                         val.Emit (ec);
3512                                                         EmitObjectInteger (ec, key);
3513                                                         ec.Emit (OpCodes.Beq, sl.GetILLabel (ec));
3514                                                 }
3515                                         }
3516                                 }
3517                                 else
3518                                 {
3519                                         // TODO: if all the keys in the block are the same and there are
3520                                         //       no gaps/defaults then just use a range-check.
3521                                         if (compare_type == TypeManager.int64_type ||
3522                                                 compare_type == TypeManager.uint64_type)
3523                                         {
3524                                                 // TODO: optimize constant/I4 cases
3525
3526                                                 // check block range (could be > 2^31)
3527                                                 val.Emit (ec);
3528                                                 EmitObjectInteger (ec, System.Convert.ChangeType (kb.first, type_keys));
3529                                                 ec.Emit (OpCodes.Blt, lbl_default);
3530                                                 val.Emit (ec);
3531                                                 EmitObjectInteger (ec, System.Convert.ChangeType (kb.last, type_keys));
3532                                                 ec.Emit (OpCodes.Bgt, lbl_default);
3533
3534                                                 // normalize range
3535                                                 val.Emit (ec);
3536                                                 if (kb.first != 0)
3537                                                 {
3538                                                         EmitObjectInteger (ec, System.Convert.ChangeType (kb.first, type_keys));
3539                                                         ec.Emit (OpCodes.Sub);
3540                                                 }
3541                                                 ec.Emit (OpCodes.Conv_I4);      // assumes < 2^31 labels!
3542                                         }
3543                                         else
3544                                         {
3545                                                 // normalize range
3546                                                 val.Emit (ec);
3547                                                 int first = (int) kb.first;
3548                                                 if (first > 0)
3549                                                 {
3550                                                         ec.EmitInt (first);
3551                                                         ec.Emit (OpCodes.Sub);
3552                                                 }
3553                                                 else if (first < 0)
3554                                                 {
3555                                                         ec.EmitInt (-first);
3556                                                         ec.Emit (OpCodes.Add);
3557                                                 }
3558                                         }
3559
3560                                         // first, build the list of labels for the switch
3561                                         int iKey = 0;
3562                                         int cJumps = kb.Length;
3563                                         Label [] switch_labels = new Label [cJumps];
3564                                         for (int iJump = 0; iJump < cJumps; iJump++)
3565                                         {
3566                                                 object key = kb.element_keys [iKey];
3567                                                 if (System.Convert.ToInt64 (key) == kb.first + iJump)
3568                                                 {
3569                                                         SwitchLabel sl = (SwitchLabel) Elements [key];
3570                                                         switch_labels [iJump] = sl.GetILLabel (ec);
3571                                                         iKey++;
3572                                                 }
3573                                                 else
3574                                                         switch_labels [iJump] = lbl_default;
3575                                         }
3576                                         // emit the switch opcode
3577                                         ec.Emit (OpCodes.Switch, switch_labels);
3578                                 }
3579
3580                                 // mark the default for this block
3581                                 if (iBlock != 0)
3582                                         ec.MarkLabel (lbl_default);
3583                         }
3584
3585                         // TODO: find the default case and emit it here,
3586                         //       to prevent having to do the following jump.
3587                         //       make sure to mark other labels in the default section
3588
3589                         // the last default just goes to the end
3590                         if (element_keys.Length > 0)
3591                                 ec.Emit (OpCodes.Br, lbl_default);
3592
3593                         // now emit the code for the sections
3594                         bool found_default = false;
3595
3596                         foreach (SwitchSection ss in Sections) {
3597                                 foreach (SwitchLabel sl in ss.Labels) {
3598                                         if (sl.Converted == SwitchLabel.NullStringCase) {
3599                                                 ec.MarkLabel (null_target);
3600                                         } else if (sl.Label == null) {
3601                                                 ec.MarkLabel (lbl_default);
3602                                                 found_default = true;
3603                                                 if (!has_null_case)
3604                                                         ec.MarkLabel (null_target);
3605                                         }
3606                                         ec.MarkLabel (sl.GetILLabel (ec));
3607                                         ec.MarkLabel (sl.GetILLabelCode (ec));
3608                                 }
3609                                 ss.Block.Emit (ec);
3610                         }
3611                         
3612                         if (!found_default) {
3613                                 ec.MarkLabel (lbl_default);
3614                                 if (!has_null_case) {
3615                                         ec.MarkLabel (null_target);
3616                                 }
3617                         }
3618                         
3619                         ec.MarkLabel (lbl_end);
3620                 }
3621
3622                 SwitchSection FindSection (SwitchLabel label)
3623                 {
3624                         foreach (SwitchSection ss in Sections){
3625                                 foreach (SwitchLabel sl in ss.Labels){
3626                                         if (label == sl)
3627                                                 return ss;
3628                                 }
3629                         }
3630
3631                         return null;
3632                 }
3633
3634                 public static void Reset ()
3635                 {
3636                         unique_counter = 0;
3637                         allowed_types = null;
3638                 }
3639
3640                 public override bool Resolve (BlockContext ec)
3641                 {
3642                         Expr = Expr.Resolve (ec);
3643                         if (Expr == null)
3644                                 return false;
3645
3646                         new_expr = SwitchGoverningType (ec, Expr);
3647
3648                         if ((new_expr == null) && TypeManager.IsNullableType (Expr.Type)) {
3649                                 unwrap = Nullable.Unwrap.Create (Expr, false);
3650                                 if (unwrap == null)
3651                                         return false;
3652
3653                                 new_expr = SwitchGoverningType (ec, unwrap);
3654                         }
3655
3656                         if (new_expr == null){
3657                                 ec.Report.Error (151, loc,
3658                                         "A switch expression of type `{0}' cannot be converted to an integral type, bool, char, string, enum or nullable type",
3659                                         TypeManager.CSharpName (Expr.Type));
3660                                 return false;
3661                         }
3662
3663                         // Validate switch.
3664                         SwitchType = new_expr.Type;
3665
3666                         if (RootContext.Version == LanguageVersion.ISO_1 && SwitchType == TypeManager.bool_type) {
3667                                 ec.Report.FeatureIsNotAvailable (loc, "switch expression of boolean type");
3668                                 return false;
3669                         }
3670
3671                         if (!CheckSwitch (ec))
3672                                 return false;
3673
3674                         if (HaveUnwrap)
3675                                 Elements.Remove (SwitchLabel.NullStringCase);
3676
3677                         Switch old_switch = ec.Switch;
3678                         ec.Switch = this;
3679                         ec.Switch.SwitchType = SwitchType;
3680
3681                         Report.Debug (1, "START OF SWITCH BLOCK", loc, ec.CurrentBranching);
3682                         ec.StartFlowBranching (FlowBranching.BranchingType.Switch, loc);
3683
3684                         var constant = new_expr as Constant;
3685                         if (constant != null) {
3686                                 is_constant = true;
3687                                 object key = constant.GetValue ();
3688                                 SwitchLabel label;
3689                                 if (Elements.TryGetValue (key, out label))
3690                                         constant_section = FindSection (label);
3691
3692                                 if (constant_section == null)
3693                                         constant_section = default_section;
3694                         }
3695
3696                         bool first = true;
3697                         bool ok = true;
3698                         foreach (SwitchSection ss in Sections){
3699                                 if (!first)
3700                                         ec.CurrentBranching.CreateSibling (
3701                                                 null, FlowBranching.SiblingType.SwitchSection);
3702                                 else
3703                                         first = false;
3704
3705                                 if (is_constant && (ss != constant_section)) {
3706                                         // If we're a constant switch, we're only emitting
3707                                         // one single section - mark all the others as
3708                                         // unreachable.
3709                                         ec.CurrentBranching.CurrentUsageVector.Goto ();
3710                                         if (!ss.Block.ResolveUnreachable (ec, true)) {
3711                                                 ok = false;
3712                                         }
3713                                 } else {
3714                                         if (!ss.Block.Resolve (ec))
3715                                                 ok = false;
3716                                 }
3717                         }
3718
3719                         if (default_section == null)
3720                                 ec.CurrentBranching.CreateSibling (
3721                                         null, FlowBranching.SiblingType.SwitchSection);
3722
3723                         ec.EndFlowBranching ();
3724                         ec.Switch = old_switch;
3725
3726                         Report.Debug (1, "END OF SWITCH BLOCK", loc, ec.CurrentBranching);
3727
3728                         if (!ok)
3729                                 return false;
3730
3731                         if (SwitchType == TypeManager.string_type && !is_constant) {
3732                                 // TODO: Optimize single case, and single+default case
3733                                 ResolveStringSwitchMap (ec);
3734                         }
3735
3736                         return true;
3737                 }
3738
3739                 void ResolveStringSwitchMap (ResolveContext ec)
3740                 {
3741                         FullNamedExpression string_dictionary_type;
3742                         if (TypeManager.generic_ienumerable_type != null) {
3743                                 MemberAccess system_collections_generic = new MemberAccess (new MemberAccess (
3744                                         new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc), "Generic", loc);
3745
3746                                 string_dictionary_type = new MemberAccess (system_collections_generic, "Dictionary",
3747                                         new TypeArguments (
3748                                                 new TypeExpression (TypeManager.string_type, loc),
3749                                                 new TypeExpression (TypeManager.int32_type, loc)), loc);
3750                         } else {
3751                                 MemberAccess system_collections_generic = new MemberAccess (
3752                                         new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc);
3753
3754                                 string_dictionary_type = new MemberAccess (system_collections_generic, "Hashtable", loc);
3755                         }
3756
3757                         var ctype = ec.CurrentMemberDefinition.Parent.PartialContainer;
3758                         Field field = new Field (ctype, string_dictionary_type,
3759                                 Modifiers.STATIC | Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED,
3760                                 new MemberName (CompilerGeneratedClass.MakeName (null, "f", "switch$map", unique_counter++), loc), null);
3761                         if (!field.Define ())
3762                                 return;
3763                         ctype.AddField (field);
3764
3765                         var init = new List<Expression> ();
3766                         int counter = 0;
3767                         Elements.Clear ();
3768                         string value = null;
3769                         foreach (SwitchSection section in Sections) {
3770                                 int last_count = init.Count;
3771                                 foreach (SwitchLabel sl in section.Labels) {
3772                                         if (sl.Label == null || sl.Converted == SwitchLabel.NullStringCase)
3773                                                 continue;
3774
3775                                         value = (string) sl.Converted;
3776                                         var init_args = new List<Expression> (2);
3777                                         init_args.Add (new StringLiteral (value, sl.Location));
3778                                         init_args.Add (new IntConstant (counter, loc));
3779                                         init.Add (new CollectionElementInitializer (init_args, loc));
3780                                 }
3781
3782                                 //
3783                                 // Don't add empty sections
3784                                 //
3785                                 if (last_count == init.Count)
3786                                         continue;
3787
3788                                 Elements.Add (counter, section.Labels [0]);
3789                                 ++counter;
3790                         }
3791
3792                         Arguments args = new Arguments (1);
3793                         args.Add (new Argument (new IntConstant (init.Count, loc)));
3794                         Expression initializer = new NewInitialize (string_dictionary_type, args,
3795                                 new CollectionOrObjectInitializers (init, loc), loc);
3796
3797                         switch_cache_field = new FieldExpr (field, loc);
3798                         string_dictionary = new SimpleAssign (switch_cache_field, initializer.Resolve (ec));
3799                 }
3800
3801                 void DoEmitStringSwitch (LocalTemporary value, EmitContext ec)
3802                 {
3803                         Label l_initialized = ec.DefineLabel ();
3804
3805                         //
3806                         // Skip initialization when value is null
3807                         //
3808                         value.EmitBranchable (ec, null_target, false);
3809
3810                         //
3811                         // Check if string dictionary is initialized and initialize
3812                         //
3813                         switch_cache_field.EmitBranchable (ec, l_initialized, true);
3814                         string_dictionary.EmitStatement (ec);
3815                         ec.MarkLabel (l_initialized);
3816
3817                         LocalTemporary string_switch_variable = new LocalTemporary (TypeManager.int32_type);
3818
3819                         ResolveContext rc = new ResolveContext (ec.MemberContext);
3820
3821                         if (TypeManager.generic_ienumerable_type != null) {
3822                                 Arguments get_value_args = new Arguments (2);
3823                                 get_value_args.Add (new Argument (value));
3824                                 get_value_args.Add (new Argument (string_switch_variable, Argument.AType.Out));
3825                                 Expression get_item = new Invocation (new MemberAccess (switch_cache_field, "TryGetValue", loc), get_value_args).Resolve (rc);
3826                                 if (get_item == null)
3827                                         return;
3828
3829                                 //
3830                                 // A value was not found, go to default case
3831                                 //
3832                                 get_item.EmitBranchable (ec, default_target, false);
3833                         } else {
3834                                 Arguments get_value_args = new Arguments (1);
3835                                 get_value_args.Add (new Argument (value));
3836
3837                                 Expression get_item = new ElementAccess (switch_cache_field, get_value_args, loc).Resolve (rc);
3838                                 if (get_item == null)
3839                                         return;
3840
3841                                 LocalTemporary get_item_object = new LocalTemporary (TypeManager.object_type);
3842                                 get_item_object.EmitAssign (ec, get_item, true, false);
3843                                 ec.Emit (OpCodes.Brfalse, default_target);
3844
3845                                 ExpressionStatement get_item_int = (ExpressionStatement) new SimpleAssign (string_switch_variable,
3846                                         new Cast (new TypeExpression (TypeManager.int32_type, loc), get_item_object, loc)).Resolve (rc);
3847
3848                                 get_item_int.EmitStatement (ec);
3849                                 get_item_object.Release (ec);
3850                         }
3851
3852                         TableSwitchEmit (ec, string_switch_variable);
3853                         string_switch_variable.Release (ec);
3854                 }
3855                 
3856                 protected override void DoEmit (EmitContext ec)
3857                 {
3858                         default_target = ec.DefineLabel ();
3859                         null_target = ec.DefineLabel ();
3860
3861                         // Store variable for comparission purposes
3862                         // TODO: Don't duplicate non-captured VariableReference
3863                         LocalTemporary value;
3864                         if (HaveUnwrap) {
3865                                 value = new LocalTemporary (SwitchType);
3866                                 unwrap.EmitCheck (ec);
3867                                 ec.Emit (OpCodes.Brfalse, null_target);
3868                                 new_expr.Emit (ec);
3869                                 value.Store (ec);
3870                         } else if (!is_constant) {
3871                                 value = new LocalTemporary (SwitchType);
3872                                 new_expr.Emit (ec);
3873                                 value.Store (ec);
3874                         } else
3875                                 value = null;
3876
3877                         //
3878                         // Setup the codegen context
3879                         //
3880                         Label old_end = ec.LoopEnd;
3881                         Switch old_switch = ec.Switch;
3882                         
3883                         ec.LoopEnd = ec.DefineLabel ();
3884                         ec.Switch = this;
3885
3886                         // Emit Code.
3887                         if (is_constant) {
3888                                 if (constant_section != null)
3889                                         constant_section.Block.Emit (ec);
3890                         } else if (string_dictionary != null) {
3891                                 DoEmitStringSwitch (value, ec);
3892                         } else {
3893                                 TableSwitchEmit (ec, value);
3894                         }
3895
3896                         if (value != null)
3897                                 value.Release (ec);
3898
3899                         // Restore context state. 
3900                         ec.MarkLabel (ec.LoopEnd);
3901
3902                         //
3903                         // Restore the previous context
3904                         //
3905                         ec.LoopEnd = old_end;
3906                         ec.Switch = old_switch;
3907                 }
3908
3909                 protected override void CloneTo (CloneContext clonectx, Statement t)
3910                 {
3911                         Switch target = (Switch) t;
3912
3913                         target.Expr = Expr.Clone (clonectx);
3914                         target.Sections = new List<SwitchSection> ();
3915                         foreach (SwitchSection ss in Sections){
3916                                 target.Sections.Add (ss.Clone (clonectx));
3917                         }
3918                 }
3919         }
3920
3921         // A place where execution can restart in an iterator
3922         public abstract class ResumableStatement : Statement
3923         {
3924                 bool prepared;
3925                 protected Label resume_point;
3926
3927                 public Label PrepareForEmit (EmitContext ec)
3928                 {
3929                         if (!prepared) {
3930                                 prepared = true;
3931                                 resume_point = ec.DefineLabel ();
3932                         }
3933                         return resume_point;
3934                 }
3935
3936                 public virtual Label PrepareForDispose (EmitContext ec, Label end)
3937                 {
3938                         return end;
3939                 }
3940                 public virtual void EmitForDispose (EmitContext ec, Iterator iterator, Label end, bool have_dispatcher)
3941                 {
3942                 }
3943         }
3944
3945         // Base class for statements that are implemented in terms of try...finally
3946         public abstract class ExceptionStatement : ResumableStatement
3947         {
3948                 bool code_follows;
3949                 Iterator iter;
3950                 List<ResumableStatement> resume_points;
3951                 int first_resume_pc;
3952                 protected Statement stmt;
3953                 Label dispose_try_block;
3954                 bool prepared_for_dispose, emitted_dispose;
3955
3956                 protected ExceptionStatement (Statement stmt, Location loc)
3957                 {
3958                         this.stmt = stmt;
3959                         this.loc = loc;
3960                 }
3961
3962                 #region Properties
3963
3964                 public Statement Statement {
3965                         get {
3966                                 return stmt;
3967                         }
3968                 }
3969
3970                 #endregion
3971
3972                 protected abstract void EmitPreTryBody (EmitContext ec);
3973                 protected abstract void EmitTryBody (EmitContext ec);
3974                 protected abstract void EmitFinallyBody (EmitContext ec);
3975
3976                 protected sealed override void DoEmit (EmitContext ec)
3977                 {
3978                         EmitPreTryBody (ec);
3979
3980                         if (resume_points != null) {
3981                                 ec.EmitInt ((int) Iterator.State.Running);
3982                                 ec.Emit (OpCodes.Stloc, iter.CurrentPC);
3983                         }
3984
3985                         ec.BeginExceptionBlock ();
3986
3987                         if (resume_points != null) {
3988                                 ec.MarkLabel (resume_point);
3989
3990                                 // For normal control flow, we want to fall-through the Switch
3991                                 // So, we use CurrentPC rather than the $PC field, and initialize it to an outside value above
3992                                 ec.Emit (OpCodes.Ldloc, iter.CurrentPC);
3993                                 ec.EmitInt (first_resume_pc);
3994                                 ec.Emit (OpCodes.Sub);
3995
3996                                 Label [] labels = new Label [resume_points.Count];
3997                                 for (int i = 0; i < resume_points.Count; ++i)
3998                                         labels [i] = resume_points [i].PrepareForEmit (ec);
3999                                 ec.Emit (OpCodes.Switch, labels);
4000                         }
4001
4002                         EmitTryBody (ec);
4003
4004                         ec.BeginFinallyBlock ();
4005
4006                         Label start_finally = ec.DefineLabel ();
4007                         if (resume_points != null) {
4008                                 ec.Emit (OpCodes.Ldloc, iter.SkipFinally);
4009                                 ec.Emit (OpCodes.Brfalse_S, start_finally);
4010                                 ec.Emit (OpCodes.Endfinally);
4011                         }
4012
4013                         ec.MarkLabel (start_finally);
4014                         EmitFinallyBody (ec);
4015
4016                         ec.EndExceptionBlock ();
4017                 }
4018
4019                 public void SomeCodeFollows ()
4020                 {
4021                         code_follows = true;
4022                 }
4023
4024                 public override bool Resolve (BlockContext ec)
4025                 {
4026                         // System.Reflection.Emit automatically emits a 'leave' at the end of a try clause
4027                         // So, ensure there's some IL code after this statement.
4028                         if (!code_follows && resume_points == null && ec.CurrentBranching.CurrentUsageVector.IsUnreachable)
4029                                 ec.NeedReturnLabel ();
4030
4031                         iter = ec.CurrentIterator;
4032                         return true;
4033                 }
4034
4035                 public void AddResumePoint (ResumableStatement stmt, int pc)
4036                 {
4037                         if (resume_points == null) {
4038                                 resume_points = new List<ResumableStatement> ();
4039                                 first_resume_pc = pc;
4040                         }
4041
4042                         if (pc != first_resume_pc + resume_points.Count)
4043                                 throw new InternalErrorException ("missed an intervening AddResumePoint?");
4044
4045                         resume_points.Add (stmt);
4046                 }
4047
4048                 public override Label PrepareForDispose (EmitContext ec, Label end)
4049                 {
4050                         if (!prepared_for_dispose) {
4051                                 prepared_for_dispose = true;
4052                                 dispose_try_block = ec.DefineLabel ();
4053                         }
4054                         return dispose_try_block;
4055                 }
4056
4057                 public override void EmitForDispose (EmitContext ec, Iterator iterator, Label end, bool have_dispatcher)
4058                 {
4059                         if (emitted_dispose)
4060                                 return;
4061
4062                         emitted_dispose = true;
4063
4064                         Label end_of_try = ec.DefineLabel ();
4065
4066                         // Ensure that the only way we can get into this code is through a dispatcher
4067                         if (have_dispatcher)
4068                                 ec.Emit (OpCodes.Br, end);
4069
4070                         ec.BeginExceptionBlock ();
4071
4072                         ec.MarkLabel (dispose_try_block);
4073
4074                         Label [] labels = null;
4075                         for (int i = 0; i < resume_points.Count; ++i) {
4076                                 ResumableStatement s = (ResumableStatement) resume_points [i];
4077                                 Label ret = s.PrepareForDispose (ec, end_of_try);
4078                                 if (ret.Equals (end_of_try) && labels == null)
4079                                         continue;
4080                                 if (labels == null) {
4081                                         labels = new Label [resume_points.Count];
4082                                         for (int j = 0; j < i; ++j)
4083                                                 labels [j] = end_of_try;
4084                                 }
4085                                 labels [i] = ret;
4086                         }
4087
4088                         if (labels != null) {
4089                                 int j;
4090                                 for (j = 1; j < labels.Length; ++j)
4091                                         if (!labels [0].Equals (labels [j]))
4092                                                 break;
4093                                 bool emit_dispatcher = j < labels.Length;
4094
4095                                 if (emit_dispatcher) {
4096                                         //SymbolWriter.StartIteratorDispatcher (ec.ig);
4097                                         ec.Emit (OpCodes.Ldloc, iterator.CurrentPC);
4098                                         ec.EmitInt (first_resume_pc);
4099                                         ec.Emit (OpCodes.Sub);
4100                                         ec.Emit (OpCodes.Switch, labels);
4101                                         //SymbolWriter.EndIteratorDispatcher (ec.ig);
4102                                 }
4103
4104                                 foreach (ResumableStatement s in resume_points)
4105                                         s.EmitForDispose (ec, iterator, end_of_try, emit_dispatcher);
4106                         }
4107
4108                         ec.MarkLabel (end_of_try);
4109
4110                         ec.BeginFinallyBlock ();
4111
4112                         EmitFinallyBody (ec);
4113
4114                         ec.EndExceptionBlock ();
4115                 }
4116         }
4117
4118         public class Lock : ExceptionStatement {
4119                 Expression expr;
4120                 TemporaryVariableReference temp;
4121                         
4122                 public Lock (Expression expr, Statement stmt, Location loc)
4123                         : base (stmt, loc)
4124                 {
4125                         this.expr = expr;
4126                 }
4127
4128                 public override bool Resolve (BlockContext ec)
4129                 {
4130                         expr = expr.Resolve (ec);
4131                         if (expr == null)
4132                                 return false;
4133
4134                         if (!TypeManager.IsReferenceType (expr.Type)){
4135                                 ec.Report.Error (185, loc,
4136                                               "`{0}' is not a reference type as required by the lock statement",
4137                                               TypeManager.CSharpName (expr.Type));
4138                                 return false;
4139                         }
4140
4141                         ec.StartFlowBranching (this);
4142                         bool ok = Statement.Resolve (ec);
4143                         ec.EndFlowBranching ();
4144
4145                         ok &= base.Resolve (ec);
4146
4147                         temp = TemporaryVariableReference.Create (expr.Type, ec.CurrentBlock.Parent, loc);
4148                         temp.Resolve (ec);
4149
4150                         if (TypeManager.void_monitor_enter_object == null || TypeManager.void_monitor_exit_object == null) {
4151                                 TypeSpec monitor_type = TypeManager.CoreLookupType (ec.Compiler, "System.Threading", "Monitor", MemberKind.Class, true);
4152                                 TypeManager.void_monitor_enter_object = TypeManager.GetPredefinedMethod (
4153                                         monitor_type, "Enter", loc, TypeManager.object_type);
4154                                 TypeManager.void_monitor_exit_object = TypeManager.GetPredefinedMethod (
4155                                         monitor_type, "Exit", loc, TypeManager.object_type);
4156                         }
4157                         
4158                         return ok;
4159                 }
4160                 
4161                 protected override void EmitPreTryBody (EmitContext ec)
4162                 {
4163                         temp.EmitAssign (ec, expr);
4164                         temp.Emit (ec);
4165                         ec.Emit (OpCodes.Call, TypeManager.void_monitor_enter_object);
4166                 }
4167
4168                 protected override void EmitTryBody (EmitContext ec)
4169                 {
4170                         Statement.Emit (ec);
4171                 }
4172
4173                 protected override void EmitFinallyBody (EmitContext ec)
4174                 {
4175                         temp.Emit (ec);
4176                         ec.Emit (OpCodes.Call, TypeManager.void_monitor_exit_object);
4177                 }
4178
4179                 protected override void CloneTo (CloneContext clonectx, Statement t)
4180                 {
4181                         Lock target = (Lock) t;
4182
4183                         target.expr = expr.Clone (clonectx);
4184                         target.stmt = Statement.Clone (clonectx);
4185                 }
4186         }
4187
4188         public class Unchecked : Statement {
4189                 public Block Block;
4190                 
4191                 public Unchecked (Block b, Location loc)
4192                 {
4193                         Block = b;
4194                         b.Unchecked = true;
4195                         this.loc = loc;
4196                 }
4197
4198                 public override bool Resolve (BlockContext ec)
4199                 {
4200                         using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
4201                                 return Block.Resolve (ec);
4202                 }
4203                 
4204                 protected override void DoEmit (EmitContext ec)
4205                 {
4206                         using (ec.With (EmitContext.Options.AllCheckStateFlags, false))
4207                                 Block.Emit (ec);
4208                 }
4209
4210                 protected override void CloneTo (CloneContext clonectx, Statement t)
4211                 {
4212                         Unchecked target = (Unchecked) t;
4213
4214                         target.Block = clonectx.LookupBlock (Block);
4215                 }
4216         }
4217
4218         public class Checked : Statement {
4219                 public Block Block;
4220                 
4221                 public Checked (Block b, Location loc)
4222                 {
4223                         Block = b;
4224                         b.Unchecked = false;
4225                         this.loc = loc;
4226                 }
4227
4228                 public override bool Resolve (BlockContext ec)
4229                 {
4230                         using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
4231                                 return Block.Resolve (ec);
4232                 }
4233
4234                 protected override void DoEmit (EmitContext ec)
4235                 {
4236                         using (ec.With (EmitContext.Options.AllCheckStateFlags, true))
4237                                 Block.Emit (ec);
4238                 }
4239
4240                 protected override void CloneTo (CloneContext clonectx, Statement t)
4241                 {
4242                         Checked target = (Checked) t;
4243
4244                         target.Block = clonectx.LookupBlock (Block);
4245                 }
4246         }
4247
4248         public class Unsafe : Statement {
4249                 public Block Block;
4250
4251                 public Unsafe (Block b, Location loc)
4252                 {
4253                         Block = b;
4254                         Block.Unsafe = true;
4255                         this.loc = loc;
4256                 }
4257
4258                 public override bool Resolve (BlockContext ec)
4259                 {
4260                         if (ec.CurrentIterator != null)
4261                                 ec.Report.Error (1629, loc, "Unsafe code may not appear in iterators");
4262
4263                         using (ec.Set (ResolveContext.Options.UnsafeScope))
4264                                 return Block.Resolve (ec);
4265                 }
4266                 
4267                 protected override void DoEmit (EmitContext ec)
4268                 {
4269                         Block.Emit (ec);
4270                 }
4271
4272                 protected override void CloneTo (CloneContext clonectx, Statement t)
4273                 {
4274                         Unsafe target = (Unsafe) t;
4275
4276                         target.Block = clonectx.LookupBlock (Block);
4277                 }
4278         }
4279
4280         // 
4281         // Fixed statement
4282         //
4283         public class Fixed : Statement
4284         {
4285                 abstract class Emitter : ShimExpression
4286                 {
4287                         protected LocalVariable vi;
4288
4289                         protected Emitter (Expression expr, LocalVariable li)
4290                                 : base (expr)
4291                         {
4292                                 vi = li;
4293                         }
4294
4295                         public abstract void EmitExit (EmitContext ec);
4296                 }
4297
4298                 class ExpressionEmitter : Emitter {
4299                         public ExpressionEmitter (Expression converted, LocalVariable li) :
4300                                 base (converted, li)
4301                         {
4302                         }
4303
4304                         protected override Expression DoResolve (ResolveContext rc)
4305                         {
4306                                 throw new NotImplementedException ();
4307                         }
4308
4309                         public override void Emit (EmitContext ec) {
4310                                 //
4311                                 // Store pointer in pinned location
4312                                 //
4313                                 expr.Emit (ec);
4314                                 vi.EmitAssign (ec);
4315                         }
4316
4317                         public override void EmitExit (EmitContext ec)
4318                         {
4319                                 ec.Emit (OpCodes.Ldc_I4_0);
4320                                 ec.Emit (OpCodes.Conv_U);
4321                                 vi.EmitAssign (ec);
4322                         }
4323                 }
4324
4325                 class StringEmitter : Emitter
4326                 {
4327                         LocalVariable pinned_string;
4328
4329                         public StringEmitter (Expression expr, LocalVariable li, Location loc)
4330                                 : base (expr, li)
4331                         {
4332                         }
4333
4334                         protected override Expression DoResolve (ResolveContext rc)
4335                         {
4336                                 pinned_string = new LocalVariable (vi.Block, "$pinned",
4337                                         LocalVariable.Flags.FixedVariable | LocalVariable.Flags.CompilerGenerated | LocalVariable.Flags.Used,
4338                                         vi.Location);
4339
4340                                 pinned_string.Type = TypeManager.string_type;
4341
4342                                 if (TypeManager.int_get_offset_to_string_data == null) {
4343                                         TypeManager.int_get_offset_to_string_data = TypeManager.GetPredefinedProperty (
4344                                                 TypeManager.runtime_helpers_type, "OffsetToStringData", pinned_string.Location, TypeManager.int32_type);
4345                                 }
4346
4347                                 eclass = ExprClass.Variable;
4348                                 type = TypeManager.int32_type;
4349                                 return this;
4350                         }
4351
4352                         public override void Emit (EmitContext ec)
4353                         {
4354                                 pinned_string.CreateBuilder (ec);
4355
4356                                 expr.Emit (ec);
4357                                 pinned_string.EmitAssign (ec);
4358
4359                                 // TODO: Should use Binary::Add
4360                                 pinned_string.Emit (ec);
4361                                 ec.Emit (OpCodes.Conv_I);
4362
4363                                 PropertyExpr pe = new PropertyExpr (TypeManager.int_get_offset_to_string_data, pinned_string.Location);
4364                                 //pe.InstanceExpression = pinned_string;
4365                                 pe.Resolve (new ResolveContext (ec.MemberContext)).Emit (ec);
4366
4367                                 ec.Emit (OpCodes.Add);
4368                                 vi.EmitAssign (ec);
4369                         }
4370
4371                         public override void EmitExit (EmitContext ec)
4372                         {
4373                                 ec.Emit (OpCodes.Ldnull);
4374                                 pinned_string.EmitAssign (ec);
4375                         }
4376                 }
4377
4378                 public class VariableDeclaration : BlockVariableDeclaration
4379                 {
4380                         public VariableDeclaration (FullNamedExpression type, LocalVariable li)
4381                                 : base (type, li)
4382                         {
4383                         }
4384
4385                         protected override Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
4386                         {
4387                                 if (!Variable.Type.IsPointer && li == Variable) {
4388                                         bc.Report.Error (209, TypeExpression.Location,
4389                                                 "The type of locals declared in a fixed statement must be a pointer type");
4390                                         return null;
4391                                 }
4392
4393                                 //
4394                                 // The rules for the possible declarators are pretty wise,
4395                                 // but the production on the grammar is more concise.
4396                                 //
4397                                 // So we have to enforce these rules here.
4398                                 //
4399                                 // We do not resolve before doing the case 1 test,
4400                                 // because the grammar is explicit in that the token &
4401                                 // is present, so we need to test for this particular case.
4402                                 //
4403
4404                                 if (initializer is Cast) {
4405                                         bc.Report.Error (254, initializer.Location, "The right hand side of a fixed statement assignment may not be a cast expression");
4406                                         return null;
4407                                 }
4408
4409                                 initializer = initializer.Resolve (bc);
4410
4411                                 if (initializer == null)
4412                                         return null;
4413
4414                                 //
4415                                 // Case 1: Array
4416                                 //
4417                                 if (initializer.Type.IsArray) {
4418                                         TypeSpec array_type = TypeManager.GetElementType (initializer.Type);
4419
4420                                         //
4421                                         // Provided that array_type is unmanaged,
4422                                         //
4423                                         if (!TypeManager.VerifyUnmanaged (bc.Compiler, array_type, loc))
4424                                                 return null;
4425
4426                                         //
4427                                         // and T* is implicitly convertible to the
4428                                         // pointer type given in the fixed statement.
4429                                         //
4430                                         ArrayPtr array_ptr = new ArrayPtr (initializer, array_type, loc);
4431
4432                                         Expression converted = Convert.ImplicitConversionRequired (
4433                                                 bc, array_ptr, li.Type, loc);
4434                                         if (converted == null)
4435                                                 return null;
4436
4437                                         //
4438                                         // fixed (T* e_ptr = (e == null || e.Length == 0) ? null : converted [0])
4439                                         //
4440                                         converted = new Conditional (new BooleanExpression (new Binary (Binary.Operator.LogicalOr,
4441                                                 new Binary (Binary.Operator.Equality, initializer, new NullLiteral (loc), loc),
4442                                                 new Binary (Binary.Operator.Equality, new MemberAccess (initializer, "Length"), new IntConstant (0, loc), loc), loc)),
4443                                                         new NullPointer (loc),
4444                                                         converted, loc);
4445
4446                                         converted = converted.Resolve (bc);
4447
4448                                         return new ExpressionEmitter (converted, li);
4449                                 }
4450
4451                                 //
4452                                 // Case 2: string
4453                                 //
4454                                 if (initializer.Type == TypeManager.string_type) {
4455                                         return new StringEmitter (initializer, li, loc).Resolve (bc);
4456                                 }
4457
4458                                 // Case 3: fixed buffer
4459                                 if (initializer is FixedBufferPtr) {
4460                                         return new ExpressionEmitter (initializer, li);
4461                                 }
4462
4463                                 //
4464                                 // Case 4: & object.
4465                                 //
4466                                 bool already_fixed = true;
4467                                 Unary u = initializer as Unary;
4468                                 if (u != null && u.Oper == Unary.Operator.AddressOf) {
4469                                         IVariableReference vr = u.Expr as IVariableReference;
4470                                         if (vr == null || !vr.IsFixed) {
4471                                                 already_fixed = false;
4472                                         }
4473                                 }
4474
4475                                 if (already_fixed) {
4476                                         bc.Report.Error (213, loc, "You cannot use the fixed statement to take the address of an already fixed expression");
4477                                 }
4478
4479                                 initializer = Convert.ImplicitConversionRequired (bc, initializer, li.Type, loc);
4480                                 return new ExpressionEmitter (initializer, li);
4481                         }
4482                 }
4483
4484
4485                 VariableDeclaration decl;
4486                 Statement statement;
4487                 bool has_ret;
4488
4489                 public Fixed (VariableDeclaration decl, Statement stmt, Location l)
4490                 {
4491                         this.decl = decl;
4492                         statement = stmt;
4493                         loc = l;
4494                 }
4495
4496                 #region Properties
4497
4498                 public Statement Statement {
4499                         get {
4500                                 return statement;
4501                         }
4502                 }
4503
4504                 public BlockVariableDeclaration Variables {
4505                         get {
4506                                 return decl;
4507                         }
4508                 }
4509
4510                 #endregion
4511
4512                 public override bool Resolve (BlockContext ec)
4513                 {
4514                         using (ec.Set (ResolveContext.Options.FixedInitializerScope)) {
4515                                 if (!decl.Resolve (ec))
4516                                         return false;
4517                         }
4518
4519                         ec.StartFlowBranching (FlowBranching.BranchingType.Conditional, loc);
4520                         bool ok = statement.Resolve (ec);
4521                         bool flow_unreachable = ec.EndFlowBranching ();
4522                         has_ret = flow_unreachable;
4523
4524                         return ok;
4525                 }
4526                 
4527                 protected override void DoEmit (EmitContext ec)
4528                 {
4529                         decl.Variable.CreateBuilder (ec);
4530                         decl.Initializer.Emit (ec);
4531                         if (decl.Declarators != null) {
4532                                 foreach (var d in decl.Declarators) {
4533                                         d.Variable.CreateBuilder (ec);
4534                                         d.Initializer.Emit (ec);
4535                                 }
4536                         }
4537
4538                         statement.Emit (ec);
4539
4540                         if (has_ret)
4541                                 return;
4542
4543                         //
4544                         // Clear the pinned variable
4545                         //
4546                         ((Emitter) decl.Initializer).EmitExit (ec);
4547                         if (decl.Declarators != null) {
4548                                 foreach (var d in decl.Declarators) {
4549                                         ((Emitter)d.Initializer).EmitExit (ec);
4550                                 }
4551                         }
4552                 }
4553
4554                 protected override void CloneTo (CloneContext clonectx, Statement t)
4555                 {
4556                         Fixed target = (Fixed) t;
4557
4558                         target.decl = (VariableDeclaration) decl.Clone (clonectx);
4559                         target.statement = statement.Clone (clonectx);
4560                 }
4561         }
4562
4563         public class Catch : Statement
4564         {
4565                 Block block;
4566                 LocalVariable li;
4567                 FullNamedExpression type_expr;
4568                 CompilerAssign assign;
4569                 TypeSpec type;
4570                 
4571                 public Catch (Block block, Location loc)
4572                 {
4573                         this.block = block;
4574                         this.loc = loc;
4575                 }
4576
4577                 #region Properties
4578
4579                 public Block Block {
4580                         get {
4581                                 return block;
4582                         }
4583                 }
4584
4585                 public TypeSpec CatchType {
4586                         get {
4587                                 return type;
4588                         }
4589                 }
4590
4591                 public bool IsGeneral {
4592                         get {
4593                                 return type_expr == null;
4594                         }
4595                 }
4596
4597                 public FullNamedExpression TypeExpression {
4598                         get {
4599                                 return type_expr;
4600                         }
4601                         set {
4602                                 type_expr = value;
4603                         }
4604                 }
4605
4606                 public LocalVariable Variable {
4607                         get {
4608                                 return li;
4609                         }
4610                         set {
4611                                 li = value;
4612                         }
4613                 }
4614
4615                 #endregion
4616
4617                 protected override void DoEmit (EmitContext ec)
4618                 {
4619                         if (IsGeneral)
4620                                 ec.BeginCatchBlock (TypeManager.object_type);
4621                         else
4622                                 ec.BeginCatchBlock (CatchType);
4623
4624                         if (li != null) {
4625                                 li.CreateBuilder (ec);
4626
4627                                 //
4628                                 // Special case hoisted catch variable, we have to use a temporary variable
4629                                 // to pass via anonymous storey initialization with the value still on top
4630                                 // of the stack
4631                                 //
4632                                 if (li.HoistedVariant != null) {
4633                                         LocalTemporary lt = new LocalTemporary (li.Type);
4634                                         SymbolWriter.OpenCompilerGeneratedBlock (ec);
4635                                         lt.Store (ec);
4636                                         SymbolWriter.CloseCompilerGeneratedBlock (ec);
4637
4638                                         // switch to assigning from the temporary variable and not from top of the stack
4639                                         assign.UpdateSource (lt);
4640                                 }
4641                         } else {
4642                                 SymbolWriter.OpenCompilerGeneratedBlock (ec);
4643                                 ec.Emit (OpCodes.Pop);
4644                                 SymbolWriter.CloseCompilerGeneratedBlock (ec);
4645                         }
4646
4647                         Block.Emit (ec);
4648                 }
4649
4650                 public override bool Resolve (BlockContext ec)
4651                 {
4652                         using (ec.With (ResolveContext.Options.CatchScope, true)) {
4653                                 if (type_expr != null) {
4654                                         TypeExpr te = type_expr.ResolveAsTypeTerminal (ec, false);
4655                                         if (te == null)
4656                                                 return false;
4657
4658                                         type = te.Type;
4659                                         if (type != TypeManager.exception_type && !TypeSpec.IsBaseClass (type, TypeManager.exception_type, false)) {
4660                                                 ec.Report.Error (155, loc, "The type caught or thrown must be derived from System.Exception");
4661                                         } else if (li != null) {
4662                                                 li.Type = type;
4663                                                 li.PrepareForFlowAnalysis (ec);
4664
4665                                                 // source variable is at the top of the stack
4666                                                 Expression source = new EmptyExpression (li.Type);
4667                                                 if (li.Type.IsGenericParameter)
4668                                                         source = new UnboxCast (source, li.Type);
4669
4670                                                 assign = new CompilerAssign (new LocalVariableReference (li, loc), source, loc);
4671                                                 Block.AddScopeStatement (new StatementExpression (assign));
4672                                         }
4673                                 }
4674
4675                                 return Block.Resolve (ec);
4676                         }
4677                 }
4678
4679                 protected override void CloneTo (CloneContext clonectx, Statement t)
4680                 {
4681                         Catch target = (Catch) t;
4682
4683                         if (type_expr != null)
4684                                 target.type_expr = (FullNamedExpression) type_expr.Clone (clonectx);
4685
4686                         target.block = clonectx.LookupBlock (block);
4687                 }
4688         }
4689
4690         public class TryFinally : ExceptionStatement {
4691                 Block fini;
4692
4693                 public TryFinally (Statement stmt, Block fini, Location loc)
4694                          : base (stmt, loc)
4695                 {
4696                         this.fini = fini;
4697                 }
4698
4699                 public override bool Resolve (BlockContext ec)
4700                 {
4701                         bool ok = true;
4702
4703                         ec.StartFlowBranching (this);
4704
4705                         if (!stmt.Resolve (ec))
4706                                 ok = false;
4707
4708                         if (ok)
4709                                 ec.CurrentBranching.CreateSibling (fini, FlowBranching.SiblingType.Finally);
4710                         using (ec.With (ResolveContext.Options.FinallyScope, true)) {
4711                                 if (!fini.Resolve (ec))
4712                                         ok = false;
4713                         }
4714
4715                         ec.EndFlowBranching ();
4716
4717                         ok &= base.Resolve (ec);
4718
4719                         return ok;
4720                 }
4721
4722                 protected override void EmitPreTryBody (EmitContext ec)
4723                 {
4724                 }
4725
4726                 protected override void EmitTryBody (EmitContext ec)
4727                 {
4728                         stmt.Emit (ec);
4729                 }
4730
4731                 protected override void EmitFinallyBody (EmitContext ec)
4732                 {
4733                         fini.Emit (ec);
4734                 }
4735
4736                 protected override void CloneTo (CloneContext clonectx, Statement t)
4737                 {
4738                         TryFinally target = (TryFinally) t;
4739
4740                         target.stmt = (Statement) stmt.Clone (clonectx);
4741                         if (fini != null)
4742                                 target.fini = clonectx.LookupBlock (fini);
4743                 }
4744         }
4745
4746         public class TryCatch : Statement {
4747                 public Block Block;
4748                 public List<Catch> Specific;
4749                 public Catch General;
4750                 bool inside_try_finally, code_follows;
4751
4752                 public TryCatch (Block block, List<Catch> catch_clauses, Location l, bool inside_try_finally)
4753                 {
4754                         this.Block = block;
4755                         this.Specific = catch_clauses;
4756                         this.inside_try_finally = inside_try_finally;
4757
4758                         Catch c = catch_clauses [0];
4759                         if (c.IsGeneral) {
4760                                 this.General = c;                       
4761                                 catch_clauses.RemoveAt (0);
4762                         }
4763
4764                         loc = l;
4765                 }
4766
4767                 public override bool Resolve (BlockContext ec)
4768                 {
4769                         bool ok = true;
4770
4771                         ec.StartFlowBranching (this);
4772
4773                         if (!Block.Resolve (ec))
4774                                 ok = false;
4775
4776                         TypeSpec[] prev_catches = new TypeSpec [Specific.Count];
4777                         int last_index = 0;
4778                         foreach (Catch c in Specific){
4779                                 ec.CurrentBranching.CreateSibling (c.Block, FlowBranching.SiblingType.Catch);
4780
4781                                 if (!c.Resolve (ec)) {
4782                                         ok = false;
4783                                         continue;
4784                                 }
4785
4786                                 TypeSpec resolved_type = c.CatchType;
4787                                 for (int ii = 0; ii < last_index; ++ii) {
4788                                         if (resolved_type == prev_catches[ii] || TypeSpec.IsBaseClass (resolved_type, prev_catches[ii], true)) {
4789                                                 ec.Report.Error (160, c.loc,
4790                                                         "A previous catch clause already catches all exceptions of this or a super type `{0}'",
4791                                                         TypeManager.CSharpName (prev_catches [ii]));
4792                                                 ok = false;
4793                                         }
4794                                 }
4795
4796                                 prev_catches [last_index++] = resolved_type;
4797                         }
4798
4799                         if (General != null) {
4800                                 if (CodeGen.Assembly.WrapNonExceptionThrows) {
4801                                         foreach (Catch c in Specific){
4802                                                 if (c.CatchType == TypeManager.exception_type && PredefinedAttributes.Get.RuntimeCompatibility.IsDefined) {
4803                                                         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'");
4804                                                 }
4805                                         }
4806                                 }
4807
4808                                 ec.CurrentBranching.CreateSibling (General.Block, FlowBranching.SiblingType.Catch);
4809
4810                                 if (!General.Resolve (ec))
4811                                         ok = false;
4812                         }
4813
4814                         ec.EndFlowBranching ();
4815
4816                         // System.Reflection.Emit automatically emits a 'leave' at the end of a try/catch clause
4817                         // So, ensure there's some IL code after this statement
4818                         if (!inside_try_finally && !code_follows && ec.CurrentBranching.CurrentUsageVector.IsUnreachable)
4819                                 ec.NeedReturnLabel ();
4820
4821                         return ok;
4822                 }
4823
4824                 public void SomeCodeFollows ()
4825                 {
4826                         code_follows = true;
4827                 }
4828                 
4829                 protected override void DoEmit (EmitContext ec)
4830                 {
4831                         if (!inside_try_finally)
4832                                 ec.BeginExceptionBlock ();
4833
4834                         Block.Emit (ec);
4835
4836                         foreach (Catch c in Specific)
4837                                 c.Emit (ec);
4838
4839                         if (General != null)
4840                                 General.Emit (ec);
4841
4842                         if (!inside_try_finally)
4843                                 ec.EndExceptionBlock ();
4844                 }
4845
4846                 protected override void CloneTo (CloneContext clonectx, Statement t)
4847                 {
4848                         TryCatch target = (TryCatch) t;
4849
4850                         target.Block = clonectx.LookupBlock (Block);
4851                         if (General != null)
4852                                 target.General = (Catch) General.Clone (clonectx);
4853                         if (Specific != null){
4854                                 target.Specific = new List<Catch> ();
4855                                 foreach (Catch c in Specific)
4856                                         target.Specific.Add ((Catch) c.Clone (clonectx));
4857                         }
4858                 }
4859         }
4860
4861         // FIXME: Why is it almost exact copy of Using ??
4862         public class UsingTemporary : ExceptionStatement
4863         {
4864                 protected TemporaryVariableReference local_copy;
4865                 Expression expr;
4866                 protected Statement dispose_call;
4867
4868                 public UsingTemporary (Expression expr, Statement stmt, Location loc)
4869                         : base (stmt, loc)
4870                 {
4871                         this.expr = expr;
4872                 }
4873
4874                 #region Properties
4875                 public Expression Expression {
4876                         get {
4877                                 return expr;
4878                         }
4879                 }
4880
4881                 #endregion
4882
4883                 protected virtual bool DoResolve (BlockContext ec)
4884                 {
4885                         expr = expr.Resolve (ec);
4886                         if (expr == null)
4887                                 return false;
4888
4889                         if (expr.Type != TypeManager.idisposable_type && !expr.Type.ImplementsInterface (TypeManager.idisposable_type)) {
4890                                 if (TypeManager.IsNullableType (expr.Type)) {
4891                                         // it's handled it a custom code bellow
4892                                 } else if (expr.Type == InternalType.Dynamic) {
4893                                         expr = Convert.ImplicitConversionStandard (ec, expr, TypeManager.idisposable_type, loc);
4894                                 } else {
4895                                         Using.Error_IsNotConvertibleToIDisposable (ec, expr.Type, expr.Location);
4896                                         return false;
4897                                 }
4898                         }
4899
4900                         var expr_type = expr.Type;
4901
4902                         local_copy = TemporaryVariableReference.Create (expr_type, ec.CurrentBlock.Parent, loc);
4903                         local_copy.Resolve (ec);
4904
4905                         if (TypeManager.void_dispose_void == null) {
4906                                 TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
4907                                         TypeManager.idisposable_type, "Dispose", loc, TypeSpec.EmptyTypes);
4908                         }
4909
4910                         var dispose_mg = MethodGroupExpr.CreatePredefined (TypeManager.void_dispose_void, TypeManager.idisposable_type, loc);
4911                         dispose_mg.InstanceExpression = TypeManager.IsNullableType (expr_type) ?
4912                                 new Cast (new TypeExpression (TypeManager.idisposable_type, loc), local_copy, loc).Resolve (ec) :
4913                                 local_copy;
4914
4915                         dispose_call = new StatementExpression (new Invocation (dispose_mg, null));
4916
4917                         // Add conditional call when disposing possible null variable
4918                         if (!expr_type.IsStruct || TypeManager.IsNullableType (expr_type))
4919                                 dispose_call = new If (new Binary (Binary.Operator.Inequality, local_copy, new NullLiteral (loc), loc), dispose_call, loc);
4920
4921                         return dispose_call.Resolve (ec);
4922                 }
4923
4924                 public override bool Resolve (BlockContext ec)
4925                 {
4926                         bool ok = DoResolve (ec);
4927
4928                         ec.StartFlowBranching (this);
4929
4930                         ok &= stmt.Resolve (ec);
4931
4932                         ec.EndFlowBranching ();
4933
4934                         ok &= base.Resolve (ec);
4935
4936                         return ok;
4937                 }
4938
4939                 protected override void EmitPreTryBody (EmitContext ec)
4940                 {
4941                         //local_copy.Variable.
4942                         local_copy.EmitAssign (ec, expr);
4943                 }
4944
4945                 protected override void EmitTryBody (EmitContext ec)
4946                 {
4947                         stmt.Emit (ec);
4948                 }
4949
4950                 protected override void EmitFinallyBody (EmitContext ec)
4951                 {
4952                         dispose_call.Emit (ec);
4953                 }
4954
4955                 protected override void CloneTo (CloneContext clonectx, Statement t)
4956                 {
4957                         UsingTemporary target = (UsingTemporary) t;
4958
4959                         target.expr = expr.Clone (clonectx);
4960                         target.stmt = stmt.Clone (clonectx);
4961                 }
4962         }
4963
4964         public class Using : ExceptionStatement
4965         {
4966                 public class VariableDeclaration : BlockVariableDeclaration
4967                 {
4968                         public VariableDeclaration (FullNamedExpression type, LocalVariable li)
4969                                 : base (type, li)
4970                         {
4971                         }
4972
4973                         private VariableDeclaration (LocalVariable li, Location loc)
4974                                 : base (li)
4975                         {
4976                                 this.loc = loc;
4977                         }
4978
4979                         public override bool Resolve (BlockContext bc)
4980                         {
4981                                 if (type_expr == null)
4982                                         return true;
4983
4984                                 return base.Resolve (bc);
4985                         }
4986
4987                         protected override Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
4988                         {
4989                                 Assign assign;
4990
4991                                 if (li.Type == InternalType.Dynamic) {
4992                                         initializer = initializer.Resolve (bc);
4993                                         if (initializer == null)
4994                                                 return null;
4995
4996                                         initializer = Convert.ImplicitConversionRequired (bc, initializer, TypeManager.idisposable_type, loc);
4997                                         if (initializer == null)
4998                                                 return null;
4999
5000                                         var var = TemporaryVariableReference.Create (TypeManager.idisposable_type, bc.CurrentBlock, loc);
5001                                         assign = new SimpleAssign (var, initializer, loc);
5002                                         assign.ResolveStatement (bc);
5003                                         return assign;
5004                                 }
5005
5006                                 if (li == Variable) {
5007                                         if (li.Type != TypeManager.idisposable_type && !li.Type.ImplementsInterface (TypeManager.idisposable_type)) {
5008                                                 Using.Error_IsNotConvertibleToIDisposable (bc, li.Type, type_expr.Location);
5009                                                 return null;
5010                                         }
5011                                 }
5012
5013                                 return base.ResolveInitializer (bc, li, initializer);
5014                         }
5015
5016                         public Statement RewriteForDeclarators (BlockContext bc, Statement stmt)
5017                         {
5018                                 for (int i = declarators.Count - 1; i >= 0; --i) {
5019                                         var d = declarators [i];
5020                                         var vd = new VariableDeclaration (d.Variable, type_expr.Location);
5021                                         vd.Initializer = d.Initializer;
5022                                         stmt = new Using (vd, stmt, d.Variable.Location);
5023                                 }
5024
5025                                 declarators = null;
5026                                 return stmt;
5027                         }
5028                 }
5029
5030                 VariableDeclaration decl;
5031
5032                 public Using (VariableDeclaration decl, Statement stmt, Location loc)
5033                         : base (stmt, loc)
5034                 {
5035                         this.decl = decl;
5036                 }
5037
5038                 #region Properties
5039
5040                 public BlockVariableDeclaration Variables {
5041                         get {
5042                                 return decl;
5043                         }
5044                 }
5045
5046                 #endregion
5047
5048                 static public void Error_IsNotConvertibleToIDisposable (BlockContext ec, TypeSpec type, Location loc)
5049                 {
5050                         ec.Report.SymbolRelatedToPreviousError (type);
5051                         ec.Report.Error (1674, loc, "`{0}': type used in a using statement must be implicitly convertible to `System.IDisposable'",
5052                                 type.GetSignatureForError ());
5053                 }
5054
5055                 protected override void EmitPreTryBody (EmitContext ec)
5056                 {
5057                         decl.Emit (ec);
5058                 }
5059
5060                 protected override void EmitTryBody (EmitContext ec)
5061                 {
5062                         stmt.Emit (ec);
5063                 }
5064
5065                 protected override void EmitFinallyBody (EmitContext ec)
5066                 {
5067                         Label skip = ec.DefineLabel ();
5068
5069                         var var = ((Assign) decl.Initializer).Target;
5070                         bool emit_null_check = !TypeManager.IsValueType (var.Type);
5071                         if (emit_null_check) {
5072                                 var.Emit (ec);
5073                                 ec.Emit (OpCodes.Brfalse, skip);
5074                         }
5075
5076                         Invocation.EmitCall (ec, var, TypeManager.void_dispose_void, null, loc);
5077
5078                         if (emit_null_check)
5079                                 ec.MarkLabel (skip);
5080                 }
5081
5082                 public override bool Resolve (BlockContext ec)
5083                 {
5084                         using (ec.Set (ResolveContext.Options.UsingInitializerScope)) {
5085                                 if (!decl.Resolve (ec))
5086                                         return false;
5087
5088                                 if (decl.Declarators != null) {
5089                                         stmt = decl.RewriteForDeclarators (ec, stmt);
5090                                 }
5091                         }
5092
5093                         ec.StartFlowBranching (this);
5094
5095                         bool ok = stmt.Resolve (ec);
5096
5097                         ec.EndFlowBranching ();
5098
5099                         ok &= base.Resolve (ec);
5100
5101                         if (TypeManager.void_dispose_void == null) {
5102                                 TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
5103                                         TypeManager.idisposable_type, "Dispose", loc, TypeSpec.EmptyTypes);
5104                         }
5105
5106                         return ok;
5107                 }
5108
5109                 protected override void CloneTo (CloneContext clonectx, Statement t)
5110                 {
5111                         Using target = (Using) t;
5112
5113                         target.decl = (VariableDeclaration) decl.Clone (clonectx);
5114                         target.stmt = stmt.Clone (clonectx);
5115                 }
5116         }
5117
5118         /// <summary>
5119         ///   Implementation of the foreach C# statement
5120         /// </summary>
5121         public class Foreach : Statement {
5122
5123                 sealed class ArrayForeach : Statement
5124                 {
5125                         readonly Foreach for_each;
5126                         readonly Statement statement;
5127
5128                         Expression conv;
5129                         TemporaryVariableReference[] lengths;
5130                         Expression [] length_exprs;
5131                         StatementExpression[] counter;
5132                         TemporaryVariableReference[] variables;
5133
5134                         TemporaryVariableReference copy;
5135                         Expression access;
5136                         LocalVariableReference variable;
5137
5138                         public ArrayForeach (Foreach @foreach, int rank)
5139                         {
5140                                 for_each = @foreach;
5141                                 statement = for_each.statement;
5142                                 loc = @foreach.loc;
5143                                 variable = new LocalVariableReference (for_each.variable, loc);
5144
5145                                 counter = new StatementExpression[rank];
5146                                 variables = new TemporaryVariableReference[rank];
5147                                 length_exprs = new Expression [rank];
5148
5149                                 //
5150                                 // Only use temporary length variables when dealing with
5151                                 // multi-dimensional arrays
5152                                 //
5153                                 if (rank > 1)
5154                                         lengths = new TemporaryVariableReference [rank];
5155                         }
5156
5157                         protected override void CloneTo (CloneContext clonectx, Statement target)
5158                         {
5159                                 throw new NotImplementedException ();
5160                         }
5161
5162                         public override bool Resolve (BlockContext ec)
5163                         {
5164                                 Block variables_block = variable.local_info.Block;
5165                                 copy = TemporaryVariableReference.Create (for_each.expr.Type, variables_block, loc);
5166                                 copy.Resolve (ec);
5167
5168                                 int rank = length_exprs.Length;
5169                                 Arguments list = new Arguments (rank);
5170                                 for (int i = 0; i < rank; i++) {
5171                                         var v = TemporaryVariableReference.Create (TypeManager.int32_type, variables_block, loc);
5172                                         variables[i] = v;
5173                                         counter[i] = new StatementExpression (new UnaryMutator (UnaryMutator.Mode.PostIncrement, v, loc));
5174                                         counter[i].Resolve (ec);
5175
5176                                         if (rank == 1) {
5177                                                 length_exprs [i] = new MemberAccess (copy, "Length").Resolve (ec);
5178                                         } else {
5179                                                 lengths[i] = TemporaryVariableReference.Create (TypeManager.int32_type, variables_block, loc);
5180                                                 lengths[i].Resolve (ec);
5181
5182                                                 Arguments args = new Arguments (1);
5183                                                 args.Add (new Argument (new IntConstant (i, loc)));
5184                                                 length_exprs [i] = new Invocation (new MemberAccess (copy, "GetLength"), args).Resolve (ec);
5185                                         }
5186
5187                                         list.Add (new Argument (v));
5188                                 }
5189
5190                                 access = new ElementAccess (copy, list, loc).Resolve (ec);
5191                                 if (access == null)
5192                                         return false;
5193
5194                                 Expression var_type = for_each.type;
5195                                 VarExpr ve = var_type as VarExpr;
5196                                 if (ve != null) {
5197                                         // Infer implicitly typed local variable from foreach array type
5198                                         var_type = new TypeExpression (access.Type, ve.Location);
5199                                 }
5200
5201                                 var_type = var_type.ResolveAsTypeTerminal (ec, false);
5202                                 if (var_type == null)
5203                                         return false;
5204
5205                                 conv = Convert.ExplicitConversion (ec, access, var_type.Type, loc);
5206                                 if (conv == null)
5207                                         return false;
5208
5209                                 bool ok = true;
5210
5211                                 ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
5212                                 ec.CurrentBranching.CreateSibling ();
5213
5214                                 // TODO: dynamic
5215                                 variable.local_info.Type = conv.Type;
5216                                 variable.Resolve (ec);
5217
5218                                 ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc);
5219                                 if (!statement.Resolve (ec))
5220                                         ok = false;
5221                                 ec.EndFlowBranching ();
5222
5223                                 // There's no direct control flow from the end of the embedded statement to the end of the loop
5224                                 ec.CurrentBranching.CurrentUsageVector.Goto ();
5225
5226                                 ec.EndFlowBranching ();
5227
5228                                 return ok;
5229                         }
5230
5231                         protected override void DoEmit (EmitContext ec)
5232                         {
5233                                 copy.EmitAssign (ec, for_each.expr);
5234
5235                                 int rank = length_exprs.Length;
5236                                 Label[] test = new Label [rank];
5237                                 Label[] loop = new Label [rank];
5238
5239                                 for (int i = 0; i < rank; i++) {
5240                                         test [i] = ec.DefineLabel ();
5241                                         loop [i] = ec.DefineLabel ();
5242
5243                                         if (lengths != null)
5244                                                 lengths [i].EmitAssign (ec, length_exprs [i]);
5245                                 }
5246
5247                                 IntConstant zero = new IntConstant (0, loc);
5248                                 for (int i = 0; i < rank; i++) {
5249                                         variables [i].EmitAssign (ec, zero);
5250
5251                                         ec.Emit (OpCodes.Br, test [i]);
5252                                         ec.MarkLabel (loop [i]);
5253                                 }
5254
5255                                 variable.local_info.CreateBuilder (ec);
5256                                 variable.EmitAssign (ec, conv, false, false);
5257
5258                                 statement.Emit (ec);
5259
5260                                 ec.MarkLabel (ec.LoopBegin);
5261
5262                                 for (int i = rank - 1; i >= 0; i--){
5263                                         counter [i].Emit (ec);
5264
5265                                         ec.MarkLabel (test [i]);
5266                                         variables [i].Emit (ec);
5267
5268                                         if (lengths != null)
5269                                                 lengths [i].Emit (ec);
5270                                         else
5271                                                 length_exprs [i].Emit (ec);
5272
5273                                         ec.Emit (OpCodes.Blt, loop [i]);
5274                                 }
5275
5276                                 ec.MarkLabel (ec.LoopEnd);
5277                         }
5278                 }
5279
5280                 sealed class CollectionForeach : Statement, OverloadResolver.IErrorHandler
5281                 {
5282                         class Body : Statement
5283                         {
5284                                 TypeSpec type;
5285                                 LocalVariableReference variable;
5286                                 Expression current, conv;
5287                                 Statement statement;
5288
5289                                 public Body (TypeSpec type, LocalVariable variable,
5290                                                                    Expression current, Statement statement,
5291                                                                    Location loc)
5292                                 {
5293                                         this.type = type;
5294                                         this.variable = new LocalVariableReference (variable, loc);
5295                                         this.current = current;
5296                                         this.statement = statement;
5297                                         this.loc = loc;
5298                                 }
5299
5300                                 protected override void CloneTo (CloneContext clonectx, Statement target)
5301                                 {
5302                                         throw new NotImplementedException ();
5303                                 }
5304
5305                                 public override bool Resolve (BlockContext ec)
5306                                 {
5307                                         current = current.Resolve (ec);
5308                                         if (current == null)
5309                                                 return false;
5310
5311                                         conv = Convert.ExplicitConversion (ec, current, type, loc);
5312                                         if (conv == null)
5313                                                 return false;
5314
5315                                         variable.local_info.Type = conv.Type;
5316                                         variable.Resolve (ec);
5317
5318                                         if (!statement.Resolve (ec))
5319                                                 return false;
5320
5321                                         return true;
5322                                 }
5323
5324                                 protected override void DoEmit (EmitContext ec)
5325                                 {
5326                                         variable.local_info.CreateBuilder (ec);
5327                                         variable.EmitAssign (ec, conv, false, false);
5328
5329                                         statement.Emit (ec);
5330                                 }
5331                         }
5332
5333                         class Dispose : UsingTemporary
5334                         {
5335                                 LocalTemporary dispose;
5336
5337                                 public Dispose (TemporaryVariableReference variable, LocalTemporary dispose, Expression expr, Statement statement, Location loc)
5338                                         : base (expr, statement, loc)
5339                                 {
5340                                         base.local_copy = variable;
5341                                         this.dispose = dispose;
5342                                 }
5343
5344                                 protected override bool DoResolve (BlockContext ec)
5345                                 {
5346                                         if (TypeManager.void_dispose_void == null) {
5347                                                 TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
5348                                                         TypeManager.idisposable_type, "Dispose", loc, TypeSpec.EmptyTypes);
5349                                         }
5350
5351                                         Expression dispose_var = (Expression) dispose ?? local_copy;
5352
5353                                         var dispose_mg = MethodGroupExpr.CreatePredefined (TypeManager.void_dispose_void, TypeManager.idisposable_type, loc);
5354                                         dispose_mg.InstanceExpression = dispose_var;
5355
5356                                         dispose_call = new StatementExpression (new Invocation (dispose_mg, null));
5357
5358                                         if (!dispose_var.Type.IsStruct)
5359                                                 dispose_call = new If (new Binary (Binary.Operator.Inequality, dispose_var, new NullLiteral (loc), loc), dispose_call, loc);
5360
5361                                         return dispose_call.Resolve (ec);
5362                                 }
5363
5364                                 protected override void EmitFinallyBody (EmitContext ec)
5365                                 {
5366                                         Label call_dispose = ec.DefineLabel ();
5367                                         if (dispose != null) {
5368                                                 local_copy.Emit (ec, false);
5369                                                 ec.Emit (OpCodes.Isinst, dispose.Type);
5370                                                 dispose.Store (ec);
5371                                         }
5372
5373                                         base.EmitFinallyBody (ec);
5374
5375                                         if (dispose != null) {
5376                                                 ec.MarkLabel (call_dispose);
5377                                                 dispose.Release (ec);
5378                                         }
5379                                 }
5380                         }
5381
5382                         LocalVariable variable;
5383                         Expression expr;
5384                         Statement statement;
5385                         Expression var_type;
5386                         ExpressionStatement init;
5387                         TemporaryVariableReference enumerator_variable;
5388                         bool ambiguous_getenumerator_name;
5389
5390                         public CollectionForeach (Expression var_type, LocalVariable var, Expression expr, Statement stmt, Location l)
5391                         {
5392                                 this.var_type = var_type;
5393                                 this.variable = var;
5394                                 this.expr = expr;
5395                                 statement = stmt;
5396                                 loc = l;
5397                         }
5398
5399                         protected override void CloneTo (CloneContext clonectx, Statement target)
5400                         {
5401                                 throw new NotImplementedException ();
5402                         }
5403
5404                         void Error_WrongEnumerator (ResolveContext rc, MethodSpec enumerator)
5405                         {
5406                                 rc.Report.SymbolRelatedToPreviousError (enumerator);
5407                                 rc.Report.Error (202, loc,
5408                                         "foreach statement requires that the return type `{0}' of `{1}' must have a suitable public MoveNext method and public Current property",
5409                                                 enumerator.ReturnType.GetSignatureForError (), enumerator.GetSignatureForError ());
5410                         }
5411
5412                         MethodGroupExpr ResolveGetEnumerator (ResolveContext rc)
5413                         {
5414                                 //
5415                                 // Option 1: Try to match by name GetEnumerator first
5416                                 //
5417                                 var mexpr = Expression.MemberLookup (rc, rc.CurrentType, expr.Type, "GetEnumerator", 0, true, loc);             // TODO: What if CS0229 ?
5418
5419                                 var mg = mexpr as MethodGroupExpr;
5420                                 if (mg != null) {
5421                                         mg.InstanceExpression = expr;
5422                                         Arguments args = new Arguments (0);
5423                                         mg = mg.OverloadResolve (rc, ref args, this, OverloadResolver.Restrictions.None);
5424
5425                                         // For ambiguous GetEnumerator name warning CS0278 was reported, but Option 2 could still apply
5426                                         if (ambiguous_getenumerator_name)
5427                                                 mg = null;
5428
5429                                         if (mg != null && args.Count == 0 && !mg.BestCandidate.IsStatic && mg.BestCandidate.IsPublic) {
5430                                                 return mg;
5431                                         }
5432                                 }
5433
5434                                 //
5435                                 // Option 2: Try to match using IEnumerable interfaces with preference of generic version
5436                                 //
5437                                 TypeSpec iface_candidate = null;
5438                                 for (TypeSpec t = expr.Type; t != null && t != TypeManager.object_type; t = t.BaseType) {
5439                                         var ifaces = t.Interfaces;
5440                                         if (ifaces != null) {
5441                                                 foreach (var iface in ifaces) {
5442                                                         if (TypeManager.generic_ienumerable_type != null && iface.MemberDefinition == TypeManager.generic_ienumerable_type.MemberDefinition) {
5443                                                                 if (iface_candidate != null && iface_candidate != TypeManager.ienumerable_type) {
5444                                                                         rc.Report.SymbolRelatedToPreviousError (expr.Type);
5445                                                                         rc.Report.Error (1640, loc,
5446                                                                                 "foreach statement cannot operate on variables of type `{0}' because it contains multiple implementation of `{1}'. Try casting to a specific implementation",
5447                                                                                 expr.Type.GetSignatureForError (), TypeManager.generic_ienumerable_type.GetSignatureForError ());
5448
5449                                                                         return null;
5450                                                                 }
5451
5452                                                                 iface_candidate = iface;
5453                                                                 continue;
5454                                                         }
5455
5456                                                         if (iface == TypeManager.ienumerable_type && iface_candidate == null) {
5457                                                                 iface_candidate = iface;
5458                                                         }
5459                                                 }
5460                                         }
5461                                 }
5462
5463                                 if (iface_candidate == null) {
5464                                         rc.Report.Error (1579, loc,
5465                                                 "foreach statement cannot operate on variables of type `{0}' because it does not contain a definition for `{1}' or is inaccessible",
5466                                                 expr.Type.GetSignatureForError (), "GetEnumerator");
5467
5468                                         return null;
5469                                 }
5470
5471                                 var method = TypeManager.GetPredefinedMethod (iface_candidate, 
5472                                         MemberFilter.Method ("GetEnumerator", 0, ParametersCompiled.EmptyReadOnlyParameters, null), loc);
5473
5474                                 if (method == null)
5475                                         return null;
5476
5477                                 mg = MethodGroupExpr.CreatePredefined (method, expr.Type, loc);
5478                                 mg.InstanceExpression = expr;
5479                                 return mg;
5480                         }
5481
5482                         MethodGroupExpr ResolveMoveNext (ResolveContext rc, MethodSpec enumerator)
5483                         {
5484                                 var ms = MemberCache.FindMember (enumerator.ReturnType,
5485                                         MemberFilter.Method ("MoveNext", 0, ParametersCompiled.EmptyReadOnlyParameters, TypeManager.bool_type),
5486                                         BindingRestriction.InstanceOnly) as MethodSpec;
5487
5488                                 if (ms == null || !ms.IsPublic) {
5489                                         Error_WrongEnumerator (rc, enumerator);
5490                                         return null;
5491                                 }
5492
5493                                 return MethodGroupExpr.CreatePredefined (ms, enumerator.ReturnType, loc);
5494                         }
5495
5496                         PropertySpec ResolveCurrent (ResolveContext rc, MethodSpec enumerator)
5497                         {
5498                                 var ps = MemberCache.FindMember (enumerator.ReturnType,
5499                                         MemberFilter.Property ("Current", null),
5500                                         BindingRestriction.InstanceOnly) as PropertySpec;
5501
5502                                 if (ps == null || !ps.IsPublic) {
5503                                         Error_WrongEnumerator (rc, enumerator);
5504                                         return null;
5505                                 }
5506
5507                                 return ps;
5508                         }
5509
5510                         public override bool Resolve (BlockContext ec)
5511                         {
5512                                 bool is_dynamic = expr.Type == InternalType.Dynamic;
5513                                 if (is_dynamic)
5514                                         expr = Convert.ImplicitConversionRequired (ec, expr, TypeManager.ienumerable_type, loc);
5515
5516                                 var get_enumerator_mg = ResolveGetEnumerator (ec);
5517                                 if (get_enumerator_mg == null) {
5518                                         return false;
5519                                 }
5520
5521                                 var get_enumerator = get_enumerator_mg.BestCandidate;
5522                                 enumerator_variable = TemporaryVariableReference.Create (get_enumerator.ReturnType, variable.Block, loc);
5523                                 enumerator_variable.Resolve (ec);
5524
5525                                 // Prepare bool MoveNext ()
5526                                 var move_next_mg = ResolveMoveNext (ec, get_enumerator);
5527                                 if (move_next_mg == null) {
5528                                         return false;
5529                                 }
5530
5531                                 move_next_mg.InstanceExpression = enumerator_variable;
5532
5533                                 // Prepare ~T~ Current { get; }
5534                                 var current_prop = ResolveCurrent (ec, get_enumerator);
5535                                 if (current_prop == null) {
5536                                         return false;
5537                                 }
5538
5539                                 var current_pe = new PropertyExpr (current_prop, loc) { InstanceExpression = enumerator_variable }.Resolve (ec);
5540                                 if (current_pe == null)
5541                                         return false;
5542
5543                                 VarExpr ve = var_type as VarExpr;
5544                                 if (ve != null) {
5545                                         if (is_dynamic) {
5546                                                 // Source type is dynamic, set element type to dynamic too
5547                                                 var_type = new TypeExpression (InternalType.Dynamic, var_type.Location);
5548                                         } else {
5549                                                 // Infer implicitly typed local variable from foreach enumerable type
5550                                                 var_type = new TypeExpression (current_pe.Type, var_type.Location);
5551                                         }
5552                                 } else if (is_dynamic) {
5553                                         // Explicit cast of dynamic collection elements has to be done at runtime
5554                                         current_pe = EmptyCast.Create (current_pe, InternalType.Dynamic);
5555                                 }
5556
5557                                 var_type = var_type.ResolveAsTypeTerminal (ec, false);
5558                                 if (var_type == null)
5559                                         return false;
5560
5561                                 variable.Type = var_type.Type;
5562
5563                                 var init = new Invocation (get_enumerator_mg, null);
5564                                 init.Resolve (ec);
5565
5566                                 statement = new While (new BooleanExpression (new Invocation (move_next_mg, null)),
5567                                         new Body (var_type.Type, variable, current_pe, statement, loc), loc);
5568
5569                                 var enum_type = enumerator_variable.Type;
5570
5571                                 //
5572                                 // Add Dispose method call when enumerator can be IDisposable
5573                                 //
5574                                 if (!enum_type.ImplementsInterface (TypeManager.idisposable_type)) {
5575                                         if (!enum_type.IsSealed && !TypeManager.IsValueType (enum_type)) {
5576                                                 //
5577                                                 // Runtime Dispose check
5578                                                 //
5579                                                 var tv = new LocalTemporary (TypeManager.idisposable_type);
5580                                                 statement = new Dispose (enumerator_variable, tv, init, statement, loc);
5581                                         } else {
5582                                                 //
5583                                                 // No Dispose call needed
5584                                                 //
5585                                                 this.init = new SimpleAssign (enumerator_variable, init);
5586                                                 this.init.Resolve (ec);
5587                                         }
5588                                 } else {
5589                                         //
5590                                         // Static Dispose check
5591                                         //
5592                                         statement = new Dispose (enumerator_variable, null, init, statement, loc);
5593                                 }
5594
5595                                 return statement.Resolve (ec);
5596                         }
5597
5598                         protected override void DoEmit (EmitContext ec)
5599                         {
5600                                 enumerator_variable.LocalInfo.CreateBuilder (ec);
5601
5602                                 if (init != null)
5603                                         init.EmitStatement (ec);
5604
5605                                 statement.Emit (ec);
5606                         }
5607
5608                         #region IErrorHandler Members
5609
5610                         bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext ec, MemberSpec best, MemberSpec ambiguous)
5611                         {
5612                                 ec.Report.SymbolRelatedToPreviousError (best);
5613                                 ec.Report.Warning (278, 2, loc,
5614                                         "`{0}' contains ambiguous implementation of `{1}' pattern. Method `{2}' is ambiguous with method `{3}'",
5615                                         expr.Type.GetSignatureForError (), "enumerable",
5616                                         best.GetSignatureForError (), ambiguous.GetSignatureForError ());
5617
5618                                 ambiguous_getenumerator_name = true;
5619                                 return true;
5620                         }
5621
5622                         bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
5623                         {
5624                                 return false;
5625                         }
5626
5627                         bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
5628                         {
5629                                 return false;
5630                         }
5631
5632                         bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
5633                         {
5634                                 return false;
5635                         }
5636
5637                         #endregion
5638                 }
5639
5640                 Expression type;
5641                 LocalVariable variable;
5642                 Expression expr;
5643                 Statement statement;
5644
5645                 public Foreach (Expression type, LocalVariable var, Expression expr, Statement stmt, Location l)
5646                 {
5647                         this.type = type;
5648                         this.variable = var;
5649                         this.expr = expr;
5650                         statement = stmt;
5651                         loc = l;
5652                 }
5653
5654                 public Statement Statement {
5655                         get { return statement; }
5656                 }
5657
5658                 public override bool Resolve (BlockContext ec)
5659                 {
5660                         expr = expr.Resolve (ec);
5661                         if (expr == null)
5662                                 return false;
5663
5664                         if (expr.IsNull) {
5665                                 ec.Report.Error (186, loc, "Use of null is not valid in this context");
5666                                 return false;
5667                         }
5668
5669                         if (expr.Type == TypeManager.string_type) {
5670                                 statement = new ArrayForeach (this, 1);
5671                         } else if (expr.Type is ArrayContainer) {
5672                                 statement = new ArrayForeach (this, ((ArrayContainer) expr.Type).Rank);
5673                         } else {
5674                                 if (expr.eclass == ExprClass.MethodGroup || expr is AnonymousMethodExpression) {
5675                                         ec.Report.Error (446, expr.Location, "Foreach statement cannot operate on a `{0}'",
5676                                                 expr.ExprClassName);
5677                                         return false;
5678                                 }
5679
5680                                 statement = new CollectionForeach (type, variable, expr, statement, loc);
5681                         }
5682
5683                         return statement.Resolve (ec);
5684                 }
5685
5686                 protected override void DoEmit (EmitContext ec)
5687                 {
5688                         Label old_begin = ec.LoopBegin, old_end = ec.LoopEnd;
5689                         ec.LoopBegin = ec.DefineLabel ();
5690                         ec.LoopEnd = ec.DefineLabel ();
5691
5692                         statement.Emit (ec);
5693
5694                         ec.LoopBegin = old_begin;
5695                         ec.LoopEnd = old_end;
5696                 }
5697
5698                 protected override void CloneTo (CloneContext clonectx, Statement t)
5699                 {
5700                         Foreach target = (Foreach) t;
5701
5702                         target.type = type.Clone (clonectx);
5703                         target.expr = expr.Clone (clonectx);
5704                         target.statement = statement.Clone (clonectx);
5705                 }
5706         }
5707 }