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