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