Merge pull request #1068 from esdrubal/bug18421
[mono.git] / mcs / mcs / statement.cs
1 //
2 // statement.cs: Statement representation for the IL tree.
3 //
4 // Authors:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //   Martin Baulig (martin@ximian.com)
7 //   Marek Safar (marek.safar@gmail.com)
8 //
9 // Copyright 2001, 2002, 2003 Ximian, Inc.
10 // Copyright 2003, 2004 Novell, Inc.
11 // Copyright 2011 Xamarin Inc.
12 //
13
14 using System;
15 using System.Collections.Generic;
16
17 #if STATIC
18 using IKVM.Reflection.Emit;
19 #else
20 using System.Reflection.Emit;
21 #endif
22
23 namespace Mono.CSharp {
24         
25         public abstract class Statement {
26                 public Location loc;
27                 protected bool reachable;
28
29                 public bool IsUnreachable {
30                         get {
31                                 return !reachable;
32                         }
33                 }
34                 
35                 /// <summary>
36                 ///   Resolves the statement, true means that all sub-statements
37                 ///   did resolve ok.
38                 ///  </summary>
39                 public virtual bool Resolve (BlockContext bc)
40                 {
41                         return true;
42                 }
43
44                 /// <summary>
45                 ///   Return value indicates whether all code paths emitted return.
46                 /// </summary>
47                 protected abstract void DoEmit (EmitContext ec);
48
49                 public virtual void Emit (EmitContext ec)
50                 {
51                         ec.Mark (loc);
52                         DoEmit (ec);
53
54                         if (ec.StatementEpilogue != null) {
55                                 ec.EmitEpilogue ();
56                         }
57                 }
58
59                 //
60                 // This routine must be overrided in derived classes and make copies
61                 // of all the data that might be modified if resolved
62                 // 
63                 protected abstract void CloneTo (CloneContext clonectx, Statement target);
64
65                 public Statement Clone (CloneContext clonectx)
66                 {
67                         Statement s = (Statement) this.MemberwiseClone ();
68                         CloneTo (clonectx, s);
69                         return s;
70                 }
71
72                 public virtual Expression CreateExpressionTree (ResolveContext ec)
73                 {
74                         ec.Report.Error (834, loc, "A lambda expression with statement body cannot be converted to an expresion tree");
75                         return null;
76                 }
77                 
78                 public virtual object Accept (StructuralVisitor visitor)
79                 {
80                         return visitor.Visit (this);
81                 }
82
83                 //
84                 // Return value indicates whether statement has unreachable end
85                 //
86                 protected abstract bool DoFlowAnalysis (FlowAnalysisContext fc);
87
88                 public bool FlowAnalysis (FlowAnalysisContext fc)
89                 {
90                         if (reachable) {
91                                 fc.UnreachableReported = false;
92                                 var res = DoFlowAnalysis (fc);
93                                 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = null;
94                                 return res;
95                         }
96
97                         //
98                         // Special handling cases
99                         //
100                         if (this is Block) {
101                                 return DoFlowAnalysis (fc);
102                         }
103
104                         if (this is EmptyStatement || loc.IsNull)
105                                 return true;
106
107                         if (fc.UnreachableReported)
108                                 return true;
109
110                         fc.Report.Warning (162, 2, loc, "Unreachable code detected");
111                         fc.UnreachableReported = true;
112                         return true;
113                 }
114
115                 public virtual Reachability MarkReachable (Reachability rc)
116                 {
117                         if (!rc.IsUnreachable)
118                                 reachable = true;
119
120                         return rc;
121                 }
122
123                 protected void CheckExitBoundaries (BlockContext bc, Block scope)
124                 {
125                         if (bc.CurrentBlock.ParametersBlock.Original != scope.ParametersBlock.Original) {
126                                 bc.Report.Error (1632, loc, "Control cannot leave the body of an anonymous method");
127                                 return;
128                         }
129
130                         for (var b = bc.CurrentBlock; b != null && b != scope; b = b.Parent) {
131                                 if (b.IsFinallyBlock) {
132                                         Error_FinallyClauseExit (bc);
133                                         break;
134                                 }
135                         }
136                 }
137
138                 protected void Error_FinallyClauseExit (BlockContext bc)
139                 {
140                         bc.Report.Error (157, loc, "Control cannot leave the body of a finally clause");
141                 }
142         }
143
144         public sealed class EmptyStatement : Statement
145         {
146                 public EmptyStatement (Location loc)
147                 {
148                         this.loc = loc;
149                 }
150
151                 public override bool Resolve (BlockContext ec)
152                 {
153                         return true;
154                 }
155
156                 public override void Emit (EmitContext ec)
157                 {
158                 }
159
160                 protected override void DoEmit (EmitContext ec)
161                 {
162                         throw new NotSupportedException ();
163                 }
164
165                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
166                 {
167                         return false;
168                 }
169
170                 protected override void CloneTo (CloneContext clonectx, Statement target)
171                 {
172                         // nothing needed.
173                 }
174                 
175                 public override object Accept (StructuralVisitor visitor)
176                 {
177                         return visitor.Visit (this);
178                 }
179         }
180
181         public class If : Statement {
182                 Expression expr;
183                 public Statement TrueStatement;
184                 public Statement FalseStatement;
185
186                 bool true_returns, false_returns;
187
188                 public If (Expression bool_expr, Statement true_statement, Location l)
189                         : this (bool_expr, true_statement, null, l)
190                 {
191                 }
192
193                 public If (Expression bool_expr,
194                            Statement true_statement,
195                            Statement false_statement,
196                            Location l)
197                 {
198                         this.expr = bool_expr;
199                         TrueStatement = true_statement;
200                         FalseStatement = false_statement;
201                         loc = l;
202                 }
203
204                 public Expression Expr {
205                         get {
206                                 return this.expr;
207                         }
208                 }
209                 
210                 public override bool Resolve (BlockContext ec)
211                 {
212                         expr = expr.Resolve (ec);
213
214                         var ok = TrueStatement.Resolve (ec);
215
216                         if (FalseStatement != null) {
217                                 ok &= FalseStatement.Resolve (ec);
218                         }
219
220                         return ok;
221                 }
222                 
223                 protected override void DoEmit (EmitContext ec)
224                 {
225                         Label false_target = ec.DefineLabel ();
226                         Label end;
227
228                         //
229                         // If we're a boolean constant, Resolve() already
230                         // eliminated dead code for us.
231                         //
232                         Constant c = expr as Constant;
233                         if (c != null){
234                                 c.EmitSideEffect (ec);
235
236                                 if (!c.IsDefaultValue)
237                                         TrueStatement.Emit (ec);
238                                 else if (FalseStatement != null)
239                                         FalseStatement.Emit (ec);
240
241                                 return;
242                         }                       
243                         
244                         expr.EmitBranchable (ec, false_target, false);
245                         
246                         TrueStatement.Emit (ec);
247
248                         if (FalseStatement != null){
249                                 bool branch_emitted = false;
250                                 
251                                 end = ec.DefineLabel ();
252                                 if (!true_returns){
253                                         ec.Emit (OpCodes.Br, end);
254                                         branch_emitted = true;
255                                 }
256
257                                 ec.MarkLabel (false_target);
258                                 FalseStatement.Emit (ec);
259
260                                 if (branch_emitted)
261                                         ec.MarkLabel (end);
262                         } else {
263                                 ec.MarkLabel (false_target);
264                         }
265                 }
266
267                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
268                 {
269                         fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
270
271                         expr.FlowAnalysis (fc);
272
273                         var da_false = new DefiniteAssignmentBitSet (fc.DefiniteAssignmentOnFalse);
274
275                         fc.DefiniteAssignment = fc.DefiniteAssignmentOnTrue;
276                         fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = null;
277
278                         var res = TrueStatement.FlowAnalysis (fc);
279
280                         if (FalseStatement == null) {
281                                 if (true_returns)
282                                         fc.DefiniteAssignment = da_false;
283                                 else
284                                         fc.DefiniteAssignment &= da_false;
285  
286                                 return false;
287                         }
288
289                         if (true_returns) {
290                                 fc.DefiniteAssignment = da_false;
291                                 return FalseStatement.FlowAnalysis (fc);
292                         }
293
294                         var da_true = fc.DefiniteAssignment;
295
296                         fc.DefiniteAssignment = da_false;
297                         res &= FalseStatement.FlowAnalysis (fc);
298
299                         if (!TrueStatement.IsUnreachable) {
300                                 if (false_returns || FalseStatement.IsUnreachable)
301                                         fc.DefiniteAssignment = da_true;
302                                 else
303                                         fc.DefiniteAssignment &= da_true;
304                         }
305
306                         return res;
307                 }
308
309                 public override Reachability MarkReachable (Reachability rc)
310                 {
311                         if (rc.IsUnreachable)
312                                 return rc;
313
314                         base.MarkReachable (rc);
315
316                         var c = expr as Constant;
317                         if (c != null) {
318                                 bool take = !c.IsDefaultValue;
319                                 if (take) {
320                                         rc = TrueStatement.MarkReachable (rc);
321                                 } else {
322                                         if (FalseStatement != null)
323                                                 rc = FalseStatement.MarkReachable (rc);
324                                 }
325
326                                 return rc;
327                         }
328
329                         var true_rc = TrueStatement.MarkReachable (rc);
330                         true_returns = true_rc.IsUnreachable;
331         
332                         if (FalseStatement == null)
333                                 return rc;
334
335                         var false_rc = FalseStatement.MarkReachable (rc);
336                         false_returns = false_rc.IsUnreachable;
337
338                         return true_rc & false_rc;
339                 }
340
341                 protected override void CloneTo (CloneContext clonectx, Statement t)
342                 {
343                         If target = (If) t;
344
345                         target.expr = expr.Clone (clonectx);
346                         target.TrueStatement = TrueStatement.Clone (clonectx);
347                         if (FalseStatement != null)
348                                 target.FalseStatement = FalseStatement.Clone (clonectx);
349                 }
350                 
351                 public override object Accept (StructuralVisitor visitor)
352                 {
353                         return visitor.Visit (this);
354                 }
355         }
356
357         public class Do : LoopStatement
358         {
359                 public Expression expr;
360                 bool iterator_reachable, end_reachable;
361
362                 public Do (Statement statement, BooleanExpression bool_expr, Location doLocation, Location whileLocation)
363                         : base (statement)
364                 {
365                         expr = bool_expr;
366                         loc = doLocation;
367                         WhileLocation = whileLocation;
368                 }
369
370                 public Location WhileLocation {
371                         get; private set;
372                 }
373
374                 public override bool Resolve (BlockContext bc)
375                 {
376                         var ok = base.Resolve (bc);
377
378                         expr = expr.Resolve (bc);
379
380                         return ok;
381                 }
382                 
383                 protected override void DoEmit (EmitContext ec)
384                 {
385                         Label loop = ec.DefineLabel ();
386                         Label old_begin = ec.LoopBegin;
387                         Label old_end = ec.LoopEnd;
388                         
389                         ec.LoopBegin = ec.DefineLabel ();
390                         ec.LoopEnd = ec.DefineLabel ();
391                                 
392                         ec.MarkLabel (loop);
393                         Statement.Emit (ec);
394                         ec.MarkLabel (ec.LoopBegin);
395
396                         // Mark start of while condition
397                         ec.Mark (WhileLocation);
398
399                         //
400                         // Dead code elimination
401                         //
402                         if (expr is Constant) {
403                                 bool res = !((Constant) expr).IsDefaultValue;
404
405                                 expr.EmitSideEffect (ec);
406                                 if (res)
407                                         ec.Emit (OpCodes.Br, loop);
408                         } else {
409                                 expr.EmitBranchable (ec, loop, true);
410                         }
411                         
412                         ec.MarkLabel (ec.LoopEnd);
413
414                         ec.LoopBegin = old_begin;
415                         ec.LoopEnd = old_end;
416                 }
417
418                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
419                 {
420                         var res = Statement.FlowAnalysis (fc);
421
422                         fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
423                         expr.FlowAnalysis (fc);
424
425                         fc.DefiniteAssignment = fc.DefiniteAssignmentOnFalse;
426
427                         if (res && !iterator_reachable)
428                                 return !end_reachable;
429
430                         if (!end_reachable) {
431                                 var c = expr as Constant;
432                                 if (c != null && !c.IsDefaultValue)
433                                         return true;
434                         }
435
436                         return false;
437                 }
438                 
439                 public override Reachability MarkReachable (Reachability rc)
440                 {
441                         base.MarkReachable (rc);
442                         
443                         var body_rc = Statement.MarkReachable (rc);
444
445                         if (body_rc.IsUnreachable && !iterator_reachable) {
446                                 expr = new UnreachableExpression (expr);
447                                 return end_reachable ? rc : Reachability.CreateUnreachable ();
448                         }
449
450                         if (!end_reachable) {
451                                 var c = expr as Constant;
452                                 if (c != null && !c.IsDefaultValue)
453                                         return Reachability.CreateUnreachable ();
454                         }
455
456                         return rc;
457                 }
458
459                 protected override void CloneTo (CloneContext clonectx, Statement t)
460                 {
461                         Do target = (Do) t;
462
463                         target.Statement = Statement.Clone (clonectx);
464                         target.expr = expr.Clone (clonectx);
465                 }
466                 
467                 public override object Accept (StructuralVisitor visitor)
468                 {
469                         return visitor.Visit (this);
470                 }
471
472                 public override void SetEndReachable ()
473                 {
474                         end_reachable = true;
475                 }
476
477                 public override void SetIteratorReachable ()
478                 {
479                         iterator_reachable = true;
480                 }
481         }
482
483         public class While : LoopStatement
484         {
485                 public Expression expr;
486                 bool empty, infinite, end_reachable;
487                 List<DefiniteAssignmentBitSet> end_reachable_das;
488
489                 public While (BooleanExpression bool_expr, Statement statement, Location l)
490                         : base (statement)
491                 {
492                         this.expr = bool_expr;
493                         loc = l;
494                 }
495
496                 public override bool Resolve (BlockContext bc)
497                 {
498                         bool ok = true;
499
500                         expr = expr.Resolve (bc);
501                         if (expr == null)
502                                 ok = false;
503
504                         var c = expr as Constant;
505                         if (c != null) {
506                                 empty = c.IsDefaultValue;
507                                 infinite = !empty;
508                         }
509
510                         ok &= base.Resolve (bc);
511                         return ok;
512                 }
513                 
514                 protected override void DoEmit (EmitContext ec)
515                 {
516                         if (empty) {
517                                 expr.EmitSideEffect (ec);
518                                 return;
519                         }
520
521                         Label old_begin = ec.LoopBegin;
522                         Label old_end = ec.LoopEnd;
523                         
524                         ec.LoopBegin = ec.DefineLabel ();
525                         ec.LoopEnd = ec.DefineLabel ();
526
527                         //
528                         // Inform whether we are infinite or not
529                         //
530                         if (expr is Constant) {
531                                 // expr is 'true', since the 'empty' case above handles the 'false' case
532                                 ec.MarkLabel (ec.LoopBegin);
533
534                                 if (ec.EmitAccurateDebugInfo)
535                                         ec.Emit (OpCodes.Nop);
536
537                                 expr.EmitSideEffect (ec);
538                                 Statement.Emit (ec);
539                                 ec.Emit (OpCodes.Br, ec.LoopBegin);
540                                         
541                                 //
542                                 // Inform that we are infinite (ie, `we return'), only
543                                 // if we do not `break' inside the code.
544                                 //
545                                 ec.MarkLabel (ec.LoopEnd);
546                         } else {
547                                 Label while_loop = ec.DefineLabel ();
548
549                                 ec.Emit (OpCodes.Br, ec.LoopBegin);
550                                 ec.MarkLabel (while_loop);
551
552                                 Statement.Emit (ec);
553                         
554                                 ec.MarkLabel (ec.LoopBegin);
555
556                                 ec.Mark (loc);
557                                 expr.EmitBranchable (ec, while_loop, true);
558                                 
559                                 ec.MarkLabel (ec.LoopEnd);
560                         }       
561
562                         ec.LoopBegin = old_begin;
563                         ec.LoopEnd = old_end;
564                 }
565
566                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
567                 {
568                         fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
569         
570                         expr.FlowAnalysis (fc);
571
572                         fc.DefiniteAssignment = fc.DefiniteAssignmentOnTrue;
573                         var da_false = new DefiniteAssignmentBitSet (fc.DefiniteAssignmentOnFalse);
574                         fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = null;
575
576                         Statement.FlowAnalysis (fc);
577
578                         //
579                         // Special case infinite while with breaks
580                         //
581                         if (end_reachable_das != null) {
582                                 da_false = DefiniteAssignmentBitSet.And (end_reachable_das);
583                                 end_reachable_das = null;
584                         }
585
586                         fc.DefiniteAssignment = da_false;
587
588                         if (infinite && !end_reachable)
589                                 return true;
590
591                         return false;
592                 }
593
594                 public override Reachability MarkReachable (Reachability rc)
595                 {
596                         if (rc.IsUnreachable)
597                                 return rc;
598
599                         base.MarkReachable (rc);
600
601                         //
602                         // Special case unreachable while body
603                         //
604                         if (empty) {
605                                 Statement.MarkReachable (Reachability.CreateUnreachable ());
606                                 return rc;
607                         }
608
609                         Statement.MarkReachable (rc);
610
611                         //
612                         // When infinite while end is unreachable via break anything what follows is unreachable too
613                         //
614                         if (infinite && !end_reachable)
615                                 return Reachability.CreateUnreachable ();
616
617                         return rc;
618                 }
619
620                 protected override void CloneTo (CloneContext clonectx, Statement t)
621                 {
622                         While target = (While) t;
623
624                         target.expr = expr.Clone (clonectx);
625                         target.Statement = Statement.Clone (clonectx);
626                 }
627                 
628                 public override object Accept (StructuralVisitor visitor)
629                 {
630                         return visitor.Visit (this);
631                 }
632
633                 public override void AddEndDefiniteAssignment (FlowAnalysisContext fc)
634                 {
635                         if (!infinite)
636                                 return;
637
638                         if (end_reachable_das == null)
639                                 end_reachable_das = new List<DefiniteAssignmentBitSet> ();
640
641                         end_reachable_das.Add (fc.DefiniteAssignment);
642                 }
643
644                 public override void SetEndReachable ()
645                 {
646                         end_reachable = true;
647                 }
648         }
649
650         public class For : LoopStatement
651         {
652                 bool infinite, empty, iterator_reachable, end_reachable;
653                 List<DefiniteAssignmentBitSet> end_reachable_das;
654                 
655                 public For (Location l)
656                         : base (null)
657                 {
658                         loc = l;
659                 }
660
661                 public Statement Initializer {
662                         get; set;
663                 }
664
665                 public Expression Condition {
666                         get; set;
667                 }
668
669                 public Statement Iterator {
670                         get; set;
671                 }
672
673                 public override bool Resolve (BlockContext bc)
674                 {
675                         Initializer.Resolve (bc);
676
677                         if (Condition != null) {
678                                 Condition = Condition.Resolve (bc);
679                                 var condition_constant = Condition as Constant;
680                                 if (condition_constant != null) {
681                                         if (condition_constant.IsDefaultValue) {
682                                                 empty = true;
683                                         } else {
684                                                 infinite = true;
685                                         }
686                                 }
687                         } else {
688                                 infinite = true;
689                         }
690
691                         return base.Resolve (bc) && Iterator.Resolve (bc);
692                 }
693
694                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
695                 {
696                         Initializer.FlowAnalysis (fc);
697
698                         DefiniteAssignmentBitSet da_false;
699                         if (Condition != null) {
700                                 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
701
702                                 Condition.FlowAnalysis (fc);
703                                 fc.DefiniteAssignment = fc.DefiniteAssignmentOnTrue;
704                                 da_false = new DefiniteAssignmentBitSet (fc.DefiniteAssignmentOnFalse);
705                                 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = null;
706                         } else {
707                                 da_false = fc.BranchDefiniteAssignment ();
708                         }
709
710                         Statement.FlowAnalysis (fc);
711
712                         Iterator.FlowAnalysis (fc);
713
714                         //
715                         // Special case infinite for with breaks
716                         //
717                         if (end_reachable_das != null) {
718                                 da_false = DefiniteAssignmentBitSet.And (end_reachable_das);
719                                 end_reachable_das = null;
720                         }
721
722                         fc.DefiniteAssignment = da_false;
723
724                         if (infinite && !end_reachable)
725                                 return true;
726
727                         return false;
728                 }
729
730                 public override Reachability MarkReachable (Reachability rc)
731                 {
732                         base.MarkReachable (rc);
733
734                         Initializer.MarkReachable (rc);
735
736                         var body_rc = Statement.MarkReachable (rc);
737                         if (!body_rc.IsUnreachable || iterator_reachable) {
738                                 Iterator.MarkReachable (rc);
739                         }
740
741                         //
742                         // When infinite for end is unreachable via break anything what follows is unreachable too
743                         //
744                         if (infinite && !end_reachable) {
745                                 return Reachability.CreateUnreachable ();
746                         }
747
748                         return rc;
749                 }
750
751                 protected override void DoEmit (EmitContext ec)
752                 {
753                         if (Initializer != null)
754                                 Initializer.Emit (ec);
755
756                         if (empty) {
757                                 Condition.EmitSideEffect (ec);
758                                 return;
759                         }
760
761                         Label old_begin = ec.LoopBegin;
762                         Label old_end = ec.LoopEnd;
763                         Label loop = ec.DefineLabel ();
764                         Label test = ec.DefineLabel ();
765
766                         ec.LoopBegin = ec.DefineLabel ();
767                         ec.LoopEnd = ec.DefineLabel ();
768
769                         ec.Emit (OpCodes.Br, test);
770                         ec.MarkLabel (loop);
771                         Statement.Emit (ec);
772
773                         ec.MarkLabel (ec.LoopBegin);
774                         Iterator.Emit (ec);
775
776                         ec.MarkLabel (test);
777                         //
778                         // If test is null, there is no test, and we are just
779                         // an infinite loop
780                         //
781                         if (Condition != null) {
782                                 ec.Mark (Condition.Location);
783
784                                 //
785                                 // The Resolve code already catches the case for
786                                 // Test == Constant (false) so we know that
787                                 // this is true
788                                 //
789                                 if (Condition is Constant) {
790                                         Condition.EmitSideEffect (ec);
791                                         ec.Emit (OpCodes.Br, loop);
792                                 } else {
793                                         Condition.EmitBranchable (ec, loop, true);
794                                 }
795                                 
796                         } else
797                                 ec.Emit (OpCodes.Br, loop);
798                         ec.MarkLabel (ec.LoopEnd);
799
800                         ec.LoopBegin = old_begin;
801                         ec.LoopEnd = old_end;
802                 }
803
804                 protected override void CloneTo (CloneContext clonectx, Statement t)
805                 {
806                         For target = (For) t;
807
808                         if (Initializer != null)
809                                 target.Initializer = Initializer.Clone (clonectx);
810                         if (Condition != null)
811                                 target.Condition = Condition.Clone (clonectx);
812                         if (Iterator != null)
813                                 target.Iterator = Iterator.Clone (clonectx);
814                         target.Statement = Statement.Clone (clonectx);
815                 }
816
817                 public override object Accept (StructuralVisitor visitor)
818                 {
819                         return visitor.Visit (this);
820                 }
821
822                 public override void AddEndDefiniteAssignment (FlowAnalysisContext fc)
823                 {
824                         if (!infinite)
825                                 return;
826
827                         if (end_reachable_das == null)
828                                 end_reachable_das = new List<DefiniteAssignmentBitSet> ();
829
830                         end_reachable_das.Add (fc.DefiniteAssignment);
831                 }
832
833                 public override void SetEndReachable ()
834                 {
835                         end_reachable = true;
836                 }
837
838                 public override void SetIteratorReachable ()
839                 {
840                         iterator_reachable = true;
841                 }
842         }
843
844         public abstract class LoopStatement : Statement
845         {
846                 protected LoopStatement (Statement statement)
847                 {
848                         Statement = statement;
849                 }
850
851                 public Statement Statement { get; set; }
852
853                 public override bool Resolve (BlockContext bc)
854                 {
855                         var prev_loop = bc.EnclosingLoop;
856                         var prev_los = bc.EnclosingLoopOrSwitch;
857                         bc.EnclosingLoopOrSwitch = bc.EnclosingLoop = this;
858                         var ok = Statement.Resolve (bc);
859                         bc.EnclosingLoopOrSwitch = prev_los;
860                         bc.EnclosingLoop = prev_loop;
861
862                         return ok;
863                 }
864
865                 //
866                 // Needed by possibly infinite loops statements (for, while) and switch statment
867                 //
868                 public virtual void AddEndDefiniteAssignment (FlowAnalysisContext fc)
869                 {
870                 }
871
872                 public virtual void SetEndReachable ()
873                 {
874                 }
875
876                 public virtual void SetIteratorReachable ()
877                 {
878                 }
879         }
880         
881         public class StatementExpression : Statement
882         {
883                 ExpressionStatement expr;
884                 
885                 public StatementExpression (ExpressionStatement expr)
886                 {
887                         this.expr = expr;
888                         loc = expr.StartLocation;
889                 }
890
891                 public StatementExpression (ExpressionStatement expr, Location loc)
892                 {
893                         this.expr = expr;
894                         this.loc = loc;
895                 }
896
897                 public ExpressionStatement Expr {
898                         get {
899                                 return this.expr;
900                         }
901                 }
902                 
903                 protected override void CloneTo (CloneContext clonectx, Statement t)
904                 {
905                         StatementExpression target = (StatementExpression) t;
906                         target.expr = (ExpressionStatement) expr.Clone (clonectx);
907                 }
908                 
909                 protected override void DoEmit (EmitContext ec)
910                 {
911                         expr.EmitStatement (ec);
912                 }
913
914                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
915                 {
916                         expr.FlowAnalysis (fc);
917                         return false;
918                 }
919
920                 public override Reachability MarkReachable (Reachability rc)
921                 {
922                         base.MarkReachable (rc);
923                         expr.MarkReachable (rc);
924                         return rc;
925                 }
926
927                 public override bool Resolve (BlockContext ec)
928                 {
929                         expr = expr.ResolveStatement (ec);
930                         return expr != null;
931                 }
932                 
933                 public override object Accept (StructuralVisitor visitor)
934                 {
935                         return visitor.Visit (this);
936                 }
937         }
938
939         public class StatementErrorExpression : Statement
940         {
941                 Expression expr;
942
943                 public StatementErrorExpression (Expression expr)
944                 {
945                         this.expr = expr;
946                         this.loc = expr.StartLocation;
947                 }
948
949                 public Expression Expr {
950                         get {
951                                 return expr;
952                         }
953                 }
954
955                 public override bool Resolve (BlockContext bc)
956                 {
957                         expr.Error_InvalidExpressionStatement (bc);
958                         return true;
959                 }
960
961                 protected override void DoEmit (EmitContext ec)
962                 {
963                         throw new NotSupportedException ();
964                 }
965
966                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
967                 {
968                         return false;
969                 }
970
971                 protected override void CloneTo (CloneContext clonectx, Statement target)
972                 {
973                         var t = (StatementErrorExpression) target;
974
975                         t.expr = expr.Clone (clonectx);
976                 }
977                 
978                 public override object Accept (StructuralVisitor visitor)
979                 {
980                         return visitor.Visit (this);
981                 }
982         }
983
984         //
985         // Simple version of statement list not requiring a block
986         //
987         public class StatementList : Statement
988         {
989                 List<Statement> statements;
990
991                 public StatementList (Statement first, Statement second)
992                 {
993                         statements = new List<Statement> { first, second };
994                 }
995
996                 #region Properties
997                 public IList<Statement> Statements {
998                         get {
999                                 return statements;
1000                         }
1001                 }
1002                 #endregion
1003
1004                 public void Add (Statement statement)
1005                 {
1006                         statements.Add (statement);
1007                 }
1008
1009                 public override bool Resolve (BlockContext ec)
1010                 {
1011                         foreach (var s in statements)
1012                                 s.Resolve (ec);
1013
1014                         return true;
1015                 }
1016
1017                 protected override void DoEmit (EmitContext ec)
1018                 {
1019                         foreach (var s in statements)
1020                                 s.Emit (ec);
1021                 }
1022
1023                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
1024                 {
1025                         foreach (var s in statements)
1026                                 s.FlowAnalysis (fc);
1027
1028                         return false;
1029                 }
1030
1031                 public override Reachability MarkReachable (Reachability rc)
1032                 {
1033                         base.MarkReachable (rc);
1034
1035                         Reachability res = rc;
1036                         foreach (var s in statements)
1037                                 res = s.MarkReachable (rc);
1038
1039                         return res;
1040                 }
1041
1042                 protected override void CloneTo (CloneContext clonectx, Statement target)
1043                 {
1044                         StatementList t = (StatementList) target;
1045
1046                         t.statements = new List<Statement> (statements.Count);
1047                         foreach (Statement s in statements)
1048                                 t.statements.Add (s.Clone (clonectx));
1049                 }
1050                 
1051                 public override object Accept (StructuralVisitor visitor)
1052                 {
1053                         return visitor.Visit (this);
1054                 }
1055         }
1056
1057         //
1058         // For statements which require special handling when inside try or catch block
1059         //
1060         public abstract class ExitStatement : Statement
1061         {
1062                 protected bool unwind_protect;
1063
1064                 protected abstract bool DoResolve (BlockContext bc);
1065                 protected abstract bool IsLocalExit { get; }
1066
1067                 public override bool Resolve (BlockContext bc)
1068                 {
1069                         var res = DoResolve (bc);
1070
1071                         if (!IsLocalExit) {
1072                                 //
1073                                 // We are inside finally scope but is it the scope we are exiting
1074                                 //
1075                                 if (bc.HasSet (ResolveContext.Options.FinallyScope)) {
1076
1077                                         for (var b = bc.CurrentBlock; b != null; b = b.Parent) {
1078                                                 if (b.IsFinallyBlock) {
1079                                                         Error_FinallyClauseExit (bc);
1080                                                         break;
1081                                                 }
1082
1083                                                 if (b is ParametersBlock)
1084                                                         break;
1085                                         }
1086                                 }
1087                         }
1088
1089                         unwind_protect = bc.HasAny (ResolveContext.Options.TryScope | ResolveContext.Options.CatchScope);
1090                         return res;
1091                 }
1092
1093                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
1094                 {
1095                         if (IsLocalExit)
1096                                 return true;
1097
1098                         if (fc.TryFinally != null) {
1099                             fc.TryFinally.RegisterForControlExitCheck (new DefiniteAssignmentBitSet (fc.DefiniteAssignment));
1100                         } else {
1101                             fc.ParametersBlock.CheckControlExit (fc);
1102                         }
1103
1104                         return true;
1105                 }
1106         }
1107
1108         /// <summary>
1109         ///   Implements the return statement
1110         /// </summary>
1111         public class Return : ExitStatement
1112         {
1113                 Expression expr;
1114
1115                 public Return (Expression expr, Location l)
1116                 {
1117                         this.expr = expr;
1118                         loc = l;
1119                 }
1120
1121                 #region Properties
1122
1123                 public Expression Expr {
1124                         get {
1125                                 return expr;
1126                         }
1127                         protected set {
1128                                 expr = value;
1129                         }
1130                 }
1131
1132                 protected override bool IsLocalExit {
1133                         get {
1134                                 return false;
1135                         }
1136                 }
1137
1138                 #endregion
1139
1140                 protected override bool DoResolve (BlockContext ec)
1141                 {
1142                         var block_return_type = ec.ReturnType;
1143
1144                         if (expr == null) {
1145                                 if (block_return_type.Kind == MemberKind.Void)
1146                                         return true;
1147
1148                                 //
1149                                 // Return must not be followed by an expression when
1150                                 // the method return type is Task
1151                                 //
1152                                 if (ec.CurrentAnonymousMethod is AsyncInitializer) {
1153                                         var storey = (AsyncTaskStorey) ec.CurrentAnonymousMethod.Storey;
1154                                         if (storey.ReturnType == ec.Module.PredefinedTypes.Task.TypeSpec) {
1155                                                 //
1156                                                 // Extra trick not to emit ret/leave inside awaiter body
1157                                                 //
1158                                                 expr = EmptyExpression.Null;
1159                                                 return true;
1160                                         }
1161
1162                                         if (storey.ReturnType.IsGenericTask)
1163                                                 block_return_type = storey.ReturnType.TypeArguments[0];
1164                                 }
1165
1166                                 if (ec.CurrentIterator != null) {
1167                                         Error_ReturnFromIterator (ec);
1168                                 } else if (block_return_type != InternalType.ErrorType) {
1169                                         ec.Report.Error (126, loc,
1170                                                 "An object of a type convertible to `{0}' is required for the return statement",
1171                                                 block_return_type.GetSignatureForError ());
1172                                 }
1173
1174                                 return false;
1175                         }
1176
1177                         expr = expr.Resolve (ec);
1178
1179                         AnonymousExpression am = ec.CurrentAnonymousMethod;
1180                         if (am == null) {
1181                                 if (block_return_type.Kind == MemberKind.Void) {
1182                                         ec.Report.Error (127, loc,
1183                                                 "`{0}': A return keyword must not be followed by any expression when method returns void",
1184                                                 ec.GetSignatureForError ());
1185
1186                                         return false;
1187                                 }
1188                         } else {
1189                                 if (am.IsIterator) {
1190                                         Error_ReturnFromIterator (ec);
1191                                         return false;
1192                                 }
1193
1194                                 var async_block = am as AsyncInitializer;
1195                                 if (async_block != null) {
1196                                         if (expr != null) {
1197                                                 var storey = (AsyncTaskStorey) am.Storey;
1198                                                 var async_type = storey.ReturnType;
1199
1200                                                 if (async_type == null && async_block.ReturnTypeInference != null) {
1201                                                         async_block.ReturnTypeInference.AddCommonTypeBoundAsync (expr.Type);
1202                                                         return true;
1203                                                 }
1204
1205                                                 if (async_type.Kind == MemberKind.Void) {
1206                                                         ec.Report.Error (127, loc,
1207                                                                 "`{0}': A return keyword must not be followed by any expression when method returns void",
1208                                                                 ec.GetSignatureForError ());
1209
1210                                                         return false;
1211                                                 }
1212
1213                                                 if (!async_type.IsGenericTask) {
1214                                                         if (this is ContextualReturn)
1215                                                                 return true;
1216
1217                                                         // Same error code as .NET but better error message
1218                                                         if (async_block.DelegateType != null) {
1219                                                                 ec.Report.Error (1997, loc,
1220                                                                         "`{0}': A return keyword must not be followed by an expression when async delegate returns `Task'. Consider using `Task<T>' return type",
1221                                                                         async_block.DelegateType.GetSignatureForError ());
1222                                                         } else {
1223                                                                 ec.Report.Error (1997, loc,
1224                                                                         "`{0}': A return keyword must not be followed by an expression when async method returns `Task'. Consider using `Task<T>' return type",
1225                                                                         ec.GetSignatureForError ());
1226
1227                                                         }
1228
1229                                                         return false;
1230                                                 }
1231
1232                                                 //
1233                                                 // The return type is actually Task<T> type argument
1234                                                 //
1235                                                 if (expr.Type == async_type) {
1236                                                         ec.Report.Error (4016, loc,
1237                                                                 "`{0}': The return expression type of async method must be `{1}' rather than `Task<{1}>'",
1238                                                                 ec.GetSignatureForError (), async_type.TypeArguments[0].GetSignatureForError ());
1239                                                 } else {
1240                                                         block_return_type = async_type.TypeArguments[0];
1241                                                 }
1242                                         }
1243                                 } else {
1244                                         // Same error code as .NET but better error message
1245                                         if (block_return_type.Kind == MemberKind.Void) {
1246                                                 ec.Report.Error (127, loc,
1247                                                         "`{0}': A return keyword must not be followed by any expression when delegate returns void",
1248                                                         am.GetSignatureForError ());
1249
1250                                                 return false;
1251                                         }
1252
1253                                         var l = am as AnonymousMethodBody;
1254                                         if (l != null && expr != null) {
1255                                                 if (l.ReturnTypeInference != null) {
1256                                                         l.ReturnTypeInference.AddCommonTypeBound (expr.Type);
1257                                                         return true;
1258                                                 }
1259
1260                                                 //
1261                                                 // Try to optimize simple lambda. Only when optimizations are enabled not to cause
1262                                                 // unexpected debugging experience
1263                                                 //
1264                                                 if (this is ContextualReturn && !ec.IsInProbingMode && ec.Module.Compiler.Settings.Optimize) {
1265                                                         l.DirectMethodGroupConversion = expr.CanReduceLambda (l);
1266                                                 }
1267                                         }
1268                                 }
1269                         }
1270
1271                         if (expr == null)
1272                                 return false;
1273
1274                         if (expr.Type != block_return_type && expr.Type != InternalType.ErrorType) {
1275                                 expr = Convert.ImplicitConversionRequired (ec, expr, block_return_type, loc);
1276
1277                                 if (expr == null) {
1278                                         if (am != null && block_return_type == ec.ReturnType) {
1279                                                 ec.Report.Error (1662, loc,
1280                                                         "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",
1281                                                         am.ContainerType, am.GetSignatureForError ());
1282                                         }
1283                                         return false;
1284                                 }
1285                         }
1286
1287                         return true;                    
1288                 }
1289                 
1290                 protected override void DoEmit (EmitContext ec)
1291                 {
1292                         if (expr != null) {
1293                                 expr.Emit (ec);
1294
1295                                 var async_body = ec.CurrentAnonymousMethod as AsyncInitializer;
1296                                 if (async_body != null) {
1297                                         var async_return = ((AsyncTaskStorey) async_body.Storey).HoistedReturn;
1298
1299                                         // It's null for await without async
1300                                         if (async_return != null) {
1301                                                 async_return.EmitAssign (ec);
1302
1303                                                 ec.EmitEpilogue ();
1304                                         }
1305
1306                                         ec.Emit (OpCodes.Leave, async_body.BodyEnd);
1307                                         return;
1308                                 }
1309
1310                                 ec.EmitEpilogue ();
1311
1312                                 if (unwind_protect || ec.EmitAccurateDebugInfo)
1313                                         ec.Emit (OpCodes.Stloc, ec.TemporaryReturn ());
1314                         }
1315
1316                         if (unwind_protect) {
1317                                 ec.Emit (OpCodes.Leave, ec.CreateReturnLabel ());
1318                         } else if (ec.EmitAccurateDebugInfo) {
1319                                 ec.Emit (OpCodes.Br, ec.CreateReturnLabel ());
1320                         } else {
1321                                 ec.Emit (OpCodes.Ret);
1322                         }
1323                 }
1324
1325                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
1326                 {
1327                         if (expr != null)
1328                                 expr.FlowAnalysis (fc);
1329
1330                         base.DoFlowAnalysis (fc);
1331                         return true;
1332                 }
1333
1334                 void Error_ReturnFromIterator (ResolveContext rc)
1335                 {
1336                         rc.Report.Error (1622, loc,
1337                                 "Cannot return a value from iterators. Use the yield return statement to return a value, or yield break to end the iteration");
1338                 }
1339
1340                 public override Reachability MarkReachable (Reachability rc)
1341                 {
1342                         base.MarkReachable (rc);
1343                         return Reachability.CreateUnreachable ();
1344                 }
1345
1346                 protected override void CloneTo (CloneContext clonectx, Statement t)
1347                 {
1348                         Return target = (Return) t;
1349                         // It's null for simple return;
1350                         if (expr != null)
1351                                 target.expr = expr.Clone (clonectx);
1352                 }
1353
1354                 public override object Accept (StructuralVisitor visitor)
1355                 {
1356                         return visitor.Visit (this);
1357                 }
1358         }
1359
1360         public class Goto : ExitStatement
1361         {
1362                 string target;
1363                 LabeledStatement label;
1364                 TryFinally try_finally;
1365
1366                 public Goto (string label, Location l)
1367                 {
1368                         loc = l;
1369                         target = label;
1370                 }
1371
1372                 public string Target {
1373                         get { return target; }
1374                 }
1375
1376                 protected override bool IsLocalExit {
1377                         get {
1378                                 return true;
1379                         }
1380                 }
1381
1382                 protected override bool DoResolve (BlockContext bc)
1383                 {
1384                         label = bc.CurrentBlock.LookupLabel (target);
1385                         if (label == null) {
1386                                 Error_UnknownLabel (bc, target, loc);
1387                                 return false;
1388                         }
1389
1390                         try_finally = bc.CurrentTryBlock as TryFinally;
1391
1392                         CheckExitBoundaries (bc, label.Block);
1393
1394                         return true;
1395                 }
1396
1397                 public static void Error_UnknownLabel (BlockContext bc, string label, Location loc)
1398                 {
1399                         bc.Report.Error (159, loc, "The label `{0}:' could not be found within the scope of the goto statement",
1400                                 label);
1401                 }
1402
1403                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
1404                 {
1405                         if (fc.LabelStack == null) {
1406                                 fc.LabelStack = new List<LabeledStatement> ();
1407                         } else if (fc.LabelStack.Contains (label)) {
1408                                 return true;
1409                         }
1410
1411                         fc.LabelStack.Add (label);
1412                         label.Block.ScanGotoJump (label, fc);
1413                         fc.LabelStack.Remove (label);
1414                         return true;
1415                 }
1416
1417                 public override Reachability MarkReachable (Reachability rc)
1418                 {
1419                         if (rc.IsUnreachable)
1420                                 return rc;
1421
1422                         base.MarkReachable (rc);
1423
1424                         if (try_finally != null) {
1425                                 if (try_finally.FinallyBlock.HasReachableClosingBrace) {
1426                                         label.AddGotoReference (rc, false);
1427                                 } else {
1428                                         label.AddGotoReference (rc, true);
1429                                 }
1430
1431                                 try_finally = null;
1432                         } else {
1433                                 label.AddGotoReference (rc, false);
1434                         }
1435
1436                         return Reachability.CreateUnreachable ();
1437                 }
1438
1439                 protected override void CloneTo (CloneContext clonectx, Statement target)
1440                 {
1441                         // Nothing to clone
1442                 }
1443
1444                 protected override void DoEmit (EmitContext ec)
1445                 {
1446                         if (label == null)
1447                                 throw new InternalErrorException ("goto emitted before target resolved");
1448
1449                         Label l = label.LabelTarget (ec);
1450                         ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, l);
1451                 }
1452                 
1453                 public override object Accept (StructuralVisitor visitor)
1454                 {
1455                         return visitor.Visit (this);
1456                 }
1457         }
1458
1459         public class LabeledStatement : Statement {
1460                 string name;
1461                 bool defined;
1462                 bool referenced;
1463                 bool finalTarget;
1464                 Label label;
1465                 Block block;
1466                 
1467                 public LabeledStatement (string name, Block block, Location l)
1468                 {
1469                         this.name = name;
1470                         this.block = block;
1471                         this.loc = l;
1472                 }
1473
1474                 public Label LabelTarget (EmitContext ec)
1475                 {
1476                         if (defined)
1477                                 return label;
1478
1479                         label = ec.DefineLabel ();
1480                         defined = true;
1481                         return label;
1482                 }
1483
1484                 public Block Block {
1485                         get {
1486                                 return block;
1487                         }
1488                 }
1489
1490                 public string Name {
1491                         get { return name; }
1492                 }
1493
1494                 protected override void CloneTo (CloneContext clonectx, Statement target)
1495                 {
1496                         var t = (LabeledStatement) target;
1497
1498                         t.block = clonectx.RemapBlockCopy (block);
1499                 }
1500
1501                 public override bool Resolve (BlockContext bc)
1502                 {
1503                         return true;
1504                 }
1505
1506                 protected override void DoEmit (EmitContext ec)
1507                 {
1508                         LabelTarget (ec);
1509                         ec.MarkLabel (label);
1510
1511                         if (finalTarget)
1512                                 ec.Emit (OpCodes.Br_S, label);
1513                 }
1514
1515                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
1516                 {
1517                         if (!referenced) {
1518                                 fc.Report.Warning (164, 2, loc, "This label has not been referenced");
1519                         }
1520
1521                         return false;
1522                 }
1523
1524                 public override Reachability MarkReachable (Reachability rc)
1525                 {
1526                         base.MarkReachable (rc);
1527
1528                         if (referenced)
1529                                 rc = new Reachability ();
1530
1531                         return rc;
1532                 }
1533
1534                 public void AddGotoReference (Reachability rc, bool finalTarget)
1535                 {
1536                         if (referenced)
1537                                 return;
1538
1539                         referenced = true;
1540                         MarkReachable (rc);
1541
1542                         //
1543                         // Label is final target when goto jumps out of try block with
1544                         // finally clause. In that case we need leave with target but in C#
1545                         // terms the label is unreachable. Using finalTarget we emit
1546                         // explicit label not just marker
1547                         //
1548                         if (finalTarget) {
1549                                 this.finalTarget = true;
1550                                 return;
1551                         }
1552
1553                         block.ScanGotoJump (this);
1554                 }
1555
1556                 public override object Accept (StructuralVisitor visitor)
1557                 {
1558                         return visitor.Visit (this);
1559                 }
1560         }
1561         
1562
1563         /// <summary>
1564         ///   `goto default' statement
1565         /// </summary>
1566         public class GotoDefault : SwitchGoto
1567         {               
1568                 public GotoDefault (Location l)
1569                         : base (l)
1570                 {
1571                 }
1572
1573                 public override bool Resolve (BlockContext bc)
1574                 {
1575                         if (bc.Switch == null) {
1576                                 Error_GotoCaseRequiresSwitchBlock (bc);
1577                                 return false;
1578                         }
1579
1580                         bc.Switch.RegisterGotoCase (null, null);
1581                         base.Resolve (bc);
1582
1583                         return true;
1584                 }
1585
1586                 protected override void DoEmit (EmitContext ec)
1587                 {
1588                         ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.Switch.DefaultLabel.GetILLabel (ec));
1589                 }
1590
1591                 public override Reachability MarkReachable (Reachability rc)
1592                 {
1593                         if (!rc.IsUnreachable) {
1594                                 var label = switch_statement.DefaultLabel;
1595                                 if (label.IsUnreachable) {
1596                                         label.MarkReachable (rc);
1597                                         switch_statement.Block.ScanGotoJump (label);
1598                                 }
1599                         }
1600
1601                         return base.MarkReachable (rc);
1602                 }
1603
1604                 public override object Accept (StructuralVisitor visitor)
1605                 {
1606                         return visitor.Visit (this);
1607                 }
1608         }
1609
1610         /// <summary>
1611         ///   `goto case' statement
1612         /// </summary>
1613         public class GotoCase : SwitchGoto
1614         {
1615                 Expression expr;
1616                 
1617                 public GotoCase (Expression e, Location l)
1618                         : base (l)
1619                 {
1620                         expr = e;
1621                 }
1622
1623                 public Expression Expr {
1624                         get {
1625                                 return expr;
1626                         }
1627                 }
1628
1629                 public SwitchLabel Label { get; set; }
1630
1631                 public override bool Resolve (BlockContext ec)
1632                 {
1633                         if (ec.Switch == null) {
1634                                 Error_GotoCaseRequiresSwitchBlock (ec);
1635                                 return false;
1636                         }
1637
1638                         Constant c = expr.ResolveLabelConstant (ec);
1639                         if (c == null) {
1640                                 return false;
1641                         }
1642
1643                         Constant res;
1644                         if (ec.Switch.IsNullable && c is NullLiteral) {
1645                                 res = c;
1646                         } else {
1647                                 TypeSpec type = ec.Switch.SwitchType;
1648                                 res = c.Reduce (ec, type);
1649                                 if (res == null) {
1650                                         c.Error_ValueCannotBeConverted (ec, type, true);
1651                                         return false;
1652                                 }
1653
1654                                 if (!Convert.ImplicitStandardConversionExists (c, type))
1655                                         ec.Report.Warning (469, 2, loc,
1656                                                 "The `goto case' value is not implicitly convertible to type `{0}'",
1657                                                 type.GetSignatureForError ());
1658
1659                         }
1660
1661                         ec.Switch.RegisterGotoCase (this, res);
1662                         base.Resolve (ec);
1663                         expr = res;
1664
1665                         return true;
1666                 }
1667
1668                 protected override void DoEmit (EmitContext ec)
1669                 {
1670                         ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, Label.GetILLabel (ec));
1671                 }
1672
1673                 protected override void CloneTo (CloneContext clonectx, Statement t)
1674                 {
1675                         GotoCase target = (GotoCase) t;
1676
1677                         target.expr = expr.Clone (clonectx);
1678                 }
1679
1680                 public override Reachability MarkReachable (Reachability rc)
1681                 {
1682                         if (!rc.IsUnreachable) {
1683                                 var label = switch_statement.FindLabel ((Constant) expr);
1684                                 if (label.IsUnreachable) {
1685                                         label.MarkReachable (rc);
1686                                         switch_statement.Block.ScanGotoJump (label);
1687                                 }
1688                         }
1689
1690                         return base.MarkReachable (rc);
1691                 }
1692                 
1693                 public override object Accept (StructuralVisitor visitor)
1694                 {
1695                         return visitor.Visit (this);
1696                 }
1697         }
1698
1699         public abstract class SwitchGoto : Statement
1700         {
1701                 protected bool unwind_protect;
1702                 protected Switch switch_statement;
1703
1704                 protected SwitchGoto (Location loc)
1705                 {
1706                         this.loc = loc;
1707                 }
1708
1709                 protected override void CloneTo (CloneContext clonectx, Statement target)
1710                 {
1711                         // Nothing to clone
1712                 }
1713
1714                 public override bool Resolve (BlockContext bc)
1715                 {
1716                         CheckExitBoundaries (bc, bc.Switch.Block);
1717
1718                         unwind_protect = bc.HasAny (ResolveContext.Options.TryScope | ResolveContext.Options.CatchScope);
1719                         switch_statement = bc.Switch;
1720
1721                         return true;
1722                 }
1723
1724                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
1725                 {
1726                         return true;
1727                 }
1728
1729                 public override Reachability MarkReachable (Reachability rc)
1730                 {
1731                         base.MarkReachable (rc);
1732                         return Reachability.CreateUnreachable ();
1733                 }
1734
1735                 protected void Error_GotoCaseRequiresSwitchBlock (BlockContext bc)
1736                 {
1737                         bc.Report.Error (153, loc, "A goto case is only valid inside a switch statement");
1738                 }
1739         }
1740         
1741         public class Throw : Statement {
1742                 Expression expr;
1743                 
1744                 public Throw (Expression expr, Location l)
1745                 {
1746                         this.expr = expr;
1747                         loc = l;
1748                 }
1749
1750                 public Expression Expr {
1751                         get {
1752                                 return this.expr;
1753                         }
1754                 }
1755
1756                 public override bool Resolve (BlockContext ec)
1757                 {
1758                         if (expr == null) {
1759                                 if (!ec.HasSet (ResolveContext.Options.CatchScope)) {
1760                                         ec.Report.Error (156, loc, "A throw statement with no arguments is not allowed outside of a catch clause");
1761                                 } else if (ec.HasSet (ResolveContext.Options.FinallyScope)) {
1762                                         for (var b = ec.CurrentBlock; b != null && !b.IsCatchBlock; b = b.Parent) {
1763                                                 if (b.IsFinallyBlock) {
1764                                                         ec.Report.Error (724, loc,
1765                                                                 "A throw statement with no arguments is not allowed inside of a finally clause nested inside of the innermost catch clause");
1766                                                         break;
1767                                                 }
1768                                         }
1769                                 }
1770
1771                                 return true;
1772                         }
1773
1774                         expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
1775
1776                         if (expr == null)
1777                                 return false;
1778
1779                         var et = ec.BuiltinTypes.Exception;
1780                         if (Convert.ImplicitConversionExists (ec, expr, et))
1781                                 expr = Convert.ImplicitConversion (ec, expr, et, loc);
1782                         else
1783                                 ec.Report.Error (155, expr.Location, "The type caught or thrown must be derived from System.Exception");
1784
1785                         return true;
1786                 }
1787                         
1788                 protected override void DoEmit (EmitContext ec)
1789                 {
1790                         if (expr == null)
1791                                 ec.Emit (OpCodes.Rethrow);
1792                         else {
1793                                 expr.Emit (ec);
1794
1795                                 ec.Emit (OpCodes.Throw);
1796                         }
1797                 }
1798
1799                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
1800                 {
1801                         if (expr != null)
1802                                 expr.FlowAnalysis (fc);
1803
1804                         return true;
1805                 }
1806
1807                 public override Reachability MarkReachable (Reachability rc)
1808                 {
1809                         base.MarkReachable (rc);
1810                         return Reachability.CreateUnreachable ();
1811                 }
1812
1813                 protected override void CloneTo (CloneContext clonectx, Statement t)
1814                 {
1815                         Throw target = (Throw) t;
1816
1817                         if (expr != null)
1818                                 target.expr = expr.Clone (clonectx);
1819                 }
1820                 
1821                 public override object Accept (StructuralVisitor visitor)
1822                 {
1823                         return visitor.Visit (this);
1824                 }
1825         }
1826
1827         public class Break : LocalExitStatement
1828         {               
1829                 public Break (Location l)
1830                         : base (l)
1831                 {
1832                 }
1833                 
1834                 public override object Accept (StructuralVisitor visitor)
1835                 {
1836                         return visitor.Visit (this);
1837                 }
1838
1839                 protected override void DoEmit (EmitContext ec)
1840                 {
1841                         ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopEnd);
1842                 }
1843
1844                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
1845                 {
1846                         enclosing_loop.AddEndDefiniteAssignment (fc);
1847                         return true;
1848                 }
1849
1850                 protected override bool DoResolve (BlockContext bc)
1851                 {
1852                         enclosing_loop = bc.EnclosingLoopOrSwitch;
1853                         return base.DoResolve (bc);
1854                 }
1855
1856                 public override Reachability MarkReachable (Reachability rc)
1857                 {
1858                         base.MarkReachable (rc);
1859
1860                         if (!rc.IsUnreachable)
1861                                 enclosing_loop.SetEndReachable ();
1862
1863                         return Reachability.CreateUnreachable ();
1864                 }
1865         }
1866
1867         public class Continue : LocalExitStatement
1868         {               
1869                 public Continue (Location l)
1870                         : base (l)
1871                 {
1872                 }
1873
1874                 public override object Accept (StructuralVisitor visitor)
1875                 {
1876                         return visitor.Visit (this);
1877                 }
1878
1879
1880                 protected override void DoEmit (EmitContext ec)
1881                 {
1882                         ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopBegin);
1883                 }
1884
1885                 protected override bool DoResolve (BlockContext bc)
1886                 {
1887                         enclosing_loop = bc.EnclosingLoop;
1888                         return base.DoResolve (bc);
1889                 }
1890
1891                 public override Reachability MarkReachable (Reachability rc)
1892                 {
1893                         base.MarkReachable (rc);
1894
1895                         if (!rc.IsUnreachable)
1896                                 enclosing_loop.SetIteratorReachable ();
1897
1898                         return Reachability.CreateUnreachable ();
1899                 }
1900         }
1901
1902         public abstract class LocalExitStatement : ExitStatement
1903         {
1904                 protected LoopStatement enclosing_loop;
1905
1906                 protected LocalExitStatement (Location loc)
1907                 {
1908                         this.loc = loc;
1909                 }
1910
1911                 protected override bool IsLocalExit {
1912                         get {
1913                                 return true;
1914                         }
1915                 }
1916
1917                 protected override void CloneTo (CloneContext clonectx, Statement t)
1918                 {
1919                         // nothing needed.
1920                 }
1921
1922                 protected override bool DoResolve (BlockContext bc)
1923                 {
1924                         if (enclosing_loop == null) {
1925                                 bc.Report.Error (139, loc, "No enclosing loop out of which to break or continue");
1926                                 return false;
1927                         }
1928
1929                         var block = enclosing_loop.Statement as Block;
1930
1931                         // Don't need to do extra checks for simple statements loops
1932                         if (block != null) {
1933                                 CheckExitBoundaries (bc, block);
1934                         }
1935
1936                         return true;
1937                 }
1938         }
1939
1940         public interface ILocalVariable
1941         {
1942                 void Emit (EmitContext ec);
1943                 void EmitAssign (EmitContext ec);
1944                 void EmitAddressOf (EmitContext ec);
1945         }
1946
1947         public interface INamedBlockVariable
1948         {
1949                 Block Block { get; }
1950                 Expression CreateReferenceExpression (ResolveContext rc, Location loc);
1951                 bool IsDeclared { get; }
1952                 bool IsParameter { get; }
1953                 Location Location { get; }
1954         }
1955
1956         public class BlockVariableDeclarator
1957         {
1958                 LocalVariable li;
1959                 Expression initializer;
1960
1961                 public BlockVariableDeclarator (LocalVariable li, Expression initializer)
1962                 {
1963                         if (li.Type != null)
1964                                 throw new ArgumentException ("Expected null variable type");
1965
1966                         this.li = li;
1967                         this.initializer = initializer;
1968                 }
1969
1970                 #region Properties
1971
1972                 public LocalVariable Variable {
1973                         get {
1974                                 return li;
1975                         }
1976                 }
1977
1978                 public Expression Initializer {
1979                         get {
1980                                 return initializer;
1981                         }
1982                         set {
1983                                 initializer = value;
1984                         }
1985                 }
1986
1987                 #endregion
1988
1989                 public virtual BlockVariableDeclarator Clone (CloneContext cloneCtx)
1990                 {
1991                         var t = (BlockVariableDeclarator) MemberwiseClone ();
1992                         if (initializer != null)
1993                                 t.initializer = initializer.Clone (cloneCtx);
1994
1995                         return t;
1996                 }
1997         }
1998
1999         public class BlockVariable : Statement
2000         {
2001                 Expression initializer;
2002                 protected FullNamedExpression type_expr;
2003                 protected LocalVariable li;
2004                 protected List<BlockVariableDeclarator> declarators;
2005                 TypeSpec type;
2006
2007                 public BlockVariable (FullNamedExpression type, LocalVariable li)
2008                 {
2009                         this.type_expr = type;
2010                         this.li = li;
2011                         this.loc = type_expr.Location;
2012                 }
2013
2014                 protected BlockVariable (LocalVariable li)
2015                 {
2016                         this.li = li;
2017                 }
2018
2019                 #region Properties
2020
2021                 public List<BlockVariableDeclarator> Declarators {
2022                         get {
2023                                 return declarators;
2024                         }
2025                 }
2026
2027                 public Expression Initializer {
2028                         get {
2029                                 return initializer;
2030                         }
2031                         set {
2032                                 initializer = value;
2033                         }
2034                 }
2035
2036                 public FullNamedExpression TypeExpression {
2037                         get {
2038                                 return type_expr;
2039                         }
2040                 }
2041
2042                 public LocalVariable Variable {
2043                         get {
2044                                 return li;
2045                         }
2046                 }
2047
2048                 #endregion
2049
2050                 public void AddDeclarator (BlockVariableDeclarator decl)
2051                 {
2052                         if (declarators == null)
2053                                 declarators = new List<BlockVariableDeclarator> ();
2054
2055                         declarators.Add (decl);
2056                 }
2057
2058                 static void CreateEvaluatorVariable (BlockContext bc, LocalVariable li)
2059                 {
2060                         if (bc.Report.Errors != 0)
2061                                 return;
2062
2063                         var container = bc.CurrentMemberDefinition.Parent.PartialContainer;
2064
2065                         Field f = new Field (container, new TypeExpression (li.Type, li.Location), Modifiers.PUBLIC | Modifiers.STATIC,
2066                                 new MemberName (li.Name, li.Location), null);
2067
2068                         container.AddField (f);
2069                         f.Define ();
2070
2071                         li.HoistedVariant = new HoistedEvaluatorVariable (f);
2072                         li.SetIsUsed ();
2073                 }
2074
2075                 public override bool Resolve (BlockContext bc)
2076                 {
2077                         return Resolve (bc, true);
2078                 }
2079
2080                 public bool Resolve (BlockContext bc, bool resolveDeclaratorInitializers)
2081                 {
2082                         if (type == null && !li.IsCompilerGenerated) {
2083                                 var vexpr = type_expr as VarExpr;
2084
2085                                 //
2086                                 // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
2087                                 // same name exists or as a keyword when no type was found
2088                                 //
2089                                 if (vexpr != null && !vexpr.IsPossibleTypeOrNamespace (bc)) {
2090                                         if (bc.Module.Compiler.Settings.Version < LanguageVersion.V_3)
2091                                                 bc.Report.FeatureIsNotAvailable (bc.Module.Compiler, loc, "implicitly typed local variable");
2092
2093                                         if (li.IsFixed) {
2094                                                 bc.Report.Error (821, loc, "A fixed statement cannot use an implicitly typed local variable");
2095                                                 return false;
2096                                         }
2097
2098                                         if (li.IsConstant) {
2099                                                 bc.Report.Error (822, loc, "An implicitly typed local variable cannot be a constant");
2100                                                 return false;
2101                                         }
2102
2103                                         if (Initializer == null) {
2104                                                 bc.Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");
2105                                                 return false;
2106                                         }
2107
2108                                         if (declarators != null) {
2109                                                 bc.Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
2110                                                 declarators = null;
2111                                         }
2112
2113                                         Initializer = Initializer.Resolve (bc);
2114                                         if (Initializer != null) {
2115                                                 ((VarExpr) type_expr).InferType (bc, Initializer);
2116                                                 type = type_expr.Type;
2117                                         } else {
2118                                                 // Set error type to indicate the var was placed correctly but could
2119                                                 // not be infered
2120                                                 //
2121                                                 // var a = missing ();
2122                                                 //
2123                                                 type = InternalType.ErrorType;
2124                                         }
2125                                 }
2126
2127                                 if (type == null) {
2128                                         type = type_expr.ResolveAsType (bc);
2129                                         if (type == null)
2130                                                 return false;
2131
2132                                         if (li.IsConstant && !type.IsConstantCompatible) {
2133                                                 Const.Error_InvalidConstantType (type, loc, bc.Report);
2134                                         }
2135                                 }
2136
2137                                 if (type.IsStatic)
2138                                         FieldBase.Error_VariableOfStaticClass (loc, li.Name, type, bc.Report);
2139
2140                                 li.Type = type;
2141                         }
2142
2143                         bool eval_global = bc.Module.Compiler.Settings.StatementMode && bc.CurrentBlock is ToplevelBlock;
2144                         if (eval_global) {
2145                                 CreateEvaluatorVariable (bc, li);
2146                         } else if (type != InternalType.ErrorType) {
2147                                 li.PrepareAssignmentAnalysis (bc);
2148                         }
2149
2150                         if (initializer != null) {
2151                                 initializer = ResolveInitializer (bc, li, initializer);
2152                                 // li.Variable.DefinitelyAssigned 
2153                         }
2154
2155                         if (declarators != null) {
2156                                 foreach (var d in declarators) {
2157                                         d.Variable.Type = li.Type;
2158                                         if (eval_global) {
2159                                                 CreateEvaluatorVariable (bc, d.Variable);
2160                                         } else if (type != InternalType.ErrorType) {
2161                                                 d.Variable.PrepareAssignmentAnalysis (bc);
2162                                         }
2163
2164                                         if (d.Initializer != null && resolveDeclaratorInitializers) {
2165                                                 d.Initializer = ResolveInitializer (bc, d.Variable, d.Initializer);
2166                                                 // d.Variable.DefinitelyAssigned 
2167                                         } 
2168                                 }
2169                         }
2170
2171                         return true;
2172                 }
2173
2174                 protected virtual Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
2175                 {
2176                         var a = new SimpleAssign (li.CreateReferenceExpression (bc, li.Location), initializer, li.Location);
2177                         return a.ResolveStatement (bc);
2178                 }
2179
2180                 protected override void DoEmit (EmitContext ec)
2181                 {
2182                         li.CreateBuilder (ec);
2183
2184                         if (Initializer != null)
2185                                 ((ExpressionStatement) Initializer).EmitStatement (ec);
2186
2187                         if (declarators != null) {
2188                                 foreach (var d in declarators) {
2189                                         d.Variable.CreateBuilder (ec);
2190                                         if (d.Initializer != null) {
2191                                                 ec.Mark (d.Variable.Location);
2192                                                 ((ExpressionStatement) d.Initializer).EmitStatement (ec);
2193                                         }
2194                                 }
2195                         }
2196                 }
2197
2198                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
2199                 {
2200                         if (Initializer != null)
2201                                 Initializer.FlowAnalysis (fc);
2202
2203                         if (declarators != null) {
2204                                 foreach (var d in declarators) {
2205                                         if (d.Initializer != null)
2206                                                 d.Initializer.FlowAnalysis (fc);
2207                                 }
2208                         }
2209
2210                         return false;
2211                 }
2212
2213                 public override Reachability MarkReachable (Reachability rc)
2214                 {
2215                         var init = initializer as ExpressionStatement;
2216                         if (init != null)
2217                                 init.MarkReachable (rc);
2218
2219                         return base.MarkReachable (rc);
2220                 }
2221
2222                 protected override void CloneTo (CloneContext clonectx, Statement target)
2223                 {
2224                         BlockVariable t = (BlockVariable) target;
2225
2226                         if (type_expr != null)
2227                                 t.type_expr = (FullNamedExpression) type_expr.Clone (clonectx);
2228
2229                         if (initializer != null)
2230                                 t.initializer = initializer.Clone (clonectx);
2231
2232                         if (declarators != null) {
2233                                 t.declarators = null;
2234                                 foreach (var d in declarators)
2235                                         t.AddDeclarator (d.Clone (clonectx));
2236                         }
2237                 }
2238
2239                 public override object Accept (StructuralVisitor visitor)
2240                 {
2241                         return visitor.Visit (this);
2242                 }
2243         }
2244
2245         public class BlockConstant : BlockVariable
2246         {
2247                 public BlockConstant (FullNamedExpression type, LocalVariable li)
2248                         : base (type, li)
2249                 {
2250                 }
2251
2252                 public override void Emit (EmitContext ec)
2253                 {
2254                         // Nothing to emit, not even sequence point
2255                 }
2256
2257                 protected override Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
2258                 {
2259                         initializer = initializer.Resolve (bc);
2260                         if (initializer == null)
2261                                 return null;
2262
2263                         var c = initializer as Constant;
2264                         if (c == null) {
2265                                 initializer.Error_ExpressionMustBeConstant (bc, initializer.Location, li.Name);
2266                                 return null;
2267                         }
2268
2269                         c = c.ConvertImplicitly (li.Type);
2270                         if (c == null) {
2271                                 if (TypeSpec.IsReferenceType (li.Type))
2272                                         initializer.Error_ConstantCanBeInitializedWithNullOnly (bc, li.Type, initializer.Location, li.Name);
2273                                 else
2274                                         initializer.Error_ValueCannotBeConverted (bc, li.Type, false);
2275
2276                                 return null;
2277                         }
2278
2279                         li.ConstantValue = c;
2280                         return initializer;
2281                 }
2282                 
2283                 public override object Accept (StructuralVisitor visitor)
2284                 {
2285                         return visitor.Visit (this);
2286                 }
2287         }
2288
2289         //
2290         // The information about a user-perceived local variable
2291         //
2292         public sealed class LocalVariable : INamedBlockVariable, ILocalVariable
2293         {
2294                 [Flags]
2295                 public enum Flags
2296                 {
2297                         Used = 1,
2298                         IsThis = 1 << 1,
2299                         AddressTaken = 1 << 2,
2300                         CompilerGenerated = 1 << 3,
2301                         Constant = 1 << 4,
2302                         ForeachVariable = 1 << 5,
2303                         FixedVariable = 1 << 6,
2304                         UsingVariable = 1 << 7,
2305                         IsLocked = 1 << 8,
2306
2307                         ReadonlyMask = ForeachVariable | FixedVariable | UsingVariable
2308                 }
2309
2310                 TypeSpec type;
2311                 readonly string name;
2312                 readonly Location loc;
2313                 readonly Block block;
2314                 Flags flags;
2315                 Constant const_value;
2316
2317                 public VariableInfo VariableInfo;
2318                 HoistedVariable hoisted_variant;
2319
2320                 LocalBuilder builder;
2321
2322                 public LocalVariable (Block block, string name, Location loc)
2323                 {
2324                         this.block = block;
2325                         this.name = name;
2326                         this.loc = loc;
2327                 }
2328
2329                 public LocalVariable (Block block, string name, Flags flags, Location loc)
2330                         : this (block, name, loc)
2331                 {
2332                         this.flags = flags;
2333                 }
2334
2335                 //
2336                 // Used by variable declarators
2337                 //
2338                 public LocalVariable (LocalVariable li, string name, Location loc)
2339                         : this (li.block, name, li.flags, loc)
2340                 {
2341                 }
2342
2343                 #region Properties
2344
2345                 public bool AddressTaken {
2346                         get {
2347                                 return (flags & Flags.AddressTaken) != 0;
2348                         }
2349                 }
2350
2351                 public Block Block {
2352                         get {
2353                                 return block;
2354                         }
2355                 }
2356
2357                 public Constant ConstantValue {
2358                         get {
2359                                 return const_value;
2360                         }
2361                         set {
2362                                 const_value = value;
2363                         }
2364                 }
2365
2366                 //
2367                 // Hoisted local variable variant
2368                 //
2369                 public HoistedVariable HoistedVariant {
2370                         get {
2371                                 return hoisted_variant;
2372                         }
2373                         set {
2374                                 hoisted_variant = value;
2375                         }
2376                 }
2377
2378                 public bool IsDeclared {
2379                         get {
2380                                 return type != null;
2381                         }
2382                 }
2383
2384                 public bool IsCompilerGenerated {
2385                         get {
2386                                 return (flags & Flags.CompilerGenerated) != 0;
2387                         }
2388                 }
2389
2390                 public bool IsConstant {
2391                         get {
2392                                 return (flags & Flags.Constant) != 0;
2393                         }
2394                 }
2395
2396                 public bool IsLocked {
2397                         get {
2398                                 return (flags & Flags.IsLocked) != 0;
2399                         }
2400                         set {
2401                                 flags = value ? flags | Flags.IsLocked : flags & ~Flags.IsLocked;
2402                         }
2403                 }
2404
2405                 public bool IsThis {
2406                         get {
2407                                 return (flags & Flags.IsThis) != 0;
2408                         }
2409                 }
2410
2411                 public bool IsFixed {
2412                         get {
2413                                 return (flags & Flags.FixedVariable) != 0;
2414                         }
2415                 }
2416
2417                 bool INamedBlockVariable.IsParameter {
2418                         get {
2419                                 return false;
2420                         }
2421                 }
2422
2423                 public bool IsReadonly {
2424                         get {
2425                                 return (flags & Flags.ReadonlyMask) != 0;
2426                         }
2427                 }
2428
2429                 public Location Location {
2430                         get {
2431                                 return loc;
2432                         }
2433                 }
2434
2435                 public string Name {
2436                         get {
2437                                 return name;
2438                         }
2439                 }
2440
2441                 public TypeSpec Type {
2442                     get {
2443                                 return type;
2444                         }
2445                     set {
2446                                 type = value;
2447                         }
2448                 }
2449
2450                 #endregion
2451
2452                 public void CreateBuilder (EmitContext ec)
2453                 {
2454                         if ((flags & Flags.Used) == 0) {
2455                                 if (VariableInfo == null) {
2456                                         // Missing flow analysis or wrong variable flags
2457                                         throw new InternalErrorException ("VariableInfo is null and the variable `{0}' is not used", name);
2458                                 }
2459
2460                                 if (VariableInfo.IsEverAssigned)
2461                                         ec.Report.Warning (219, 3, Location, "The variable `{0}' is assigned but its value is never used", Name);
2462                                 else
2463                                         ec.Report.Warning (168, 3, Location, "The variable `{0}' is declared but never used", Name);
2464                         }
2465
2466                         if (HoistedVariant != null)
2467                                 return;
2468
2469                         if (builder != null) {
2470                                 if ((flags & Flags.CompilerGenerated) != 0)
2471                                         return;
2472
2473                                 // To avoid Used warning duplicates
2474                                 throw new InternalErrorException ("Already created variable `{0}'", name);
2475                         }
2476
2477                         //
2478                         // All fixed variabled are pinned, a slot has to be alocated
2479                         //
2480                         builder = ec.DeclareLocal (Type, IsFixed);
2481                         if (!ec.HasSet (BuilderContext.Options.OmitDebugInfo) && (flags & Flags.CompilerGenerated) == 0)
2482                                 ec.DefineLocalVariable (name, builder);
2483                 }
2484
2485                 public static LocalVariable CreateCompilerGenerated (TypeSpec type, Block block, Location loc)
2486                 {
2487                         LocalVariable li = new LocalVariable (block, GetCompilerGeneratedName (block), Flags.CompilerGenerated | Flags.Used, loc);
2488                         li.Type = type;
2489                         return li;
2490                 }
2491
2492                 public Expression CreateReferenceExpression (ResolveContext rc, Location loc)
2493                 {
2494                         if (IsConstant && const_value != null)
2495                                 return Constant.CreateConstantFromValue (Type, const_value.GetValue (), loc);
2496
2497                         return new LocalVariableReference (this, loc);
2498                 }
2499
2500                 public void Emit (EmitContext ec)
2501                 {
2502                         // TODO: Need something better for temporary variables
2503                         if ((flags & Flags.CompilerGenerated) != 0)
2504                                 CreateBuilder (ec);
2505
2506                         ec.Emit (OpCodes.Ldloc, builder);
2507                 }
2508
2509                 public void EmitAssign (EmitContext ec)
2510                 {
2511                         // TODO: Need something better for temporary variables
2512                         if ((flags & Flags.CompilerGenerated) != 0)
2513                                 CreateBuilder (ec);
2514
2515                         ec.Emit (OpCodes.Stloc, builder);
2516                 }
2517
2518                 public void EmitAddressOf (EmitContext ec)
2519                 {
2520                         ec.Emit (OpCodes.Ldloca, builder);
2521                 }
2522
2523                 public static string GetCompilerGeneratedName (Block block)
2524                 {
2525                         // HACK: Debugger depends on the name semantics
2526                         return "$locvar" + block.ParametersBlock.TemporaryLocalsCount++.ToString ("X");
2527                 }
2528
2529                 public string GetReadOnlyContext ()
2530                 {
2531                         switch (flags & Flags.ReadonlyMask) {
2532                         case Flags.FixedVariable:
2533                                 return "fixed variable";
2534                         case Flags.ForeachVariable:
2535                                 return "foreach iteration variable";
2536                         case Flags.UsingVariable:
2537                                 return "using variable";
2538                         }
2539
2540                         throw new InternalErrorException ("Variable is not readonly");
2541                 }
2542
2543                 public bool IsThisAssigned (FlowAnalysisContext fc, Block block)
2544                 {
2545                         if (VariableInfo == null)
2546                                 throw new Exception ();
2547
2548                         if (IsAssigned (fc))
2549                                 return true;
2550
2551                         return VariableInfo.IsFullyInitialized (fc, block.StartLocation);
2552                 }
2553
2554                 public bool IsAssigned (FlowAnalysisContext fc)
2555                 {
2556                         return fc.IsDefinitelyAssigned (VariableInfo);
2557                 }
2558
2559                 public void PrepareAssignmentAnalysis (BlockContext bc)
2560                 {
2561                         //
2562                         // No need to run assignment analysis for these guys
2563                         //
2564                         if ((flags & (Flags.Constant | Flags.ReadonlyMask | Flags.CompilerGenerated)) != 0)
2565                                 return;
2566
2567                         VariableInfo = VariableInfo.Create (bc, this);
2568                 }
2569
2570                 //
2571                 // Mark the variables as referenced in the user code
2572                 //
2573                 public void SetIsUsed ()
2574                 {
2575                         flags |= Flags.Used;
2576                 }
2577
2578                 public void SetHasAddressTaken ()
2579                 {
2580                         flags |= (Flags.AddressTaken | Flags.Used);
2581                 }
2582
2583                 public override string ToString ()
2584                 {
2585                         return string.Format ("LocalInfo ({0},{1},{2},{3})", name, type, VariableInfo, Location);
2586                 }
2587         }
2588
2589         /// <summary>
2590         ///   Block represents a C# block.
2591         /// </summary>
2592         ///
2593         /// <remarks>
2594         ///   This class is used in a number of places: either to represent
2595         ///   explicit blocks that the programmer places or implicit blocks.
2596         ///
2597         ///   Implicit blocks are used as labels or to introduce variable
2598         ///   declarations.
2599         ///
2600         ///   Top-level blocks derive from Block, and they are called ToplevelBlock
2601         ///   they contain extra information that is not necessary on normal blocks.
2602         /// </remarks>
2603         public class Block : Statement {
2604                 [Flags]
2605                 public enum Flags
2606                 {
2607                         Unchecked = 1,
2608                         ReachableEnd = 8,
2609                         Unsafe = 16,
2610                         HasCapturedVariable = 64,
2611                         HasCapturedThis = 1 << 7,
2612                         IsExpressionTree = 1 << 8,
2613                         CompilerGenerated = 1 << 9,
2614                         HasAsyncModifier = 1 << 10,
2615                         Resolved = 1 << 11,
2616                         YieldBlock = 1 << 12,
2617                         AwaitBlock = 1 << 13,
2618                         FinallyBlock = 1 << 14,
2619                         CatchBlock = 1 << 15,
2620                         Iterator = 1 << 20,
2621                         NoFlowAnalysis = 1 << 21
2622                 }
2623
2624                 public Block Parent;
2625                 public Location StartLocation;
2626                 public Location EndLocation;
2627
2628                 public ExplicitBlock Explicit;
2629                 public ParametersBlock ParametersBlock;
2630
2631                 protected Flags flags;
2632
2633                 //
2634                 // The statements in this block
2635                 //
2636                 protected List<Statement> statements;
2637
2638                 protected List<Statement> scope_initializers;
2639
2640                 int? resolving_init_idx;
2641
2642                 Block original;
2643
2644 #if DEBUG
2645                 static int id;
2646                 public int ID = id++;
2647
2648                 static int clone_id_counter;
2649                 int clone_id;
2650 #endif
2651
2652 //              int assignable_slots;
2653
2654                 public Block (Block parent, Location start, Location end)
2655                         : this (parent, 0, start, end)
2656                 {
2657                 }
2658
2659                 public Block (Block parent, Flags flags, Location start, Location end)
2660                 {
2661                         if (parent != null) {
2662                                 // the appropriate constructors will fixup these fields
2663                                 ParametersBlock = parent.ParametersBlock;
2664                                 Explicit = parent.Explicit;
2665                         }
2666                         
2667                         this.Parent = parent;
2668                         this.flags = flags;
2669                         this.StartLocation = start;
2670                         this.EndLocation = end;
2671                         this.loc = start;
2672                         statements = new List<Statement> (4);
2673
2674                         this.original = this;
2675                 }
2676
2677                 #region Properties
2678
2679                 public Block Original {
2680                         get {
2681                                 return original;
2682                         }
2683                         protected set {
2684                                 original = value;
2685                         }
2686                 }
2687
2688                 public bool IsCompilerGenerated {
2689                         get { return (flags & Flags.CompilerGenerated) != 0; }
2690                         set { flags = value ? flags | Flags.CompilerGenerated : flags & ~Flags.CompilerGenerated; }
2691                 }
2692
2693
2694                 public bool IsCatchBlock {
2695                         get {
2696                                 return (flags & Flags.CatchBlock) != 0;
2697                         }
2698                 }
2699
2700                 public bool IsFinallyBlock {
2701                         get {
2702                                 return (flags & Flags.FinallyBlock) != 0;
2703                         }
2704                 }
2705
2706                 public bool Unchecked {
2707                         get { return (flags & Flags.Unchecked) != 0; }
2708                         set { flags = value ? flags | Flags.Unchecked : flags & ~Flags.Unchecked; }
2709                 }
2710
2711                 public bool Unsafe {
2712                         get { return (flags & Flags.Unsafe) != 0; }
2713                         set { flags |= Flags.Unsafe; }
2714                 }
2715
2716                 public List<Statement> Statements {
2717                         get { return statements; }
2718                 }
2719
2720                 #endregion
2721
2722                 public void SetEndLocation (Location loc)
2723                 {
2724                         EndLocation = loc;
2725                 }
2726
2727                 public void AddLabel (LabeledStatement target)
2728                 {
2729                         ParametersBlock.TopBlock.AddLabel (target.Name, target);
2730                 }
2731
2732                 public void AddLocalName (LocalVariable li)
2733                 {
2734                         AddLocalName (li.Name, li);
2735                 }
2736
2737                 public void AddLocalName (string name, INamedBlockVariable li)
2738                 {
2739                         ParametersBlock.TopBlock.AddLocalName (name, li, false);
2740                 }
2741
2742                 public virtual void Error_AlreadyDeclared (string name, INamedBlockVariable variable, string reason)
2743                 {
2744                         if (reason == null) {
2745                                 Error_AlreadyDeclared (name, variable);
2746                                 return;
2747                         }
2748
2749                         ParametersBlock.TopBlock.Report.Error (136, variable.Location,
2750                                 "A local variable named `{0}' cannot be declared in this scope because it would give a different meaning " +
2751                                 "to `{0}', which is already used in a `{1}' scope to denote something else",
2752                                 name, reason);
2753                 }
2754
2755                 public virtual void Error_AlreadyDeclared (string name, INamedBlockVariable variable)
2756                 {
2757                         var pi = variable as ParametersBlock.ParameterInfo;
2758                         if (pi != null) {
2759                                 pi.Parameter.Error_DuplicateName (ParametersBlock.TopBlock.Report);
2760                         } else {
2761                                 ParametersBlock.TopBlock.Report.Error (128, variable.Location,
2762                                         "A local variable named `{0}' is already defined in this scope", name);
2763                         }
2764                 }
2765                                         
2766                 public virtual void Error_AlreadyDeclaredTypeParameter (string name, Location loc)
2767                 {
2768                         ParametersBlock.TopBlock.Report.Error (412, loc,
2769                                 "The type parameter name `{0}' is the same as local variable or parameter name",
2770                                 name);
2771                 }
2772
2773                 //
2774                 // It should be used by expressions which require to
2775                 // register a statement during resolve process.
2776                 //
2777                 public void AddScopeStatement (Statement s)
2778                 {
2779                         if (scope_initializers == null)
2780                                 scope_initializers = new List<Statement> ();
2781
2782                         //
2783                         // Simple recursive helper, when resolve scope initializer another
2784                         // new scope initializer can be added, this ensures it's initialized
2785                         // before existing one. For now this can happen with expression trees
2786                         // in base ctor initializer only
2787                         //
2788                         if (resolving_init_idx.HasValue) {
2789                                 scope_initializers.Insert (resolving_init_idx.Value, s);
2790                                 ++resolving_init_idx;
2791                         } else {
2792                                 scope_initializers.Add (s);
2793                         }
2794                 }
2795
2796                 public void InsertStatement (int index, Statement s)
2797                 {
2798                         statements.Insert (index, s);
2799                 }
2800                 
2801                 public void AddStatement (Statement s)
2802                 {
2803                         statements.Add (s);
2804                 }
2805
2806                 public LabeledStatement LookupLabel (string name)
2807                 {
2808                         return ParametersBlock.GetLabel (name, this);
2809                 }
2810
2811                 public override Reachability MarkReachable (Reachability rc)
2812                 {
2813                         if (rc.IsUnreachable)
2814                                 return rc;
2815
2816                         MarkReachableScope (rc);
2817
2818                         foreach (var s in statements) {
2819                                 rc = s.MarkReachable (rc);
2820                                 if (rc.IsUnreachable) {
2821                                         if ((flags & Flags.ReachableEnd) != 0)
2822                                                 return new Reachability ();
2823
2824                                         return rc;
2825                                 }
2826                         }
2827
2828                         flags |= Flags.ReachableEnd;
2829
2830                         return rc;
2831                 }
2832
2833                 public void MarkReachableScope (Reachability rc)
2834                 {
2835                         base.MarkReachable (rc);
2836
2837                         if (scope_initializers != null) {
2838                                 foreach (var si in scope_initializers)
2839                                         si.MarkReachable (rc);
2840                         }
2841                 }
2842
2843                 public override bool Resolve (BlockContext bc)
2844                 {
2845                         if ((flags & Flags.Resolved) != 0)
2846                                 return true;
2847
2848                         Block prev_block = bc.CurrentBlock;
2849                         bc.CurrentBlock = this;
2850
2851                         //
2852                         // Compiler generated scope statements
2853                         //
2854                         if (scope_initializers != null) {
2855                                 for (resolving_init_idx = 0; resolving_init_idx < scope_initializers.Count; ++resolving_init_idx) {
2856                                         scope_initializers[resolving_init_idx.Value].Resolve (bc);
2857                                 }
2858
2859                                 resolving_init_idx = null;
2860                         }
2861
2862                         bool ok = true;
2863                         int statement_count = statements.Count;
2864                         for (int ix = 0; ix < statement_count; ix++){
2865                                 Statement s = statements [ix];
2866
2867                                 if (!s.Resolve (bc)) {
2868                                         ok = false;
2869                                         if (!bc.IsInProbingMode)
2870                                                 statements [ix] = new EmptyStatement (s.loc);
2871
2872                                         continue;
2873                                 }
2874                         }
2875
2876                         bc.CurrentBlock = prev_block;
2877
2878                         flags |= Flags.Resolved;
2879                         return ok;
2880                 }
2881
2882                 protected override void DoEmit (EmitContext ec)
2883                 {
2884                         for (int ix = 0; ix < statements.Count; ix++){
2885                                 statements [ix].Emit (ec);
2886                         }
2887                 }
2888
2889                 public override void Emit (EmitContext ec)
2890                 {
2891                         if (scope_initializers != null)
2892                                 EmitScopeInitializers (ec);
2893
2894                         DoEmit (ec);
2895                 }
2896
2897                 protected void EmitScopeInitializers (EmitContext ec)
2898                 {
2899                         foreach (Statement s in scope_initializers)
2900                                 s.Emit (ec);
2901                 }
2902
2903                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
2904                 {
2905                         if (scope_initializers != null) {
2906                                 foreach (var si in scope_initializers)
2907                                         si.FlowAnalysis (fc);
2908                         }
2909
2910                         return DoFlowAnalysis (fc, 0);  
2911                 }
2912
2913                 bool DoFlowAnalysis (FlowAnalysisContext fc, int startIndex)
2914                 {
2915                         bool end_unreachable = !reachable;
2916                         for (; startIndex < statements.Count; ++startIndex) {
2917                                 var s = statements[startIndex];
2918
2919                                 end_unreachable = s.FlowAnalysis (fc);
2920                                 if (s.IsUnreachable) {
2921                                         statements[startIndex] = new EmptyStatement (s.loc);
2922                                         continue;
2923                                 }
2924
2925                                 //
2926                                 // Statement end reachability is needed mostly due to goto support. Consider
2927                                 //
2928                                 // if (cond) {
2929                                 //    goto X;
2930                                 // } else {
2931                                 //    goto Y;
2932                                 // }
2933                                 // X:
2934                                 //
2935                                 // X label is reachable only via goto not as another statement after if. We need
2936                                 // this for flow-analysis only to carry variable info correctly.
2937                                 //
2938                                 if (end_unreachable) {
2939                                         for (++startIndex; startIndex < statements.Count; ++startIndex) {
2940                                                 s = statements[startIndex];
2941                                                 if (s is SwitchLabel) {
2942                                                         s.FlowAnalysis (fc);
2943                                                         break;
2944                                                 }
2945
2946                                                 if (s.IsUnreachable) {
2947                                                         s.FlowAnalysis (fc);
2948                                                         statements[startIndex] = new EmptyStatement (s.loc);
2949                                                 }
2950                                         }
2951                                 }
2952                         }
2953
2954                         //
2955                         // The condition should be true unless there is forward jumping goto
2956                         // 
2957                         // if (this is ExplicitBlock && end_unreachable != Explicit.HasReachableClosingBrace)
2958                         //      Debug.Fail ();
2959
2960                         return !Explicit.HasReachableClosingBrace;
2961                 }
2962
2963                 public void ScanGotoJump (Statement label)
2964                 {
2965                         int i;
2966                         for (i = 0; i < statements.Count; ++i) {
2967                                 if (statements[i] == label)
2968                                         break;
2969                         }
2970
2971                         var rc = new Reachability ();
2972                         for (++i; i < statements.Count; ++i) {
2973                                 var s = statements[i];
2974                                 rc = s.MarkReachable (rc);
2975                                 if (rc.IsUnreachable)
2976                                         return;
2977                         }
2978
2979                         flags |= Flags.ReachableEnd;
2980                 }
2981
2982                 public void ScanGotoJump (Statement label, FlowAnalysisContext fc)
2983                 {
2984                         int i;
2985                         for (i = 0; i < statements.Count; ++i) {
2986                                 if (statements[i] == label)
2987                                         break;
2988                         }
2989
2990                         DoFlowAnalysis (fc, ++i);
2991                 }
2992
2993 #if DEBUG
2994                 public override string ToString ()
2995                 {
2996                         return String.Format ("{0}: ID={1} Clone={2} Location={3}", GetType (), ID, clone_id != 0, StartLocation);
2997                 }
2998 #endif
2999
3000                 protected override void CloneTo (CloneContext clonectx, Statement t)
3001                 {
3002                         Block target = (Block) t;
3003 #if DEBUG
3004                         target.clone_id = ++clone_id_counter;
3005 #endif
3006
3007                         clonectx.AddBlockMap (this, target);
3008                         if (original != this)
3009                                 clonectx.AddBlockMap (original, target);
3010
3011                         target.ParametersBlock = (ParametersBlock) (ParametersBlock == this ? target : clonectx.RemapBlockCopy (ParametersBlock));
3012                         target.Explicit = (ExplicitBlock) (Explicit == this ? target : clonectx.LookupBlock (Explicit));
3013
3014                         if (Parent != null)
3015                                 target.Parent = clonectx.RemapBlockCopy (Parent);
3016
3017                         target.statements = new List<Statement> (statements.Count);
3018                         foreach (Statement s in statements)
3019                                 target.statements.Add (s.Clone (clonectx));
3020                 }
3021
3022                 public override object Accept (StructuralVisitor visitor)
3023                 {
3024                         return visitor.Visit (this);
3025                 }
3026         }
3027
3028         public class ExplicitBlock : Block
3029         {
3030                 protected AnonymousMethodStorey am_storey;
3031
3032                 public ExplicitBlock (Block parent, Location start, Location end)
3033                         : this (parent, (Flags) 0, start, end)
3034                 {
3035                 }
3036
3037                 public ExplicitBlock (Block parent, Flags flags, Location start, Location end)
3038                         : base (parent, flags, start, end)
3039                 {
3040                         this.Explicit = this;
3041                 }
3042
3043                 #region Properties
3044
3045                 public AnonymousMethodStorey AnonymousMethodStorey {
3046                         get {
3047                                 return am_storey;
3048                         }
3049                 }
3050
3051                 public bool HasAwait {
3052                         get {
3053                                 return (flags & Flags.AwaitBlock) != 0;
3054                         }
3055                 }
3056
3057                 public bool HasCapturedThis {
3058                         set {
3059                                 flags = value ? flags | Flags.HasCapturedThis : flags & ~Flags.HasCapturedThis;
3060                         }
3061                         get {
3062                                 return (flags & Flags.HasCapturedThis) != 0;
3063                         }
3064                 }
3065
3066                 //
3067                 // Used to indicate that the block has reference to parent
3068                 // block and cannot be made static when defining anonymous method
3069                 //
3070                 public bool HasCapturedVariable {
3071                         set {
3072                                 flags = value ? flags | Flags.HasCapturedVariable : flags & ~Flags.HasCapturedVariable;
3073                         }
3074                         get {
3075                                 return (flags & Flags.HasCapturedVariable) != 0;
3076                         }
3077                 }
3078
3079                 public bool HasReachableClosingBrace {
3080                     get {
3081                         return (flags & Flags.ReachableEnd) != 0;
3082                     }
3083                         set {
3084                                 flags = value ? flags | Flags.ReachableEnd : flags & ~Flags.ReachableEnd;
3085                         }
3086                 }
3087
3088                 public bool HasYield {
3089                         get {
3090                                 return (flags & Flags.YieldBlock) != 0;
3091                         }
3092                 }
3093
3094                 #endregion
3095
3096                 //
3097                 // Creates anonymous method storey in current block
3098                 //
3099                 public AnonymousMethodStorey CreateAnonymousMethodStorey (ResolveContext ec)
3100                 {
3101                         //
3102                         // Return same story for iterator and async blocks unless we are
3103                         // in nested anonymous method
3104                         //
3105                         if (ec.CurrentAnonymousMethod is StateMachineInitializer && ParametersBlock.Original == ec.CurrentAnonymousMethod.Block.Original)
3106                                 return ec.CurrentAnonymousMethod.Storey;
3107
3108                         if (am_storey == null) {
3109                                 MemberBase mc = ec.MemberContext as MemberBase;
3110
3111                                 //
3112                                 // Creates anonymous method storey for this block
3113                                 //
3114                                 am_storey = new AnonymousMethodStorey (this, ec.CurrentMemberDefinition.Parent.PartialContainer, mc, ec.CurrentTypeParameters, "AnonStorey", MemberKind.Class);
3115                         }
3116
3117                         return am_storey;
3118                 }
3119
3120                 public override void Emit (EmitContext ec)
3121                 {
3122                         if (am_storey != null) {
3123                                 DefineStoreyContainer (ec, am_storey);
3124                                 am_storey.EmitStoreyInstantiation (ec, this);
3125                         }
3126
3127                         if (scope_initializers != null)
3128                                 EmitScopeInitializers (ec);
3129
3130                         if (ec.EmitAccurateDebugInfo && !IsCompilerGenerated && ec.Mark (StartLocation)) {
3131                                 ec.Emit (OpCodes.Nop);
3132                         }
3133
3134                         if (Parent != null)
3135                                 ec.BeginScope ();
3136
3137                         DoEmit (ec);
3138
3139                         if (Parent != null)
3140                                 ec.EndScope ();
3141
3142                         if (ec.EmitAccurateDebugInfo && HasReachableClosingBrace && !(this is ParametersBlock) &&
3143                                 !IsCompilerGenerated && ec.Mark (EndLocation)) {
3144                                 ec.Emit (OpCodes.Nop);
3145                         }
3146                 }
3147
3148                 protected void DefineStoreyContainer (EmitContext ec, AnonymousMethodStorey storey)
3149                 {
3150                         if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.Storey != null) {
3151                                 storey.SetNestedStoryParent (ec.CurrentAnonymousMethod.Storey);
3152                                 storey.Mutator = ec.CurrentAnonymousMethod.Storey.Mutator;
3153                         }
3154
3155                         //
3156                         // Creates anonymous method storey
3157                         //
3158                         storey.CreateContainer ();
3159                         storey.DefineContainer ();
3160
3161                         if (Original.Explicit.HasCapturedThis && Original.ParametersBlock.TopBlock.ThisReferencesFromChildrenBlock != null) {
3162
3163                                 //
3164                                 // Only first storey in path will hold this reference. All children blocks will
3165                                 // reference it indirectly using $ref field
3166                                 //
3167                                 for (Block b = Original.Explicit; b != null; b = b.Parent) {
3168                                         if (b.Parent != null) {
3169                                                 var s = b.Parent.Explicit.AnonymousMethodStorey;
3170                                                 if (s != null) {
3171                                                         storey.HoistedThis = s.HoistedThis;
3172                                                         break;
3173                                                 }
3174                                         }
3175
3176                                         if (b.Explicit == b.Explicit.ParametersBlock && b.Explicit.ParametersBlock.StateMachine != null) {
3177                                                 if (storey.HoistedThis == null)
3178                                                         storey.HoistedThis = b.Explicit.ParametersBlock.StateMachine.HoistedThis;
3179
3180                                                 if (storey.HoistedThis != null)
3181                                                         break;
3182                                         }
3183                                 }
3184                                 
3185                                 //
3186                                 // We are the first storey on path and 'this' has to be hoisted
3187                                 //
3188                                 if (storey.HoistedThis == null) {
3189                                         foreach (ExplicitBlock ref_block in Original.ParametersBlock.TopBlock.ThisReferencesFromChildrenBlock) {
3190                                                 //
3191                                                 // ThisReferencesFromChildrenBlock holds all reference even if they
3192                                                 // are not on this path. It saves some memory otherwise it'd have to
3193                                                 // be in every explicit block. We run this check to see if the reference
3194                                                 // is valid for this storey
3195                                                 //
3196                                                 Block block_on_path = ref_block;
3197                                                 for (; block_on_path != null && block_on_path != Original; block_on_path = block_on_path.Parent);
3198
3199                                                 if (block_on_path == null)
3200                                                         continue;
3201
3202                                                 if (storey.HoistedThis == null) {
3203                                                         storey.AddCapturedThisField (ec, null);
3204                                                 }
3205
3206                                                 for (ExplicitBlock b = ref_block; b.AnonymousMethodStorey != storey; b = b.Parent.Explicit) {
3207                                                         ParametersBlock pb;
3208                                                         AnonymousMethodStorey b_storey = b.AnonymousMethodStorey;
3209
3210                                                         if (b_storey != null) {
3211                                                                 //
3212                                                                 // Don't add storey cross reference for `this' when the storey ends up not
3213                                                                 // beeing attached to any parent
3214                                                                 //
3215                                                                 if (b.ParametersBlock.StateMachine == null) {
3216                                                                         AnonymousMethodStorey s = null;
3217                                                                         for (Block ab = b.AnonymousMethodStorey.OriginalSourceBlock.Parent; ab != null; ab = ab.Parent) {
3218                                                                                 s = ab.Explicit.AnonymousMethodStorey;
3219                                                                                 if (s != null)
3220                                                                                         break;
3221                                                                         }
3222
3223                                                                         // Needs to be in sync with AnonymousMethodBody::DoCreateMethodHost
3224                                                                         if (s == null) {
3225                                                                                 var parent = storey == null || storey.Kind == MemberKind.Struct ? null : storey;
3226                                                                                 b.AnonymousMethodStorey.AddCapturedThisField (ec, parent);
3227                                                                                 break;
3228                                                                         }
3229
3230                                                                 }
3231
3232                                                                 //
3233                                                                 // Stop propagation inside same top block
3234                                                                 //
3235                                                                 if (b.ParametersBlock == ParametersBlock.Original) {
3236                                                                         b_storey.AddParentStoreyReference (ec, storey);
3237 //                                                                      b_storey.HoistedThis = storey.HoistedThis;
3238                                                                         break;
3239                                                                 }
3240
3241                                                                 b = pb = b.ParametersBlock;
3242                                                         } else {
3243                                                                 pb = b as ParametersBlock;
3244                                                         }
3245
3246                                                         if (pb != null && pb.StateMachine != null) {
3247                                                                 if (pb.StateMachine == storey)
3248                                                                         break;
3249
3250                                                                 //
3251                                                                 // If we are state machine with no parent. We can hook into parent without additional
3252                                                                 // reference and capture this directly
3253                                                                 //
3254                                                                 ExplicitBlock parent_storey_block = pb;
3255                                                                 while (parent_storey_block.Parent != null) {
3256                                                                         parent_storey_block = parent_storey_block.Parent.Explicit;
3257                                                                         if (parent_storey_block.AnonymousMethodStorey != null) {
3258                                                                                 break;
3259                                                                         }
3260                                                                 }
3261
3262                                                                 if (parent_storey_block.AnonymousMethodStorey == null) {
3263                                                                         pb.StateMachine.AddCapturedThisField (ec, null);
3264                                                                         b.HasCapturedThis = true;
3265                                                                         continue;
3266                                                                 }
3267
3268                                                                 pb.StateMachine.AddParentStoreyReference (ec, storey);
3269                                                         }
3270
3271                                                         //
3272                                                         // Add parent storey reference only when this is not captured directly
3273                                                         //
3274                                                         if (b_storey != null) {
3275                                                                 b_storey.AddParentStoreyReference (ec, storey);
3276                                                                 b_storey.HoistedThis = storey.HoistedThis;
3277                                                         }
3278                                                 }
3279                                         }
3280                                 }
3281                         }
3282
3283                         var ref_blocks = storey.ReferencesFromChildrenBlock;
3284                         if (ref_blocks != null) {
3285                                 foreach (ExplicitBlock ref_block in ref_blocks) {
3286                                         for (ExplicitBlock b = ref_block; b.AnonymousMethodStorey != storey; b = b.Parent.Explicit) {
3287                                                 if (b.AnonymousMethodStorey != null) {
3288                                                         b.AnonymousMethodStorey.AddParentStoreyReference (ec, storey);
3289
3290                                                         //
3291                                                         // Stop propagation inside same top block
3292                                                         //
3293                                                         if (b.ParametersBlock == ParametersBlock.Original)
3294                                                                 break;
3295
3296                                                         b = b.ParametersBlock;
3297                                                 }
3298
3299                                                 var pb = b as ParametersBlock;
3300                                                 if (pb != null && pb.StateMachine != null) {
3301                                                         if (pb.StateMachine == storey)
3302                                                                 break;
3303
3304                                                         pb.StateMachine.AddParentStoreyReference (ec, storey);
3305                                                 }
3306
3307                                                 b.HasCapturedVariable = true;
3308                                         }
3309                                 }
3310                         }
3311
3312                         storey.Define ();
3313                         storey.PrepareEmit ();
3314                         storey.Parent.PartialContainer.AddCompilerGeneratedClass (storey);
3315                 }
3316
3317                 public void RegisterAsyncAwait ()
3318                 {
3319                         var block = this;
3320                         while ((block.flags & Flags.AwaitBlock) == 0) {
3321                                 block.flags |= Flags.AwaitBlock;
3322
3323                                 if (block is ParametersBlock)
3324                                         return;
3325
3326                                 block = block.Parent.Explicit;
3327                         }
3328                 }
3329
3330                 public void RegisterIteratorYield ()
3331                 {
3332                         ParametersBlock.TopBlock.IsIterator = true;
3333
3334                         var block = this;
3335                         while ((block.flags & Flags.YieldBlock) == 0) {
3336                                 block.flags |= Flags.YieldBlock;
3337
3338                                 if (block.Parent == null)
3339                                         return;
3340
3341                                 block = block.Parent.Explicit;
3342                         }
3343                 }
3344
3345                 public void SetCatchBlock ()
3346                 {
3347                         flags |= Flags.CatchBlock;
3348                 }
3349
3350                 public void SetFinallyBlock ()
3351                 {
3352                         flags |= Flags.FinallyBlock;
3353                 }
3354
3355                 public void WrapIntoDestructor (TryFinally tf, ExplicitBlock tryBlock)
3356                 {
3357                         tryBlock.statements = statements;
3358                         statements = new List<Statement> (1);
3359                         statements.Add (tf);
3360                 }
3361         }
3362
3363         //
3364         // ParametersBlock was introduced to support anonymous methods
3365         // and lambda expressions
3366         // 
3367         public class ParametersBlock : ExplicitBlock
3368         {
3369                 public class ParameterInfo : INamedBlockVariable
3370                 {
3371                         readonly ParametersBlock block;
3372                         readonly int index;
3373                         public VariableInfo VariableInfo;
3374                         bool is_locked;
3375
3376                         public ParameterInfo (ParametersBlock block, int index)
3377                         {
3378                                 this.block = block;
3379                                 this.index = index;
3380                         }
3381
3382                         #region Properties
3383
3384                         public ParametersBlock Block {
3385                                 get {
3386                                         return block;
3387                                 }
3388                         }
3389
3390                         Block INamedBlockVariable.Block {
3391                                 get {
3392                                         return block;
3393                                 }
3394                         }
3395
3396                         public bool IsDeclared {
3397                                 get {
3398                                         return true;
3399                                 }
3400                         }
3401
3402                         public bool IsParameter {
3403                                 get {
3404                                         return true;
3405                                 }
3406                         }
3407
3408                         public bool IsLocked {
3409                                 get {
3410                                         return is_locked;
3411                                 }
3412                                 set {
3413                                         is_locked = value;
3414                                 }
3415                         }
3416
3417                         public Location Location {
3418                                 get {
3419                                         return Parameter.Location;
3420                                 }
3421                         }
3422
3423                         public Parameter Parameter {
3424                                 get {
3425                                         return block.Parameters [index];
3426                                 }
3427                         }
3428
3429                         public TypeSpec ParameterType {
3430                                 get {
3431                                         return Parameter.Type;
3432                                 }
3433                         }
3434
3435                         #endregion
3436
3437                         public Expression CreateReferenceExpression (ResolveContext rc, Location loc)
3438                         {
3439                                 return new ParameterReference (this, loc);
3440                         }
3441                 }
3442
3443                 // 
3444                 // Block is converted into an expression
3445                 //
3446                 sealed class BlockScopeExpression : Expression
3447                 {
3448                         Expression child;
3449                         readonly ParametersBlock block;
3450
3451                         public BlockScopeExpression (Expression child, ParametersBlock block)
3452                         {
3453                                 this.child = child;
3454                                 this.block = block;
3455                         }
3456
3457                         public override bool ContainsEmitWithAwait ()
3458                         {
3459                                 return child.ContainsEmitWithAwait ();
3460                         }
3461
3462                         public override Expression CreateExpressionTree (ResolveContext ec)
3463                         {
3464                                 throw new NotSupportedException ();
3465                         }
3466
3467                         protected override Expression DoResolve (ResolveContext ec)
3468                         {
3469                                 if (child == null)
3470                                         return null;
3471
3472                                 child = child.Resolve (ec);
3473                                 if (child == null)
3474                                         return null;
3475
3476                                 eclass = child.eclass;
3477                                 type = child.Type;
3478                                 return this;
3479                         }
3480
3481                         public override void Emit (EmitContext ec)
3482                         {
3483                                 block.EmitScopeInitializers (ec);
3484                                 child.Emit (ec);
3485                         }
3486                 }
3487
3488                 protected ParametersCompiled parameters;
3489                 protected ParameterInfo[] parameter_info;
3490                 protected bool resolved;
3491                 protected ToplevelBlock top_block;
3492                 protected StateMachine state_machine;
3493                 protected Dictionary<string, object> labels;
3494
3495                 public ParametersBlock (Block parent, ParametersCompiled parameters, Location start, Flags flags = 0)
3496                         : base (parent, 0, start, start)
3497                 {
3498                         if (parameters == null)
3499                                 throw new ArgumentNullException ("parameters");
3500
3501                         this.parameters = parameters;
3502                         ParametersBlock = this;
3503
3504                         this.flags |= flags | (parent.ParametersBlock.flags & (Flags.YieldBlock | Flags.AwaitBlock));
3505
3506                         this.top_block = parent.ParametersBlock.top_block;
3507                         ProcessParameters ();
3508                 }
3509
3510                 protected ParametersBlock (ParametersCompiled parameters, Location start)
3511                         : base (null, 0, start, start)
3512                 {
3513                         if (parameters == null)
3514                                 throw new ArgumentNullException ("parameters");
3515
3516                         this.parameters = parameters;
3517                         ParametersBlock = this;
3518                 }
3519
3520                 //
3521                 // It's supposed to be used by method body implementation of anonymous methods
3522                 //
3523                 protected ParametersBlock (ParametersBlock source, ParametersCompiled parameters)
3524                         : base (null, 0, source.StartLocation, source.EndLocation)
3525                 {
3526                         this.parameters = parameters;
3527                         this.statements = source.statements;
3528                         this.scope_initializers = source.scope_initializers;
3529
3530                         this.resolved = true;
3531                         this.reachable = source.reachable;
3532                         this.am_storey = source.am_storey;
3533                         this.state_machine = source.state_machine;
3534                         this.flags = source.flags & Flags.ReachableEnd;
3535
3536                         ParametersBlock = this;
3537
3538                         //
3539                         // Overwrite original for comparison purposes when linking cross references
3540                         // between anonymous methods
3541                         //
3542                         Original = source.Original;
3543                 }
3544
3545                 #region Properties
3546
3547                 public bool IsAsync {
3548                         get {
3549                                 return (flags & Flags.HasAsyncModifier) != 0;
3550                         }
3551                         set {
3552                                 flags = value ? flags | Flags.HasAsyncModifier : flags & ~Flags.HasAsyncModifier;
3553                         }
3554                 }
3555
3556                 //
3557                 // Block has been converted to expression tree
3558                 //
3559                 public bool IsExpressionTree {
3560                         get {
3561                                 return (flags & Flags.IsExpressionTree) != 0;
3562                         }
3563                 }
3564
3565                 //
3566                 // The parameters for the block.
3567                 //
3568                 public ParametersCompiled Parameters {
3569                         get {
3570                                 return parameters;
3571                         }
3572                 }
3573
3574                 public StateMachine StateMachine {
3575                         get {
3576                                 return state_machine;
3577                         }
3578                 }
3579
3580                 public ToplevelBlock TopBlock {
3581                         get {
3582                                 return top_block;
3583                         }
3584                 }
3585
3586                 public bool Resolved {
3587                         get {
3588                                 return (flags & Flags.Resolved) != 0;
3589                         }
3590                 }
3591
3592                 public int TemporaryLocalsCount { get; set; }
3593
3594                 #endregion
3595
3596                 //
3597                 // Checks whether all `out' parameters have been assigned.
3598                 //
3599                 public void CheckControlExit (FlowAnalysisContext fc)
3600                 {
3601                         CheckControlExit (fc, fc.DefiniteAssignment);
3602                 }
3603
3604                 public virtual void CheckControlExit (FlowAnalysisContext fc, DefiniteAssignmentBitSet dat)
3605                 {
3606                         if (parameter_info == null)
3607                                 return;
3608
3609                         foreach (var p in parameter_info) {
3610                                 if (p.VariableInfo == null)
3611                                         continue;
3612
3613                                 if (p.VariableInfo.IsAssigned (dat))
3614                                         continue;
3615
3616                                 fc.Report.Error (177, p.Location,
3617                                         "The out parameter `{0}' must be assigned to before control leaves the current method",
3618                                         p.Parameter.Name);
3619                         }                                       
3620                 }
3621
3622                 protected override void CloneTo (CloneContext clonectx, Statement t)
3623                 {
3624                         base.CloneTo (clonectx, t);
3625
3626                         var target = (ParametersBlock) t;
3627
3628                         //
3629                         // Clone label statements as well as they contain block reference
3630                         //
3631                         var pb = this;
3632                         while (true) {
3633                                 if (pb.labels != null) {
3634                                         target.labels = new Dictionary<string, object> ();
3635
3636                                         foreach (var entry in pb.labels) {
3637                                                 var list = entry.Value as List<LabeledStatement>;
3638
3639                                                 if (list != null) {
3640                                                         var list_clone = new List<LabeledStatement> ();
3641                                                         foreach (var lentry in list) {
3642                                                                 list_clone.Add (RemapLabeledStatement (lentry, lentry.Block, clonectx.RemapBlockCopy (lentry.Block)));
3643                                                         }
3644
3645                                                         target.labels.Add (entry.Key, list_clone);
3646                                                 } else {
3647                                                         var labeled = (LabeledStatement) entry.Value;
3648                                                         target.labels.Add (entry.Key, RemapLabeledStatement (labeled, labeled.Block, clonectx.RemapBlockCopy (labeled.Block)));
3649                                                 }
3650                                         }
3651
3652                                         break;
3653                                 }
3654
3655                                 if (pb.Parent == null)
3656                                         break;
3657
3658                                 pb = pb.Parent.ParametersBlock;
3659                         }
3660                 }
3661
3662                 public override Expression CreateExpressionTree (ResolveContext ec)
3663                 {
3664                         if (statements.Count == 1) {
3665                                 Expression expr = statements[0].CreateExpressionTree (ec);
3666                                 if (scope_initializers != null)
3667                                         expr = new BlockScopeExpression (expr, this);
3668
3669                                 return expr;
3670                         }
3671
3672                         return base.CreateExpressionTree (ec);
3673                 }
3674
3675                 public override void Emit (EmitContext ec)
3676                 {
3677                         if (state_machine != null && state_machine.OriginalSourceBlock != this) {
3678                                 DefineStoreyContainer (ec, state_machine);
3679                                 state_machine.EmitStoreyInstantiation (ec, this);
3680                         }
3681
3682                         base.Emit (ec);
3683                 }
3684
3685                 public void EmitEmbedded (EmitContext ec)
3686                 {
3687                         if (state_machine != null && state_machine.OriginalSourceBlock != this) {
3688                                 DefineStoreyContainer (ec, state_machine);
3689                                 state_machine.EmitStoreyInstantiation (ec, this);
3690                         }
3691
3692                         base.Emit (ec);
3693                 }
3694
3695                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
3696                 {
3697                         var res = base.DoFlowAnalysis (fc);
3698
3699                         if (HasReachableClosingBrace)
3700                                 CheckControlExit (fc);
3701
3702                         return res;
3703                 }
3704
3705                 public LabeledStatement GetLabel (string name, Block block)
3706                 {
3707                         //
3708                         // Cloned parameters blocks can have their own cloned version of top-level labels
3709                         //
3710                         if (labels == null) {
3711                                 if (Parent != null)
3712                                         return Parent.ParametersBlock.GetLabel (name, block);
3713
3714                                 return null;
3715                         }
3716
3717                         object value;
3718                         if (!labels.TryGetValue (name, out value)) {
3719                                 return null;
3720                         }
3721
3722                         var label = value as LabeledStatement;
3723                         Block b = block;
3724                         if (label != null) {
3725                                 if (IsLabelVisible (label, b))
3726                                         return label;
3727
3728                         } else {
3729                                 List<LabeledStatement> list = (List<LabeledStatement>) value;
3730                                 for (int i = 0; i < list.Count; ++i) {
3731                                         label = list[i];
3732                                         if (IsLabelVisible (label, b))
3733                                                 return label;
3734                                 }
3735                         }
3736
3737                         return null;
3738                 }
3739
3740                 static bool IsLabelVisible (LabeledStatement label, Block b)
3741                 {
3742                         do {
3743                                 if (label.Block == b)
3744                                         return true;
3745                                 b = b.Parent;
3746                         } while (b != null);
3747
3748                         return false;
3749                 }
3750
3751                 public ParameterInfo GetParameterInfo (Parameter p)
3752                 {
3753                         for (int i = 0; i < parameters.Count; ++i) {
3754                                 if (parameters[i] == p)
3755                                         return parameter_info[i];
3756                         }
3757
3758                         throw new ArgumentException ("Invalid parameter");
3759                 }
3760
3761                 public ParameterReference GetParameterReference (int index, Location loc)
3762                 {
3763                         return new ParameterReference (parameter_info[index], loc);
3764                 }
3765
3766                 public Statement PerformClone ()
3767                 {
3768                         CloneContext clonectx = new CloneContext ();
3769                         return Clone (clonectx);
3770                 }
3771
3772                 protected void ProcessParameters ()
3773                 {
3774                         if (parameters.Count == 0)
3775                                 return;
3776
3777                         parameter_info = new ParameterInfo[parameters.Count];
3778                         for (int i = 0; i < parameter_info.Length; ++i) {
3779                                 var p = parameters.FixedParameters[i];
3780                                 if (p == null)
3781                                         continue;
3782
3783                                 // TODO: Should use Parameter only and more block there
3784                                 parameter_info[i] = new ParameterInfo (this, i);
3785                                 if (p.Name != null)
3786                                         AddLocalName (p.Name, parameter_info[i]);
3787                         }
3788                 }
3789
3790                 static LabeledStatement RemapLabeledStatement (LabeledStatement stmt, Block src, Block dst)
3791                 {
3792                         var src_stmts = src.Statements;
3793                         for (int i = 0; i < src_stmts.Count; ++i) {
3794                                 if (src_stmts[i] == stmt)
3795                                         return (LabeledStatement) dst.Statements[i];
3796                         }
3797
3798                         throw new InternalErrorException ("Should never be reached");
3799                 }
3800
3801                 public override bool Resolve (BlockContext bc)
3802                 {
3803                         // TODO: if ((flags & Flags.Resolved) != 0)
3804
3805                         if (resolved)
3806                                 return true;
3807
3808                         resolved = true;
3809
3810                         if (bc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
3811                                 flags |= Flags.IsExpressionTree;
3812
3813                         try {
3814                                 PrepareAssignmentAnalysis (bc);
3815
3816                                 if (!base.Resolve (bc))
3817                                         return false;
3818
3819                         } catch (Exception e) {
3820                                 if (e is CompletionResult || bc.Report.IsDisabled || e is FatalException || bc.Report.Printer is NullReportPrinter || bc.Module.Compiler.Settings.BreakOnInternalError)
3821                                         throw;
3822
3823                                 if (bc.CurrentBlock != null) {
3824                                         bc.Report.Error (584, bc.CurrentBlock.StartLocation, "Internal compiler error: {0}", e.Message);
3825                                 } else {
3826                                         bc.Report.Error (587, "Internal compiler error: {0}", e.Message);
3827                                 }
3828                         }
3829
3830                         //
3831                         // If an asynchronous body of F is either an expression classified as nothing, or a 
3832                         // statement block where no return statements have expressions, the inferred return type is Task
3833                         //
3834                         if (IsAsync) {
3835                                 var am = bc.CurrentAnonymousMethod as AnonymousMethodBody;
3836                                 if (am != null && am.ReturnTypeInference != null && !am.ReturnTypeInference.HasBounds (0)) {
3837                                         am.ReturnTypeInference = null;
3838                                         am.ReturnType = bc.Module.PredefinedTypes.Task.TypeSpec;
3839                                         return true;
3840                                 }
3841                         }
3842
3843                         return true;
3844                 }
3845
3846                 void PrepareAssignmentAnalysis (BlockContext bc)
3847                 {
3848                         for (int i = 0; i < parameters.Count; ++i) {
3849                                 var par = parameters.FixedParameters[i];
3850
3851                                 if ((par.ModFlags & Parameter.Modifier.OUT) == 0)
3852                                         continue;
3853
3854                                 parameter_info [i].VariableInfo = VariableInfo.Create (bc, (Parameter) par);
3855                         }
3856                 }
3857
3858                 public ToplevelBlock ConvertToIterator (IMethodData method, TypeDefinition host, TypeSpec iterator_type, bool is_enumerable)
3859                 {
3860                         var iterator = new Iterator (this, method, host, iterator_type, is_enumerable);
3861                         var stateMachine = new IteratorStorey (iterator);
3862
3863                         state_machine = stateMachine;
3864                         iterator.SetStateMachine (stateMachine);
3865
3866                         var tlb = new ToplevelBlock (host.Compiler, Parameters, Location.Null, Flags.CompilerGenerated);
3867                         tlb.Original = this;
3868                         tlb.state_machine = stateMachine;
3869                         tlb.AddStatement (new Return (iterator, iterator.Location));
3870                         return tlb;
3871                 }
3872
3873                 public ParametersBlock ConvertToAsyncTask (IMemberContext context, TypeDefinition host, ParametersCompiled parameters, TypeSpec returnType, TypeSpec delegateType, Location loc)
3874                 {
3875                         for (int i = 0; i < parameters.Count; i++) {
3876                                 Parameter p = parameters[i];
3877                                 Parameter.Modifier mod = p.ModFlags;
3878                                 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
3879                                         host.Compiler.Report.Error (1988, p.Location,
3880                                                 "Async methods cannot have ref or out parameters");
3881                                         return this;
3882                                 }
3883
3884                                 if (p is ArglistParameter) {
3885                                         host.Compiler.Report.Error (4006, p.Location,
3886                                                 "__arglist is not allowed in parameter list of async methods");
3887                                         return this;
3888                                 }
3889
3890                                 if (parameters.Types[i].IsPointer) {
3891                                         host.Compiler.Report.Error (4005, p.Location,
3892                                                 "Async methods cannot have unsafe parameters");
3893                                         return this;
3894                                 }
3895                         }
3896
3897                         if (!HasAwait) {
3898                                 host.Compiler.Report.Warning (1998, 1, loc,
3899                                         "Async block lacks `await' operator and will run synchronously");
3900                         }
3901
3902                         var block_type = host.Module.Compiler.BuiltinTypes.Void;
3903                         var initializer = new AsyncInitializer (this, host, block_type);
3904                         initializer.Type = block_type;
3905                         initializer.DelegateType = delegateType;
3906
3907                         var stateMachine = new AsyncTaskStorey (this, context, initializer, returnType);
3908
3909                         state_machine = stateMachine;
3910                         initializer.SetStateMachine (stateMachine);
3911
3912                         const Flags flags = Flags.CompilerGenerated;
3913
3914                         var b = this is ToplevelBlock ?
3915                                 new ToplevelBlock (host.Compiler, Parameters, Location.Null, flags) :
3916                                 new ParametersBlock (Parent, parameters, Location.Null, flags | Flags.HasAsyncModifier);
3917
3918                         b.Original = this;
3919                         b.state_machine = stateMachine;
3920                         b.AddStatement (new AsyncInitializerStatement (initializer));
3921                         return b;
3922                 }
3923         }
3924
3925         //
3926         //
3927         //
3928         public class ToplevelBlock : ParametersBlock
3929         {
3930                 LocalVariable this_variable;
3931                 CompilerContext compiler;
3932                 Dictionary<string, object> names;
3933
3934                 List<ExplicitBlock> this_references;
3935
3936                 public ToplevelBlock (CompilerContext ctx, Location loc)
3937                         : this (ctx, ParametersCompiled.EmptyReadOnlyParameters, loc)
3938                 {
3939                 }
3940
3941                 public ToplevelBlock (CompilerContext ctx, ParametersCompiled parameters, Location start, Flags flags = 0)
3942                         : base (parameters, start)
3943                 {
3944                         this.compiler = ctx;
3945                         this.flags = flags;
3946                         top_block = this;
3947
3948                         ProcessParameters ();
3949                 }
3950
3951                 //
3952                 // Recreates a top level block from parameters block. Used for
3953                 // compiler generated methods where the original block comes from
3954                 // explicit child block. This works for already resolved blocks
3955                 // only to ensure we resolve them in the correct flow order
3956                 //
3957                 public ToplevelBlock (ParametersBlock source, ParametersCompiled parameters)
3958                         : base (source, parameters)
3959                 {
3960                         this.compiler = source.TopBlock.compiler;
3961                         top_block = this;
3962                 }
3963
3964                 public bool IsIterator {
3965                         get {
3966                                 return (flags & Flags.Iterator) != 0;
3967                         }
3968                         set {
3969                                 flags = value ? flags | Flags.Iterator : flags & ~Flags.Iterator;
3970                         }
3971                 }
3972
3973                 public Report Report {
3974                         get {
3975                                 return compiler.Report;
3976                         }
3977                 }
3978
3979                 //
3980                 // Used by anonymous blocks to track references of `this' variable
3981                 //
3982                 public List<ExplicitBlock> ThisReferencesFromChildrenBlock {
3983                         get {
3984                                 return this_references;
3985                         }
3986                 }
3987
3988                 //
3989                 // Returns the "this" instance variable of this block.
3990                 // See AddThisVariable() for more information.
3991                 //
3992                 public LocalVariable ThisVariable {
3993                         get {
3994                                 return this_variable;
3995                         }
3996                 }
3997
3998                 public void AddLocalName (string name, INamedBlockVariable li, bool ignoreChildrenBlocks)
3999                 {
4000                         if (names == null)
4001                                 names = new Dictionary<string, object> ();
4002
4003                         object value;
4004                         if (!names.TryGetValue (name, out value)) {
4005                                 names.Add (name, li);
4006                                 return;
4007                         }
4008
4009                         INamedBlockVariable existing = value as INamedBlockVariable;
4010                         List<INamedBlockVariable> existing_list;
4011                         if (existing != null) {
4012                                 existing_list = new List<INamedBlockVariable> ();
4013                                 existing_list.Add (existing);
4014                                 names[name] = existing_list;
4015                         } else {
4016                                 existing_list = (List<INamedBlockVariable>) value;
4017                         }
4018
4019                         //
4020                         // A collision checking between local names
4021                         //
4022                         var variable_block = li.Block.Explicit;
4023                         for (int i = 0; i < existing_list.Count; ++i) {
4024                                 existing = existing_list[i];
4025                                 Block b = existing.Block.Explicit;
4026
4027                                 // Collision at same level
4028                                 if (variable_block == b) {
4029                                         li.Block.Error_AlreadyDeclared (name, li);
4030                                         break;
4031                                 }
4032
4033                                 // Collision with parent
4034                                 Block parent = variable_block;
4035                                 while ((parent = parent.Parent) != null) {
4036                                         if (parent == b) {
4037                                                 li.Block.Error_AlreadyDeclared (name, li, "parent or current");
4038                                                 i = existing_list.Count;
4039                                                 break;
4040                                         }
4041                                 }
4042
4043                                 if (!ignoreChildrenBlocks && variable_block.Parent != b.Parent) {
4044                                         // Collision with children
4045                                         while ((b = b.Parent) != null) {
4046                                                 if (variable_block == b) {
4047                                                         li.Block.Error_AlreadyDeclared (name, li, "child");
4048                                                         i = existing_list.Count;
4049                                                         break;
4050                                                 }
4051                                         }
4052                                 }
4053                         }
4054
4055                         existing_list.Add (li);
4056                 }
4057
4058                 public void AddLabel (string name, LabeledStatement label)
4059                 {
4060                         if (labels == null)
4061                                 labels = new Dictionary<string, object> ();
4062
4063                         object value;
4064                         if (!labels.TryGetValue (name, out value)) {
4065                                 labels.Add (name, label);
4066                                 return;
4067                         }
4068
4069                         LabeledStatement existing = value as LabeledStatement;
4070                         List<LabeledStatement> existing_list;
4071                         if (existing != null) {
4072                                 existing_list = new List<LabeledStatement> ();
4073                                 existing_list.Add (existing);
4074                                 labels[name] = existing_list;
4075                         } else {
4076                                 existing_list = (List<LabeledStatement>) value;
4077                         }
4078
4079                         //
4080                         // A collision checking between labels
4081                         //
4082                         for (int i = 0; i < existing_list.Count; ++i) {
4083                                 existing = existing_list[i];
4084                                 Block b = existing.Block;
4085
4086                                 // Collision at same level
4087                                 if (label.Block == b) {
4088                                         Report.SymbolRelatedToPreviousError (existing.loc, name);
4089                                         Report.Error (140, label.loc, "The label `{0}' is a duplicate", name);
4090                                         break;
4091                                 }
4092
4093                                 // Collision with parent
4094                                 b = label.Block;
4095                                 while ((b = b.Parent) != null) {
4096                                         if (existing.Block == b) {
4097                                                 Report.Error (158, label.loc,
4098                                                         "The label `{0}' shadows another label by the same name in a contained scope", name);
4099                                                 i = existing_list.Count;
4100                                                 break;
4101                                         }
4102                                 }
4103
4104                                 // Collision with with children
4105                                 b = existing.Block;
4106                                 while ((b = b.Parent) != null) {
4107                                         if (label.Block == b) {
4108                                                 Report.Error (158, label.loc,
4109                                                         "The label `{0}' shadows another label by the same name in a contained scope", name);
4110                                                 i = existing_list.Count;
4111                                                 break;
4112                                         }
4113                                 }
4114                         }
4115
4116                         existing_list.Add (label);
4117                 }
4118
4119                 public void AddThisReferenceFromChildrenBlock (ExplicitBlock block)
4120                 {
4121                         if (this_references == null)
4122                                 this_references = new List<ExplicitBlock> ();
4123
4124                         if (!this_references.Contains (block))
4125                                 this_references.Add (block);
4126                 }
4127
4128                 public void RemoveThisReferenceFromChildrenBlock (ExplicitBlock block)
4129                 {
4130                         this_references.Remove (block);
4131                 }
4132
4133                 //
4134                 // Creates an arguments set from all parameters, useful for method proxy calls
4135                 //
4136                 public Arguments GetAllParametersArguments ()
4137                 {
4138                         int count = parameters.Count;
4139                         Arguments args = new Arguments (count);
4140                         for (int i = 0; i < count; ++i) {
4141                                 var pi = parameter_info[i];
4142                                 var arg_expr = GetParameterReference (i, pi.Location);
4143
4144                                 Argument.AType atype_modifier;
4145                                 switch (pi.Parameter.ParameterModifier & Parameter.Modifier.RefOutMask) {
4146                                 case Parameter.Modifier.REF:
4147                                         atype_modifier = Argument.AType.Ref;
4148                                         break;
4149                                 case Parameter.Modifier.OUT:
4150                                         atype_modifier = Argument.AType.Out;
4151                                         break;
4152                                 default:
4153                                         atype_modifier = 0;
4154                                         break;
4155                                 }
4156
4157                                 args.Add (new Argument (arg_expr, atype_modifier));
4158                         }
4159
4160                         return args;
4161                 }
4162
4163                 //
4164                 // Lookup inside a block, the returned value can represent 3 states
4165                 //
4166                 // true+variable: A local name was found and it's valid
4167                 // false+variable: A local name was found in a child block only
4168                 // false+null: No local name was found
4169                 //
4170                 public bool GetLocalName (string name, Block block, ref INamedBlockVariable variable)
4171                 {
4172                         if (names == null)
4173                                 return false;
4174
4175                         object value;
4176                         if (!names.TryGetValue (name, out value))
4177                                 return false;
4178
4179                         variable = value as INamedBlockVariable;
4180                         Block b = block;
4181                         if (variable != null) {
4182                                 do {
4183                                         if (variable.Block == b.Original)
4184                                                 return true;
4185
4186                                         b = b.Parent;
4187                                 } while (b != null);
4188
4189                                 b = variable.Block;
4190                                 do {
4191                                         if (block == b)
4192                                                 return false;
4193
4194                                         b = b.Parent;
4195                                 } while (b != null);
4196                         } else {
4197                                 List<INamedBlockVariable> list = (List<INamedBlockVariable>) value;
4198                                 for (int i = 0; i < list.Count; ++i) {
4199                                         variable = list[i];
4200                                         do {
4201                                                 if (variable.Block == b.Original)
4202                                                         return true;
4203
4204                                                 b = b.Parent;
4205                                         } while (b != null);
4206
4207                                         b = variable.Block;
4208                                         do {
4209                                                 if (block == b)
4210                                                         return false;
4211
4212                                                 b = b.Parent;
4213                                         } while (b != null);
4214
4215                                         b = block;
4216                                 }
4217                         }
4218
4219                         variable = null;
4220                         return false;
4221                 }
4222
4223                 // <summary>
4224                 //   This is used by non-static `struct' constructors which do not have an
4225                 //   initializer - in this case, the constructor must initialize all of the
4226                 //   struct's fields.  To do this, we add a "this" variable and use the flow
4227                 //   analysis code to ensure that it's been fully initialized before control
4228                 //   leaves the constructor.
4229                 // </summary>
4230                 public void AddThisVariable (BlockContext bc)
4231                 {
4232                         if (this_variable != null)
4233                                 throw new InternalErrorException (StartLocation.ToString ());
4234
4235                         this_variable = new LocalVariable (this, "this", LocalVariable.Flags.IsThis | LocalVariable.Flags.Used, StartLocation);
4236                         this_variable.Type = bc.CurrentType;
4237                         this_variable.PrepareAssignmentAnalysis (bc);
4238                 }
4239
4240                 public override void CheckControlExit (FlowAnalysisContext fc, DefiniteAssignmentBitSet dat)
4241                 {
4242                         //
4243                         // If we're a non-static struct constructor which doesn't have an
4244                         // initializer, then we must initialize all of the struct's fields.
4245                         //
4246                         if (this_variable != null)
4247                                 this_variable.IsThisAssigned (fc, this);
4248
4249                         base.CheckControlExit (fc, dat);
4250                 }
4251
4252                 public override void Emit (EmitContext ec)
4253                 {
4254                         if (Report.Errors > 0)
4255                                 return;
4256
4257                         try {
4258                         if (IsCompilerGenerated) {
4259                                 using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
4260                                         base.Emit (ec);
4261                                 }
4262                         } else {
4263                                 base.Emit (ec);
4264                         }
4265
4266                         //
4267                         // If `HasReturnLabel' is set, then we already emitted a
4268                         // jump to the end of the method, so we must emit a `ret'
4269                         // there.
4270                         //
4271                         // Unfortunately, System.Reflection.Emit automatically emits
4272                         // a leave to the end of a finally block.  This is a problem
4273                         // if no code is following the try/finally block since we may
4274                         // jump to a point after the end of the method.
4275                         // As a workaround, we're always creating a return label in
4276                         // this case.
4277                         //
4278                         if (ec.HasReturnLabel || HasReachableClosingBrace) {
4279                                 if (ec.HasReturnLabel)
4280                                         ec.MarkLabel (ec.ReturnLabel);
4281
4282                                 if (ec.EmitAccurateDebugInfo && !IsCompilerGenerated)
4283                                         ec.Mark (EndLocation);
4284
4285                                 if (ec.ReturnType.Kind != MemberKind.Void)
4286                                         ec.Emit (OpCodes.Ldloc, ec.TemporaryReturn ());
4287
4288                                 ec.Emit (OpCodes.Ret);
4289                         }
4290
4291                         } catch (Exception e) {
4292                                 throw new InternalErrorException (e, StartLocation);
4293                         }
4294                 }
4295
4296                 public bool Resolve (BlockContext bc, IMethodData md)
4297                 {
4298                         if (resolved)
4299                                 return true;
4300
4301                         var errors = bc.Report.Errors;
4302
4303                         base.Resolve (bc);
4304
4305                         if (bc.Report.Errors > errors)
4306                                 return false;
4307
4308                         MarkReachable (new Reachability ());
4309
4310                         if (HasReachableClosingBrace && bc.ReturnType.Kind != MemberKind.Void) {
4311                                 // TODO: var md = bc.CurrentMemberDefinition;
4312                                 bc.Report.Error (161, md.Location, "`{0}': not all code paths return a value", md.GetSignatureForError ());
4313                         }
4314
4315                         if ((flags & Flags.NoFlowAnalysis) != 0)
4316                                 return true;
4317
4318                         var fc = new FlowAnalysisContext (bc.Module.Compiler, this, bc.AssignmentInfoOffset);
4319                         try {
4320                                 FlowAnalysis (fc);
4321                         } catch (Exception e) {
4322                                 throw new InternalErrorException (e, StartLocation);
4323                         }
4324
4325                         return true;
4326                 }
4327         }
4328         
4329         public class SwitchLabel : Statement
4330         {
4331                 Constant converted;
4332                 Expression label;
4333
4334                 Label? il_label;
4335
4336                 //
4337                 // if expr == null, then it is the default case.
4338                 //
4339                 public SwitchLabel (Expression expr, Location l)
4340                 {
4341                         label = expr;
4342                         loc = l;
4343                 }
4344
4345                 public bool IsDefault {
4346                         get {
4347                                 return label == null;
4348                         }
4349                 }
4350
4351                 public Expression Label {
4352                         get {
4353                                 return label;
4354                         }
4355                 }
4356
4357                 public Location Location {
4358                         get {
4359                                 return loc;
4360                         }
4361                 }
4362
4363                 public Constant Converted {
4364                         get {
4365                                 return converted;
4366                         }
4367                         set {
4368                                 converted = value; 
4369                         }
4370                 }
4371
4372                 public bool SectionStart { get; set; }
4373
4374                 public Label GetILLabel (EmitContext ec)
4375                 {
4376                         if (il_label == null){
4377                                 il_label = ec.DefineLabel ();
4378                         }
4379
4380                         return il_label.Value;
4381                 }
4382
4383                 protected override void DoEmit (EmitContext ec)
4384                 {
4385                         ec.MarkLabel (GetILLabel (ec));
4386                 }
4387
4388                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
4389                 {
4390                         if (!SectionStart)
4391                                 return false;
4392
4393                         fc.DefiniteAssignment = new DefiniteAssignmentBitSet (fc.SwitchInitialDefinitiveAssignment);
4394                         return false;
4395                 }
4396
4397                 public override bool Resolve (BlockContext bc)
4398                 {
4399                         if (ResolveAndReduce (bc))
4400                                 bc.Switch.RegisterLabel (bc, this);
4401
4402                         return true;
4403                 }
4404
4405                 //
4406                 // Resolves the expression, reduces it to a literal if possible
4407                 // and then converts it to the requested type.
4408                 //
4409                 bool ResolveAndReduce (BlockContext rc)
4410                 {
4411                         if (IsDefault)
4412                                 return true;
4413
4414                         var c = label.ResolveLabelConstant (rc);
4415                         if (c == null)
4416                                 return false;
4417
4418                         if (rc.Switch.IsNullable && c is NullLiteral) {
4419                                 converted = c;
4420                                 return true;
4421                         }
4422
4423                         converted = c.ImplicitConversionRequired (rc, rc.Switch.SwitchType);
4424                         return converted != null;
4425                 }
4426
4427                 public void Error_AlreadyOccurs (ResolveContext ec, SwitchLabel collision_with)
4428                 {
4429                         ec.Report.SymbolRelatedToPreviousError (collision_with.loc, null);
4430                         ec.Report.Error (152, loc, "The label `{0}' already occurs in this switch statement", GetSignatureForError ());
4431                 }
4432
4433                 protected override void CloneTo (CloneContext clonectx, Statement target)
4434                 {
4435                         var t = (SwitchLabel) target;
4436                         if (label != null)
4437                                 t.label = label.Clone (clonectx);
4438                 }
4439
4440                 public override object Accept (StructuralVisitor visitor)
4441                 {
4442                         return visitor.Visit (this);
4443                 }
4444
4445                 public string GetSignatureForError ()
4446                 {
4447                         string label;
4448                         if (converted == null)
4449                                 label = "default";
4450                         else
4451                                 label = converted.GetValueAsLiteral ();
4452
4453                         return string.Format ("case {0}:", label);
4454                 }
4455         }
4456
4457         public class Switch : LoopStatement
4458         {
4459                 // structure used to hold blocks of keys while calculating table switch
4460                 sealed class LabelsRange : IComparable<LabelsRange>
4461                 {
4462                         public readonly long min;
4463                         public long max;
4464                         public readonly List<long> label_values;
4465
4466                         public LabelsRange (long value)
4467                         {
4468                                 min = max = value;
4469                                 label_values = new List<long> ();
4470                                 label_values.Add (value);
4471                         }
4472
4473                         public LabelsRange (long min, long max, ICollection<long> values)
4474                         {
4475                                 this.min = min;
4476                                 this.max = max;
4477                                 this.label_values = new List<long> (values);
4478                         }
4479
4480                         public long Range {
4481                                 get {
4482                                         return max - min + 1;
4483                                 }
4484                         }
4485
4486                         public bool AddValue (long value)
4487                         {
4488                                 var gap = value - min + 1;
4489                                 // Ensure the range has > 50% occupancy
4490                                 if (gap > 2 * (label_values.Count + 1) || gap <= 0)
4491                                         return false;
4492
4493                                 max = value;
4494                                 label_values.Add (value);
4495                                 return true;
4496                         }
4497
4498                         public int CompareTo (LabelsRange other)
4499                         {
4500                                 int nLength = label_values.Count;
4501                                 int nLengthOther = other.label_values.Count;
4502                                 if (nLengthOther == nLength)
4503                                         return (int) (other.min - min);
4504
4505                                 return nLength - nLengthOther;
4506                         }
4507                 }
4508
4509                 sealed class DispatchStatement : Statement
4510                 {
4511                         readonly Switch body;
4512
4513                         public DispatchStatement (Switch body)
4514                         {
4515                                 this.body = body;
4516                         }
4517
4518                         protected override void CloneTo (CloneContext clonectx, Statement target)
4519                         {
4520                                 throw new NotImplementedException ();
4521                         }
4522
4523                         protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
4524                         {
4525                                 return false;
4526                         }
4527
4528                         protected override void DoEmit (EmitContext ec)
4529                         {
4530                                 body.EmitDispatch (ec);
4531                         }
4532                 }
4533
4534                 class MissingBreak : Statement
4535                 {
4536                         SwitchLabel label;
4537
4538                         public MissingBreak (SwitchLabel sl)
4539                         {
4540                                 this.label = sl;
4541                                 this.loc = sl.loc;
4542                         }
4543
4544                         protected override void DoEmit (EmitContext ec)
4545                         {
4546                         }
4547
4548                         protected override void CloneTo (CloneContext clonectx, Statement target)
4549                         {
4550                         }
4551
4552                         protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
4553                         {
4554                                 fc.Report.Error (163, loc, "Control cannot fall through from one case label `{0}' to another",
4555                                         label.GetSignatureForError ());
4556
4557                                 return true;
4558                         }
4559                 }
4560
4561                 public Expression Expr;
4562
4563                 //
4564                 // Mapping of all labels to their SwitchLabels
4565                 //
4566                 Dictionary<long, SwitchLabel> labels;
4567                 Dictionary<string, SwitchLabel> string_labels;
4568                 List<SwitchLabel> case_labels;
4569
4570                 List<Tuple<GotoCase, Constant>> goto_cases;
4571                 List<DefiniteAssignmentBitSet> end_reachable_das;
4572
4573                 /// <summary>
4574                 ///   The governing switch type
4575                 /// </summary>
4576                 public TypeSpec SwitchType;
4577
4578                 Expression new_expr;
4579
4580                 SwitchLabel case_null;
4581                 SwitchLabel case_default;
4582
4583                 Label defaultLabel, nullLabel;
4584                 VariableReference value;
4585                 ExpressionStatement string_dictionary;
4586                 FieldExpr switch_cache_field;
4587                 ExplicitBlock block;
4588                 bool end_reachable;
4589
4590                 //
4591                 // Nullable Types support
4592                 //
4593                 Nullable.Unwrap unwrap;
4594
4595                 public Switch (Expression e, ExplicitBlock block, Location l)
4596                         : base (block)
4597                 {
4598                         Expr = e;
4599                         this.block = block;
4600                         loc = l;
4601                 }
4602
4603                 public SwitchLabel ActiveLabel { get; set; }
4604
4605                 public ExplicitBlock Block {
4606                         get {
4607                                 return block;
4608                         }
4609                 }
4610
4611                 public SwitchLabel DefaultLabel {
4612                         get {
4613                                 return case_default;
4614                         }
4615                 }
4616
4617                 public bool IsNullable {
4618                         get {
4619                                 return unwrap != null;
4620                         }
4621                 }
4622
4623                 public List<SwitchLabel> RegisteredLabels {
4624                         get {
4625                                 return case_labels;
4626                         }
4627                 }
4628
4629                 //
4630                 // Determines the governing type for a switch.  The returned
4631                 // expression might be the expression from the switch, or an
4632                 // expression that includes any potential conversions to
4633                 //
4634                 Expression SwitchGoverningType (ResolveContext ec, Expression expr)
4635                 {
4636                         switch (expr.Type.BuiltinType) {
4637                         case BuiltinTypeSpec.Type.Byte:
4638                         case BuiltinTypeSpec.Type.SByte:
4639                         case BuiltinTypeSpec.Type.UShort:
4640                         case BuiltinTypeSpec.Type.Short:
4641                         case BuiltinTypeSpec.Type.UInt:
4642                         case BuiltinTypeSpec.Type.Int:
4643                         case BuiltinTypeSpec.Type.ULong:
4644                         case BuiltinTypeSpec.Type.Long:
4645                         case BuiltinTypeSpec.Type.Char:
4646                         case BuiltinTypeSpec.Type.String:
4647                         case BuiltinTypeSpec.Type.Bool:
4648                                 return expr;
4649                         }
4650
4651                         if (expr.Type.IsEnum)
4652                                 return expr;
4653
4654                         //
4655                         // Try to find a *user* defined implicit conversion.
4656                         //
4657                         // If there is no implicit conversion, or if there are multiple
4658                         // conversions, we have to report an error
4659                         //
4660                         Expression converted = null;
4661                         foreach (TypeSpec tt in ec.BuiltinTypes.SwitchUserTypes) {
4662                                 Expression e;
4663                                 
4664                                 e = Convert.ImplicitUserConversion (ec, expr, tt, loc);
4665                                 if (e == null)
4666                                         continue;
4667
4668                                 //
4669                                 // Ignore over-worked ImplicitUserConversions that do
4670                                 // an implicit conversion in addition to the user conversion.
4671                                 // 
4672                                 if (!(e is UserCast))
4673                                         continue;
4674
4675                                 if (converted != null){
4676                                         ec.Report.ExtraInformation (loc, "(Ambiguous implicit user defined conversion in previous ");
4677                                         return null;
4678                                 }
4679
4680                                 converted = e;
4681                         }
4682                         return converted;
4683                 }
4684
4685                 public static TypeSpec[] CreateSwitchUserTypes (BuiltinTypes types)
4686                 {
4687                         // LAMESPEC: For some reason it does not contain bool which looks like csc bug
4688                         return new[] {
4689                                 types.SByte,
4690                                 types.Byte,
4691                                 types.Short,
4692                                 types.UShort,
4693                                 types.Int,
4694                                 types.UInt,
4695                                 types.Long,
4696                                 types.ULong,
4697                                 types.Char,
4698                                 types.String
4699                         };
4700                 }
4701
4702                 public void RegisterLabel (BlockContext rc, SwitchLabel sl)
4703                 {
4704                         case_labels.Add (sl);
4705
4706                         if (sl.IsDefault) {
4707                                 if (case_default != null) {
4708                                         sl.Error_AlreadyOccurs (rc, case_default);
4709                                 } else {
4710                                         case_default = sl;
4711                                 }
4712
4713                                 return;
4714                         }
4715
4716                         try {
4717                                 if (string_labels != null) {
4718                                         string string_value = sl.Converted.GetValue () as string;
4719                                         if (string_value == null)
4720                                                 case_null = sl;
4721                                         else
4722                                                 string_labels.Add (string_value, sl);
4723                                 } else {
4724                                         if (sl.Converted is NullLiteral) {
4725                                                 case_null = sl;
4726                                         } else {
4727                                                 labels.Add (sl.Converted.GetValueAsLong (), sl);
4728                                         }
4729                                 }
4730                         } catch (ArgumentException) {
4731                                 if (string_labels != null)
4732                                         sl.Error_AlreadyOccurs (rc, string_labels[(string) sl.Converted.GetValue ()]);
4733                                 else
4734                                         sl.Error_AlreadyOccurs (rc, labels[sl.Converted.GetValueAsLong ()]);
4735                         }
4736                 }
4737                 
4738                 //
4739                 // This method emits code for a lookup-based switch statement (non-string)
4740                 // Basically it groups the cases into blocks that are at least half full,
4741                 // and then spits out individual lookup opcodes for each block.
4742                 // It emits the longest blocks first, and short blocks are just
4743                 // handled with direct compares.
4744                 //
4745                 void EmitTableSwitch (EmitContext ec, Expression val)
4746                 {
4747                         if (labels != null && labels.Count > 0) {
4748                                 List<LabelsRange> ranges;
4749                                 if (string_labels != null) {
4750                                         // We have done all hard work for string already
4751                                         // setup single range only
4752                                         ranges = new List<LabelsRange> (1);
4753                                         ranges.Add (new LabelsRange (0, labels.Count - 1, labels.Keys));
4754                                 } else {
4755                                         var element_keys = new long[labels.Count];
4756                                         labels.Keys.CopyTo (element_keys, 0);
4757                                         Array.Sort (element_keys);
4758
4759                                         //
4760                                         // Build possible ranges of switch labes to reduce number
4761                                         // of comparisons
4762                                         //
4763                                         ranges = new List<LabelsRange> (element_keys.Length);
4764                                         var range = new LabelsRange (element_keys[0]);
4765                                         ranges.Add (range);
4766                                         for (int i = 1; i < element_keys.Length; ++i) {
4767                                                 var l = element_keys[i];
4768                                                 if (range.AddValue (l))
4769                                                         continue;
4770
4771                                                 range = new LabelsRange (l);
4772                                                 ranges.Add (range);
4773                                         }
4774
4775                                         // sort the blocks so we can tackle the largest ones first
4776                                         ranges.Sort ();
4777                                 }
4778
4779                                 Label lbl_default = defaultLabel;
4780                                 TypeSpec compare_type = SwitchType.IsEnum ? EnumSpec.GetUnderlyingType (SwitchType) : SwitchType;
4781
4782                                 for (int range_index = ranges.Count - 1; range_index >= 0; --range_index) {
4783                                         LabelsRange kb = ranges[range_index];
4784                                         lbl_default = (range_index == 0) ? defaultLabel : ec.DefineLabel ();
4785
4786                                         // Optimize small ranges using simple equality check
4787                                         if (kb.Range <= 2) {
4788                                                 foreach (var key in kb.label_values) {
4789                                                         SwitchLabel sl = labels[key];
4790                                                         if (sl == case_default || sl == case_null)
4791                                                                 continue;
4792
4793                                                         if (sl.Converted.IsZeroInteger) {
4794                                                                 val.EmitBranchable (ec, sl.GetILLabel (ec), false);
4795                                                         } else {
4796                                                                 val.Emit (ec);
4797                                                                 sl.Converted.Emit (ec);
4798                                                                 ec.Emit (OpCodes.Beq, sl.GetILLabel (ec));
4799                                                         }
4800                                                 }
4801                                         } else {
4802                                                 // TODO: if all the keys in the block are the same and there are
4803                                                 //       no gaps/defaults then just use a range-check.
4804                                                 if (compare_type.BuiltinType == BuiltinTypeSpec.Type.Long || compare_type.BuiltinType == BuiltinTypeSpec.Type.ULong) {
4805                                                         // TODO: optimize constant/I4 cases
4806
4807                                                         // check block range (could be > 2^31)
4808                                                         val.Emit (ec);
4809                                                         ec.EmitLong (kb.min);
4810                                                         ec.Emit (OpCodes.Blt, lbl_default);
4811
4812                                                         val.Emit (ec);
4813                                                         ec.EmitLong (kb.max);
4814                                                         ec.Emit (OpCodes.Bgt, lbl_default);
4815
4816                                                         // normalize range
4817                                                         val.Emit (ec);
4818                                                         if (kb.min != 0) {
4819                                                                 ec.EmitLong (kb.min);
4820                                                                 ec.Emit (OpCodes.Sub);
4821                                                         }
4822
4823                                                         ec.Emit (OpCodes.Conv_I4);      // assumes < 2^31 labels!
4824                                                 } else {
4825                                                         // normalize range
4826                                                         val.Emit (ec);
4827                                                         int first = (int) kb.min;
4828                                                         if (first > 0) {
4829                                                                 ec.EmitInt (first);
4830                                                                 ec.Emit (OpCodes.Sub);
4831                                                         } else if (first < 0) {
4832                                                                 ec.EmitInt (-first);
4833                                                                 ec.Emit (OpCodes.Add);
4834                                                         }
4835                                                 }
4836
4837                                                 // first, build the list of labels for the switch
4838                                                 int iKey = 0;
4839                                                 long cJumps = kb.Range;
4840                                                 Label[] switch_labels = new Label[cJumps];
4841                                                 for (int iJump = 0; iJump < cJumps; iJump++) {
4842                                                         var key = kb.label_values[iKey];
4843                                                         if (key == kb.min + iJump) {
4844                                                                 switch_labels[iJump] = labels[key].GetILLabel (ec);
4845                                                                 iKey++;
4846                                                         } else {
4847                                                                 switch_labels[iJump] = lbl_default;
4848                                                         }
4849                                                 }
4850
4851                                                 // emit the switch opcode
4852                                                 ec.Emit (OpCodes.Switch, switch_labels);
4853                                         }
4854
4855                                         // mark the default for this block
4856                                         if (range_index != 0)
4857                                                 ec.MarkLabel (lbl_default);
4858                                 }
4859
4860                                 // the last default just goes to the end
4861                                 if (ranges.Count > 0)
4862                                         ec.Emit (OpCodes.Br, lbl_default);
4863                         }
4864                 }
4865                 
4866                 public SwitchLabel FindLabel (Constant value)
4867                 {
4868                         SwitchLabel sl = null;
4869
4870                         if (string_labels != null) {
4871                                 string s = value.GetValue () as string;
4872                                 if (s == null) {
4873                                         if (case_null != null)
4874                                                 sl = case_null;
4875                                         else if (case_default != null)
4876                                                 sl = case_default;
4877                                 } else {
4878                                         string_labels.TryGetValue (s, out sl);
4879                                 }
4880                         } else {
4881                                 if (value is NullLiteral) {
4882                                         sl = case_null;
4883                                 } else {
4884                                         labels.TryGetValue (value.GetValueAsLong (), out sl);
4885                                 }
4886                         }
4887
4888                         return sl;
4889                 }
4890
4891                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
4892                 {
4893                         Expr.FlowAnalysis (fc);
4894
4895                         var prev_switch = fc.SwitchInitialDefinitiveAssignment;
4896                         var InitialDefinitiveAssignment = fc.DefiniteAssignment;
4897                         fc.SwitchInitialDefinitiveAssignment = InitialDefinitiveAssignment;
4898
4899                         block.FlowAnalysis (fc);
4900
4901                         fc.SwitchInitialDefinitiveAssignment = prev_switch;
4902
4903                         if (end_reachable_das != null) {
4904                                 var sections_das = DefiniteAssignmentBitSet.And (end_reachable_das);
4905                                 InitialDefinitiveAssignment |= sections_das;
4906                                 end_reachable_das = null;
4907                         }
4908
4909                         fc.DefiniteAssignment = InitialDefinitiveAssignment;
4910
4911                         return case_default != null && !end_reachable;
4912                 }
4913
4914                 public override bool Resolve (BlockContext ec)
4915                 {
4916                         Expr = Expr.Resolve (ec);
4917                         if (Expr == null)
4918                                 return false;
4919
4920                         new_expr = SwitchGoverningType (ec, Expr);
4921
4922                         if (new_expr == null && Expr.Type.IsNullableType) {
4923                                 unwrap = Nullable.Unwrap.Create (Expr, false);
4924                                 if (unwrap == null)
4925                                         return false;
4926
4927                                 new_expr = SwitchGoverningType (ec, unwrap);
4928                         }
4929
4930                         if (new_expr == null) {
4931                                 if (Expr.Type != InternalType.ErrorType) {
4932                                         ec.Report.Error (151, loc,
4933                                                 "A switch expression of type `{0}' cannot be converted to an integral type, bool, char, string, enum or nullable type",
4934                                                 Expr.Type.GetSignatureForError ());
4935                                 }
4936
4937                                 return false;
4938                         }
4939
4940                         // Validate switch.
4941                         SwitchType = new_expr.Type;
4942
4943                         if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.Bool && ec.Module.Compiler.Settings.Version == LanguageVersion.ISO_1) {
4944                                 ec.Report.FeatureIsNotAvailable (ec.Module.Compiler, loc, "switch expression of boolean type");
4945                                 return false;
4946                         }
4947
4948                         if (block.Statements.Count == 0)
4949                                 return true;
4950
4951                         if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String) {
4952                                 string_labels = new Dictionary<string, SwitchLabel> ();
4953                         } else {
4954                                 labels = new Dictionary<long, SwitchLabel> ();
4955                         }
4956
4957                         case_labels = new List<SwitchLabel> ();
4958
4959                         var constant = new_expr as Constant;
4960
4961                         //
4962                         // Don't need extra variable for constant switch or switch with
4963                         // only default case
4964                         //
4965                         if (constant == null) {
4966                                 //
4967                                 // Store switch expression for comparison purposes
4968                                 //
4969                                 value = new_expr as VariableReference;
4970                                 if (value == null && !HasOnlyDefaultSection ()) {
4971                                         var current_block = ec.CurrentBlock;
4972                                         ec.CurrentBlock = Block;
4973                                         // Create temporary variable inside switch scope
4974                                         value = TemporaryVariableReference.Create (SwitchType, ec.CurrentBlock, loc);
4975                                         value.Resolve (ec);
4976                                         ec.CurrentBlock = current_block;
4977                                 }
4978                         }
4979
4980                         Switch old_switch = ec.Switch;
4981                         ec.Switch = this;
4982                         var parent_los = ec.EnclosingLoopOrSwitch;
4983                         ec.EnclosingLoopOrSwitch = this;
4984
4985                         var ok = Statement.Resolve (ec);
4986
4987                         ec.EnclosingLoopOrSwitch = parent_los;
4988                         ec.Switch = old_switch;
4989
4990                         //
4991                         // Check if all goto cases are valid. Needs to be done after switch
4992                         // is resolved because goto can jump forward in the scope.
4993                         //
4994                         if (goto_cases != null) {
4995                                 foreach (var gc in goto_cases) {
4996                                         if (gc.Item1 == null) {
4997                                                 if (DefaultLabel == null) {
4998                                                         Goto.Error_UnknownLabel (ec, "default", loc);
4999                                                 }
5000
5001                                                 continue;
5002                                         }
5003
5004                                         var sl = FindLabel (gc.Item2);
5005                                         if (sl == null) {
5006                                                 Goto.Error_UnknownLabel (ec, "case " + gc.Item2.GetValueAsLiteral (), loc);
5007                                         } else {
5008                                                 gc.Item1.Label = sl;
5009                                         }
5010                                 }
5011                         }
5012
5013                         if (!ok)
5014                                 return false;
5015
5016                         if (constant == null && SwitchType.BuiltinType == BuiltinTypeSpec.Type.String && string_labels.Count > 6) {
5017                                 ResolveStringSwitchMap (ec);
5018                         }
5019
5020                         //
5021                         // Anonymous storey initialization has to happen before
5022                         // any generated switch dispatch
5023                         //
5024                         block.InsertStatement (0, new DispatchStatement (this));
5025
5026                         return true;
5027                 }
5028
5029                 bool HasOnlyDefaultSection ()
5030                 {
5031                         for (int i = 0; i < block.Statements.Count; ++i) {
5032                                 var s = block.Statements[i] as SwitchLabel;
5033
5034                                 if (s == null || s.IsDefault)
5035                                         continue;
5036
5037                                 return false;
5038                         }
5039
5040                         return true;
5041                 }
5042
5043                 public override Reachability MarkReachable (Reachability rc)
5044                 {
5045                         if (rc.IsUnreachable)
5046                                 return rc;
5047
5048                         base.MarkReachable (rc);
5049
5050                         block.MarkReachableScope (rc);
5051
5052                         if (block.Statements.Count == 0)
5053                                 return rc;
5054
5055                         SwitchLabel constant_label = null;
5056                         var constant = new_expr as Constant;
5057
5058                         if (constant != null) {
5059                                 constant_label = FindLabel (constant) ?? case_default;
5060                                 if (constant_label == null) {
5061                                         block.Statements.RemoveAt (0);
5062                                         return rc;
5063                                 }
5064                         }
5065
5066                         var section_rc = new Reachability ();
5067                         SwitchLabel prev_label = null;
5068
5069                         for (int i = 0; i < block.Statements.Count; ++i) {
5070                                 var s = block.Statements[i];
5071                                 var sl = s as SwitchLabel;
5072
5073                                 if (sl != null && sl.SectionStart) {
5074                                         //
5075                                         // Section is marked already via constant switch or goto case
5076                                         //
5077                                         if (!sl.IsUnreachable) {
5078                                                 section_rc = new Reachability ();
5079                                                 continue;
5080                                         }
5081
5082                                         if (section_rc.IsUnreachable) {
5083                                                 section_rc = new Reachability ();
5084                                         } else {
5085                                                 if (prev_label != null) {
5086                                                         sl.SectionStart = false;
5087                                                         s = new MissingBreak (prev_label);
5088                                                         s.MarkReachable (rc);
5089                                                         block.Statements.Insert (i - 1, s);
5090                                                         ++i;
5091                                                 }
5092                                         }
5093
5094                                         prev_label = sl;
5095
5096                                         if (constant_label != null && constant_label != sl)
5097                                                 section_rc = Reachability.CreateUnreachable ();
5098                                 }
5099
5100                                 section_rc = s.MarkReachable (section_rc);
5101                         }
5102
5103                         if (!section_rc.IsUnreachable && prev_label != null) {
5104                                 prev_label.SectionStart = false;
5105                                 var s = new MissingBreak (prev_label);
5106                                 s.MarkReachable (rc);
5107                                 block.Statements.Add (s);
5108                         }
5109
5110                         //
5111                         // Reachability can affect parent only when all possible paths are handled but
5112                         // we still need to run reachability check on switch body to check for fall-through
5113                         //
5114                         if (case_default == null && constant_label == null)
5115                                 return rc;
5116
5117                         //
5118                         // We have at least one local exit from the switch
5119                         //
5120                         if (end_reachable)
5121                                 return rc;
5122
5123                         return Reachability.CreateUnreachable ();
5124                 }
5125
5126                 public void RegisterGotoCase (GotoCase gotoCase, Constant value)
5127                 {
5128                         if (goto_cases == null)
5129                                 goto_cases = new List<Tuple<GotoCase, Constant>> ();
5130
5131                         goto_cases.Add (Tuple.Create (gotoCase, value));
5132                 }
5133
5134                 //
5135                 // Converts string switch into string hashtable
5136                 //
5137                 void ResolveStringSwitchMap (ResolveContext ec)
5138                 {
5139                         FullNamedExpression string_dictionary_type;
5140                         if (ec.Module.PredefinedTypes.Dictionary.Define ()) {
5141                                 string_dictionary_type = new TypeExpression (
5142                                         ec.Module.PredefinedTypes.Dictionary.TypeSpec.MakeGenericType (ec,
5143                                                 new [] { ec.BuiltinTypes.String, ec.BuiltinTypes.Int }),
5144                                         loc);
5145                         } else if (ec.Module.PredefinedTypes.Hashtable.Define ()) {
5146                                 string_dictionary_type = new TypeExpression (ec.Module.PredefinedTypes.Hashtable.TypeSpec, loc);
5147                         } else {
5148                                 ec.Module.PredefinedTypes.Dictionary.Resolve ();
5149                                 return;
5150                         }
5151
5152                         var ctype = ec.CurrentMemberDefinition.Parent.PartialContainer;
5153                         Field field = new Field (ctype, string_dictionary_type,
5154                                 Modifiers.STATIC | Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED,
5155                                 new MemberName (CompilerGeneratedContainer.MakeName (null, "f", "switch$map", ec.Module.CounterSwitchTypes++), loc), null);
5156                         if (!field.Define ())
5157                                 return;
5158                         ctype.AddField (field);
5159
5160                         var init = new List<Expression> ();
5161                         int counter = -1;
5162                         labels = new Dictionary<long, SwitchLabel> (string_labels.Count);
5163                         string value = null;
5164
5165                         foreach (SwitchLabel sl in case_labels) {
5166
5167                                 if (sl.SectionStart)
5168                                         labels.Add (++counter, sl);
5169
5170                                 if (sl == case_default || sl == case_null)
5171                                         continue;
5172
5173                                 value = (string) sl.Converted.GetValue ();
5174                                 var init_args = new List<Expression> (2);
5175                                 init_args.Add (new StringLiteral (ec.BuiltinTypes, value, sl.Location));
5176
5177                                 sl.Converted = new IntConstant (ec.BuiltinTypes, counter, loc);
5178                                 init_args.Add (sl.Converted);
5179
5180                                 init.Add (new CollectionElementInitializer (init_args, loc));
5181                         }
5182         
5183                         Arguments args = new Arguments (1);
5184                         args.Add (new Argument (new IntConstant (ec.BuiltinTypes, init.Count, loc)));
5185                         Expression initializer = new NewInitialize (string_dictionary_type, args,
5186                                 new CollectionOrObjectInitializers (init, loc), loc);
5187
5188                         switch_cache_field = new FieldExpr (field, loc);
5189                         string_dictionary = new SimpleAssign (switch_cache_field, initializer.Resolve (ec));
5190                 }
5191
5192                 void DoEmitStringSwitch (EmitContext ec)
5193                 {
5194                         Label l_initialized = ec.DefineLabel ();
5195
5196                         //
5197                         // Skip initialization when value is null
5198                         //
5199                         value.EmitBranchable (ec, nullLabel, false);
5200
5201                         //
5202                         // Check if string dictionary is initialized and initialize
5203                         //
5204                         switch_cache_field.EmitBranchable (ec, l_initialized, true);
5205                         using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
5206                                 string_dictionary.EmitStatement (ec);
5207                         }
5208                         ec.MarkLabel (l_initialized);
5209
5210                         LocalTemporary string_switch_variable = new LocalTemporary (ec.BuiltinTypes.Int);
5211
5212                         ResolveContext rc = new ResolveContext (ec.MemberContext);
5213
5214                         if (switch_cache_field.Type.IsGeneric) {
5215                                 Arguments get_value_args = new Arguments (2);
5216                                 get_value_args.Add (new Argument (value));
5217                                 get_value_args.Add (new Argument (string_switch_variable, Argument.AType.Out));
5218                                 Expression get_item = new Invocation (new MemberAccess (switch_cache_field, "TryGetValue", loc), get_value_args).Resolve (rc);
5219                                 if (get_item == null)
5220                                         return;
5221
5222                                 //
5223                                 // A value was not found, go to default case
5224                                 //
5225                                 get_item.EmitBranchable (ec, defaultLabel, false);
5226                         } else {
5227                                 Arguments get_value_args = new Arguments (1);
5228                                 get_value_args.Add (new Argument (value));
5229
5230                                 Expression get_item = new ElementAccess (switch_cache_field, get_value_args, loc).Resolve (rc);
5231                                 if (get_item == null)
5232                                         return;
5233
5234                                 LocalTemporary get_item_object = new LocalTemporary (ec.BuiltinTypes.Object);
5235                                 get_item_object.EmitAssign (ec, get_item, true, false);
5236                                 ec.Emit (OpCodes.Brfalse, defaultLabel);
5237
5238                                 ExpressionStatement get_item_int = (ExpressionStatement) new SimpleAssign (string_switch_variable,
5239                                         new Cast (new TypeExpression (ec.BuiltinTypes.Int, loc), get_item_object, loc)).Resolve (rc);
5240
5241                                 get_item_int.EmitStatement (ec);
5242                                 get_item_object.Release (ec);
5243                         }
5244
5245                         EmitTableSwitch (ec, string_switch_variable);
5246                         string_switch_variable.Release (ec);
5247                 }
5248
5249                 //
5250                 // Emits switch using simple if/else comparison for small label count (4 + optional default)
5251                 //
5252                 void EmitShortSwitch (EmitContext ec)
5253                 {
5254                         MethodSpec equal_method = null;
5255                         if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String) {
5256                                 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (loc);
5257                         }
5258
5259                         if (equal_method != null) {
5260                                 value.EmitBranchable (ec, nullLabel, false);
5261                         }
5262
5263                         for (int i = 0; i < case_labels.Count; ++i) {
5264                                 var label = case_labels [i];
5265                                 if (label == case_default || label == case_null)
5266                                         continue;
5267
5268                                 var constant = label.Converted;
5269
5270                                 if (equal_method != null) {
5271                                         value.Emit (ec);
5272                                         constant.Emit (ec);
5273
5274                                         var call = new CallEmitter ();
5275                                         call.EmitPredefined (ec, equal_method, new Arguments (0));
5276                                         ec.Emit (OpCodes.Brtrue, label.GetILLabel (ec));
5277                                         continue;
5278                                 }
5279
5280                                 if (constant.IsZeroInteger && constant.Type.BuiltinType != BuiltinTypeSpec.Type.Long && constant.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
5281                                         value.EmitBranchable (ec, label.GetILLabel (ec), false);
5282                                         continue;
5283                                 }
5284
5285                                 value.Emit (ec);
5286                                 constant.Emit (ec);
5287                                 ec.Emit (OpCodes.Beq, label.GetILLabel (ec));
5288                         }
5289
5290                         ec.Emit (OpCodes.Br, defaultLabel);
5291                 }
5292
5293                 void EmitDispatch (EmitContext ec)
5294                 {
5295                         if (value == null) {
5296                                 //
5297                                 // Constant switch, we've already done the work if there is only 1 label
5298                                 // referenced
5299                                 //
5300                                 int reachable = 0;
5301                                 foreach (var sl in case_labels) {
5302                                         if (sl.IsUnreachable)
5303                                                 continue;
5304
5305                                         if (reachable++ > 0) {
5306                                                 var constant = (Constant) new_expr;
5307                                                 var constant_label = FindLabel (constant) ?? case_default;
5308
5309                                                 ec.Emit (OpCodes.Br, constant_label.GetILLabel (ec));
5310                                                 break;
5311                                         }
5312                                 }
5313
5314                                 return;
5315                         }
5316
5317                         if (string_dictionary != null) {
5318                                 DoEmitStringSwitch (ec);
5319                         } else if (case_labels.Count < 4 || string_labels != null) {
5320                                 EmitShortSwitch (ec);
5321                         } else {
5322                                 EmitTableSwitch (ec, value);
5323                         }
5324                 }
5325
5326                 protected override void DoEmit (EmitContext ec)
5327                 {
5328                         //
5329                         // Setup the codegen context
5330                         //
5331                         Label old_end = ec.LoopEnd;
5332                         Switch old_switch = ec.Switch;
5333
5334                         ec.LoopEnd = ec.DefineLabel ();
5335                         ec.Switch = this;
5336
5337                         defaultLabel = case_default == null ? ec.LoopEnd : case_default.GetILLabel (ec);
5338                         nullLabel = case_null == null ? defaultLabel : case_null.GetILLabel (ec);
5339
5340                         if (value != null) {
5341                                 ec.Mark (loc);
5342                                 if (IsNullable) {
5343                                         unwrap.EmitCheck (ec);
5344                                         ec.Emit (OpCodes.Brfalse, nullLabel);
5345                                         value.EmitAssign (ec, new_expr, false, false);
5346                                 } else if (new_expr != value) {
5347                                         value.EmitAssign (ec, new_expr, false, false);
5348                                 }
5349
5350
5351                                 //
5352                                 // Next statement is compiler generated we don't need extra
5353                                 // nop when we can use the statement for sequence point
5354                                 //
5355                                 ec.Mark (block.StartLocation);
5356                                 block.IsCompilerGenerated = true;
5357                         }
5358
5359                         block.Emit (ec);
5360
5361                         // Restore context state. 
5362                         ec.MarkLabel (ec.LoopEnd);
5363
5364                         //
5365                         // Restore the previous context
5366                         //
5367                         ec.LoopEnd = old_end;
5368                         ec.Switch = old_switch;
5369                 }
5370
5371                 protected override void CloneTo (CloneContext clonectx, Statement t)
5372                 {
5373                         Switch target = (Switch) t;
5374
5375                         target.Expr = Expr.Clone (clonectx);
5376                         target.Statement = target.block = (ExplicitBlock) block.Clone (clonectx);
5377                 }
5378                 
5379                 public override object Accept (StructuralVisitor visitor)
5380                 {
5381                         return visitor.Visit (this);
5382                 }
5383
5384                 public override void AddEndDefiniteAssignment (FlowAnalysisContext fc)
5385                 {
5386                         if (case_default == null)
5387                                 return;
5388
5389                         if (end_reachable_das == null)
5390                                 end_reachable_das = new List<DefiniteAssignmentBitSet> ();
5391
5392                         end_reachable_das.Add (fc.DefiniteAssignment);
5393                 }
5394
5395                 public override void SetEndReachable ()
5396                 {
5397                         end_reachable = true;
5398                 }
5399         }
5400
5401         // A place where execution can restart in a state machine
5402         public abstract class ResumableStatement : Statement
5403         {
5404                 bool prepared;
5405                 protected Label resume_point;
5406
5407                 public Label PrepareForEmit (EmitContext ec)
5408                 {
5409                         if (!prepared) {
5410                                 prepared = true;
5411                                 resume_point = ec.DefineLabel ();
5412                         }
5413                         return resume_point;
5414                 }
5415
5416                 public virtual Label PrepareForDispose (EmitContext ec, Label end)
5417                 {
5418                         return end;
5419                 }
5420
5421                 public virtual void EmitForDispose (EmitContext ec, LocalBuilder pc, Label end, bool have_dispatcher)
5422                 {
5423                 }
5424         }
5425
5426         public abstract class TryFinallyBlock : ExceptionStatement
5427         {
5428                 protected Statement stmt;
5429                 Label dispose_try_block;
5430                 bool prepared_for_dispose, emitted_dispose;
5431                 Method finally_host;
5432
5433                 protected TryFinallyBlock (Statement stmt, Location loc)
5434                         : base (loc)
5435                 {
5436                         this.stmt = stmt;
5437                 }
5438
5439                 #region Properties
5440
5441                 public Statement Statement {
5442                         get {
5443                                 return stmt;
5444                         }
5445                 }
5446
5447                 #endregion
5448
5449                 protected abstract void EmitTryBody (EmitContext ec);
5450                 public abstract void EmitFinallyBody (EmitContext ec);
5451
5452                 public override Label PrepareForDispose (EmitContext ec, Label end)
5453                 {
5454                         if (!prepared_for_dispose) {
5455                                 prepared_for_dispose = true;
5456                                 dispose_try_block = ec.DefineLabel ();
5457                         }
5458                         return dispose_try_block;
5459                 }
5460
5461                 protected sealed override void DoEmit (EmitContext ec)
5462                 {
5463                         EmitTryBodyPrepare (ec);
5464                         EmitTryBody (ec);
5465
5466                         ec.BeginFinallyBlock ();
5467
5468                         Label start_finally = ec.DefineLabel ();
5469                         if (resume_points != null) {
5470                                 var state_machine = (StateMachineInitializer) ec.CurrentAnonymousMethod;
5471
5472                                 ec.Emit (OpCodes.Ldloc, state_machine.SkipFinally);
5473                                 ec.Emit (OpCodes.Brfalse_S, start_finally);
5474                                 ec.Emit (OpCodes.Endfinally);
5475                         }
5476
5477                         ec.MarkLabel (start_finally);
5478
5479                         if (finally_host != null) {
5480                                 finally_host.Define ();
5481                                 finally_host.PrepareEmit ();
5482                                 finally_host.Emit ();
5483
5484                                 // Now it's safe to add, to close it properly and emit sequence points
5485                                 finally_host.Parent.AddMember (finally_host);
5486
5487                                 var ce = new CallEmitter ();
5488                                 ce.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, loc);
5489                                 ce.EmitPredefined (ec, finally_host.Spec, new Arguments (0));
5490                         } else {
5491                                 EmitFinallyBody (ec);
5492                         }
5493
5494                         ec.EndExceptionBlock ();
5495                 }
5496
5497                 public override void EmitForDispose (EmitContext ec, LocalBuilder pc, Label end, bool have_dispatcher)
5498                 {
5499                         if (emitted_dispose)
5500                                 return;
5501
5502                         emitted_dispose = true;
5503
5504                         Label end_of_try = ec.DefineLabel ();
5505
5506                         // Ensure that the only way we can get into this code is through a dispatcher
5507                         if (have_dispatcher)
5508                                 ec.Emit (OpCodes.Br, end);
5509
5510                         ec.BeginExceptionBlock ();
5511
5512                         ec.MarkLabel (dispose_try_block);
5513
5514                         Label[] labels = null;
5515                         for (int i = 0; i < resume_points.Count; ++i) {
5516                                 ResumableStatement s = resume_points[i];
5517                                 Label ret = s.PrepareForDispose (ec, end_of_try);
5518                                 if (ret.Equals (end_of_try) && labels == null)
5519                                         continue;
5520                                 if (labels == null) {
5521                                         labels = new Label[resume_points.Count];
5522                                         for (int j = 0; j < i; ++j)
5523                                                 labels[j] = end_of_try;
5524                                 }
5525                                 labels[i] = ret;
5526                         }
5527
5528                         if (labels != null) {
5529                                 int j;
5530                                 for (j = 1; j < labels.Length; ++j)
5531                                         if (!labels[0].Equals (labels[j]))
5532                                                 break;
5533                                 bool emit_dispatcher = j < labels.Length;
5534
5535                                 if (emit_dispatcher) {
5536                                         ec.Emit (OpCodes.Ldloc, pc);
5537                                         ec.EmitInt (first_resume_pc);
5538                                         ec.Emit (OpCodes.Sub);
5539                                         ec.Emit (OpCodes.Switch, labels);
5540                                 }
5541
5542                                 foreach (ResumableStatement s in resume_points)
5543                                         s.EmitForDispose (ec, pc, end_of_try, emit_dispatcher);
5544                         }
5545
5546                         ec.MarkLabel (end_of_try);
5547
5548                         ec.BeginFinallyBlock ();
5549
5550                         if (finally_host != null) {
5551                                 var ce = new CallEmitter ();
5552                                 ce.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, loc);
5553                                 ce.EmitPredefined (ec, finally_host.Spec, new Arguments (0));
5554                         } else {
5555                                 EmitFinallyBody (ec);
5556                         }
5557
5558                         ec.EndExceptionBlock ();
5559                 }
5560
5561                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
5562                 {
5563                         var res = stmt.FlowAnalysis (fc);
5564                         parent = null;
5565                         return res;
5566                 }
5567
5568                 public override Reachability MarkReachable (Reachability rc)
5569                 {
5570                         base.MarkReachable (rc);
5571                         return Statement.MarkReachable (rc);
5572                 }
5573
5574                 public override bool Resolve (BlockContext bc)
5575                 {
5576                         bool ok;
5577
5578                         parent = bc.CurrentTryBlock;
5579                         bc.CurrentTryBlock = this;
5580
5581                         using (bc.Set (ResolveContext.Options.TryScope)) {
5582                                 ok = stmt.Resolve (bc);
5583                         }
5584
5585                         bc.CurrentTryBlock = parent;
5586
5587                         //
5588                         // Finally block inside iterator is called from MoveNext and
5589                         // Dispose methods that means we need to lift the block into
5590                         // newly created host method to emit the body only once. The
5591                         // original block then simply calls the newly generated method.
5592                         //
5593                         if (bc.CurrentIterator != null && !bc.IsInProbingMode) {
5594                                 var b = stmt as Block;
5595                                 if (b != null && b.Explicit.HasYield) {
5596                                         finally_host = bc.CurrentIterator.CreateFinallyHost (this);
5597                                 }
5598                         }
5599
5600                         return base.Resolve (bc) && ok;
5601                 }
5602         }
5603
5604         //
5605         // Base class for blocks using exception handling
5606         //
5607         public abstract class ExceptionStatement : ResumableStatement
5608         {
5609                 protected List<ResumableStatement> resume_points;
5610                 protected int first_resume_pc;
5611                 protected ExceptionStatement parent;
5612
5613                 protected ExceptionStatement (Location loc)
5614                 {
5615                         this.loc = loc;
5616                 }
5617
5618                 protected virtual void EmitTryBodyPrepare (EmitContext ec)
5619                 {
5620                         StateMachineInitializer state_machine = null;
5621                         if (resume_points != null) {
5622                                 state_machine = (StateMachineInitializer) ec.CurrentAnonymousMethod;
5623
5624                                 ec.EmitInt ((int) IteratorStorey.State.Running);
5625                                 ec.Emit (OpCodes.Stloc, state_machine.CurrentPC);
5626                         }
5627
5628                         ec.BeginExceptionBlock ();
5629
5630                         if (resume_points != null) {
5631                                 ec.MarkLabel (resume_point);
5632
5633                                 // For normal control flow, we want to fall-through the Switch
5634                                 // So, we use CurrentPC rather than the $PC field, and initialize it to an outside value above
5635                                 ec.Emit (OpCodes.Ldloc, state_machine.CurrentPC);
5636                                 ec.EmitInt (first_resume_pc);
5637                                 ec.Emit (OpCodes.Sub);
5638
5639                                 Label[] labels = new Label[resume_points.Count];
5640                                 for (int i = 0; i < resume_points.Count; ++i)
5641                                         labels[i] = resume_points[i].PrepareForEmit (ec);
5642                                 ec.Emit (OpCodes.Switch, labels);
5643                         }
5644                 }
5645
5646                 public virtual int AddResumePoint (ResumableStatement stmt, int pc, StateMachineInitializer stateMachine)
5647                 {
5648                         if (parent != null) {
5649                                 // TODO: MOVE to virtual TryCatch
5650                                 var tc = this as TryCatch;
5651                                 var s = tc != null && tc.IsTryCatchFinally ? stmt : this;
5652
5653                                 pc = parent.AddResumePoint (s, pc, stateMachine);
5654                         } else {
5655                                 pc = stateMachine.AddResumePoint (this);
5656                         }
5657
5658                         if (resume_points == null) {
5659                                 resume_points = new List<ResumableStatement> ();
5660                                 first_resume_pc = pc;
5661                         }
5662
5663                         if (pc != first_resume_pc + resume_points.Count)
5664                                 throw new InternalErrorException ("missed an intervening AddResumePoint?");
5665
5666                         resume_points.Add (stmt);
5667                         return pc;
5668                 }
5669         }
5670
5671         public class Lock : TryFinallyBlock
5672         {
5673                 Expression expr;
5674                 TemporaryVariableReference expr_copy;
5675                 TemporaryVariableReference lock_taken;
5676                         
5677                 public Lock (Expression expr, Statement stmt, Location loc)
5678                         : base (stmt, loc)
5679                 {
5680                         this.expr = expr;
5681                 }
5682
5683                 public Expression Expr {
5684                         get {
5685                                 return this.expr;
5686                         }
5687                 }
5688
5689                 public override bool Resolve (BlockContext ec)
5690                 {
5691                         expr = expr.Resolve (ec);
5692                         if (expr == null)
5693                                 return false;
5694
5695                         if (!TypeSpec.IsReferenceType (expr.Type)) {
5696                                 ec.Report.Error (185, loc,
5697                                         "`{0}' is not a reference type as required by the lock statement",
5698                                         expr.Type.GetSignatureForError ());
5699                         }
5700
5701                         if (expr.Type.IsGenericParameter) {
5702                                 expr = Convert.ImplicitTypeParameterConversion (expr, (TypeParameterSpec)expr.Type, ec.BuiltinTypes.Object);
5703                         }
5704
5705                         VariableReference lv = expr as VariableReference;
5706                         bool locked;
5707                         if (lv != null) {
5708                                 locked = lv.IsLockedByStatement;
5709                                 lv.IsLockedByStatement = true;
5710                         } else {
5711                                 lv = null;
5712                                 locked = false;
5713                         }
5714
5715                         //
5716                         // Have to keep original lock value around to unlock same location
5717                         // in the case of original value has changed or is null
5718                         //
5719                         expr_copy = TemporaryVariableReference.Create (ec.BuiltinTypes.Object, ec.CurrentBlock, loc);
5720                         expr_copy.Resolve (ec);
5721
5722                         //
5723                         // Ensure Monitor methods are available
5724                         //
5725                         if (ResolvePredefinedMethods (ec) > 1) {
5726                                 lock_taken = TemporaryVariableReference.Create (ec.BuiltinTypes.Bool, ec.CurrentBlock, loc);
5727                                 lock_taken.Resolve (ec);
5728                         }
5729
5730                         using (ec.Set (ResolveContext.Options.LockScope)) {
5731                                 base.Resolve (ec);
5732                         }
5733
5734                         if (lv != null) {
5735                                 lv.IsLockedByStatement = locked;
5736                         }
5737
5738                         return true;
5739                 }
5740                 
5741                 protected override void EmitTryBodyPrepare (EmitContext ec)
5742                 {
5743                         expr_copy.EmitAssign (ec, expr);
5744
5745                         if (lock_taken != null) {
5746                                 //
5747                                 // Initialize ref variable
5748                                 //
5749                                 lock_taken.EmitAssign (ec, new BoolLiteral (ec.BuiltinTypes, false, loc));
5750                         } else {
5751                                 //
5752                                 // Monitor.Enter (expr_copy)
5753                                 //
5754                                 expr_copy.Emit (ec);
5755                                 ec.Emit (OpCodes.Call, ec.Module.PredefinedMembers.MonitorEnter.Get ());
5756                         }
5757
5758                         base.EmitTryBodyPrepare (ec);
5759                 }
5760
5761                 protected override void EmitTryBody (EmitContext ec)
5762                 {
5763                         //
5764                         // Monitor.Enter (expr_copy, ref lock_taken)
5765                         //
5766                         if (lock_taken != null) {
5767                                 expr_copy.Emit (ec);
5768                                 lock_taken.LocalInfo.CreateBuilder (ec);
5769                                 lock_taken.AddressOf (ec, AddressOp.Load);
5770                                 ec.Emit (OpCodes.Call, ec.Module.PredefinedMembers.MonitorEnter_v4.Get ());
5771                         }
5772
5773                         Statement.Emit (ec);
5774                 }
5775
5776                 public override void EmitFinallyBody (EmitContext ec)
5777                 {
5778                         //
5779                         // if (lock_taken) Monitor.Exit (expr_copy)
5780                         //
5781                         Label skip = ec.DefineLabel ();
5782
5783                         if (lock_taken != null) {
5784                                 lock_taken.Emit (ec);
5785                                 ec.Emit (OpCodes.Brfalse_S, skip);
5786                         }
5787
5788                         expr_copy.Emit (ec);
5789                         var m = ec.Module.PredefinedMembers.MonitorExit.Resolve (loc);
5790                         if (m != null)
5791                                 ec.Emit (OpCodes.Call, m);
5792
5793                         ec.MarkLabel (skip);
5794                 }
5795
5796                 int ResolvePredefinedMethods (ResolveContext rc)
5797                 {
5798                         // Try 4.0 Monitor.Enter (object, ref bool) overload first
5799                         var m = rc.Module.PredefinedMembers.MonitorEnter_v4.Get ();
5800                         if (m != null)
5801                                 return 4;
5802
5803                         m = rc.Module.PredefinedMembers.MonitorEnter.Get ();
5804                         if (m != null)
5805                                 return 1;
5806
5807                         rc.Module.PredefinedMembers.MonitorEnter_v4.Resolve (loc);
5808                         return 0;
5809                 }
5810
5811                 protected override void CloneTo (CloneContext clonectx, Statement t)
5812                 {
5813                         Lock target = (Lock) t;
5814
5815                         target.expr = expr.Clone (clonectx);
5816                         target.stmt = Statement.Clone (clonectx);
5817                 }
5818                 
5819                 public override object Accept (StructuralVisitor visitor)
5820                 {
5821                         return visitor.Visit (this);
5822                 }
5823
5824         }
5825
5826         public class Unchecked : Statement {
5827                 public Block Block;
5828                 
5829                 public Unchecked (Block b, Location loc)
5830                 {
5831                         Block = b;
5832                         b.Unchecked = true;
5833                         this.loc = loc;
5834                 }
5835
5836                 public override bool Resolve (BlockContext ec)
5837                 {
5838                         using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
5839                                 return Block.Resolve (ec);
5840                 }
5841                 
5842                 protected override void DoEmit (EmitContext ec)
5843                 {
5844                         using (ec.With (EmitContext.Options.CheckedScope, false))
5845                                 Block.Emit (ec);
5846                 }
5847
5848                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
5849                 {
5850                         return Block.FlowAnalysis (fc);
5851                 }
5852
5853                 public override Reachability MarkReachable (Reachability rc)
5854                 {
5855                         base.MarkReachable (rc);
5856                         return Block.MarkReachable (rc);
5857                 }
5858
5859                 protected override void CloneTo (CloneContext clonectx, Statement t)
5860                 {
5861                         Unchecked target = (Unchecked) t;
5862
5863                         target.Block = clonectx.LookupBlock (Block);
5864                 }
5865                 
5866                 public override object Accept (StructuralVisitor visitor)
5867                 {
5868                         return visitor.Visit (this);
5869                 }
5870         }
5871
5872         public class Checked : Statement {
5873                 public Block Block;
5874                 
5875                 public Checked (Block b, Location loc)
5876                 {
5877                         Block = b;
5878                         b.Unchecked = false;
5879                         this.loc = loc;
5880                 }
5881
5882                 public override bool Resolve (BlockContext ec)
5883                 {
5884                         using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
5885                                 return Block.Resolve (ec);
5886                 }
5887
5888                 protected override void DoEmit (EmitContext ec)
5889                 {
5890                         using (ec.With (EmitContext.Options.CheckedScope, true))
5891                                 Block.Emit (ec);
5892                 }
5893
5894                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
5895                 {
5896                         return Block.FlowAnalysis (fc);
5897                 }
5898
5899                 public override Reachability MarkReachable (Reachability rc)
5900                 {
5901                         base.MarkReachable (rc);
5902                         return Block.MarkReachable (rc);
5903                 }
5904
5905                 protected override void CloneTo (CloneContext clonectx, Statement t)
5906                 {
5907                         Checked target = (Checked) t;
5908
5909                         target.Block = clonectx.LookupBlock (Block);
5910                 }
5911                 
5912                 public override object Accept (StructuralVisitor visitor)
5913                 {
5914                         return visitor.Visit (this);
5915                 }
5916         }
5917
5918         public class Unsafe : Statement {
5919                 public Block Block;
5920
5921                 public Unsafe (Block b, Location loc)
5922                 {
5923                         Block = b;
5924                         Block.Unsafe = true;
5925                         this.loc = loc;
5926                 }
5927
5928                 public override bool Resolve (BlockContext ec)
5929                 {
5930                         if (ec.CurrentIterator != null)
5931                                 ec.Report.Error (1629, loc, "Unsafe code may not appear in iterators");
5932
5933                         using (ec.Set (ResolveContext.Options.UnsafeScope))
5934                                 return Block.Resolve (ec);
5935                 }
5936                 
5937                 protected override void DoEmit (EmitContext ec)
5938                 {
5939                         Block.Emit (ec);
5940                 }
5941
5942                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
5943                 {
5944                         return Block.FlowAnalysis (fc);
5945                 }
5946
5947                 public override Reachability MarkReachable (Reachability rc)
5948                 {
5949                         base.MarkReachable (rc);
5950                         return Block.MarkReachable (rc);
5951                 }
5952
5953                 protected override void CloneTo (CloneContext clonectx, Statement t)
5954                 {
5955                         Unsafe target = (Unsafe) t;
5956
5957                         target.Block = clonectx.LookupBlock (Block);
5958                 }
5959                 
5960                 public override object Accept (StructuralVisitor visitor)
5961                 {
5962                         return visitor.Visit (this);
5963                 }
5964         }
5965
5966         // 
5967         // Fixed statement
5968         //
5969         public class Fixed : Statement
5970         {
5971                 abstract class Emitter : ShimExpression
5972                 {
5973                         protected LocalVariable vi;
5974
5975                         protected Emitter (Expression expr, LocalVariable li)
5976                                 : base (expr)
5977                         {
5978                                 vi = li;
5979                         }
5980
5981                         public abstract void EmitExit (EmitContext ec);
5982
5983                         public override void FlowAnalysis (FlowAnalysisContext fc)
5984                         {
5985                                 expr.FlowAnalysis (fc);
5986                         }
5987                 }
5988
5989                 class ExpressionEmitter : Emitter {
5990                         public ExpressionEmitter (Expression converted, LocalVariable li) :
5991                                 base (converted, li)
5992                         {
5993                         }
5994
5995                         protected override Expression DoResolve (ResolveContext rc)
5996                         {
5997                                 throw new NotImplementedException ();
5998                         }
5999
6000                         public override void Emit (EmitContext ec) {
6001                                 //
6002                                 // Store pointer in pinned location
6003                                 //
6004                                 expr.Emit (ec);
6005                                 vi.EmitAssign (ec);
6006                         }
6007
6008                         public override void EmitExit (EmitContext ec)
6009                         {
6010                                 ec.EmitInt (0);
6011                                 ec.Emit (OpCodes.Conv_U);
6012                                 vi.EmitAssign (ec);
6013                         }
6014                 }
6015
6016                 class StringEmitter : Emitter
6017                 {
6018                         LocalVariable pinned_string;
6019
6020                         public StringEmitter (Expression expr, LocalVariable li)
6021                                 : base (expr, li)
6022                         {
6023                         }
6024
6025                         protected override Expression DoResolve (ResolveContext rc)
6026                         {
6027                                 pinned_string = new LocalVariable (vi.Block, "$pinned",
6028                                         LocalVariable.Flags.FixedVariable | LocalVariable.Flags.CompilerGenerated | LocalVariable.Flags.Used,
6029                                         vi.Location);
6030                                 pinned_string.Type = rc.BuiltinTypes.String;
6031
6032                                 eclass = ExprClass.Variable;
6033                                 type = rc.BuiltinTypes.Int;
6034                                 return this;
6035                         }
6036
6037                         public override void Emit (EmitContext ec)
6038                         {
6039                                 pinned_string.CreateBuilder (ec);
6040
6041                                 expr.Emit (ec);
6042                                 pinned_string.EmitAssign (ec);
6043
6044                                 // TODO: Should use Binary::Add
6045                                 pinned_string.Emit (ec);
6046                                 ec.Emit (OpCodes.Conv_I);
6047
6048                                 var m = ec.Module.PredefinedMembers.RuntimeHelpersOffsetToStringData.Resolve (loc);
6049                                 if (m == null)
6050                                         return;
6051
6052                                 PropertyExpr pe = new PropertyExpr (m, pinned_string.Location);
6053                                 //pe.InstanceExpression = pinned_string;
6054                                 pe.Resolve (new ResolveContext (ec.MemberContext)).Emit (ec);
6055
6056                                 ec.Emit (OpCodes.Add);
6057                                 vi.EmitAssign (ec);
6058                         }
6059
6060                         public override void EmitExit (EmitContext ec)
6061                         {
6062                                 ec.EmitNull ();
6063                                 pinned_string.EmitAssign (ec);
6064                         }
6065                 }
6066
6067                 public class VariableDeclaration : BlockVariable
6068                 {
6069                         public VariableDeclaration (FullNamedExpression type, LocalVariable li)
6070                                 : base (type, li)
6071                         {
6072                         }
6073
6074                         protected override Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
6075                         {
6076                                 if (!Variable.Type.IsPointer && li == Variable) {
6077                                         bc.Report.Error (209, TypeExpression.Location,
6078                                                 "The type of locals declared in a fixed statement must be a pointer type");
6079                                         return null;
6080                                 }
6081
6082                                 //
6083                                 // The rules for the possible declarators are pretty wise,
6084                                 // but the production on the grammar is more concise.
6085                                 //
6086                                 // So we have to enforce these rules here.
6087                                 //
6088                                 // We do not resolve before doing the case 1 test,
6089                                 // because the grammar is explicit in that the token &
6090                                 // is present, so we need to test for this particular case.
6091                                 //
6092
6093                                 if (initializer is Cast) {
6094                                         bc.Report.Error (254, initializer.Location, "The right hand side of a fixed statement assignment may not be a cast expression");
6095                                         return null;
6096                                 }
6097
6098                                 initializer = initializer.Resolve (bc);
6099
6100                                 if (initializer == null)
6101                                         return null;
6102
6103                                 //
6104                                 // Case 1: Array
6105                                 //
6106                                 if (initializer.Type.IsArray) {
6107                                         TypeSpec array_type = TypeManager.GetElementType (initializer.Type);
6108
6109                                         //
6110                                         // Provided that array_type is unmanaged,
6111                                         //
6112                                         if (!TypeManager.VerifyUnmanaged (bc.Module, array_type, loc))
6113                                                 return null;
6114
6115                                         //
6116                                         // and T* is implicitly convertible to the
6117                                         // pointer type given in the fixed statement.
6118                                         //
6119                                         ArrayPtr array_ptr = new ArrayPtr (initializer, array_type, loc);
6120
6121                                         Expression converted = Convert.ImplicitConversionRequired (bc, array_ptr.Resolve (bc), li.Type, loc);
6122                                         if (converted == null)
6123                                                 return null;
6124
6125                                         //
6126                                         // fixed (T* e_ptr = (e == null || e.Length == 0) ? null : converted [0])
6127                                         //
6128                                         converted = new Conditional (new BooleanExpression (new Binary (Binary.Operator.LogicalOr,
6129                                                 new Binary (Binary.Operator.Equality, initializer, new NullLiteral (loc)),
6130                                                 new Binary (Binary.Operator.Equality, new MemberAccess (initializer, "Length"), new IntConstant (bc.BuiltinTypes, 0, loc)))),
6131                                                         new NullLiteral (loc),
6132                                                         converted, loc);
6133
6134                                         converted = converted.Resolve (bc);
6135
6136                                         return new ExpressionEmitter (converted, li);
6137                                 }
6138
6139                                 //
6140                                 // Case 2: string
6141                                 //
6142                                 if (initializer.Type.BuiltinType == BuiltinTypeSpec.Type.String) {
6143                                         return new StringEmitter (initializer, li).Resolve (bc);
6144                                 }
6145
6146                                 // Case 3: fixed buffer
6147                                 if (initializer is FixedBufferPtr) {
6148                                         return new ExpressionEmitter (initializer, li);
6149                                 }
6150
6151                                 //
6152                                 // Case 4: & object.
6153                                 //
6154                                 bool already_fixed = true;
6155                                 Unary u = initializer as Unary;
6156                                 if (u != null && u.Oper == Unary.Operator.AddressOf) {
6157                                         IVariableReference vr = u.Expr as IVariableReference;
6158                                         if (vr == null || !vr.IsFixed) {
6159                                                 already_fixed = false;
6160                                         }
6161                                 }
6162
6163                                 if (already_fixed) {
6164                                         bc.Report.Error (213, loc, "You cannot use the fixed statement to take the address of an already fixed expression");
6165                                 }
6166
6167                                 initializer = Convert.ImplicitConversionRequired (bc, initializer, li.Type, loc);
6168                                 return new ExpressionEmitter (initializer, li);
6169                         }
6170                 }
6171
6172
6173                 VariableDeclaration decl;
6174                 Statement statement;
6175                 bool has_ret;
6176
6177                 public Fixed (VariableDeclaration decl, Statement stmt, Location l)
6178                 {
6179                         this.decl = decl;
6180                         statement = stmt;
6181                         loc = l;
6182                 }
6183
6184                 #region Properties
6185
6186                 public Statement Statement {
6187                         get {
6188                                 return statement;
6189                         }
6190                 }
6191
6192                 public BlockVariable Variables {
6193                         get {
6194                                 return decl;
6195                         }
6196                 }
6197
6198                 #endregion
6199
6200                 public override bool Resolve (BlockContext bc)
6201                 {
6202                         using (bc.Set (ResolveContext.Options.FixedInitializerScope)) {
6203                                 if (!decl.Resolve (bc))
6204                                         return false;
6205                         }
6206
6207                         return statement.Resolve (bc);
6208                 }
6209
6210                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6211                 {
6212                         decl.FlowAnalysis (fc);
6213                         return statement.FlowAnalysis (fc);
6214                 }
6215                 
6216                 protected override void DoEmit (EmitContext ec)
6217                 {
6218                         decl.Variable.CreateBuilder (ec);
6219                         decl.Initializer.Emit (ec);
6220                         if (decl.Declarators != null) {
6221                                 foreach (var d in decl.Declarators) {
6222                                         d.Variable.CreateBuilder (ec);
6223                                         d.Initializer.Emit (ec);
6224                                 }
6225                         }
6226
6227                         statement.Emit (ec);
6228
6229                         if (has_ret)
6230                                 return;
6231
6232                         //
6233                         // Clear the pinned variable
6234                         //
6235                         ((Emitter) decl.Initializer).EmitExit (ec);
6236                         if (decl.Declarators != null) {
6237                                 foreach (var d in decl.Declarators) {
6238                                         ((Emitter)d.Initializer).EmitExit (ec);
6239                                 }
6240                         }
6241                 }
6242
6243                 public override Reachability MarkReachable (Reachability rc)
6244                 {
6245                         base.MarkReachable (rc);
6246
6247                         decl.MarkReachable (rc);
6248
6249                         rc = statement.MarkReachable (rc);
6250
6251                         // TODO: What if there is local exit?
6252                         has_ret = rc.IsUnreachable;
6253                         return rc;
6254                 }
6255
6256                 protected override void CloneTo (CloneContext clonectx, Statement t)
6257                 {
6258                         Fixed target = (Fixed) t;
6259
6260                         target.decl = (VariableDeclaration) decl.Clone (clonectx);
6261                         target.statement = statement.Clone (clonectx);
6262                 }
6263                 
6264                 public override object Accept (StructuralVisitor visitor)
6265                 {
6266                         return visitor.Visit (this);
6267                 }
6268         }
6269
6270         public class Catch : Statement
6271         {
6272                 class FilterStatement : Statement
6273                 {
6274                         readonly Catch ctch;
6275
6276                         public FilterStatement (Catch ctch)
6277                         {
6278                                 this.ctch = ctch;
6279                         }
6280
6281                         protected override void CloneTo (CloneContext clonectx, Statement target)
6282                         {
6283                         }
6284
6285                         protected override void DoEmit (EmitContext ec)
6286                         {
6287                                 if (ctch.li != null) {
6288                                         if (ctch.hoisted_temp != null)
6289                                                 ctch.hoisted_temp.Emit (ec);
6290                                         else
6291                                                 ctch.li.Emit (ec);
6292                                 }
6293
6294                                 var expr_start = ec.DefineLabel ();
6295                                 var end = ec.DefineLabel ();
6296
6297                                 ec.Emit (OpCodes.Brtrue_S, expr_start);
6298                                 ec.EmitInt (0);
6299                                 ec.Emit (OpCodes.Br, end);
6300                                 ec.MarkLabel (expr_start);
6301
6302                                 ctch.Filter.Emit (ec);
6303
6304                                 ec.MarkLabel (end);
6305                                 ec.Emit (OpCodes.Endfilter);
6306                                 ec.BeginFilterHandler ();
6307                                 ec.Emit (OpCodes.Pop);
6308                         }
6309
6310                         protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6311                         {
6312                                 ctch.Filter.FlowAnalysis (fc);
6313                                 return true;
6314                         }
6315
6316                         public override bool Resolve (BlockContext bc)
6317                         {
6318                                 ctch.Filter = ctch.Filter.Resolve (bc);
6319                                 var c = ctch.Filter as Constant;
6320                                 if (c != null && !c.IsDefaultValue) {
6321                                         bc.Report.Warning (7095, 1, ctch.Filter.Location, "Exception filter expression is a constant");
6322                                 }
6323
6324                                 return true;
6325                         }
6326                 }
6327
6328                 ExplicitBlock block;
6329                 LocalVariable li;
6330                 FullNamedExpression type_expr;
6331                 CompilerAssign assign;
6332                 TypeSpec type;
6333                 LocalTemporary hoisted_temp;
6334
6335                 public Catch (ExplicitBlock block, Location loc)
6336                 {
6337                         this.block = block;
6338                         this.loc = loc;
6339                 }
6340
6341                 #region Properties
6342
6343                 public ExplicitBlock Block {
6344                         get {
6345                                 return block;
6346                         }
6347                 }
6348
6349                 public TypeSpec CatchType {
6350                         get {
6351                                 return type;
6352                         }
6353                 }
6354
6355                 public Expression Filter {
6356                         get; set;
6357                 }
6358
6359                 public bool IsGeneral {
6360                         get {
6361                                 return type_expr == null;
6362                         }
6363                 }
6364
6365                 public FullNamedExpression TypeExpression {
6366                         get {
6367                                 return type_expr;
6368                         }
6369                         set {
6370                                 type_expr = value;
6371                         }
6372                 }
6373
6374                 public LocalVariable Variable {
6375                         get {
6376                                 return li;
6377                         }
6378                         set {
6379                                 li = value;
6380                         }
6381                 }
6382
6383                 #endregion
6384
6385                 protected override void DoEmit (EmitContext ec)
6386                 {
6387                         if (Filter != null) {
6388                                 ec.BeginExceptionFilterBlock ();
6389                                 ec.Emit (OpCodes.Isinst, IsGeneral ? ec.BuiltinTypes.Object : CatchType);
6390
6391                                 if (li != null)
6392                                         EmitCatchVariableStore (ec);
6393                         } else {
6394                                 if (IsGeneral)
6395                                         ec.BeginCatchBlock (ec.BuiltinTypes.Object);
6396                                 else
6397                                         ec.BeginCatchBlock (CatchType);
6398
6399                                 if (li != null) {
6400                                         EmitCatchVariableStore (ec);
6401                                 } else {
6402                                         ec.Emit (OpCodes.Pop);
6403                                 }
6404                         }
6405
6406                         Block.Emit (ec);
6407                 }
6408
6409                 void EmitCatchVariableStore (EmitContext ec)
6410                 {
6411                         li.CreateBuilder (ec);
6412
6413                         //
6414                         // Special case hoisted catch variable, we have to use a temporary variable
6415                         // to pass via anonymous storey initialization with the value still on top
6416                         // of the stack
6417                         //
6418                         if (li.HoistedVariant != null) {
6419                                 hoisted_temp = new LocalTemporary (li.Type);
6420                                 hoisted_temp.Store (ec);
6421
6422                                 // switch to assigning from the temporary variable and not from top of the stack
6423                                 assign.UpdateSource (hoisted_temp);
6424                         }
6425                 }
6426
6427                 public override bool Resolve (BlockContext ec)
6428                 {
6429                         using (ec.Set (ResolveContext.Options.CatchScope)) {
6430                                 if (type_expr != null) {
6431                                         type = type_expr.ResolveAsType (ec);
6432                                         if (type == null)
6433                                                 return false;
6434
6435                                         if (type.BuiltinType != BuiltinTypeSpec.Type.Exception && !TypeSpec.IsBaseClass (type, ec.BuiltinTypes.Exception, false)) {
6436                                                 ec.Report.Error (155, loc, "The type caught or thrown must be derived from System.Exception");
6437                                         } else if (li != null) {
6438                                                 li.Type = type;
6439                                                 li.PrepareAssignmentAnalysis (ec);
6440
6441                                                 // source variable is at the top of the stack
6442                                                 Expression source = new EmptyExpression (li.Type);
6443                                                 if (li.Type.IsGenericParameter)
6444                                                         source = new UnboxCast (source, li.Type);
6445
6446                                                 //
6447                                                 // Uses Location.Null to hide from symbol file
6448                                                 //
6449                                                 assign = new CompilerAssign (new LocalVariableReference (li, Location.Null), source, Location.Null);
6450                                                 Block.AddScopeStatement (new StatementExpression (assign, Location.Null));
6451                                         }
6452                                 }
6453
6454                                 if (Filter != null) {
6455                                         Block.AddScopeStatement (new FilterStatement (this));
6456                                 }
6457
6458                                 Block.SetCatchBlock ();
6459                                 return Block.Resolve (ec);
6460                         }
6461                 }
6462
6463                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6464                 {
6465                         if (li != null) {
6466                                 fc.SetVariableAssigned (li.VariableInfo, true);
6467                         }
6468
6469                         return block.FlowAnalysis (fc);
6470                 }
6471
6472                 public override Reachability MarkReachable (Reachability rc)
6473                 {
6474                         base.MarkReachable (rc);
6475
6476                         var c = Filter as Constant;
6477                         if (c != null && c.IsDefaultValue)
6478                                 return Reachability.CreateUnreachable ();
6479
6480                         return block.MarkReachable (rc);
6481                 }
6482
6483                 protected override void CloneTo (CloneContext clonectx, Statement t)
6484                 {
6485                         Catch target = (Catch) t;
6486
6487                         if (type_expr != null)
6488                                 target.type_expr = (FullNamedExpression) type_expr.Clone (clonectx);
6489
6490                         if (Filter != null)
6491                                 target.Filter = Filter.Clone (clonectx);
6492
6493                         target.block = (ExplicitBlock) clonectx.LookupBlock (block);
6494                 }
6495         }
6496
6497         public class TryFinally : TryFinallyBlock
6498         {
6499                 ExplicitBlock fini;
6500                 List<DefiniteAssignmentBitSet> try_exit_dat;
6501
6502                 public TryFinally (Statement stmt, ExplicitBlock fini, Location loc)
6503                          : base (stmt, loc)
6504                 {
6505                         this.fini = fini;
6506                 }
6507
6508                 public ExplicitBlock FinallyBlock {
6509                         get {
6510                                 return fini;
6511                         }
6512                 }
6513
6514                 public void RegisterForControlExitCheck (DefiniteAssignmentBitSet vector)
6515                 {
6516                         if (try_exit_dat == null)
6517                                 try_exit_dat = new List<DefiniteAssignmentBitSet> ();
6518
6519                         try_exit_dat.Add (vector);
6520                 }
6521
6522                 public override bool Resolve (BlockContext bc)
6523                 {
6524                         bool ok = base.Resolve (bc);
6525
6526                         fini.SetFinallyBlock ();
6527                         using (bc.Set (ResolveContext.Options.FinallyScope)) {
6528                                 ok &= fini.Resolve (bc);
6529                         }
6530
6531                         return ok;
6532                 }
6533
6534                 protected override void EmitTryBody (EmitContext ec)
6535                 {
6536                         stmt.Emit (ec);
6537                 }
6538
6539                 public override void EmitFinallyBody (EmitContext ec)
6540                 {
6541                         fini.Emit (ec);
6542                 }
6543
6544                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6545                 {
6546                         var da = fc.BranchDefiniteAssignment ();
6547
6548                         var tf = fc.TryFinally;
6549                         fc.TryFinally = this;
6550
6551                         var res_stmt = Statement.FlowAnalysis (fc);
6552
6553                         fc.TryFinally = tf;
6554
6555                         var try_da = fc.DefiniteAssignment;
6556                         fc.DefiniteAssignment = da;
6557
6558                         var res_fin = fini.FlowAnalysis (fc);
6559
6560                         if (try_exit_dat != null) {
6561                                 //
6562                                 // try block has global exit but we need to run definite assignment check
6563                                 // for parameter block out parameter after finally block because it's always
6564                                 // executed before exit
6565                                 //
6566                                 foreach (var try_da_part in try_exit_dat)
6567                                         fc.ParametersBlock.CheckControlExit (fc, fc.DefiniteAssignment | try_da_part);
6568
6569                                 try_exit_dat = null;
6570                         }
6571
6572                         fc.DefiniteAssignment |= try_da;
6573                         return res_stmt | res_fin;
6574                 }
6575
6576                 public override Reachability MarkReachable (Reachability rc)
6577                 {
6578                         //
6579                         // Mark finally block first for any exit statement in try block
6580                         // to know whether the code which follows finally is reachable
6581                         //
6582                         return fini.MarkReachable (rc) | base.MarkReachable (rc);
6583                 }
6584
6585                 protected override void CloneTo (CloneContext clonectx, Statement t)
6586                 {
6587                         TryFinally target = (TryFinally) t;
6588
6589                         target.stmt = stmt.Clone (clonectx);
6590                         if (fini != null)
6591                                 target.fini = (ExplicitBlock) clonectx.LookupBlock (fini);
6592                 }
6593                 
6594                 public override object Accept (StructuralVisitor visitor)
6595                 {
6596                         return visitor.Visit (this);
6597                 }
6598         }
6599
6600         public class TryCatch : ExceptionStatement
6601         {
6602                 public Block Block;
6603                 List<Catch> clauses;
6604                 readonly bool inside_try_finally;
6605
6606                 public TryCatch (Block block, List<Catch> catch_clauses, Location l, bool inside_try_finally)
6607                         : base (l)
6608                 {
6609                         this.Block = block;
6610                         this.clauses = catch_clauses;
6611                         this.inside_try_finally = inside_try_finally;
6612                 }
6613
6614                 public List<Catch> Clauses {
6615                         get {
6616                                 return clauses;
6617                         }
6618                 }
6619
6620                 public bool IsTryCatchFinally {
6621                         get {
6622                                 return inside_try_finally;
6623                         }
6624                 }
6625
6626                 public override bool Resolve (BlockContext bc)
6627                 {
6628                         bool ok;
6629
6630                         using (bc.Set (ResolveContext.Options.TryScope)) {
6631                                 parent = bc.CurrentTryBlock;
6632
6633                                 if (IsTryCatchFinally) {
6634                                         ok = Block.Resolve (bc);
6635                                 } else {
6636                                         using (bc.Set (ResolveContext.Options.TryWithCatchScope)) {
6637                                                 bc.CurrentTryBlock = this;
6638                                                 ok = Block.Resolve (bc);
6639                                                 bc.CurrentTryBlock = parent;
6640                                         }
6641                                 }
6642                         }
6643
6644                         for (int i = 0; i < clauses.Count; ++i) {
6645                                 var c = clauses[i];
6646
6647                                 ok &= c.Resolve (bc);
6648
6649                                 if (c.Filter != null)
6650                                         continue;
6651
6652                                 TypeSpec resolved_type = c.CatchType;
6653                                 if (resolved_type == null)
6654                                         continue;
6655
6656                                 for (int ii = 0; ii < clauses.Count; ++ii) {
6657                                         if (ii == i)
6658                                                 continue;
6659
6660                                         if (clauses[ii].Filter != null)
6661                                                 continue;
6662
6663                                         if (clauses[ii].IsGeneral) {
6664                                                 if (resolved_type.BuiltinType != BuiltinTypeSpec.Type.Exception)
6665                                                         continue;
6666
6667                                                 if (!bc.Module.DeclaringAssembly.WrapNonExceptionThrows)
6668                                                         continue;
6669
6670                                                 if (!bc.Module.PredefinedAttributes.RuntimeCompatibility.IsDefined)
6671                                                         continue;
6672
6673                                                 bc.Report.Warning (1058, 1, c.loc,
6674                                                         "A previous catch clause already catches all exceptions. All non-exceptions thrown will be wrapped in a `System.Runtime.CompilerServices.RuntimeWrappedException'");
6675
6676                                                 continue;
6677                                         }
6678
6679                                         if (ii >= i)
6680                                                 continue;
6681
6682                                         var ct = clauses[ii].CatchType;
6683                                         if (ct == null)
6684                                                 continue;
6685
6686                                         if (resolved_type == ct || TypeSpec.IsBaseClass (resolved_type, ct, true)) {
6687                                                 bc.Report.Error (160, c.loc,
6688                                                         "A previous catch clause already catches all exceptions of this or a super type `{0}'",
6689                                                         ct.GetSignatureForError ());
6690                                                 ok = false;
6691                                         }
6692                                 }
6693                         }
6694
6695                         return base.Resolve (bc) && ok;
6696                 }
6697
6698                 protected sealed override void DoEmit (EmitContext ec)
6699                 {
6700                         if (!inside_try_finally)
6701                                 EmitTryBodyPrepare (ec);
6702
6703                         Block.Emit (ec);
6704
6705                         foreach (Catch c in clauses)
6706                                 c.Emit (ec);
6707
6708                         if (!inside_try_finally)
6709                                 ec.EndExceptionBlock ();
6710                 }
6711
6712                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6713                 {
6714                         var start_fc = fc.BranchDefiniteAssignment ();
6715                         var res = Block.FlowAnalysis (fc);
6716
6717                         DefiniteAssignmentBitSet try_fc = res ? null : fc.DefiniteAssignment;
6718
6719                         foreach (var c in clauses) {
6720                                 fc.DefiniteAssignment = new DefiniteAssignmentBitSet (start_fc);
6721                                 if (!c.FlowAnalysis (fc)) {
6722                                         if (try_fc == null)
6723                                                 try_fc = fc.DefiniteAssignment;
6724                                         else
6725                                                 try_fc &= fc.DefiniteAssignment;
6726
6727                                         res = false;
6728                                 }
6729                         }
6730
6731                         fc.DefiniteAssignment = try_fc ?? start_fc;
6732                         parent = null;
6733                         return res;
6734                 }
6735
6736                 public override Reachability MarkReachable (Reachability rc)
6737                 {
6738                         if (rc.IsUnreachable)
6739                                 return rc;
6740
6741                         base.MarkReachable (rc);
6742
6743                         var tc_rc = Block.MarkReachable (rc);
6744
6745                         foreach (var c in clauses)
6746                                 tc_rc &= c.MarkReachable (rc);
6747
6748                         return tc_rc;
6749                 }
6750
6751                 protected override void CloneTo (CloneContext clonectx, Statement t)
6752                 {
6753                         TryCatch target = (TryCatch) t;
6754
6755                         target.Block = clonectx.LookupBlock (Block);
6756                         if (clauses != null){
6757                                 target.clauses = new List<Catch> ();
6758                                 foreach (Catch c in clauses)
6759                                         target.clauses.Add ((Catch) c.Clone (clonectx));
6760                         }
6761                 }
6762
6763                 public override object Accept (StructuralVisitor visitor)
6764                 {
6765                         return visitor.Visit (this);
6766                 }
6767         }
6768
6769         public class Using : TryFinallyBlock
6770         {
6771                 public class VariableDeclaration : BlockVariable
6772                 {
6773                         Statement dispose_call;
6774
6775                         public VariableDeclaration (FullNamedExpression type, LocalVariable li)
6776                                 : base (type, li)
6777                         {
6778                         }
6779
6780                         public VariableDeclaration (LocalVariable li, Location loc)
6781                                 : base (li)
6782                         {
6783                                 this.loc = loc;
6784                         }
6785
6786                         public VariableDeclaration (Expression expr)
6787                                 : base (null)
6788                         {
6789                                 loc = expr.Location;
6790                                 Initializer = expr;
6791                         }
6792
6793                         #region Properties
6794
6795                         public bool IsNested { get; private set; }
6796
6797                         #endregion
6798
6799                         public void EmitDispose (EmitContext ec)
6800                         {
6801                                 dispose_call.Emit (ec);
6802                         }
6803
6804                         public override bool Resolve (BlockContext bc)
6805                         {
6806                                 if (IsNested)
6807                                         return true;
6808
6809                                 return base.Resolve (bc, false);
6810                         }
6811
6812                         public Expression ResolveExpression (BlockContext bc)
6813                         {
6814                                 var e = Initializer.Resolve (bc);
6815                                 if (e == null)
6816                                         return null;
6817
6818                                 li = LocalVariable.CreateCompilerGenerated (e.Type, bc.CurrentBlock, loc);
6819                                 Initializer = ResolveInitializer (bc, Variable, e);
6820                                 return e;
6821                         }
6822
6823                         protected override Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
6824                         {
6825                                 if (li.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
6826                                         initializer = initializer.Resolve (bc);
6827                                         if (initializer == null)
6828                                                 return null;
6829
6830                                         // Once there is dynamic used defer conversion to runtime even if we know it will never succeed
6831                                         Arguments args = new Arguments (1);
6832                                         args.Add (new Argument (initializer));
6833                                         initializer = new DynamicConversion (bc.BuiltinTypes.IDisposable, 0, args, initializer.Location).Resolve (bc);
6834                                         if (initializer == null)
6835                                                 return null;
6836
6837                                         var var = LocalVariable.CreateCompilerGenerated (initializer.Type, bc.CurrentBlock, loc);
6838                                         dispose_call = CreateDisposeCall (bc, var);
6839                                         dispose_call.Resolve (bc);
6840
6841                                         return base.ResolveInitializer (bc, li, new SimpleAssign (var.CreateReferenceExpression (bc, loc), initializer, loc));
6842                                 }
6843
6844                                 if (li == Variable) {
6845                                         CheckIDiposableConversion (bc, li, initializer);
6846                                         dispose_call = CreateDisposeCall (bc, li);
6847                                         dispose_call.Resolve (bc);
6848                                 }
6849
6850                                 return base.ResolveInitializer (bc, li, initializer);
6851                         }
6852
6853                         protected virtual void CheckIDiposableConversion (BlockContext bc, LocalVariable li, Expression initializer)
6854                         {
6855                                 var type = li.Type;
6856
6857                                 if (type.BuiltinType != BuiltinTypeSpec.Type.IDisposable && !CanConvertToIDisposable (bc, type)) {
6858                                         if (type.IsNullableType) {
6859                                                 // it's handled in CreateDisposeCall
6860                                                 return;
6861                                         }
6862
6863                                         if (type != InternalType.ErrorType) {
6864                                                 bc.Report.SymbolRelatedToPreviousError (type);
6865                                                 var loc = type_expr == null ? initializer.Location : type_expr.Location;
6866                                                 bc.Report.Error (1674, loc, "`{0}': type used in a using statement must be implicitly convertible to `System.IDisposable'",
6867                                                         type.GetSignatureForError ());
6868                                         }
6869
6870                                         return;
6871                                 }
6872                         }
6873
6874                         static bool CanConvertToIDisposable (BlockContext bc, TypeSpec type)
6875                         {
6876                                 var target = bc.BuiltinTypes.IDisposable;
6877                                 var tp = type as TypeParameterSpec;
6878                                 if (tp != null)
6879                                         return Convert.ImplicitTypeParameterConversion (null, tp, target) != null;
6880
6881                                 return type.ImplementsInterface (target, false);
6882                         }
6883
6884                         protected virtual Statement CreateDisposeCall (BlockContext bc, LocalVariable lv)
6885                         {
6886                                 var lvr = lv.CreateReferenceExpression (bc, lv.Location);
6887                                 var type = lv.Type;
6888                                 var loc = lv.Location;
6889
6890                                 var idt = bc.BuiltinTypes.IDisposable;
6891                                 var m = bc.Module.PredefinedMembers.IDisposableDispose.Resolve (loc);
6892
6893                                 var dispose_mg = MethodGroupExpr.CreatePredefined (m, idt, loc);
6894                                 dispose_mg.InstanceExpression = type.IsNullableType ?
6895                                         new Cast (new TypeExpression (idt, loc), lvr, loc).Resolve (bc) :
6896                                         lvr;
6897
6898                                 //
6899                                 // Hide it from symbol file via null location
6900                                 //
6901                                 Statement dispose = new StatementExpression (new Invocation (dispose_mg, null), Location.Null);
6902
6903                                 // Add conditional call when disposing possible null variable
6904                                 if (!TypeSpec.IsValueType (type) || type.IsNullableType)
6905                                         dispose = new If (new Binary (Binary.Operator.Inequality, lvr, new NullLiteral (loc)), dispose, dispose.loc);
6906
6907                                 return dispose;
6908                         }
6909
6910                         public void ResolveDeclaratorInitializer (BlockContext bc)
6911                         {
6912                                 Initializer = base.ResolveInitializer (bc, Variable, Initializer);
6913                         }
6914
6915                         public Statement RewriteUsingDeclarators (BlockContext bc, Statement stmt)
6916                         {
6917                                 for (int i = declarators.Count - 1; i >= 0; --i) {
6918                                         var d = declarators [i];
6919                                         var vd = new VariableDeclaration (d.Variable, d.Variable.Location);
6920                                         vd.Initializer = d.Initializer;
6921                                         vd.IsNested = true;
6922                                         vd.dispose_call = CreateDisposeCall (bc, d.Variable);
6923                                         vd.dispose_call.Resolve (bc);
6924
6925                                         stmt = new Using (vd, stmt, d.Variable.Location);
6926                                 }
6927
6928                                 declarators = null;
6929                                 return stmt;
6930                         }       
6931
6932                         public override object Accept (StructuralVisitor visitor)
6933                         {
6934                                 return visitor.Visit (this);
6935                         }       
6936                 }
6937
6938                 VariableDeclaration decl;
6939
6940                 public Using (VariableDeclaration decl, Statement stmt, Location loc)
6941                         : base (stmt, loc)
6942                 {
6943                         this.decl = decl;
6944                 }
6945
6946                 public Using (Expression expr, Statement stmt, Location loc)
6947                         : base (stmt, loc)
6948                 {
6949                         this.decl = new VariableDeclaration (expr);
6950                 }
6951
6952                 #region Properties
6953
6954                 public Expression Expr {
6955                         get {
6956                                 return decl.Variable == null ? decl.Initializer : null;
6957                         }
6958                 }
6959
6960                 public BlockVariable Variables {
6961                         get {
6962                                 return decl;
6963                         }
6964                 }
6965
6966                 #endregion
6967
6968                 public override void Emit (EmitContext ec)
6969                 {
6970                         //
6971                         // Don't emit sequence point it will be set on variable declaration
6972                         //
6973                         DoEmit (ec);
6974                 }
6975
6976                 protected override void EmitTryBodyPrepare (EmitContext ec)
6977                 {
6978                         decl.Emit (ec);
6979                         base.EmitTryBodyPrepare (ec);
6980                 }
6981
6982                 protected override void EmitTryBody (EmitContext ec)
6983                 {
6984                         stmt.Emit (ec);
6985                 }
6986
6987                 public override void EmitFinallyBody (EmitContext ec)
6988                 {
6989                         decl.EmitDispose (ec);
6990                 }
6991
6992                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6993                 {
6994                         decl.FlowAnalysis (fc);
6995                         return stmt.FlowAnalysis (fc);
6996                 }
6997
6998                 public override Reachability MarkReachable (Reachability rc)
6999                 {
7000                         decl.MarkReachable (rc);
7001                         return base.MarkReachable (rc);
7002                 }
7003
7004                 public override bool Resolve (BlockContext ec)
7005                 {
7006                         VariableReference vr;
7007                         bool vr_locked = false;
7008
7009                         using (ec.Set (ResolveContext.Options.UsingInitializerScope)) {
7010                                 if (decl.Variable == null) {
7011                                         vr = decl.ResolveExpression (ec) as VariableReference;
7012                                         if (vr != null) {
7013                                                 vr_locked = vr.IsLockedByStatement;
7014                                                 vr.IsLockedByStatement = true;
7015                                         }
7016                                 } else {
7017                                         if (decl.IsNested) {
7018                                                 decl.ResolveDeclaratorInitializer (ec);
7019                                         } else {
7020                                                 if (!decl.Resolve (ec))
7021                                                         return false;
7022
7023                                                 if (decl.Declarators != null) {
7024                                                         stmt = decl.RewriteUsingDeclarators (ec, stmt);
7025                                                 }
7026                                         }
7027
7028                                         vr = null;
7029                                 }
7030                         }
7031
7032                         var ok = base.Resolve (ec);
7033
7034                         if (vr != null)
7035                                 vr.IsLockedByStatement = vr_locked;
7036
7037                         return ok;
7038                 }
7039
7040                 protected override void CloneTo (CloneContext clonectx, Statement t)
7041                 {
7042                         Using target = (Using) t;
7043
7044                         target.decl = (VariableDeclaration) decl.Clone (clonectx);
7045                         target.stmt = stmt.Clone (clonectx);
7046                 }
7047
7048                 public override object Accept (StructuralVisitor visitor)
7049                 {
7050                         return visitor.Visit (this);
7051                 }
7052         }
7053
7054         /// <summary>
7055         ///   Implementation of the foreach C# statement
7056         /// </summary>
7057         public class Foreach : LoopStatement
7058         {
7059                 abstract class IteratorStatement : Statement
7060                 {
7061                         protected readonly Foreach for_each;
7062
7063                         protected IteratorStatement (Foreach @foreach)
7064                         {
7065                                 this.for_each = @foreach;
7066                                 this.loc = @foreach.expr.Location;
7067                         }
7068
7069                         protected override void CloneTo (CloneContext clonectx, Statement target)
7070                         {
7071                                 throw new NotImplementedException ();
7072                         }
7073
7074                         public override void Emit (EmitContext ec)
7075                         {
7076                                 if (ec.EmitAccurateDebugInfo) {
7077                                         ec.Emit (OpCodes.Nop);
7078                                 }
7079
7080                                 base.Emit (ec);
7081                         }
7082
7083                         protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7084                         {
7085                                 throw new NotImplementedException ();
7086                         }
7087                 }
7088
7089                 sealed class ArrayForeach : IteratorStatement
7090                 {
7091                         TemporaryVariableReference[] lengths;
7092                         Expression [] length_exprs;
7093                         StatementExpression[] counter;
7094                         TemporaryVariableReference[] variables;
7095
7096                         TemporaryVariableReference copy;
7097
7098                         public ArrayForeach (Foreach @foreach, int rank)
7099                                 : base (@foreach)
7100                         {
7101                                 counter = new StatementExpression[rank];
7102                                 variables = new TemporaryVariableReference[rank];
7103                                 length_exprs = new Expression [rank];
7104
7105                                 //
7106                                 // Only use temporary length variables when dealing with
7107                                 // multi-dimensional arrays
7108                                 //
7109                                 if (rank > 1)
7110                                         lengths = new TemporaryVariableReference [rank];
7111                         }
7112
7113                         public override bool Resolve (BlockContext ec)
7114                         {
7115                                 Block variables_block = for_each.variable.Block;
7116                                 copy = TemporaryVariableReference.Create (for_each.expr.Type, variables_block, loc);
7117                                 copy.Resolve (ec);
7118
7119                                 int rank = length_exprs.Length;
7120                                 Arguments list = new Arguments (rank);
7121                                 for (int i = 0; i < rank; i++) {
7122                                         var v = TemporaryVariableReference.Create (ec.BuiltinTypes.Int, variables_block, loc);
7123                                         variables[i] = v;
7124                                         counter[i] = new StatementExpression (new UnaryMutator (UnaryMutator.Mode.PostIncrement, v, Location.Null));
7125                                         counter[i].Resolve (ec);
7126
7127                                         if (rank == 1) {
7128                                                 length_exprs [i] = new MemberAccess (copy, "Length").Resolve (ec);
7129                                         } else {
7130                                                 lengths[i] = TemporaryVariableReference.Create (ec.BuiltinTypes.Int, variables_block, loc);
7131                                                 lengths[i].Resolve (ec);
7132
7133                                                 Arguments args = new Arguments (1);
7134                                                 args.Add (new Argument (new IntConstant (ec.BuiltinTypes, i, loc)));
7135                                                 length_exprs [i] = new Invocation (new MemberAccess (copy, "GetLength"), args).Resolve (ec);
7136                                         }
7137
7138                                         list.Add (new Argument (v));
7139                                 }
7140
7141                                 var access = new ElementAccess (copy, list, loc).Resolve (ec);
7142                                 if (access == null)
7143                                         return false;
7144
7145                                 TypeSpec var_type;
7146                                 if (for_each.type is VarExpr) {
7147                                         // Infer implicitly typed local variable from foreach array type
7148                                         var_type = access.Type;
7149                                 } else {
7150                                         var_type = for_each.type.ResolveAsType (ec);
7151
7152                                         if (var_type == null)
7153                                                 return false;
7154
7155                                         access = Convert.ExplicitConversion (ec, access, var_type, loc);
7156                                         if (access == null)
7157                                                 return false;
7158                                 }
7159
7160                                 for_each.variable.Type = var_type;
7161
7162                                 var variable_ref = new LocalVariableReference (for_each.variable, loc).Resolve (ec);
7163                                 if (variable_ref == null)
7164                                         return false;
7165
7166                                 for_each.body.AddScopeStatement (new StatementExpression (new CompilerAssign (variable_ref, access, Location.Null), for_each.type.Location));
7167
7168                                 return for_each.body.Resolve (ec);
7169                         }
7170
7171                         protected override void DoEmit (EmitContext ec)
7172                         {
7173                                 copy.EmitAssign (ec, for_each.expr);
7174
7175                                 int rank = length_exprs.Length;
7176                                 Label[] test = new Label [rank];
7177                                 Label[] loop = new Label [rank];
7178
7179                                 for (int i = 0; i < rank; i++) {
7180                                         test [i] = ec.DefineLabel ();
7181                                         loop [i] = ec.DefineLabel ();
7182
7183                                         if (lengths != null)
7184                                                 lengths [i].EmitAssign (ec, length_exprs [i]);
7185                                 }
7186
7187                                 IntConstant zero = new IntConstant (ec.BuiltinTypes, 0, loc);
7188                                 for (int i = 0; i < rank; i++) {
7189                                         variables [i].EmitAssign (ec, zero);
7190
7191                                         ec.Emit (OpCodes.Br, test [i]);
7192                                         ec.MarkLabel (loop [i]);
7193                                 }
7194
7195                                 for_each.body.Emit (ec);
7196
7197                                 ec.MarkLabel (ec.LoopBegin);
7198                                 ec.Mark (for_each.expr.Location);
7199
7200                                 for (int i = rank - 1; i >= 0; i--){
7201                                         counter [i].Emit (ec);
7202
7203                                         ec.MarkLabel (test [i]);
7204                                         variables [i].Emit (ec);
7205
7206                                         if (lengths != null)
7207                                                 lengths [i].Emit (ec);
7208                                         else
7209                                                 length_exprs [i].Emit (ec);
7210
7211                                         ec.Emit (OpCodes.Blt, loop [i]);
7212                                 }
7213
7214                                 ec.MarkLabel (ec.LoopEnd);
7215                         }
7216                 }
7217
7218                 sealed class CollectionForeach : IteratorStatement, OverloadResolver.IErrorHandler
7219                 {
7220                         class RuntimeDispose : Using.VariableDeclaration
7221                         {
7222                                 public RuntimeDispose (LocalVariable lv, Location loc)
7223                                         : base (lv, loc)
7224                                 {
7225                                 }
7226
7227                                 protected override void CheckIDiposableConversion (BlockContext bc, LocalVariable li, Expression initializer)
7228                                 {
7229                                         // Defered to runtime check
7230                                 }
7231
7232                                 protected override Statement CreateDisposeCall (BlockContext bc, LocalVariable lv)
7233                                 {
7234                                         var idt = bc.BuiltinTypes.IDisposable;
7235
7236                                         //
7237                                         // Fabricates code like
7238                                         //
7239                                         // if ((temp = vr as IDisposable) != null) temp.Dispose ();
7240                                         //
7241
7242                                         var dispose_variable = LocalVariable.CreateCompilerGenerated (idt, bc.CurrentBlock, loc);
7243
7244                                         var idisaposable_test = new Binary (Binary.Operator.Inequality, new CompilerAssign (
7245                                                 dispose_variable.CreateReferenceExpression (bc, loc),
7246                                                 new As (lv.CreateReferenceExpression (bc, loc), new TypeExpression (dispose_variable.Type, loc), loc),
7247                                                 loc), new NullLiteral (loc));
7248
7249                                         var m = bc.Module.PredefinedMembers.IDisposableDispose.Resolve (loc);
7250
7251                                         var dispose_mg = MethodGroupExpr.CreatePredefined (m, idt, loc);
7252                                         dispose_mg.InstanceExpression = dispose_variable.CreateReferenceExpression (bc, loc);
7253
7254                                         Statement dispose = new StatementExpression (new Invocation (dispose_mg, null));
7255                                         return new If (idisaposable_test, dispose, loc);
7256                                 }
7257                         }
7258
7259                         LocalVariable variable;
7260                         Expression expr;
7261                         Statement statement;
7262                         ExpressionStatement init;
7263                         TemporaryVariableReference enumerator_variable;
7264                         bool ambiguous_getenumerator_name;
7265
7266                         public CollectionForeach (Foreach @foreach, LocalVariable var, Expression expr)
7267                                 : base (@foreach)
7268                         {
7269                                 this.variable = var;
7270                                 this.expr = expr;
7271                         }
7272
7273                         void Error_WrongEnumerator (ResolveContext rc, MethodSpec enumerator)
7274                         {
7275                                 rc.Report.SymbolRelatedToPreviousError (enumerator);
7276                                 rc.Report.Error (202, loc,
7277                                         "foreach statement requires that the return type `{0}' of `{1}' must have a suitable public MoveNext method and public Current property",
7278                                                 enumerator.ReturnType.GetSignatureForError (), enumerator.GetSignatureForError ());
7279                         }
7280
7281                         MethodGroupExpr ResolveGetEnumerator (ResolveContext rc)
7282                         {
7283                                 //
7284                                 // Option 1: Try to match by name GetEnumerator first
7285                                 //
7286                                 var mexpr = Expression.MemberLookup (rc, false, expr.Type,
7287                                         "GetEnumerator", 0, Expression.MemberLookupRestrictions.ExactArity, loc);               // TODO: What if CS0229 ?
7288
7289                                 var mg = mexpr as MethodGroupExpr;
7290                                 if (mg != null) {
7291                                         mg.InstanceExpression = expr;
7292                                         Arguments args = new Arguments (0);
7293                                         mg = mg.OverloadResolve (rc, ref args, this, OverloadResolver.Restrictions.ProbingOnly);
7294
7295                                         // For ambiguous GetEnumerator name warning CS0278 was reported, but Option 2 could still apply
7296                                         if (ambiguous_getenumerator_name)
7297                                                 mg = null;
7298
7299                                         if (mg != null && args.Count == 0 && !mg.BestCandidate.IsStatic && mg.BestCandidate.IsPublic) {
7300                                                 return mg;
7301                                         }
7302                                 }
7303
7304                                 //
7305                                 // Option 2: Try to match using IEnumerable interfaces with preference of generic version
7306                                 //
7307                                 var t = expr.Type;
7308                                 PredefinedMember<MethodSpec> iface_candidate = null;
7309                                 var ptypes = rc.Module.PredefinedTypes;
7310                                 var gen_ienumerable = ptypes.IEnumerableGeneric;
7311                                 if (!gen_ienumerable.Define ())
7312                                         gen_ienumerable = null;
7313
7314                                 var ifaces = t.Interfaces;
7315                                 if (ifaces != null) {
7316                                         foreach (var iface in ifaces) {
7317                                                 if (gen_ienumerable != null && iface.MemberDefinition == gen_ienumerable.TypeSpec.MemberDefinition) {
7318                                                         if (iface_candidate != null && iface_candidate != rc.Module.PredefinedMembers.IEnumerableGetEnumerator) {
7319                                                                 rc.Report.SymbolRelatedToPreviousError (expr.Type);
7320                                                                 rc.Report.Error (1640, loc,
7321                                                                         "foreach statement cannot operate on variables of type `{0}' because it contains multiple implementation of `{1}'. Try casting to a specific implementation",
7322                                                                         expr.Type.GetSignatureForError (), gen_ienumerable.TypeSpec.GetSignatureForError ());
7323
7324                                                                 return null;
7325                                                         }
7326
7327                                                         // TODO: Cache this somehow
7328                                                         iface_candidate = new PredefinedMember<MethodSpec> (rc.Module, iface,
7329                                                                 MemberFilter.Method ("GetEnumerator", 0, ParametersCompiled.EmptyReadOnlyParameters, null));
7330
7331                                                         continue;
7332                                                 }
7333
7334                                                 if (iface.BuiltinType == BuiltinTypeSpec.Type.IEnumerable && iface_candidate == null) {
7335                                                         iface_candidate = rc.Module.PredefinedMembers.IEnumerableGetEnumerator;
7336                                                 }
7337                                         }
7338                                 }
7339
7340                                 if (iface_candidate == null) {
7341                                         if (expr.Type != InternalType.ErrorType) {
7342                                                 rc.Report.Error (1579, loc,
7343                                                         "foreach statement cannot operate on variables of type `{0}' because it does not contain a definition for `{1}' or is inaccessible",
7344                                                         expr.Type.GetSignatureForError (), "GetEnumerator");
7345                                         }
7346
7347                                         return null;
7348                                 }
7349
7350                                 var method = iface_candidate.Resolve (loc);
7351                                 if (method == null)
7352                                         return null;
7353
7354                                 mg = MethodGroupExpr.CreatePredefined (method, expr.Type, loc);
7355                                 mg.InstanceExpression = expr;
7356                                 return mg;
7357                         }
7358
7359                         MethodGroupExpr ResolveMoveNext (ResolveContext rc, MethodSpec enumerator)
7360                         {
7361                                 var ms = MemberCache.FindMember (enumerator.ReturnType,
7362                                         MemberFilter.Method ("MoveNext", 0, ParametersCompiled.EmptyReadOnlyParameters, rc.BuiltinTypes.Bool),
7363                                         BindingRestriction.InstanceOnly) as MethodSpec;
7364
7365                                 if (ms == null || !ms.IsPublic) {
7366                                         Error_WrongEnumerator (rc, enumerator);
7367                                         return null;
7368                                 }
7369
7370                                 return MethodGroupExpr.CreatePredefined (ms, enumerator.ReturnType, expr.Location);
7371                         }
7372
7373                         PropertySpec ResolveCurrent (ResolveContext rc, MethodSpec enumerator)
7374                         {
7375                                 var ps = MemberCache.FindMember (enumerator.ReturnType,
7376                                         MemberFilter.Property ("Current", null),
7377                                         BindingRestriction.InstanceOnly) as PropertySpec;
7378
7379                                 if (ps == null || !ps.IsPublic) {
7380                                         Error_WrongEnumerator (rc, enumerator);
7381                                         return null;
7382                                 }
7383
7384                                 return ps;
7385                         }
7386
7387                         public override bool Resolve (BlockContext ec)
7388                         {
7389                                 bool is_dynamic = expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
7390
7391                                 if (is_dynamic) {
7392                                         expr = Convert.ImplicitConversionRequired (ec, expr, ec.BuiltinTypes.IEnumerable, loc);
7393                                 } else if (expr.Type.IsNullableType) {
7394                                         expr = new Nullable.UnwrapCall (expr).Resolve (ec);
7395                                 }
7396
7397                                 var get_enumerator_mg = ResolveGetEnumerator (ec);
7398                                 if (get_enumerator_mg == null) {
7399                                         return false;
7400                                 }
7401
7402                                 var get_enumerator = get_enumerator_mg.BestCandidate;
7403                                 enumerator_variable = TemporaryVariableReference.Create (get_enumerator.ReturnType, variable.Block, loc);
7404                                 enumerator_variable.Resolve (ec);
7405
7406                                 // Prepare bool MoveNext ()
7407                                 var move_next_mg = ResolveMoveNext (ec, get_enumerator);
7408                                 if (move_next_mg == null) {
7409                                         return false;
7410                                 }
7411
7412                                 move_next_mg.InstanceExpression = enumerator_variable;
7413
7414                                 // Prepare ~T~ Current { get; }
7415                                 var current_prop = ResolveCurrent (ec, get_enumerator);
7416                                 if (current_prop == null) {
7417                                         return false;
7418                                 }
7419
7420                                 var current_pe = new PropertyExpr (current_prop, loc) { InstanceExpression = enumerator_variable }.Resolve (ec);
7421                                 if (current_pe == null)
7422                                         return false;
7423
7424                                 VarExpr ve = for_each.type as VarExpr;
7425
7426                                 if (ve != null) {
7427                                         if (is_dynamic) {
7428                                                 // Source type is dynamic, set element type to dynamic too
7429                                                 variable.Type = ec.BuiltinTypes.Dynamic;
7430                                         } else {
7431                                                 // Infer implicitly typed local variable from foreach enumerable type
7432                                                 variable.Type = current_pe.Type;
7433                                         }
7434                                 } else {
7435                                         if (is_dynamic) {
7436                                                 // Explicit cast of dynamic collection elements has to be done at runtime
7437                                                 current_pe = EmptyCast.Create (current_pe, ec.BuiltinTypes.Dynamic);
7438                                         }
7439
7440                                         variable.Type = for_each.type.ResolveAsType (ec);
7441
7442                                         if (variable.Type == null)
7443                                                 return false;
7444
7445                                         current_pe = Convert.ExplicitConversion (ec, current_pe, variable.Type, loc);
7446                                         if (current_pe == null)
7447                                                 return false;
7448                                 }
7449
7450                                 var variable_ref = new LocalVariableReference (variable, loc).Resolve (ec);
7451                                 if (variable_ref == null)
7452                                         return false;
7453
7454                                 for_each.body.AddScopeStatement (new StatementExpression (new CompilerAssign (variable_ref, current_pe, Location.Null), for_each.type.Location));
7455
7456                                 var init = new Invocation (get_enumerator_mg, null);
7457
7458                                 statement = new While (new BooleanExpression (new Invocation (move_next_mg, null)),
7459                                          for_each.body, Location.Null);
7460
7461                                 var enum_type = enumerator_variable.Type;
7462
7463                                 //
7464                                 // Add Dispose method call when enumerator can be IDisposable
7465                                 //
7466                                 if (!enum_type.ImplementsInterface (ec.BuiltinTypes.IDisposable, false)) {
7467                                         if (!enum_type.IsSealed && !TypeSpec.IsValueType (enum_type)) {
7468                                                 //
7469                                                 // Runtime Dispose check
7470                                                 //
7471                                                 var vd = new RuntimeDispose (enumerator_variable.LocalInfo, Location.Null);
7472                                                 vd.Initializer = init;
7473                                                 statement = new Using (vd, statement, Location.Null);
7474                                         } else {
7475                                                 //
7476                                                 // No Dispose call needed
7477                                                 //
7478                                                 this.init = new SimpleAssign (enumerator_variable, init, Location.Null);
7479                                                 this.init.Resolve (ec);
7480                                         }
7481                                 } else {
7482                                         //
7483                                         // Static Dispose check
7484                                         //
7485                                         var vd = new Using.VariableDeclaration (enumerator_variable.LocalInfo, Location.Null);
7486                                         vd.Initializer = init;
7487                                         statement = new Using (vd, statement, Location.Null);
7488                                 }
7489
7490                                 return statement.Resolve (ec);
7491                         }
7492
7493                         protected override void DoEmit (EmitContext ec)
7494                         {
7495                                 enumerator_variable.LocalInfo.CreateBuilder (ec);
7496
7497                                 if (init != null)
7498                                         init.EmitStatement (ec);
7499
7500                                 statement.Emit (ec);
7501                         }
7502
7503                         #region IErrorHandler Members
7504
7505                         bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext ec, MemberSpec best, MemberSpec ambiguous)
7506                         {
7507                                 ec.Report.SymbolRelatedToPreviousError (best);
7508                                 ec.Report.Warning (278, 2, expr.Location,
7509                                         "`{0}' contains ambiguous implementation of `{1}' pattern. Method `{2}' is ambiguous with method `{3}'",
7510                                         expr.Type.GetSignatureForError (), "enumerable",
7511                                         best.GetSignatureForError (), ambiguous.GetSignatureForError ());
7512
7513                                 ambiguous_getenumerator_name = true;
7514                                 return true;
7515                         }
7516
7517                         bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
7518                         {
7519                                 return false;
7520                         }
7521
7522                         bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
7523                         {
7524                                 return false;
7525                         }
7526
7527                         bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
7528                         {
7529                                 return false;
7530                         }
7531
7532                         #endregion
7533                 }
7534
7535                 Expression type;
7536                 LocalVariable variable;
7537                 Expression expr;
7538                 Block body;
7539
7540                 public Foreach (Expression type, LocalVariable var, Expression expr, Statement stmt, Block body, Location l)
7541                         : base (stmt)
7542                 {
7543                         this.type = type;
7544                         this.variable = var;
7545                         this.expr = expr;
7546                         this.body = body;
7547                         loc = l;
7548                 }
7549
7550                 public Expression Expr {
7551                         get { return expr; }
7552                 }
7553
7554                 public Expression TypeExpression {
7555                         get { return type; }
7556                 }
7557
7558                 public LocalVariable Variable {
7559                         get { return variable; }
7560                 }
7561
7562                 public override Reachability MarkReachable (Reachability rc)
7563                 {
7564                         base.MarkReachable (rc);
7565
7566                         body.MarkReachable (rc);
7567
7568                         return rc;
7569                 }
7570
7571                 public override bool Resolve (BlockContext ec)
7572                 {
7573                         expr = expr.Resolve (ec);
7574                         if (expr == null)
7575                                 return false;
7576
7577                         if (expr.IsNull) {
7578                                 ec.Report.Error (186, loc, "Use of null is not valid in this context");
7579                                 return false;
7580                         }
7581
7582                         body.AddStatement (Statement);
7583
7584                         if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.String) {
7585                                 Statement = new ArrayForeach (this, 1);
7586                         } else if (expr.Type is ArrayContainer) {
7587                                 Statement = new ArrayForeach (this, ((ArrayContainer) expr.Type).Rank);
7588                         } else {
7589                                 if (expr.eclass == ExprClass.MethodGroup || expr is AnonymousMethodExpression) {
7590                                         ec.Report.Error (446, expr.Location, "Foreach statement cannot operate on a `{0}'",
7591                                                 expr.ExprClassName);
7592                                         return false;
7593                                 }
7594
7595                                 Statement = new CollectionForeach (this, variable, expr);
7596                         }
7597
7598                         return base.Resolve (ec);
7599                 }
7600
7601                 protected override void DoEmit (EmitContext ec)
7602                 {
7603                         Label old_begin = ec.LoopBegin, old_end = ec.LoopEnd;
7604                         ec.LoopBegin = ec.DefineLabel ();
7605                         ec.LoopEnd = ec.DefineLabel ();
7606
7607                         if (!(Statement is Block))
7608                                 ec.BeginCompilerScope ();
7609
7610                         variable.CreateBuilder (ec);
7611
7612                         Statement.Emit (ec);
7613
7614                         if (!(Statement is Block))
7615                                 ec.EndScope ();
7616
7617                         ec.LoopBegin = old_begin;
7618                         ec.LoopEnd = old_end;
7619                 }
7620
7621                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7622                 {
7623                         expr.FlowAnalysis (fc);
7624
7625                         var da = fc.BranchDefiniteAssignment ();
7626                         body.FlowAnalysis (fc);
7627                         fc.DefiniteAssignment = da;
7628                         return false;
7629                 }
7630
7631                 protected override void CloneTo (CloneContext clonectx, Statement t)
7632                 {
7633                         Foreach target = (Foreach) t;
7634
7635                         target.type = type.Clone (clonectx);
7636                         target.expr = expr.Clone (clonectx);
7637                         target.body = (Block) body.Clone (clonectx);
7638                         target.Statement = Statement.Clone (clonectx);
7639                 }
7640                 
7641                 public override object Accept (StructuralVisitor visitor)
7642                 {
7643                         return visitor.Visit (this);
7644                 }
7645         }
7646 }