Merge pull request #1936 from esdrubal/DotNetRelativeOrAbsolute
[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 && async_type.TypeArguments [0] != ec.Module.PredefinedTypes.Task.TypeSpec) {
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                         SymbolFileHidden = 1 << 9,
2350
2351                         ReadonlyMask = ForeachVariable | FixedVariable | UsingVariable
2352                 }
2353
2354                 TypeSpec type;
2355                 readonly string name;
2356                 readonly Location loc;
2357                 readonly Block block;
2358                 Flags flags;
2359                 Constant const_value;
2360
2361                 public VariableInfo VariableInfo;
2362                 HoistedVariable hoisted_variant;
2363
2364                 LocalBuilder builder;
2365
2366                 public LocalVariable (Block block, string name, Location loc)
2367                 {
2368                         this.block = block;
2369                         this.name = name;
2370                         this.loc = loc;
2371                 }
2372
2373                 public LocalVariable (Block block, string name, Flags flags, Location loc)
2374                         : this (block, name, loc)
2375                 {
2376                         this.flags = flags;
2377                 }
2378
2379                 //
2380                 // Used by variable declarators
2381                 //
2382                 public LocalVariable (LocalVariable li, string name, Location loc)
2383                         : this (li.block, name, li.flags, loc)
2384                 {
2385                 }
2386
2387                 #region Properties
2388
2389                 public bool AddressTaken {
2390                         get {
2391                                 return (flags & Flags.AddressTaken) != 0;
2392                         }
2393                 }
2394
2395                 public Block Block {
2396                         get {
2397                                 return block;
2398                         }
2399                 }
2400
2401                 public Constant ConstantValue {
2402                         get {
2403                                 return const_value;
2404                         }
2405                         set {
2406                                 const_value = value;
2407                         }
2408                 }
2409
2410                 //
2411                 // Hoisted local variable variant
2412                 //
2413                 public HoistedVariable HoistedVariant {
2414                         get {
2415                                 return hoisted_variant;
2416                         }
2417                         set {
2418                                 hoisted_variant = value;
2419                         }
2420                 }
2421
2422                 public bool IsDeclared {
2423                         get {
2424                                 return type != null;
2425                         }
2426                 }
2427
2428                 public bool IsCompilerGenerated {
2429                         get {
2430                                 return (flags & Flags.CompilerGenerated) != 0;
2431                         }
2432                 }
2433
2434                 public bool IsConstant {
2435                         get {
2436                                 return (flags & Flags.Constant) != 0;
2437                         }
2438                 }
2439
2440                 public bool IsLocked {
2441                         get {
2442                                 return (flags & Flags.IsLocked) != 0;
2443                         }
2444                         set {
2445                                 flags = value ? flags | Flags.IsLocked : flags & ~Flags.IsLocked;
2446                         }
2447                 }
2448
2449                 public bool IsThis {
2450                         get {
2451                                 return (flags & Flags.IsThis) != 0;
2452                         }
2453                 }
2454
2455                 public bool IsFixed {
2456                         get {
2457                                 return (flags & Flags.FixedVariable) != 0;
2458                         }
2459                 }
2460
2461                 bool INamedBlockVariable.IsParameter {
2462                         get {
2463                                 return false;
2464                         }
2465                 }
2466
2467                 public bool IsReadonly {
2468                         get {
2469                                 return (flags & Flags.ReadonlyMask) != 0;
2470                         }
2471                 }
2472
2473                 public Location Location {
2474                         get {
2475                                 return loc;
2476                         }
2477                 }
2478
2479                 public string Name {
2480                         get {
2481                                 return name;
2482                         }
2483                 }
2484
2485                 public TypeSpec Type {
2486                     get {
2487                                 return type;
2488                         }
2489                     set {
2490                                 type = value;
2491                         }
2492                 }
2493
2494                 #endregion
2495
2496                 public void CreateBuilder (EmitContext ec)
2497                 {
2498                         if ((flags & Flags.Used) == 0) {
2499                                 if (VariableInfo == null) {
2500                                         // Missing flow analysis or wrong variable flags
2501                                         throw new InternalErrorException ("VariableInfo is null and the variable `{0}' is not used", name);
2502                                 }
2503
2504                                 if (VariableInfo.IsEverAssigned)
2505                                         ec.Report.Warning (219, 3, Location, "The variable `{0}' is assigned but its value is never used", Name);
2506                                 else
2507                                         ec.Report.Warning (168, 3, Location, "The variable `{0}' is declared but never used", Name);
2508                         }
2509
2510                         if (HoistedVariant != null)
2511                                 return;
2512
2513                         if (builder != null) {
2514                                 if ((flags & Flags.CompilerGenerated) != 0)
2515                                         return;
2516
2517                                 // To avoid Used warning duplicates
2518                                 throw new InternalErrorException ("Already created variable `{0}'", name);
2519                         }
2520
2521                         //
2522                         // All fixed variabled are pinned, a slot has to be alocated
2523                         //
2524                         builder = ec.DeclareLocal (Type, IsFixed);
2525                         if ((flags & Flags.SymbolFileHidden) == 0)
2526                                 ec.DefineLocalVariable (name, builder);
2527                 }
2528
2529                 public static LocalVariable CreateCompilerGenerated (TypeSpec type, Block block, Location loc, bool writeToSymbolFile = false)
2530                 {
2531                         LocalVariable li = new LocalVariable (block, GetCompilerGeneratedName (block), Flags.CompilerGenerated | Flags.Used, loc);
2532                         if (!writeToSymbolFile)
2533                                 li.flags |= Flags.SymbolFileHidden;
2534                         
2535                         li.Type = type;
2536                         return li;
2537                 }
2538
2539                 public Expression CreateReferenceExpression (ResolveContext rc, Location loc)
2540                 {
2541                         if (IsConstant && const_value != null)
2542                                 return Constant.CreateConstantFromValue (Type, const_value.GetValue (), loc);
2543
2544                         return new LocalVariableReference (this, loc);
2545                 }
2546
2547                 public void Emit (EmitContext ec)
2548                 {
2549                         // TODO: Need something better for temporary variables
2550                         if ((flags & Flags.CompilerGenerated) != 0)
2551                                 CreateBuilder (ec);
2552
2553                         ec.Emit (OpCodes.Ldloc, builder);
2554                 }
2555
2556                 public void EmitAssign (EmitContext ec)
2557                 {
2558                         // TODO: Need something better for temporary variables
2559                         if ((flags & Flags.CompilerGenerated) != 0)
2560                                 CreateBuilder (ec);
2561
2562                         ec.Emit (OpCodes.Stloc, builder);
2563                 }
2564
2565                 public void EmitAddressOf (EmitContext ec)
2566                 {
2567                         // TODO: Need something better for temporary variables
2568                         if ((flags & Flags.CompilerGenerated) != 0)
2569                                 CreateBuilder (ec);
2570
2571                         ec.Emit (OpCodes.Ldloca, builder);
2572                 }
2573
2574                 public static string GetCompilerGeneratedName (Block block)
2575                 {
2576                         // HACK: Debugger depends on the name semantics
2577                         return "$locvar" + block.ParametersBlock.TemporaryLocalsCount++.ToString ("X");
2578                 }
2579
2580                 public string GetReadOnlyContext ()
2581                 {
2582                         switch (flags & Flags.ReadonlyMask) {
2583                         case Flags.FixedVariable:
2584                                 return "fixed variable";
2585                         case Flags.ForeachVariable:
2586                                 return "foreach iteration variable";
2587                         case Flags.UsingVariable:
2588                                 return "using variable";
2589                         }
2590
2591                         throw new InternalErrorException ("Variable is not readonly");
2592                 }
2593
2594                 public bool IsThisAssigned (FlowAnalysisContext fc, Block block)
2595                 {
2596                         if (VariableInfo == null)
2597                                 throw new Exception ();
2598
2599                         if (IsAssigned (fc))
2600                                 return true;
2601
2602                         return VariableInfo.IsFullyInitialized (fc, block.StartLocation);
2603                 }
2604
2605                 public bool IsAssigned (FlowAnalysisContext fc)
2606                 {
2607                         return fc.IsDefinitelyAssigned (VariableInfo);
2608                 }
2609
2610                 public void PrepareAssignmentAnalysis (BlockContext bc)
2611                 {
2612                         //
2613                         // No need to run assignment analysis for these guys
2614                         //
2615                         if ((flags & (Flags.Constant | Flags.ReadonlyMask | Flags.CompilerGenerated)) != 0)
2616                                 return;
2617
2618                         VariableInfo = VariableInfo.Create (bc, this);
2619                 }
2620
2621                 //
2622                 // Mark the variables as referenced in the user code
2623                 //
2624                 public void SetIsUsed ()
2625                 {
2626                         flags |= Flags.Used;
2627                 }
2628
2629                 public void SetHasAddressTaken ()
2630                 {
2631                         flags |= (Flags.AddressTaken | Flags.Used);
2632                 }
2633
2634                 public override string ToString ()
2635                 {
2636                         return string.Format ("LocalInfo ({0},{1},{2},{3})", name, type, VariableInfo, Location);
2637                 }
2638         }
2639
2640         /// <summary>
2641         ///   Block represents a C# block.
2642         /// </summary>
2643         ///
2644         /// <remarks>
2645         ///   This class is used in a number of places: either to represent
2646         ///   explicit blocks that the programmer places or implicit blocks.
2647         ///
2648         ///   Implicit blocks are used as labels or to introduce variable
2649         ///   declarations.
2650         ///
2651         ///   Top-level blocks derive from Block, and they are called ToplevelBlock
2652         ///   they contain extra information that is not necessary on normal blocks.
2653         /// </remarks>
2654         public class Block : Statement {
2655                 [Flags]
2656                 public enum Flags
2657                 {
2658                         Unchecked = 1,
2659                         ReachableEnd = 8,
2660                         Unsafe = 16,
2661                         HasCapturedVariable = 64,
2662                         HasCapturedThis = 1 << 7,
2663                         IsExpressionTree = 1 << 8,
2664                         CompilerGenerated = 1 << 9,
2665                         HasAsyncModifier = 1 << 10,
2666                         Resolved = 1 << 11,
2667                         YieldBlock = 1 << 12,
2668                         AwaitBlock = 1 << 13,
2669                         FinallyBlock = 1 << 14,
2670                         CatchBlock = 1 << 15,
2671                         Iterator = 1 << 20,
2672                         NoFlowAnalysis = 1 << 21,
2673                         InitializationEmitted = 1 << 22
2674                 }
2675
2676                 public Block Parent;
2677                 public Location StartLocation;
2678                 public Location EndLocation;
2679
2680                 public ExplicitBlock Explicit;
2681                 public ParametersBlock ParametersBlock;
2682
2683                 protected Flags flags;
2684
2685                 //
2686                 // The statements in this block
2687                 //
2688                 protected List<Statement> statements;
2689
2690                 protected List<Statement> scope_initializers;
2691
2692                 int? resolving_init_idx;
2693
2694                 Block original;
2695
2696 #if DEBUG
2697                 static int id;
2698                 public int ID = id++;
2699
2700                 static int clone_id_counter;
2701                 int clone_id;
2702 #endif
2703
2704 //              int assignable_slots;
2705
2706                 public Block (Block parent, Location start, Location end)
2707                         : this (parent, 0, start, end)
2708                 {
2709                 }
2710
2711                 public Block (Block parent, Flags flags, Location start, Location end)
2712                 {
2713                         if (parent != null) {
2714                                 // the appropriate constructors will fixup these fields
2715                                 ParametersBlock = parent.ParametersBlock;
2716                                 Explicit = parent.Explicit;
2717                         }
2718                         
2719                         this.Parent = parent;
2720                         this.flags = flags;
2721                         this.StartLocation = start;
2722                         this.EndLocation = end;
2723                         this.loc = start;
2724                         statements = new List<Statement> (4);
2725
2726                         this.original = this;
2727                 }
2728
2729                 #region Properties
2730
2731                 public Block Original {
2732                         get {
2733                                 return original;
2734                         }
2735                         protected set {
2736                                 original = value;
2737                         }
2738                 }
2739
2740                 public bool IsCompilerGenerated {
2741                         get { return (flags & Flags.CompilerGenerated) != 0; }
2742                         set { flags = value ? flags | Flags.CompilerGenerated : flags & ~Flags.CompilerGenerated; }
2743                 }
2744
2745
2746                 public bool IsCatchBlock {
2747                         get {
2748                                 return (flags & Flags.CatchBlock) != 0;
2749                         }
2750                 }
2751
2752                 public bool IsFinallyBlock {
2753                         get {
2754                                 return (flags & Flags.FinallyBlock) != 0;
2755                         }
2756                 }
2757
2758                 public bool Unchecked {
2759                         get { return (flags & Flags.Unchecked) != 0; }
2760                         set { flags = value ? flags | Flags.Unchecked : flags & ~Flags.Unchecked; }
2761                 }
2762
2763                 public bool Unsafe {
2764                         get { return (flags & Flags.Unsafe) != 0; }
2765                         set { flags |= Flags.Unsafe; }
2766                 }
2767
2768                 public List<Statement> Statements {
2769                         get { return statements; }
2770                 }
2771
2772                 #endregion
2773
2774                 public void SetEndLocation (Location loc)
2775                 {
2776                         EndLocation = loc;
2777                 }
2778
2779                 public void AddLabel (LabeledStatement target)
2780                 {
2781                         ParametersBlock.TopBlock.AddLabel (target.Name, target);
2782                 }
2783
2784                 public void AddLocalName (LocalVariable li)
2785                 {
2786                         AddLocalName (li.Name, li);
2787                 }
2788
2789                 public void AddLocalName (string name, INamedBlockVariable li)
2790                 {
2791                         ParametersBlock.TopBlock.AddLocalName (name, li, false);
2792                 }
2793
2794                 public virtual void Error_AlreadyDeclared (string name, INamedBlockVariable variable, string reason)
2795                 {
2796                         if (reason == null) {
2797                                 Error_AlreadyDeclared (name, variable);
2798                                 return;
2799                         }
2800
2801                         ParametersBlock.TopBlock.Report.Error (136, variable.Location,
2802                                 "A local variable named `{0}' cannot be declared in this scope because it would give a different meaning " +
2803                                 "to `{0}', which is already used in a `{1}' scope to denote something else",
2804                                 name, reason);
2805                 }
2806
2807                 public virtual void Error_AlreadyDeclared (string name, INamedBlockVariable variable)
2808                 {
2809                         var pi = variable as ParametersBlock.ParameterInfo;
2810                         if (pi != null) {
2811                                 pi.Parameter.Error_DuplicateName (ParametersBlock.TopBlock.Report);
2812                         } else {
2813                                 ParametersBlock.TopBlock.Report.Error (128, variable.Location,
2814                                         "A local variable named `{0}' is already defined in this scope", name);
2815                         }
2816                 }
2817                                         
2818                 public virtual void Error_AlreadyDeclaredTypeParameter (string name, Location loc)
2819                 {
2820                         ParametersBlock.TopBlock.Report.Error (412, loc,
2821                                 "The type parameter name `{0}' is the same as local variable or parameter name",
2822                                 name);
2823                 }
2824
2825                 //
2826                 // It should be used by expressions which require to
2827                 // register a statement during resolve process.
2828                 //
2829                 public void AddScopeStatement (Statement s)
2830                 {
2831                         if (scope_initializers == null)
2832                                 scope_initializers = new List<Statement> ();
2833
2834                         //
2835                         // Simple recursive helper, when resolve scope initializer another
2836                         // new scope initializer can be added, this ensures it's initialized
2837                         // before existing one. For now this can happen with expression trees
2838                         // in base ctor initializer only
2839                         //
2840                         if (resolving_init_idx.HasValue) {
2841                                 scope_initializers.Insert (resolving_init_idx.Value, s);
2842                                 ++resolving_init_idx;
2843                         } else {
2844                                 scope_initializers.Add (s);
2845                         }
2846                 }
2847
2848                 public void InsertStatement (int index, Statement s)
2849                 {
2850                         statements.Insert (index, s);
2851                 }
2852                 
2853                 public void AddStatement (Statement s)
2854                 {
2855                         statements.Add (s);
2856                 }
2857
2858                 public LabeledStatement LookupLabel (string name)
2859                 {
2860                         return ParametersBlock.GetLabel (name, this);
2861                 }
2862
2863                 public override Reachability MarkReachable (Reachability rc)
2864                 {
2865                         if (rc.IsUnreachable)
2866                                 return rc;
2867
2868                         MarkReachableScope (rc);
2869
2870                         foreach (var s in statements) {
2871                                 rc = s.MarkReachable (rc);
2872                                 if (rc.IsUnreachable) {
2873                                         if ((flags & Flags.ReachableEnd) != 0)
2874                                                 return new Reachability ();
2875
2876                                         return rc;
2877                                 }
2878                         }
2879
2880                         flags |= Flags.ReachableEnd;
2881
2882                         return rc;
2883                 }
2884
2885                 public void MarkReachableScope (Reachability rc)
2886                 {
2887                         base.MarkReachable (rc);
2888
2889                         if (scope_initializers != null) {
2890                                 foreach (var si in scope_initializers)
2891                                         si.MarkReachable (rc);
2892                         }
2893                 }
2894
2895                 public override bool Resolve (BlockContext bc)
2896                 {
2897                         if ((flags & Flags.Resolved) != 0)
2898                                 return true;
2899
2900                         Block prev_block = bc.CurrentBlock;
2901                         bc.CurrentBlock = this;
2902
2903                         //
2904                         // Compiler generated scope statements
2905                         //
2906                         if (scope_initializers != null) {
2907                                 for (resolving_init_idx = 0; resolving_init_idx < scope_initializers.Count; ++resolving_init_idx) {
2908                                         scope_initializers[resolving_init_idx.Value].Resolve (bc);
2909                                 }
2910
2911                                 resolving_init_idx = null;
2912                         }
2913
2914                         bool ok = true;
2915                         int statement_count = statements.Count;
2916                         for (int ix = 0; ix < statement_count; ix++){
2917                                 Statement s = statements [ix];
2918
2919                                 if (!s.Resolve (bc)) {
2920                                         ok = false;
2921                                         statements [ix] = new EmptyStatement (s.loc);
2922                                         continue;
2923                                 }
2924                         }
2925
2926                         bc.CurrentBlock = prev_block;
2927
2928                         flags |= Flags.Resolved;
2929                         return ok;
2930                 }
2931
2932                 protected override void DoEmit (EmitContext ec)
2933                 {
2934                         for (int ix = 0; ix < statements.Count; ix++){
2935                                 statements [ix].Emit (ec);
2936                         }
2937                 }
2938
2939                 public override void Emit (EmitContext ec)
2940                 {
2941                         if (scope_initializers != null)
2942                                 EmitScopeInitializers (ec);
2943
2944                         DoEmit (ec);
2945                 }
2946
2947                 protected void EmitScopeInitializers (EmitContext ec)
2948                 {
2949                         foreach (Statement s in scope_initializers)
2950                                 s.Emit (ec);
2951                 }
2952
2953                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
2954                 {
2955                         if (scope_initializers != null) {
2956                                 foreach (var si in scope_initializers)
2957                                         si.FlowAnalysis (fc);
2958                         }
2959
2960                         return DoFlowAnalysis (fc, 0);  
2961                 }
2962
2963                 bool DoFlowAnalysis (FlowAnalysisContext fc, int startIndex)
2964                 {
2965                         bool end_unreachable = !reachable;
2966                         bool goto_flow_analysis = startIndex != 0;
2967                         for (; startIndex < statements.Count; ++startIndex) {
2968                                 var s = statements[startIndex];
2969
2970                                 end_unreachable = s.FlowAnalysis (fc);
2971                                 if (s.IsUnreachable) {
2972                                         statements [startIndex] = RewriteUnreachableStatement (s);
2973                                         continue;
2974                                 }
2975
2976                                 //
2977                                 // Statement end reachability is needed mostly due to goto support. Consider
2978                                 //
2979                                 // if (cond) {
2980                                 //    goto X;
2981                                 // } else {
2982                                 //    goto Y;
2983                                 // }
2984                                 // X:
2985                                 //
2986                                 // X label is reachable only via goto not as another statement after if. We need
2987                                 // this for flow-analysis only to carry variable info correctly.
2988                                 //
2989                                 if (end_unreachable) {
2990                                         bool after_goto_case = goto_flow_analysis && s is GotoCase;
2991
2992                                         for (++startIndex; startIndex < statements.Count; ++startIndex) {
2993                                                 s = statements[startIndex];
2994                                                 if (s is SwitchLabel) {
2995                                                         if (!after_goto_case)
2996                                                                 s.FlowAnalysis (fc);
2997
2998                                                         break;
2999                                                 }
3000
3001                                                 if (s.IsUnreachable) {
3002                                                         s.FlowAnalysis (fc);
3003                                                         statements [startIndex] = RewriteUnreachableStatement (s);
3004                                                 }
3005                                         }
3006
3007                                         //
3008                                         // Idea is to stop after goto case because goto case will always have at least same
3009                                         // variable assigned as switch case label. This saves a lot for complex goto case tests
3010                                         //
3011                                         if (after_goto_case)
3012                                                 break;
3013
3014                                         continue;
3015                                 }
3016
3017                                 var lb = s as LabeledStatement;
3018                                 if (lb != null && fc.AddReachedLabel (lb))
3019                                         break;
3020                         }
3021
3022                         //
3023                         // The condition should be true unless there is forward jumping goto
3024                         // 
3025                         // if (this is ExplicitBlock && end_unreachable != Explicit.HasReachableClosingBrace)
3026                         //      Debug.Fail ();
3027
3028                         return !Explicit.HasReachableClosingBrace;
3029                 }
3030
3031                 static Statement RewriteUnreachableStatement (Statement s)
3032                 {
3033                         // LAMESPEC: It's not clear whether declararion statement should be part of reachability
3034                         // analysis. Even csc report unreachable warning for it but it's actually used hence
3035                         // we try to emulate this behaviour
3036                         //
3037                         // Consider:
3038                         //      goto L;
3039                         //      int v;
3040                         // L:
3041                         //      v = 1;
3042
3043                         if (s is BlockVariable || s is EmptyStatement)
3044                                 return s;
3045
3046                         return new EmptyStatement (s.loc);
3047                 }
3048
3049                 public void ScanGotoJump (Statement label)
3050                 {
3051                         int i;
3052                         for (i = 0; i < statements.Count; ++i) {
3053                                 if (statements[i] == label)
3054                                         break;
3055                         }
3056
3057                         var rc = new Reachability ();
3058                         for (++i; i < statements.Count; ++i) {
3059                                 var s = statements[i];
3060                                 rc = s.MarkReachable (rc);
3061                                 if (rc.IsUnreachable)
3062                                         return;
3063                         }
3064
3065                         flags |= Flags.ReachableEnd;
3066                 }
3067
3068                 public void ScanGotoJump (Statement label, FlowAnalysisContext fc)
3069                 {
3070                         int i;
3071                         for (i = 0; i < statements.Count; ++i) {
3072                                 if (statements[i] == label)
3073                                         break;
3074                         }
3075
3076                         DoFlowAnalysis (fc, ++i);
3077                 }
3078
3079 #if DEBUG
3080                 public override string ToString ()
3081                 {
3082                         return String.Format ("{0}: ID={1} Clone={2} Location={3}", GetType (), ID, clone_id != 0, StartLocation);
3083                 }
3084 #endif
3085
3086                 protected override void CloneTo (CloneContext clonectx, Statement t)
3087                 {
3088                         Block target = (Block) t;
3089 #if DEBUG
3090                         target.clone_id = ++clone_id_counter;
3091 #endif
3092
3093                         clonectx.AddBlockMap (this, target);
3094                         if (original != this)
3095                                 clonectx.AddBlockMap (original, target);
3096
3097                         target.ParametersBlock = (ParametersBlock) (ParametersBlock == this ? target : clonectx.RemapBlockCopy (ParametersBlock));
3098                         target.Explicit = (ExplicitBlock) (Explicit == this ? target : clonectx.LookupBlock (Explicit));
3099
3100                         if (Parent != null)
3101                                 target.Parent = clonectx.RemapBlockCopy (Parent);
3102
3103                         target.statements = new List<Statement> (statements.Count);
3104                         foreach (Statement s in statements)
3105                                 target.statements.Add (s.Clone (clonectx));
3106                 }
3107
3108                 public override object Accept (StructuralVisitor visitor)
3109                 {
3110                         return visitor.Visit (this);
3111                 }
3112         }
3113
3114         public class ExplicitBlock : Block
3115         {
3116                 protected AnonymousMethodStorey am_storey;
3117
3118                 public ExplicitBlock (Block parent, Location start, Location end)
3119                         : this (parent, (Flags) 0, start, end)
3120                 {
3121                 }
3122
3123                 public ExplicitBlock (Block parent, Flags flags, Location start, Location end)
3124                         : base (parent, flags, start, end)
3125                 {
3126                         this.Explicit = this;
3127                 }
3128
3129                 #region Properties
3130
3131                 public AnonymousMethodStorey AnonymousMethodStorey {
3132                         get {
3133                                 return am_storey;
3134                         }
3135                 }
3136
3137                 public bool HasAwait {
3138                         get {
3139                                 return (flags & Flags.AwaitBlock) != 0;
3140                         }
3141                 }
3142
3143                 public bool HasCapturedThis {
3144                         set {
3145                                 flags = value ? flags | Flags.HasCapturedThis : flags & ~Flags.HasCapturedThis;
3146                         }
3147                         get {
3148                                 return (flags & Flags.HasCapturedThis) != 0;
3149                         }
3150                 }
3151
3152                 //
3153                 // Used to indicate that the block has reference to parent
3154                 // block and cannot be made static when defining anonymous method
3155                 //
3156                 public bool HasCapturedVariable {
3157                         set {
3158                                 flags = value ? flags | Flags.HasCapturedVariable : flags & ~Flags.HasCapturedVariable;
3159                         }
3160                         get {
3161                                 return (flags & Flags.HasCapturedVariable) != 0;
3162                         }
3163                 }
3164
3165                 public bool HasReachableClosingBrace {
3166                     get {
3167                         return (flags & Flags.ReachableEnd) != 0;
3168                     }
3169                         set {
3170                                 flags = value ? flags | Flags.ReachableEnd : flags & ~Flags.ReachableEnd;
3171                         }
3172                 }
3173
3174                 public bool HasYield {
3175                         get {
3176                                 return (flags & Flags.YieldBlock) != 0;
3177                         }
3178                 }
3179
3180                 #endregion
3181
3182                 //
3183                 // Creates anonymous method storey in current block
3184                 //
3185                 public AnonymousMethodStorey CreateAnonymousMethodStorey (ResolveContext ec)
3186                 {
3187                         //
3188                         // Return same story for iterator and async blocks unless we are
3189                         // in nested anonymous method
3190                         //
3191                         if (ec.CurrentAnonymousMethod is StateMachineInitializer && ParametersBlock.Original == ec.CurrentAnonymousMethod.Block.Original)
3192                                 return ec.CurrentAnonymousMethod.Storey;
3193
3194                         if (am_storey == null) {
3195                                 MemberBase mc = ec.MemberContext as MemberBase;
3196
3197                                 //
3198                                 // Creates anonymous method storey for this block
3199                                 //
3200                                 am_storey = new AnonymousMethodStorey (this, ec.CurrentMemberDefinition.Parent.PartialContainer, mc, ec.CurrentTypeParameters, "AnonStorey", MemberKind.Class);
3201                         }
3202
3203                         return am_storey;
3204                 }
3205
3206                 public void EmitScopeInitialization (EmitContext ec)
3207                 {
3208                         if ((flags & Flags.InitializationEmitted) != 0)
3209                                 return;
3210
3211                         if (am_storey != null) {
3212                                 DefineStoreyContainer (ec, am_storey);
3213                                 am_storey.EmitStoreyInstantiation (ec, this);
3214                         }
3215
3216                         if (scope_initializers != null)
3217                                 EmitScopeInitializers (ec);
3218
3219                         flags |= Flags.InitializationEmitted;
3220                 }
3221
3222                 public override void Emit (EmitContext ec)
3223                 {
3224                         if (Parent != null)
3225                                 ec.BeginScope ();
3226
3227                         EmitScopeInitialization (ec);
3228
3229                         if (ec.EmitAccurateDebugInfo && !IsCompilerGenerated && ec.Mark (StartLocation)) {
3230                                 ec.Emit (OpCodes.Nop);
3231                         }
3232
3233                         DoEmit (ec);
3234
3235                         if (Parent != null)
3236                                 ec.EndScope ();
3237
3238                         if (ec.EmitAccurateDebugInfo && HasReachableClosingBrace && !(this is ParametersBlock) &&
3239                                 !IsCompilerGenerated && ec.Mark (EndLocation)) {
3240                                 ec.Emit (OpCodes.Nop);
3241                         }
3242                 }
3243
3244                 protected void DefineStoreyContainer (EmitContext ec, AnonymousMethodStorey storey)
3245                 {
3246                         if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.Storey != null) {
3247                                 storey.SetNestedStoryParent (ec.CurrentAnonymousMethod.Storey);
3248                                 storey.Mutator = ec.CurrentAnonymousMethod.Storey.Mutator;
3249                         }
3250
3251                         //
3252                         // Creates anonymous method storey
3253                         //
3254                         storey.CreateContainer ();
3255                         storey.DefineContainer ();
3256
3257                         if (Original.Explicit.HasCapturedThis && Original.ParametersBlock.TopBlock.ThisReferencesFromChildrenBlock != null) {
3258
3259                                 //
3260                                 // Only first storey in path will hold this reference. All children blocks will
3261                                 // reference it indirectly using $ref field
3262                                 //
3263                                 for (Block b = Original.Explicit; b != null; b = b.Parent) {
3264                                         if (b.Parent != null) {
3265                                                 var s = b.Parent.Explicit.AnonymousMethodStorey;
3266                                                 if (s != null) {
3267                                                         storey.HoistedThis = s.HoistedThis;
3268                                                         break;
3269                                                 }
3270                                         }
3271
3272                                         if (b.Explicit == b.Explicit.ParametersBlock && b.Explicit.ParametersBlock.StateMachine != null) {
3273                                                 if (storey.HoistedThis == null)
3274                                                         storey.HoistedThis = b.Explicit.ParametersBlock.StateMachine.HoistedThis;
3275
3276                                                 if (storey.HoistedThis != null)
3277                                                         break;
3278                                         }
3279                                 }
3280                                 
3281                                 //
3282                                 // We are the first storey on path and 'this' has to be hoisted
3283                                 //
3284                                 if (storey.HoistedThis == null || !(storey.Parent is HoistedStoreyClass)) {
3285                                         foreach (ExplicitBlock ref_block in Original.ParametersBlock.TopBlock.ThisReferencesFromChildrenBlock) {
3286                                                 //
3287                                                 // ThisReferencesFromChildrenBlock holds all reference even if they
3288                                                 // are not on this path. It saves some memory otherwise it'd have to
3289                                                 // be in every explicit block. We run this check to see if the reference
3290                                                 // is valid for this storey
3291                                                 //
3292                                                 Block block_on_path = ref_block;
3293                                                 for (; block_on_path != null && block_on_path != Original; block_on_path = block_on_path.Parent);
3294
3295                                                 if (block_on_path == null)
3296                                                         continue;
3297
3298                                                 if (storey.HoistedThis == null) {
3299                                                         storey.AddCapturedThisField (ec, null);
3300                                                 }
3301
3302                                                 for (ExplicitBlock b = ref_block; b.AnonymousMethodStorey != storey; b = b.Parent.Explicit) {
3303                                                         ParametersBlock pb;
3304                                                         AnonymousMethodStorey b_storey = b.AnonymousMethodStorey;
3305
3306                                                         if (b_storey != null) {
3307                                                                 //
3308                                                                 // Don't add storey cross reference for `this' when the storey ends up not
3309                                                                 // beeing attached to any parent
3310                                                                 //
3311                                                                 if (b.ParametersBlock.StateMachine == null) {
3312                                                                         AnonymousMethodStorey s = null;
3313                                                                         for (Block ab = b.AnonymousMethodStorey.OriginalSourceBlock.Parent; ab != null; ab = ab.Parent) {
3314                                                                                 s = ab.Explicit.AnonymousMethodStorey;
3315                                                                                 if (s != null)
3316                                                                                         break;
3317                                                                         }
3318
3319                                                                         // Needs to be in sync with AnonymousMethodBody::DoCreateMethodHost
3320                                                                         if (s == null) {
3321                                                                                 var parent = storey == null || storey.Kind == MemberKind.Struct ? null : storey;
3322                                                                                 b.AnonymousMethodStorey.AddCapturedThisField (ec, parent);
3323                                                                                 break;
3324                                                                         }
3325
3326                                                                 }
3327
3328                                                                 //
3329                                                                 // Stop propagation inside same top block
3330                                                                 //
3331                                                                 if (b.ParametersBlock == ParametersBlock.Original) {
3332                                                                         b_storey.AddParentStoreyReference (ec, storey);
3333 //                                                                      b_storey.HoistedThis = storey.HoistedThis;
3334                                                                         break;
3335                                                                 }
3336
3337                                                                 b = pb = b.ParametersBlock;
3338                                                         } else {
3339                                                                 pb = b as ParametersBlock;
3340                                                         }
3341
3342                                                         if (pb != null && pb.StateMachine != null) {
3343                                                                 if (pb.StateMachine == storey)
3344                                                                         break;
3345
3346                                                                 //
3347                                                                 // If we are state machine with no parent. We can hook into parent without additional
3348                                                                 // reference and capture this directly
3349                                                                 //
3350                                                                 ExplicitBlock parent_storey_block = pb;
3351                                                                 while (parent_storey_block.Parent != null) {
3352                                                                         parent_storey_block = parent_storey_block.Parent.Explicit;
3353                                                                         if (parent_storey_block.AnonymousMethodStorey != null) {
3354                                                                                 break;
3355                                                                         }
3356                                                                 }
3357
3358                                                                 if (parent_storey_block.AnonymousMethodStorey == null) {
3359                                                                         if (pb.StateMachine.HoistedThis == null) {
3360                                                                                 pb.StateMachine.AddCapturedThisField (ec, null);
3361                                                                                 b.HasCapturedThis = true;
3362                                                                         }
3363
3364                                                                         continue;
3365                                                                 }
3366
3367                                                                 var parent_this_block = pb;
3368                                                                 while (parent_this_block.Parent != null) {
3369                                                                         parent_this_block = parent_this_block.Parent.ParametersBlock;
3370                                                                         if (parent_this_block.StateMachine != null) {
3371                                                                                 break;
3372                                                                         }
3373                                                                 }
3374
3375                                                                 //
3376                                                                 // Add reference to closest storey which holds captured this
3377                                                                 //
3378                                                                 pb.StateMachine.AddParentStoreyReference (ec, parent_this_block.StateMachine ?? storey);
3379                                                         }
3380
3381                                                         //
3382                                                         // Add parent storey reference only when this is not captured directly
3383                                                         //
3384                                                         if (b_storey != null) {
3385                                                                 b_storey.AddParentStoreyReference (ec, storey);
3386                                                                 b_storey.HoistedThis = storey.HoistedThis;
3387                                                         }
3388                                                 }
3389                                         }
3390                                 }
3391                         }
3392
3393                         var ref_blocks = storey.ReferencesFromChildrenBlock;
3394                         if (ref_blocks != null) {
3395                                 foreach (ExplicitBlock ref_block in ref_blocks) {
3396                                         for (ExplicitBlock b = ref_block; b.AnonymousMethodStorey != storey; b = b.Parent.Explicit) {
3397                                                 if (b.AnonymousMethodStorey != null) {
3398                                                         b.AnonymousMethodStorey.AddParentStoreyReference (ec, storey);
3399
3400                                                         //
3401                                                         // Stop propagation inside same top block
3402                                                         //
3403                                                         if (b.ParametersBlock == ParametersBlock.Original)
3404                                                                 break;
3405
3406                                                         b = b.ParametersBlock;
3407                                                 }
3408
3409                                                 var pb = b as ParametersBlock;
3410                                                 if (pb != null && pb.StateMachine != null) {
3411                                                         if (pb.StateMachine == storey)
3412                                                                 break;
3413
3414                                                         pb.StateMachine.AddParentStoreyReference (ec, storey);
3415                                                 }
3416
3417                                                 b.HasCapturedVariable = true;
3418                                         }
3419                                 }
3420                         }
3421
3422                         storey.Define ();
3423                         storey.PrepareEmit ();
3424                         storey.Parent.PartialContainer.AddCompilerGeneratedClass (storey);
3425                 }
3426
3427                 public void RegisterAsyncAwait ()
3428                 {
3429                         var block = this;
3430                         while ((block.flags & Flags.AwaitBlock) == 0) {
3431                                 block.flags |= Flags.AwaitBlock;
3432
3433                                 if (block is ParametersBlock)
3434                                         return;
3435
3436                                 block = block.Parent.Explicit;
3437                         }
3438                 }
3439
3440                 public void RegisterIteratorYield ()
3441                 {
3442                         ParametersBlock.TopBlock.IsIterator = true;
3443
3444                         var block = this;
3445                         while ((block.flags & Flags.YieldBlock) == 0) {
3446                                 block.flags |= Flags.YieldBlock;
3447
3448                                 if (block.Parent == null)
3449                                         return;
3450
3451                                 block = block.Parent.Explicit;
3452                         }
3453                 }
3454
3455                 public void SetCatchBlock ()
3456                 {
3457                         flags |= Flags.CatchBlock;
3458                 }
3459
3460                 public void SetFinallyBlock ()
3461                 {
3462                         flags |= Flags.FinallyBlock;
3463                 }
3464
3465                 public void WrapIntoDestructor (TryFinally tf, ExplicitBlock tryBlock)
3466                 {
3467                         tryBlock.statements = statements;
3468                         statements = new List<Statement> (1);
3469                         statements.Add (tf);
3470                 }
3471         }
3472
3473         //
3474         // ParametersBlock was introduced to support anonymous methods
3475         // and lambda expressions
3476         // 
3477         public class ParametersBlock : ExplicitBlock
3478         {
3479                 public class ParameterInfo : INamedBlockVariable
3480                 {
3481                         readonly ParametersBlock block;
3482                         readonly int index;
3483                         public VariableInfo VariableInfo;
3484                         bool is_locked;
3485
3486                         public ParameterInfo (ParametersBlock block, int index)
3487                         {
3488                                 this.block = block;
3489                                 this.index = index;
3490                         }
3491
3492                         #region Properties
3493
3494                         public ParametersBlock Block {
3495                                 get {
3496                                         return block;
3497                                 }
3498                         }
3499
3500                         Block INamedBlockVariable.Block {
3501                                 get {
3502                                         return block;
3503                                 }
3504                         }
3505
3506                         public bool IsDeclared {
3507                                 get {
3508                                         return true;
3509                                 }
3510                         }
3511
3512                         public bool IsParameter {
3513                                 get {
3514                                         return true;
3515                                 }
3516                         }
3517
3518                         public bool IsLocked {
3519                                 get {
3520                                         return is_locked;
3521                                 }
3522                                 set {
3523                                         is_locked = value;
3524                                 }
3525                         }
3526
3527                         public Location Location {
3528                                 get {
3529                                         return Parameter.Location;
3530                                 }
3531                         }
3532
3533                         public Parameter Parameter {
3534                                 get {
3535                                         return block.Parameters [index];
3536                                 }
3537                         }
3538
3539                         public TypeSpec ParameterType {
3540                                 get {
3541                                         return Parameter.Type;
3542                                 }
3543                         }
3544
3545                         #endregion
3546
3547                         public Expression CreateReferenceExpression (ResolveContext rc, Location loc)
3548                         {
3549                                 return new ParameterReference (this, loc);
3550                         }
3551                 }
3552
3553                 // 
3554                 // Block is converted into an expression
3555                 //
3556                 sealed class BlockScopeExpression : Expression
3557                 {
3558                         Expression child;
3559                         readonly ParametersBlock block;
3560
3561                         public BlockScopeExpression (Expression child, ParametersBlock block)
3562                         {
3563                                 this.child = child;
3564                                 this.block = block;
3565                         }
3566
3567                         public override bool ContainsEmitWithAwait ()
3568                         {
3569                                 return child.ContainsEmitWithAwait ();
3570                         }
3571
3572                         public override Expression CreateExpressionTree (ResolveContext ec)
3573                         {
3574                                 throw new NotSupportedException ();
3575                         }
3576
3577                         protected override Expression DoResolve (ResolveContext ec)
3578                         {
3579                                 if (child == null)
3580                                         return null;
3581
3582                                 child = child.Resolve (ec);
3583                                 if (child == null)
3584                                         return null;
3585
3586                                 eclass = child.eclass;
3587                                 type = child.Type;
3588                                 return this;
3589                         }
3590
3591                         public override void Emit (EmitContext ec)
3592                         {
3593                                 block.EmitScopeInitializers (ec);
3594                                 child.Emit (ec);
3595                         }
3596                 }
3597
3598                 protected ParametersCompiled parameters;
3599                 protected ParameterInfo[] parameter_info;
3600                 protected bool resolved;
3601                 protected ToplevelBlock top_block;
3602                 protected StateMachine state_machine;
3603                 protected Dictionary<string, object> labels;
3604
3605                 public ParametersBlock (Block parent, ParametersCompiled parameters, Location start, Flags flags = 0)
3606                         : base (parent, 0, start, start)
3607                 {
3608                         if (parameters == null)
3609                                 throw new ArgumentNullException ("parameters");
3610
3611                         this.parameters = parameters;
3612                         ParametersBlock = this;
3613
3614                         this.flags |= flags | (parent.ParametersBlock.flags & (Flags.YieldBlock | Flags.AwaitBlock));
3615
3616                         this.top_block = parent.ParametersBlock.top_block;
3617                         ProcessParameters ();
3618                 }
3619
3620                 protected ParametersBlock (ParametersCompiled parameters, Location start)
3621                         : base (null, 0, start, start)
3622                 {
3623                         if (parameters == null)
3624                                 throw new ArgumentNullException ("parameters");
3625
3626                         this.parameters = parameters;
3627                         ParametersBlock = this;
3628                 }
3629
3630                 //
3631                 // It's supposed to be used by method body implementation of anonymous methods
3632                 //
3633                 protected ParametersBlock (ParametersBlock source, ParametersCompiled parameters)
3634                         : base (null, 0, source.StartLocation, source.EndLocation)
3635                 {
3636                         this.parameters = parameters;
3637                         this.statements = source.statements;
3638                         this.scope_initializers = source.scope_initializers;
3639
3640                         this.resolved = true;
3641                         this.reachable = source.reachable;
3642                         this.am_storey = source.am_storey;
3643                         this.state_machine = source.state_machine;
3644                         this.flags = source.flags & Flags.ReachableEnd;
3645
3646                         ParametersBlock = this;
3647
3648                         //
3649                         // Overwrite original for comparison purposes when linking cross references
3650                         // between anonymous methods
3651                         //
3652                         Original = source.Original;
3653                 }
3654
3655                 #region Properties
3656
3657                 public bool IsAsync {
3658                         get {
3659                                 return (flags & Flags.HasAsyncModifier) != 0;
3660                         }
3661                         set {
3662                                 flags = value ? flags | Flags.HasAsyncModifier : flags & ~Flags.HasAsyncModifier;
3663                         }
3664                 }
3665
3666                 //
3667                 // Block has been converted to expression tree
3668                 //
3669                 public bool IsExpressionTree {
3670                         get {
3671                                 return (flags & Flags.IsExpressionTree) != 0;
3672                         }
3673                 }
3674
3675                 //
3676                 // The parameters for the block.
3677                 //
3678                 public ParametersCompiled Parameters {
3679                         get {
3680                                 return parameters;
3681                         }
3682                 }
3683
3684                 public StateMachine StateMachine {
3685                         get {
3686                                 return state_machine;
3687                         }
3688                 }
3689
3690                 public ToplevelBlock TopBlock {
3691                         get {
3692                                 return top_block;
3693                         }
3694                         set {
3695                                 top_block = value;
3696                         }
3697                 }
3698
3699                 public bool Resolved {
3700                         get {
3701                                 return (flags & Flags.Resolved) != 0;
3702                         }
3703                 }
3704
3705                 public int TemporaryLocalsCount { get; set; }
3706
3707                 #endregion
3708
3709                 //
3710                 // Checks whether all `out' parameters have been assigned.
3711                 //
3712                 public void CheckControlExit (FlowAnalysisContext fc)
3713                 {
3714                         CheckControlExit (fc, fc.DefiniteAssignment);
3715                 }
3716
3717                 public virtual void CheckControlExit (FlowAnalysisContext fc, DefiniteAssignmentBitSet dat)
3718                 {
3719                         if (parameter_info == null)
3720                                 return;
3721
3722                         foreach (var p in parameter_info) {
3723                                 if (p.VariableInfo == null)
3724                                         continue;
3725
3726                                 if (p.VariableInfo.IsAssigned (dat))
3727                                         continue;
3728
3729                                 fc.Report.Error (177, p.Location,
3730                                         "The out parameter `{0}' must be assigned to before control leaves the current method",
3731                                         p.Parameter.Name);
3732                         }                                       
3733                 }
3734
3735                 protected override void CloneTo (CloneContext clonectx, Statement t)
3736                 {
3737                         base.CloneTo (clonectx, t);
3738
3739                         var target = (ParametersBlock) t;
3740
3741                         //
3742                         // Clone label statements as well as they contain block reference
3743                         //
3744                         var pb = this;
3745                         while (true) {
3746                                 if (pb.labels != null) {
3747                                         target.labels = new Dictionary<string, object> ();
3748
3749                                         foreach (var entry in pb.labels) {
3750                                                 var list = entry.Value as List<LabeledStatement>;
3751
3752                                                 if (list != null) {
3753                                                         var list_clone = new List<LabeledStatement> ();
3754                                                         foreach (var lentry in list) {
3755                                                                 list_clone.Add (RemapLabeledStatement (lentry, clonectx.RemapBlockCopy (lentry.Block)));
3756                                                         }
3757
3758                                                         target.labels.Add (entry.Key, list_clone);
3759                                                 } else {
3760                                                         var labeled = (LabeledStatement) entry.Value;
3761                                                         target.labels.Add (entry.Key, RemapLabeledStatement (labeled, clonectx.RemapBlockCopy (labeled.Block)));
3762                                                 }
3763                                         }
3764
3765                                         break;
3766                                 }
3767
3768                                 if (pb.Parent == null)
3769                                         break;
3770
3771                                 pb = pb.Parent.ParametersBlock;
3772                         }
3773                 }
3774
3775                 public override Expression CreateExpressionTree (ResolveContext ec)
3776                 {
3777                         if (statements.Count == 1) {
3778                                 Expression expr = statements[0].CreateExpressionTree (ec);
3779                                 if (scope_initializers != null)
3780                                         expr = new BlockScopeExpression (expr, this);
3781
3782                                 return expr;
3783                         }
3784
3785                         return base.CreateExpressionTree (ec);
3786                 }
3787
3788                 public override void Emit (EmitContext ec)
3789                 {
3790                         if (state_machine != null && state_machine.OriginalSourceBlock != this) {
3791                                 DefineStoreyContainer (ec, state_machine);
3792                                 state_machine.EmitStoreyInstantiation (ec, this);
3793                         }
3794
3795                         base.Emit (ec);
3796                 }
3797
3798                 public void EmitEmbedded (EmitContext ec)
3799                 {
3800                         if (state_machine != null && state_machine.OriginalSourceBlock != this) {
3801                                 DefineStoreyContainer (ec, state_machine);
3802                                 state_machine.EmitStoreyInstantiation (ec, this);
3803                         }
3804
3805                         base.Emit (ec);
3806                 }
3807
3808                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
3809                 {
3810                         var res = base.DoFlowAnalysis (fc);
3811
3812                         if (HasReachableClosingBrace)
3813                                 CheckControlExit (fc);
3814
3815                         return res;
3816                 }
3817
3818                 public LabeledStatement GetLabel (string name, Block block)
3819                 {
3820                         //
3821                         // Cloned parameters blocks can have their own cloned version of top-level labels
3822                         //
3823                         if (labels == null) {
3824                                 if (Parent != null)
3825                                         return Parent.ParametersBlock.GetLabel (name, block);
3826
3827                                 return null;
3828                         }
3829
3830                         object value;
3831                         if (!labels.TryGetValue (name, out value)) {
3832                                 return null;
3833                         }
3834
3835                         var label = value as LabeledStatement;
3836                         Block b = block;
3837                         if (label != null) {
3838                                 if (IsLabelVisible (label, b))
3839                                         return label;
3840
3841                         } else {
3842                                 List<LabeledStatement> list = (List<LabeledStatement>) value;
3843                                 for (int i = 0; i < list.Count; ++i) {
3844                                         label = list[i];
3845                                         if (IsLabelVisible (label, b))
3846                                                 return label;
3847                                 }
3848                         }
3849
3850                         return null;
3851                 }
3852
3853                 static bool IsLabelVisible (LabeledStatement label, Block b)
3854                 {
3855                         do {
3856                                 if (label.Block == b)
3857                                         return true;
3858                                 b = b.Parent;
3859                         } while (b != null);
3860
3861                         return false;
3862                 }
3863
3864                 public ParameterInfo GetParameterInfo (Parameter p)
3865                 {
3866                         for (int i = 0; i < parameters.Count; ++i) {
3867                                 if (parameters[i] == p)
3868                                         return parameter_info[i];
3869                         }
3870
3871                         throw new ArgumentException ("Invalid parameter");
3872                 }
3873
3874                 public ParameterReference GetParameterReference (int index, Location loc)
3875                 {
3876                         return new ParameterReference (parameter_info[index], loc);
3877                 }
3878
3879                 public Statement PerformClone ()
3880                 {
3881                         CloneContext clonectx = new CloneContext ();
3882                         return Clone (clonectx);
3883                 }
3884
3885                 protected void ProcessParameters ()
3886                 {
3887                         if (parameters.Count == 0)
3888                                 return;
3889
3890                         parameter_info = new ParameterInfo[parameters.Count];
3891                         for (int i = 0; i < parameter_info.Length; ++i) {
3892                                 var p = parameters.FixedParameters[i];
3893                                 if (p == null)
3894                                         continue;
3895
3896                                 // TODO: Should use Parameter only and more block there
3897                                 parameter_info[i] = new ParameterInfo (this, i);
3898                                 if (p.Name != null)
3899                                         AddLocalName (p.Name, parameter_info[i]);
3900                         }
3901                 }
3902
3903                 LabeledStatement RemapLabeledStatement (LabeledStatement stmt, Block dst)
3904                 {
3905                         var src = stmt.Block;
3906
3907                         //
3908                         // Cannot remap label block if the label was not yet cloned which
3909                         // can happen in case of anonymous method inside anoynymous method
3910                         // with a label. But in this case we don't care because goto cannot
3911                         // jump of out anonymous method
3912                         //
3913                         if (src.ParametersBlock != this)
3914                                 return stmt;
3915
3916                         var src_stmts = src.Statements;
3917                         for (int i = 0; i < src_stmts.Count; ++i) {
3918                                 if (src_stmts[i] == stmt)
3919                                         return (LabeledStatement) dst.Statements[i];
3920                         }
3921
3922                         throw new InternalErrorException ("Should never be reached");
3923                 }
3924
3925                 public override bool Resolve (BlockContext bc)
3926                 {
3927                         // TODO: if ((flags & Flags.Resolved) != 0)
3928
3929                         if (resolved)
3930                                 return true;
3931
3932                         resolved = true;
3933
3934                         if (bc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
3935                                 flags |= Flags.IsExpressionTree;
3936
3937                         try {
3938                                 PrepareAssignmentAnalysis (bc);
3939
3940                                 if (!base.Resolve (bc))
3941                                         return false;
3942
3943                         } catch (Exception e) {
3944                                 if (e is CompletionResult || bc.Report.IsDisabled || e is FatalException || bc.Report.Printer is NullReportPrinter || bc.Module.Compiler.Settings.BreakOnInternalError)
3945                                         throw;
3946
3947                                 if (bc.CurrentBlock != null) {
3948                                         bc.Report.Error (584, bc.CurrentBlock.StartLocation, "Internal compiler error: {0}", e.Message);
3949                                 } else {
3950                                         bc.Report.Error (587, "Internal compiler error: {0}", e.Message);
3951                                 }
3952                         }
3953
3954                         //
3955                         // If an asynchronous body of F is either an expression classified as nothing, or a 
3956                         // statement block where no return statements have expressions, the inferred return type is Task
3957                         //
3958                         if (IsAsync) {
3959                                 var am = bc.CurrentAnonymousMethod as AnonymousMethodBody;
3960                                 if (am != null && am.ReturnTypeInference != null && !am.ReturnTypeInference.HasBounds (0)) {
3961                                         am.ReturnTypeInference = null;
3962                                         am.ReturnType = bc.Module.PredefinedTypes.Task.TypeSpec;
3963                                         return true;
3964                                 }
3965                         }
3966
3967                         return true;
3968                 }
3969
3970                 void PrepareAssignmentAnalysis (BlockContext bc)
3971                 {
3972                         for (int i = 0; i < parameters.Count; ++i) {
3973                                 var par = parameters.FixedParameters[i];
3974
3975                                 if ((par.ModFlags & Parameter.Modifier.OUT) == 0)
3976                                         continue;
3977
3978                                 parameter_info [i].VariableInfo = VariableInfo.Create (bc, (Parameter) par);
3979                         }
3980                 }
3981
3982                 public ToplevelBlock ConvertToIterator (IMethodData method, TypeDefinition host, TypeSpec iterator_type, bool is_enumerable)
3983                 {
3984                         var iterator = new Iterator (this, method, host, iterator_type, is_enumerable);
3985                         var stateMachine = new IteratorStorey (iterator);
3986
3987                         state_machine = stateMachine;
3988                         iterator.SetStateMachine (stateMachine);
3989
3990                         var tlb = new ToplevelBlock (host.Compiler, Parameters, Location.Null, Flags.CompilerGenerated);
3991                         tlb.Original = this;
3992                         tlb.state_machine = stateMachine;
3993                         tlb.AddStatement (new Return (iterator, iterator.Location));
3994                         return tlb;
3995                 }
3996
3997                 public ParametersBlock ConvertToAsyncTask (IMemberContext context, TypeDefinition host, ParametersCompiled parameters, TypeSpec returnType, TypeSpec delegateType, Location loc)
3998                 {
3999                         for (int i = 0; i < parameters.Count; i++) {
4000                                 Parameter p = parameters[i];
4001                                 Parameter.Modifier mod = p.ModFlags;
4002                                 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
4003                                         host.Compiler.Report.Error (1988, p.Location,
4004                                                 "Async methods cannot have ref or out parameters");
4005                                         return this;
4006                                 }
4007
4008                                 if (p is ArglistParameter) {
4009                                         host.Compiler.Report.Error (4006, p.Location,
4010                                                 "__arglist is not allowed in parameter list of async methods");
4011                                         return this;
4012                                 }
4013
4014                                 if (parameters.Types[i].IsPointer) {
4015                                         host.Compiler.Report.Error (4005, p.Location,
4016                                                 "Async methods cannot have unsafe parameters");
4017                                         return this;
4018                                 }
4019                         }
4020
4021                         if (!HasAwait) {
4022                                 host.Compiler.Report.Warning (1998, 1, loc,
4023                                         "Async block lacks `await' operator and will run synchronously");
4024                         }
4025
4026                         var block_type = host.Module.Compiler.BuiltinTypes.Void;
4027                         var initializer = new AsyncInitializer (this, host, block_type);
4028                         initializer.Type = block_type;
4029                         initializer.DelegateType = delegateType;
4030
4031                         var stateMachine = new AsyncTaskStorey (this, context, initializer, returnType);
4032
4033                         state_machine = stateMachine;
4034                         initializer.SetStateMachine (stateMachine);
4035
4036                         const Flags flags = Flags.CompilerGenerated;
4037
4038                         var b = this is ToplevelBlock ?
4039                                 new ToplevelBlock (host.Compiler, Parameters, Location.Null, flags) :
4040                                 new ParametersBlock (Parent, parameters, Location.Null, flags | Flags.HasAsyncModifier);
4041
4042                         b.Original = this;
4043                         b.state_machine = stateMachine;
4044                         b.AddStatement (new AsyncInitializerStatement (initializer));
4045                         return b;
4046                 }
4047         }
4048
4049         //
4050         //
4051         //
4052         public class ToplevelBlock : ParametersBlock
4053         {
4054                 LocalVariable this_variable;
4055                 CompilerContext compiler;
4056                 Dictionary<string, object> names;
4057
4058                 List<ExplicitBlock> this_references;
4059
4060                 public ToplevelBlock (CompilerContext ctx, Location loc)
4061                         : this (ctx, ParametersCompiled.EmptyReadOnlyParameters, loc)
4062                 {
4063                 }
4064
4065                 public ToplevelBlock (CompilerContext ctx, ParametersCompiled parameters, Location start, Flags flags = 0)
4066                         : base (parameters, start)
4067                 {
4068                         this.compiler = ctx;
4069                         this.flags = flags;
4070                         top_block = this;
4071
4072                         ProcessParameters ();
4073                 }
4074
4075                 //
4076                 // Recreates a top level block from parameters block. Used for
4077                 // compiler generated methods where the original block comes from
4078                 // explicit child block. This works for already resolved blocks
4079                 // only to ensure we resolve them in the correct flow order
4080                 //
4081                 public ToplevelBlock (ParametersBlock source, ParametersCompiled parameters)
4082                         : base (source, parameters)
4083                 {
4084                         this.compiler = source.TopBlock.compiler;
4085                         top_block = this;
4086                 }
4087
4088                 public bool IsIterator {
4089                         get {
4090                                 return (flags & Flags.Iterator) != 0;
4091                         }
4092                         set {
4093                                 flags = value ? flags | Flags.Iterator : flags & ~Flags.Iterator;
4094                         }
4095                 }
4096
4097                 public Report Report {
4098                         get {
4099                                 return compiler.Report;
4100                         }
4101                 }
4102
4103                 //
4104                 // Used by anonymous blocks to track references of `this' variable
4105                 //
4106                 public List<ExplicitBlock> ThisReferencesFromChildrenBlock {
4107                         get {
4108                                 return this_references;
4109                         }
4110                 }
4111
4112                 //
4113                 // Returns the "this" instance variable of this block.
4114                 // See AddThisVariable() for more information.
4115                 //
4116                 public LocalVariable ThisVariable {
4117                         get {
4118                                 return this_variable;
4119                         }
4120                 }
4121
4122                 public void AddLocalName (string name, INamedBlockVariable li, bool ignoreChildrenBlocks)
4123                 {
4124                         if (names == null)
4125                                 names = new Dictionary<string, object> ();
4126
4127                         object value;
4128                         if (!names.TryGetValue (name, out value)) {
4129                                 names.Add (name, li);
4130                                 return;
4131                         }
4132
4133                         INamedBlockVariable existing = value as INamedBlockVariable;
4134                         List<INamedBlockVariable> existing_list;
4135                         if (existing != null) {
4136                                 existing_list = new List<INamedBlockVariable> ();
4137                                 existing_list.Add (existing);
4138                                 names[name] = existing_list;
4139                         } else {
4140                                 existing_list = (List<INamedBlockVariable>) value;
4141                         }
4142
4143                         //
4144                         // A collision checking between local names
4145                         //
4146                         var variable_block = li.Block.Explicit;
4147                         for (int i = 0; i < existing_list.Count; ++i) {
4148                                 existing = existing_list[i];
4149                                 Block b = existing.Block.Explicit;
4150
4151                                 // Collision at same level
4152                                 if (variable_block == b) {
4153                                         li.Block.Error_AlreadyDeclared (name, li);
4154                                         break;
4155                                 }
4156
4157                                 // Collision with parent
4158                                 Block parent = variable_block;
4159                                 while ((parent = parent.Parent) != null) {
4160                                         if (parent == b) {
4161                                                 li.Block.Error_AlreadyDeclared (name, li, "parent or current");
4162                                                 i = existing_list.Count;
4163                                                 break;
4164                                         }
4165                                 }
4166
4167                                 if (!ignoreChildrenBlocks && variable_block.Parent != b.Parent) {
4168                                         // Collision with children
4169                                         while ((b = b.Parent) != null) {
4170                                                 if (variable_block == b) {
4171                                                         li.Block.Error_AlreadyDeclared (name, li, "child");
4172                                                         i = existing_list.Count;
4173                                                         break;
4174                                                 }
4175                                         }
4176                                 }
4177                         }
4178
4179                         existing_list.Add (li);
4180                 }
4181
4182                 public void AddLabel (string name, LabeledStatement label)
4183                 {
4184                         if (labels == null)
4185                                 labels = new Dictionary<string, object> ();
4186
4187                         object value;
4188                         if (!labels.TryGetValue (name, out value)) {
4189                                 labels.Add (name, label);
4190                                 return;
4191                         }
4192
4193                         LabeledStatement existing = value as LabeledStatement;
4194                         List<LabeledStatement> existing_list;
4195                         if (existing != null) {
4196                                 existing_list = new List<LabeledStatement> ();
4197                                 existing_list.Add (existing);
4198                                 labels[name] = existing_list;
4199                         } else {
4200                                 existing_list = (List<LabeledStatement>) value;
4201                         }
4202
4203                         //
4204                         // A collision checking between labels
4205                         //
4206                         for (int i = 0; i < existing_list.Count; ++i) {
4207                                 existing = existing_list[i];
4208                                 Block b = existing.Block;
4209
4210                                 // Collision at same level
4211                                 if (label.Block == b) {
4212                                         Report.SymbolRelatedToPreviousError (existing.loc, name);
4213                                         Report.Error (140, label.loc, "The label `{0}' is a duplicate", name);
4214                                         break;
4215                                 }
4216
4217                                 // Collision with parent
4218                                 b = label.Block;
4219                                 while ((b = b.Parent) != null) {
4220                                         if (existing.Block == b) {
4221                                                 Report.Error (158, label.loc,
4222                                                         "The label `{0}' shadows another label by the same name in a contained scope", name);
4223                                                 i = existing_list.Count;
4224                                                 break;
4225                                         }
4226                                 }
4227
4228                                 // Collision with with children
4229                                 b = existing.Block;
4230                                 while ((b = b.Parent) != null) {
4231                                         if (label.Block == b) {
4232                                                 Report.Error (158, label.loc,
4233                                                         "The label `{0}' shadows another label by the same name in a contained scope", name);
4234                                                 i = existing_list.Count;
4235                                                 break;
4236                                         }
4237                                 }
4238                         }
4239
4240                         existing_list.Add (label);
4241                 }
4242
4243                 public void AddThisReferenceFromChildrenBlock (ExplicitBlock block)
4244                 {
4245                         if (this_references == null)
4246                                 this_references = new List<ExplicitBlock> ();
4247
4248                         if (!this_references.Contains (block))
4249                                 this_references.Add (block);
4250                 }
4251
4252                 public void RemoveThisReferenceFromChildrenBlock (ExplicitBlock block)
4253                 {
4254                         this_references.Remove (block);
4255                 }
4256
4257                 //
4258                 // Creates an arguments set from all parameters, useful for method proxy calls
4259                 //
4260                 public Arguments GetAllParametersArguments ()
4261                 {
4262                         int count = parameters.Count;
4263                         Arguments args = new Arguments (count);
4264                         for (int i = 0; i < count; ++i) {
4265                                 var pi = parameter_info[i];
4266                                 var arg_expr = GetParameterReference (i, pi.Location);
4267
4268                                 Argument.AType atype_modifier;
4269                                 switch (pi.Parameter.ParameterModifier & Parameter.Modifier.RefOutMask) {
4270                                 case Parameter.Modifier.REF:
4271                                         atype_modifier = Argument.AType.Ref;
4272                                         break;
4273                                 case Parameter.Modifier.OUT:
4274                                         atype_modifier = Argument.AType.Out;
4275                                         break;
4276                                 default:
4277                                         atype_modifier = 0;
4278                                         break;
4279                                 }
4280
4281                                 args.Add (new Argument (arg_expr, atype_modifier));
4282                         }
4283
4284                         return args;
4285                 }
4286
4287                 //
4288                 // Lookup inside a block, the returned value can represent 3 states
4289                 //
4290                 // true+variable: A local name was found and it's valid
4291                 // false+variable: A local name was found in a child block only
4292                 // false+null: No local name was found
4293                 //
4294                 public bool GetLocalName (string name, Block block, ref INamedBlockVariable variable)
4295                 {
4296                         if (names == null)
4297                                 return false;
4298
4299                         object value;
4300                         if (!names.TryGetValue (name, out value))
4301                                 return false;
4302
4303                         variable = value as INamedBlockVariable;
4304                         Block b = block;
4305                         if (variable != null) {
4306                                 do {
4307                                         if (variable.Block == b.Original)
4308                                                 return true;
4309
4310                                         b = b.Parent;
4311                                 } while (b != null);
4312
4313                                 b = variable.Block;
4314                                 do {
4315                                         if (block == b)
4316                                                 return false;
4317
4318                                         b = b.Parent;
4319                                 } while (b != null);
4320                         } else {
4321                                 List<INamedBlockVariable> list = (List<INamedBlockVariable>) value;
4322                                 for (int i = 0; i < list.Count; ++i) {
4323                                         variable = list[i];
4324                                         do {
4325                                                 if (variable.Block == b.Original)
4326                                                         return true;
4327
4328                                                 b = b.Parent;
4329                                         } while (b != null);
4330
4331                                         b = variable.Block;
4332                                         do {
4333                                                 if (block == b)
4334                                                         return false;
4335
4336                                                 b = b.Parent;
4337                                         } while (b != null);
4338
4339                                         b = block;
4340                                 }
4341                         }
4342
4343                         variable = null;
4344                         return false;
4345                 }
4346
4347                 public void IncludeBlock (ParametersBlock pb, ToplevelBlock block)
4348                 {
4349                         if (block.names != null) {
4350                                 foreach (var n in block.names) {
4351                                         var variable = n.Value as INamedBlockVariable;
4352                                         if (variable != null) {
4353                                                 if (variable.Block.ParametersBlock == pb)
4354                                                         AddLocalName (n.Key, variable, false);
4355                                                 continue;
4356                                         }
4357
4358                                         foreach (var v in (List<INamedBlockVariable>) n.Value)
4359                                                 if (v.Block.ParametersBlock == pb)
4360                                                         AddLocalName (n.Key, v, false);
4361                                 }
4362                         }
4363                 }
4364
4365                 // <summary>
4366                 //   This is used by non-static `struct' constructors which do not have an
4367                 //   initializer - in this case, the constructor must initialize all of the
4368                 //   struct's fields.  To do this, we add a "this" variable and use the flow
4369                 //   analysis code to ensure that it's been fully initialized before control
4370                 //   leaves the constructor.
4371                 // </summary>
4372                 public void AddThisVariable (BlockContext bc)
4373                 {
4374                         if (this_variable != null)
4375                                 throw new InternalErrorException (StartLocation.ToString ());
4376
4377                         this_variable = new LocalVariable (this, "this", LocalVariable.Flags.IsThis | LocalVariable.Flags.Used, StartLocation);
4378                         this_variable.Type = bc.CurrentType;
4379                         this_variable.PrepareAssignmentAnalysis (bc);
4380                 }
4381
4382                 public override void CheckControlExit (FlowAnalysisContext fc, DefiniteAssignmentBitSet dat)
4383                 {
4384                         //
4385                         // If we're a non-static struct constructor which doesn't have an
4386                         // initializer, then we must initialize all of the struct's fields.
4387                         //
4388                         if (this_variable != null)
4389                                 this_variable.IsThisAssigned (fc, this);
4390
4391                         base.CheckControlExit (fc, dat);
4392                 }
4393
4394                 public override void Emit (EmitContext ec)
4395                 {
4396                         if (Report.Errors > 0)
4397                                 return;
4398
4399                         try {
4400                         if (IsCompilerGenerated) {
4401                                 using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
4402                                         base.Emit (ec);
4403                                 }
4404                         } else {
4405                                 base.Emit (ec);
4406                         }
4407
4408                         //
4409                         // If `HasReturnLabel' is set, then we already emitted a
4410                         // jump to the end of the method, so we must emit a `ret'
4411                         // there.
4412                         //
4413                         // Unfortunately, System.Reflection.Emit automatically emits
4414                         // a leave to the end of a finally block.  This is a problem
4415                         // if no code is following the try/finally block since we may
4416                         // jump to a point after the end of the method.
4417                         // As a workaround, we're always creating a return label in
4418                         // this case.
4419                         //
4420                         if (ec.HasReturnLabel || HasReachableClosingBrace) {
4421                                 if (ec.HasReturnLabel)
4422                                         ec.MarkLabel (ec.ReturnLabel);
4423
4424                                 if (ec.EmitAccurateDebugInfo && !IsCompilerGenerated)
4425                                         ec.Mark (EndLocation);
4426
4427                                 if (ec.ReturnType.Kind != MemberKind.Void)
4428                                         ec.Emit (OpCodes.Ldloc, ec.TemporaryReturn ());
4429
4430                                 ec.Emit (OpCodes.Ret);
4431                         }
4432
4433                         } catch (Exception e) {
4434                                 throw new InternalErrorException (e, StartLocation);
4435                         }
4436                 }
4437
4438                 public bool Resolve (BlockContext bc, IMethodData md)
4439                 {
4440                         if (resolved)
4441                                 return true;
4442
4443                         var errors = bc.Report.Errors;
4444
4445                         base.Resolve (bc);
4446
4447                         if (bc.Report.Errors > errors)
4448                                 return false;
4449
4450                         MarkReachable (new Reachability ());
4451
4452                         if (HasReachableClosingBrace && bc.ReturnType.Kind != MemberKind.Void) {
4453                                 // TODO: var md = bc.CurrentMemberDefinition;
4454                                 bc.Report.Error (161, md.Location, "`{0}': not all code paths return a value", md.GetSignatureForError ());
4455                         }
4456
4457                         if ((flags & Flags.NoFlowAnalysis) != 0)
4458                                 return true;
4459
4460                         var fc = new FlowAnalysisContext (bc.Module.Compiler, this, bc.AssignmentInfoOffset);
4461                         try {
4462                                 FlowAnalysis (fc);
4463                         } catch (Exception e) {
4464                                 throw new InternalErrorException (e, StartLocation);
4465                         }
4466
4467                         return true;
4468                 }
4469         }
4470         
4471         public class SwitchLabel : Statement
4472         {
4473                 Constant converted;
4474                 Expression label;
4475
4476                 Label? il_label;
4477
4478                 //
4479                 // if expr == null, then it is the default case.
4480                 //
4481                 public SwitchLabel (Expression expr, Location l)
4482                 {
4483                         label = expr;
4484                         loc = l;
4485                 }
4486
4487                 public bool IsDefault {
4488                         get {
4489                                 return label == null;
4490                         }
4491                 }
4492
4493                 public Expression Label {
4494                         get {
4495                                 return label;
4496                         }
4497                 }
4498
4499                 public Location Location {
4500                         get {
4501                                 return loc;
4502                         }
4503                 }
4504
4505                 public Constant Converted {
4506                         get {
4507                                 return converted;
4508                         }
4509                         set {
4510                                 converted = value; 
4511                         }
4512                 }
4513
4514                 public bool PatternMatching { get; set; }
4515
4516                 public bool SectionStart { get; set; }
4517
4518                 public Label GetILLabel (EmitContext ec)
4519                 {
4520                         if (il_label == null){
4521                                 il_label = ec.DefineLabel ();
4522                         }
4523
4524                         return il_label.Value;
4525                 }
4526
4527                 protected override void DoEmit (EmitContext ec)
4528                 {
4529                         ec.MarkLabel (GetILLabel (ec));
4530                 }
4531
4532                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
4533                 {
4534                         if (!SectionStart)
4535                                 return false;
4536
4537                         fc.BranchDefiniteAssignment (fc.SwitchInitialDefinitiveAssignment);
4538                         return false;
4539                 }
4540
4541                 public override bool Resolve (BlockContext bc)
4542                 {
4543                         if (ResolveAndReduce (bc))
4544                                 bc.Switch.RegisterLabel (bc, this);
4545
4546                         return true;
4547                 }
4548
4549                 //
4550                 // Resolves the expression, reduces it to a literal if possible
4551                 // and then converts it to the requested type.
4552                 //
4553                 bool ResolveAndReduce (BlockContext bc)
4554                 {
4555                         if (IsDefault)
4556                                 return true;
4557
4558                         var switch_statement = bc.Switch;
4559
4560                         if (PatternMatching) {
4561                                 label = new Is (switch_statement.ExpressionValue, label, loc).Resolve (bc);
4562                                 return label != null;
4563                         }
4564
4565                         var c = label.ResolveLabelConstant (bc);
4566                         if (c == null)
4567                                 return false;
4568
4569                         if (switch_statement.IsNullable && c is NullLiteral) {
4570                                 converted = c;
4571                                 return true;
4572                         }
4573
4574                         if (switch_statement.IsPatternMatching) {
4575                                 label = new Is (switch_statement.ExpressionValue, label, loc).Resolve (bc);
4576                                 return true;
4577                         }
4578
4579                         converted = c.ImplicitConversionRequired (bc, switch_statement.SwitchType);
4580                         return converted != null;
4581                 }
4582
4583                 public void Error_AlreadyOccurs (ResolveContext ec, SwitchLabel collision_with)
4584                 {
4585                         ec.Report.SymbolRelatedToPreviousError (collision_with.loc, null);
4586                         ec.Report.Error (152, loc, "The label `{0}' already occurs in this switch statement", GetSignatureForError ());
4587                 }
4588
4589                 protected override void CloneTo (CloneContext clonectx, Statement target)
4590                 {
4591                         var t = (SwitchLabel) target;
4592                         if (label != null)
4593                                 t.label = label.Clone (clonectx);
4594                 }
4595
4596                 public override object Accept (StructuralVisitor visitor)
4597                 {
4598                         return visitor.Visit (this);
4599                 }
4600
4601                 public string GetSignatureForError ()
4602                 {
4603                         string label;
4604                         if (converted == null)
4605                                 label = "default";
4606                         else
4607                                 label = converted.GetValueAsLiteral ();
4608
4609                         return string.Format ("case {0}:", label);
4610                 }
4611         }
4612
4613         public class Switch : LoopStatement
4614         {
4615                 // structure used to hold blocks of keys while calculating table switch
4616                 sealed class LabelsRange : IComparable<LabelsRange>
4617                 {
4618                         public readonly long min;
4619                         public long max;
4620                         public readonly List<long> label_values;
4621
4622                         public LabelsRange (long value)
4623                         {
4624                                 min = max = value;
4625                                 label_values = new List<long> ();
4626                                 label_values.Add (value);
4627                         }
4628
4629                         public LabelsRange (long min, long max, ICollection<long> values)
4630                         {
4631                                 this.min = min;
4632                                 this.max = max;
4633                                 this.label_values = new List<long> (values);
4634                         }
4635
4636                         public long Range {
4637                                 get {
4638                                         return max - min + 1;
4639                                 }
4640                         }
4641
4642                         public bool AddValue (long value)
4643                         {
4644                                 var gap = value - min + 1;
4645                                 // Ensure the range has > 50% occupancy
4646                                 if (gap > 2 * (label_values.Count + 1) || gap <= 0)
4647                                         return false;
4648
4649                                 max = value;
4650                                 label_values.Add (value);
4651                                 return true;
4652                         }
4653
4654                         public int CompareTo (LabelsRange other)
4655                         {
4656                                 int nLength = label_values.Count;
4657                                 int nLengthOther = other.label_values.Count;
4658                                 if (nLengthOther == nLength)
4659                                         return (int) (other.min - min);
4660
4661                                 return nLength - nLengthOther;
4662                         }
4663                 }
4664
4665                 sealed class DispatchStatement : Statement
4666                 {
4667                         readonly Switch body;
4668
4669                         public DispatchStatement (Switch body)
4670                         {
4671                                 this.body = body;
4672                         }
4673
4674                         protected override void CloneTo (CloneContext clonectx, Statement target)
4675                         {
4676                                 throw new NotImplementedException ();
4677                         }
4678
4679                         protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
4680                         {
4681                                 return false;
4682                         }
4683
4684                         protected override void DoEmit (EmitContext ec)
4685                         {
4686                                 body.EmitDispatch (ec);
4687                         }
4688                 }
4689
4690                 class MissingBreak : Statement
4691                 {
4692                         readonly SwitchLabel label;
4693
4694                         public MissingBreak (SwitchLabel sl)
4695                         {
4696                                 this.label = sl;
4697                                 this.loc = sl.loc;
4698                         }
4699
4700                         public bool FallOut { get; set; }
4701
4702                         protected override void DoEmit (EmitContext ec)
4703                         {
4704                         }
4705
4706                         protected override void CloneTo (CloneContext clonectx, Statement target)
4707                         {
4708                         }
4709
4710                         protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
4711                         {
4712                                 if (FallOut) {
4713                                         fc.Report.Error (8070, loc, "Control cannot fall out of switch statement through final case label `{0}'",
4714                                                 label.GetSignatureForError ());
4715                                 } else {
4716                                         fc.Report.Error (163, loc, "Control cannot fall through from one case label `{0}' to another",
4717                                                 label.GetSignatureForError ());
4718                                 }
4719                                 return true;
4720                         }
4721                 }
4722
4723                 public Expression Expr;
4724
4725                 //
4726                 // Mapping of all labels to their SwitchLabels
4727                 //
4728                 Dictionary<long, SwitchLabel> labels;
4729                 Dictionary<string, SwitchLabel> string_labels;
4730                 List<SwitchLabel> case_labels;
4731
4732                 List<Tuple<GotoCase, Constant>> goto_cases;
4733                 List<DefiniteAssignmentBitSet> end_reachable_das;
4734
4735                 /// <summary>
4736                 ///   The governing switch type
4737                 /// </summary>
4738                 public TypeSpec SwitchType;
4739
4740                 Expression new_expr;
4741
4742                 SwitchLabel case_null;
4743                 SwitchLabel case_default;
4744
4745                 Label defaultLabel, nullLabel;
4746                 VariableReference value;
4747                 ExpressionStatement string_dictionary;
4748                 FieldExpr switch_cache_field;
4749                 ExplicitBlock block;
4750                 bool end_reachable;
4751
4752                 //
4753                 // Nullable Types support
4754                 //
4755                 Nullable.Unwrap unwrap;
4756
4757                 public Switch (Expression e, ExplicitBlock block, Location l)
4758                         : base (block)
4759                 {
4760                         Expr = e;
4761                         this.block = block;
4762                         loc = l;
4763                 }
4764
4765                 public SwitchLabel ActiveLabel { get; set; }
4766
4767                 public ExplicitBlock Block {
4768                         get {
4769                                 return block;
4770                         }
4771                 }
4772
4773                 public SwitchLabel DefaultLabel {
4774                         get {
4775                                 return case_default;
4776                         }
4777                 }
4778
4779                 public bool IsNullable {
4780                         get {
4781                                 return unwrap != null;
4782                         }
4783                 }
4784
4785                 public bool IsPatternMatching {
4786                         get {
4787                                 return new_expr == null && SwitchType != null;
4788                         }
4789                 }
4790
4791                 public List<SwitchLabel> RegisteredLabels {
4792                         get {
4793                                 return case_labels;
4794                         }
4795                 }
4796
4797                 public VariableReference ExpressionValue {
4798                         get {
4799                                 return value;
4800                         }
4801                 }
4802
4803                 //
4804                 // Determines the governing type for a switch.  The returned
4805                 // expression might be the expression from the switch, or an
4806                 // expression that includes any potential conversions to
4807                 //
4808                 static Expression SwitchGoverningType (ResolveContext rc, Expression expr, bool unwrapExpr)
4809                 {
4810                         switch (expr.Type.BuiltinType) {
4811                         case BuiltinTypeSpec.Type.Byte:
4812                         case BuiltinTypeSpec.Type.SByte:
4813                         case BuiltinTypeSpec.Type.UShort:
4814                         case BuiltinTypeSpec.Type.Short:
4815                         case BuiltinTypeSpec.Type.UInt:
4816                         case BuiltinTypeSpec.Type.Int:
4817                         case BuiltinTypeSpec.Type.ULong:
4818                         case BuiltinTypeSpec.Type.Long:
4819                         case BuiltinTypeSpec.Type.Char:
4820                         case BuiltinTypeSpec.Type.String:
4821                         case BuiltinTypeSpec.Type.Bool:
4822                                 return expr;
4823                         }
4824
4825                         if (expr.Type.IsEnum)
4826                                 return expr;
4827
4828                         //
4829                         // Try to find a *user* defined implicit conversion.
4830                         //
4831                         // If there is no implicit conversion, or if there are multiple
4832                         // conversions, we have to report an error
4833                         //
4834                         Expression converted = null;
4835                         foreach (TypeSpec tt in rc.Module.PredefinedTypes.SwitchUserTypes) {
4836
4837                                 if (!unwrapExpr && tt.IsNullableType && expr.Type.IsNullableType)
4838                                         break;
4839
4840                                 var restr = Convert.UserConversionRestriction.ImplicitOnly |
4841                                         Convert.UserConversionRestriction.ProbingOnly;
4842
4843                                 if (unwrapExpr)
4844                                         restr |= Convert.UserConversionRestriction.NullableSourceOnly;
4845
4846                                 var e = Convert.UserDefinedConversion (rc, expr, tt, restr, Location.Null);
4847                                 if (e == null)
4848                                         continue;
4849
4850                                 //
4851                                 // Ignore over-worked ImplicitUserConversions that do
4852                                 // an implicit conversion in addition to the user conversion.
4853                                 // 
4854                                 var uc = e as UserCast;
4855                                 if (uc == null)
4856                                         continue;
4857
4858                                 if (converted != null){
4859 //                                      rc.Report.ExtraInformation (loc, "(Ambiguous implicit user defined conversion in previous ");
4860                                         return null;
4861                                 }
4862
4863                                 converted = e;
4864                         }
4865                         return converted;
4866                 }
4867
4868                 public static TypeSpec[] CreateSwitchUserTypes (ModuleContainer module, TypeSpec nullable)
4869                 {
4870                         var types = module.Compiler.BuiltinTypes;
4871
4872                         // LAMESPEC: For some reason it does not contain bool which looks like csc bug
4873                         TypeSpec[] stypes = new[] {
4874                                 types.SByte,
4875                                 types.Byte,
4876                                 types.Short,
4877                                 types.UShort,
4878                                 types.Int,
4879                                 types.UInt,
4880                                 types.Long,
4881                                 types.ULong,
4882                                 types.Char,
4883                                 types.String
4884                         };
4885
4886                         if (nullable != null) {
4887
4888                                 Array.Resize (ref stypes, stypes.Length + 9);
4889
4890                                 for (int i = 0; i < 9; ++i) {
4891                                         stypes [10 + i] = nullable.MakeGenericType (module, new [] { stypes [i] });
4892                                 }
4893                         }
4894
4895                         return stypes;
4896                 }
4897
4898                 public void RegisterLabel (BlockContext rc, SwitchLabel sl)
4899                 {
4900                         case_labels.Add (sl);
4901
4902                         if (sl.IsDefault) {
4903                                 if (case_default != null) {
4904                                         sl.Error_AlreadyOccurs (rc, case_default);
4905                                 } else {
4906                                         case_default = sl;
4907                                 }
4908
4909                                 return;
4910                         }
4911
4912                         if (sl.Converted == null)
4913                                 return;
4914
4915                         try {
4916                                 if (string_labels != null) {
4917                                         string string_value = sl.Converted.GetValue () as string;
4918                                         if (string_value == null)
4919                                                 case_null = sl;
4920                                         else
4921                                                 string_labels.Add (string_value, sl);
4922                                 } else {
4923                                         if (sl.Converted.IsNull) {
4924                                                 case_null = sl;
4925                                         } else {
4926                                                 labels.Add (sl.Converted.GetValueAsLong (), sl);
4927                                         }
4928                                 }
4929                         } catch (ArgumentException) {
4930                                 if (string_labels != null)
4931                                         sl.Error_AlreadyOccurs (rc, string_labels[(string) sl.Converted.GetValue ()]);
4932                                 else
4933                                         sl.Error_AlreadyOccurs (rc, labels[sl.Converted.GetValueAsLong ()]);
4934                         }
4935                 }
4936                 
4937                 //
4938                 // This method emits code for a lookup-based switch statement (non-string)
4939                 // Basically it groups the cases into blocks that are at least half full,
4940                 // and then spits out individual lookup opcodes for each block.
4941                 // It emits the longest blocks first, and short blocks are just
4942                 // handled with direct compares.
4943                 //
4944                 void EmitTableSwitch (EmitContext ec, Expression val)
4945                 {
4946                         if (labels != null && labels.Count > 0) {
4947                                 List<LabelsRange> ranges;
4948                                 if (string_labels != null) {
4949                                         // We have done all hard work for string already
4950                                         // setup single range only
4951                                         ranges = new List<LabelsRange> (1);
4952                                         ranges.Add (new LabelsRange (0, labels.Count - 1, labels.Keys));
4953                                 } else {
4954                                         var element_keys = new long[labels.Count];
4955                                         labels.Keys.CopyTo (element_keys, 0);
4956                                         Array.Sort (element_keys);
4957
4958                                         //
4959                                         // Build possible ranges of switch labes to reduce number
4960                                         // of comparisons
4961                                         //
4962                                         ranges = new List<LabelsRange> (element_keys.Length);
4963                                         var range = new LabelsRange (element_keys[0]);
4964                                         ranges.Add (range);
4965                                         for (int i = 1; i < element_keys.Length; ++i) {
4966                                                 var l = element_keys[i];
4967                                                 if (range.AddValue (l))
4968                                                         continue;
4969
4970                                                 range = new LabelsRange (l);
4971                                                 ranges.Add (range);
4972                                         }
4973
4974                                         // sort the blocks so we can tackle the largest ones first
4975                                         ranges.Sort ();
4976                                 }
4977
4978                                 Label lbl_default = defaultLabel;
4979                                 TypeSpec compare_type = SwitchType.IsEnum ? EnumSpec.GetUnderlyingType (SwitchType) : SwitchType;
4980
4981                                 for (int range_index = ranges.Count - 1; range_index >= 0; --range_index) {
4982                                         LabelsRange kb = ranges[range_index];
4983                                         lbl_default = (range_index == 0) ? defaultLabel : ec.DefineLabel ();
4984
4985                                         // Optimize small ranges using simple equality check
4986                                         if (kb.Range <= 2) {
4987                                                 foreach (var key in kb.label_values) {
4988                                                         SwitchLabel sl = labels[key];
4989                                                         if (sl == case_default || sl == case_null)
4990                                                                 continue;
4991
4992                                                         if (sl.Converted.IsZeroInteger) {
4993                                                                 val.EmitBranchable (ec, sl.GetILLabel (ec), false);
4994                                                         } else {
4995                                                                 val.Emit (ec);
4996                                                                 sl.Converted.Emit (ec);
4997                                                                 ec.Emit (OpCodes.Beq, sl.GetILLabel (ec));
4998                                                         }
4999                                                 }
5000                                         } else {
5001                                                 // TODO: if all the keys in the block are the same and there are
5002                                                 //       no gaps/defaults then just use a range-check.
5003                                                 if (compare_type.BuiltinType == BuiltinTypeSpec.Type.Long || compare_type.BuiltinType == BuiltinTypeSpec.Type.ULong) {
5004                                                         // TODO: optimize constant/I4 cases
5005
5006                                                         // check block range (could be > 2^31)
5007                                                         val.Emit (ec);
5008                                                         ec.EmitLong (kb.min);
5009                                                         ec.Emit (OpCodes.Blt, lbl_default);
5010
5011                                                         val.Emit (ec);
5012                                                         ec.EmitLong (kb.max);
5013                                                         ec.Emit (OpCodes.Bgt, lbl_default);
5014
5015                                                         // normalize range
5016                                                         val.Emit (ec);
5017                                                         if (kb.min != 0) {
5018                                                                 ec.EmitLong (kb.min);
5019                                                                 ec.Emit (OpCodes.Sub);
5020                                                         }
5021
5022                                                         ec.Emit (OpCodes.Conv_I4);      // assumes < 2^31 labels!
5023                                                 } else {
5024                                                         // normalize range
5025                                                         val.Emit (ec);
5026                                                         int first = (int) kb.min;
5027                                                         if (first > 0) {
5028                                                                 ec.EmitInt (first);
5029                                                                 ec.Emit (OpCodes.Sub);
5030                                                         } else if (first < 0) {
5031                                                                 ec.EmitInt (-first);
5032                                                                 ec.Emit (OpCodes.Add);
5033                                                         }
5034                                                 }
5035
5036                                                 // first, build the list of labels for the switch
5037                                                 int iKey = 0;
5038                                                 long cJumps = kb.Range;
5039                                                 Label[] switch_labels = new Label[cJumps];
5040                                                 for (int iJump = 0; iJump < cJumps; iJump++) {
5041                                                         var key = kb.label_values[iKey];
5042                                                         if (key == kb.min + iJump) {
5043                                                                 switch_labels[iJump] = labels[key].GetILLabel (ec);
5044                                                                 iKey++;
5045                                                         } else {
5046                                                                 switch_labels[iJump] = lbl_default;
5047                                                         }
5048                                                 }
5049
5050                                                 // emit the switch opcode
5051                                                 ec.Emit (OpCodes.Switch, switch_labels);
5052                                         }
5053
5054                                         // mark the default for this block
5055                                         if (range_index != 0)
5056                                                 ec.MarkLabel (lbl_default);
5057                                 }
5058
5059                                 // the last default just goes to the end
5060                                 if (ranges.Count > 0)
5061                                         ec.Emit (OpCodes.Br, lbl_default);
5062                         }
5063                 }
5064                 
5065                 public SwitchLabel FindLabel (Constant value)
5066                 {
5067                         SwitchLabel sl = null;
5068
5069                         if (string_labels != null) {
5070                                 string s = value.GetValue () as string;
5071                                 if (s == null) {
5072                                         if (case_null != null)
5073                                                 sl = case_null;
5074                                         else if (case_default != null)
5075                                                 sl = case_default;
5076                                 } else {
5077                                         string_labels.TryGetValue (s, out sl);
5078                                 }
5079                         } else {
5080                                 if (value is NullLiteral) {
5081                                         sl = case_null;
5082                                 } else {
5083                                         labels.TryGetValue (value.GetValueAsLong (), out sl);
5084                                 }
5085                         }
5086
5087                         if (sl == null || sl.SectionStart)
5088                                 return sl;
5089
5090                         //
5091                         // Always return section start, it simplifies handling of switch labels
5092                         //
5093                         for (int idx = case_labels.IndexOf (sl); ; --idx) {
5094                                 var cs = case_labels [idx];
5095                                 if (cs.SectionStart)
5096                                         return cs;
5097                         }
5098                 }
5099
5100                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
5101                 {
5102                         Expr.FlowAnalysis (fc);
5103
5104                         var prev_switch = fc.SwitchInitialDefinitiveAssignment;
5105                         var InitialDefinitiveAssignment = fc.DefiniteAssignment;
5106                         fc.SwitchInitialDefinitiveAssignment = InitialDefinitiveAssignment;
5107
5108                         block.FlowAnalysis (fc);
5109
5110                         fc.SwitchInitialDefinitiveAssignment = prev_switch;
5111
5112                         if (end_reachable_das != null) {
5113                                 var sections_das = DefiniteAssignmentBitSet.And (end_reachable_das);
5114                                 InitialDefinitiveAssignment |= sections_das;
5115                                 end_reachable_das = null;
5116                         }
5117
5118                         fc.DefiniteAssignment = InitialDefinitiveAssignment;
5119
5120                         return case_default != null && !end_reachable;
5121                 }
5122
5123                 public override bool Resolve (BlockContext ec)
5124                 {
5125                         Expr = Expr.Resolve (ec);
5126                         if (Expr == null)
5127                                 return false;
5128
5129                         //
5130                         // LAMESPEC: User conversion from non-nullable governing type has a priority
5131                         //
5132                         new_expr = SwitchGoverningType (ec, Expr, false);
5133
5134                         if (new_expr == null) {
5135                                 if (Expr.Type.IsNullableType) {
5136                                         unwrap = Nullable.Unwrap.Create (Expr, false);
5137                                         if (unwrap == null)
5138                                                 return false;
5139
5140                                         //
5141                                         // Unwrap + user conversion using non-nullable type is not allowed but user operator
5142                                         // involving nullable Expr and nullable governing type is
5143                                         //
5144                                         new_expr = SwitchGoverningType (ec, unwrap, true);
5145                                 }
5146                         }
5147
5148                         Expression switch_expr;
5149                         if (new_expr == null) {
5150                                 if (ec.Module.Compiler.Settings.Version != LanguageVersion.Experimental) {
5151                                         if (Expr.Type != InternalType.ErrorType) {
5152                                                 ec.Report.Error (151, loc,
5153                                                         "A switch expression of type `{0}' cannot be converted to an integral type, bool, char, string, enum or nullable type",
5154                                                         Expr.Type.GetSignatureForError ());
5155                                         }
5156
5157                                         return false;
5158                                 }
5159
5160                                 switch_expr = Expr;
5161                                 SwitchType = Expr.Type;
5162                         } else {
5163                                 switch_expr = new_expr;
5164                                 SwitchType = new_expr.Type;
5165                                 if (SwitchType.IsNullableType) {
5166                                         new_expr = unwrap = Nullable.Unwrap.Create (new_expr, true);
5167                                         SwitchType = Nullable.NullableInfo.GetUnderlyingType (SwitchType);
5168                                 }
5169
5170                                 if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.Bool && ec.Module.Compiler.Settings.Version == LanguageVersion.ISO_1) {
5171                                         ec.Report.FeatureIsNotAvailable (ec.Module.Compiler, loc, "switch expression of boolean type");
5172                                         return false;
5173                                 }
5174
5175                                 if (block.Statements.Count == 0)
5176                                         return true;
5177
5178                                 if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String) {
5179                                         string_labels = new Dictionary<string, SwitchLabel> ();
5180                                 } else {
5181                                         labels = new Dictionary<long, SwitchLabel> ();
5182                                 }
5183                         }
5184
5185                         var constant = switch_expr as Constant;
5186
5187                         //
5188                         // Don't need extra variable for constant switch or switch with
5189                         // only default case
5190                         //
5191                         if (constant == null) {
5192                                 //
5193                                 // Store switch expression for comparison purposes
5194                                 //
5195                                 value = switch_expr as VariableReference;
5196                                 if (value == null && !HasOnlyDefaultSection ()) {
5197                                         var current_block = ec.CurrentBlock;
5198                                         ec.CurrentBlock = Block;
5199                                         // Create temporary variable inside switch scope
5200                                         value = TemporaryVariableReference.Create (SwitchType, ec.CurrentBlock, loc);
5201                                         value.Resolve (ec);
5202                                         ec.CurrentBlock = current_block;
5203                                 }
5204                         }
5205
5206                         case_labels = new List<SwitchLabel> ();
5207
5208                         Switch old_switch = ec.Switch;
5209                         ec.Switch = this;
5210                         var parent_los = ec.EnclosingLoopOrSwitch;
5211                         ec.EnclosingLoopOrSwitch = this;
5212
5213                         var ok = Statement.Resolve (ec);
5214
5215                         ec.EnclosingLoopOrSwitch = parent_los;
5216                         ec.Switch = old_switch;
5217
5218                         //
5219                         // Check if all goto cases are valid. Needs to be done after switch
5220                         // is resolved because goto can jump forward in the scope.
5221                         //
5222                         if (goto_cases != null) {
5223                                 foreach (var gc in goto_cases) {
5224                                         if (gc.Item1 == null) {
5225                                                 if (DefaultLabel == null) {
5226                                                         Goto.Error_UnknownLabel (ec, "default", loc);
5227                                                 }
5228
5229                                                 continue;
5230                                         }
5231
5232                                         var sl = FindLabel (gc.Item2);
5233                                         if (sl == null) {
5234                                                 Goto.Error_UnknownLabel (ec, "case " + gc.Item2.GetValueAsLiteral (), loc);
5235                                         } else {
5236                                                 gc.Item1.Label = sl;
5237                                         }
5238                                 }
5239                         }
5240
5241                         if (!ok)
5242                                 return false;
5243
5244                         if (constant == null && SwitchType.BuiltinType == BuiltinTypeSpec.Type.String && string_labels.Count > 6) {
5245                                 ResolveStringSwitchMap (ec);
5246                         }
5247
5248                         //
5249                         // Anonymous storey initialization has to happen before
5250                         // any generated switch dispatch
5251                         //
5252                         block.InsertStatement (0, new DispatchStatement (this));
5253
5254                         return true;
5255                 }
5256
5257                 bool HasOnlyDefaultSection ()
5258                 {
5259                         for (int i = 0; i < block.Statements.Count; ++i) {
5260                                 var s = block.Statements[i] as SwitchLabel;
5261
5262                                 if (s == null || s.IsDefault)
5263                                         continue;
5264
5265                                 return false;
5266                         }
5267
5268                         return true;
5269                 }
5270
5271                 public override Reachability MarkReachable (Reachability rc)
5272                 {
5273                         if (rc.IsUnreachable)
5274                                 return rc;
5275
5276                         base.MarkReachable (rc);
5277
5278                         block.MarkReachableScope (rc);
5279
5280                         if (block.Statements.Count == 0)
5281                                 return rc;
5282
5283                         SwitchLabel constant_label = null;
5284                         var constant = new_expr as Constant;
5285
5286                         if (constant != null) {
5287                                 constant_label = FindLabel (constant) ?? case_default;
5288                                 if (constant_label == null) {
5289                                         block.Statements.RemoveAt (0);
5290                                         return rc;
5291                                 }
5292                         }
5293
5294                         var section_rc = new Reachability ();
5295                         SwitchLabel prev_label = null;
5296
5297                         for (int i = 0; i < block.Statements.Count; ++i) {
5298                                 var s = block.Statements[i];
5299                                 var sl = s as SwitchLabel;
5300
5301                                 if (sl != null && sl.SectionStart) {
5302                                         //
5303                                         // Section is marked already via goto case
5304                                         //
5305                                         if (!sl.IsUnreachable) {
5306                                                 section_rc = new Reachability ();
5307                                                 continue;
5308                                         }
5309
5310                                         if (constant_label != null && constant_label != sl)
5311                                                 section_rc = Reachability.CreateUnreachable ();
5312                                         else if (section_rc.IsUnreachable) {
5313                                                 section_rc = new Reachability ();
5314                                         } else {
5315                                                 if (prev_label != null) {
5316                                                         sl.SectionStart = false;
5317                                                         s = new MissingBreak (prev_label);
5318                                                         s.MarkReachable (rc);
5319                                                         block.Statements.Insert (i - 1, s);
5320                                                         ++i;
5321                                                 }
5322                                         }
5323
5324                                         prev_label = sl;
5325                                 }
5326
5327                                 section_rc = s.MarkReachable (section_rc);
5328                         }
5329
5330                         if (!section_rc.IsUnreachable && prev_label != null) {
5331                                 prev_label.SectionStart = false;
5332                                 var s = new MissingBreak (prev_label) {
5333                                         FallOut = true
5334                                 };
5335
5336                                 s.MarkReachable (rc);
5337                                 block.Statements.Add (s);
5338                         }
5339
5340                         //
5341                         // Reachability can affect parent only when all possible paths are handled but
5342                         // we still need to run reachability check on switch body to check for fall-through
5343                         //
5344                         if (case_default == null && constant_label == null)
5345                                 return rc;
5346
5347                         //
5348                         // We have at least one local exit from the switch
5349                         //
5350                         if (end_reachable)
5351                                 return rc;
5352
5353                         return Reachability.CreateUnreachable ();
5354                 }
5355
5356                 public void RegisterGotoCase (GotoCase gotoCase, Constant value)
5357                 {
5358                         if (goto_cases == null)
5359                                 goto_cases = new List<Tuple<GotoCase, Constant>> ();
5360
5361                         goto_cases.Add (Tuple.Create (gotoCase, value));
5362                 }
5363
5364                 //
5365                 // Converts string switch into string hashtable
5366                 //
5367                 void ResolveStringSwitchMap (ResolveContext ec)
5368                 {
5369                         FullNamedExpression string_dictionary_type;
5370                         if (ec.Module.PredefinedTypes.Dictionary.Define ()) {
5371                                 string_dictionary_type = new TypeExpression (
5372                                         ec.Module.PredefinedTypes.Dictionary.TypeSpec.MakeGenericType (ec,
5373                                                 new [] { ec.BuiltinTypes.String, ec.BuiltinTypes.Int }),
5374                                         loc);
5375                         } else if (ec.Module.PredefinedTypes.Hashtable.Define ()) {
5376                                 string_dictionary_type = new TypeExpression (ec.Module.PredefinedTypes.Hashtable.TypeSpec, loc);
5377                         } else {
5378                                 ec.Module.PredefinedTypes.Dictionary.Resolve ();
5379                                 return;
5380                         }
5381
5382                         var ctype = ec.CurrentMemberDefinition.Parent.PartialContainer;
5383                         Field field = new Field (ctype, string_dictionary_type,
5384                                 Modifiers.STATIC | Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED,
5385                                 new MemberName (CompilerGeneratedContainer.MakeName (null, "f", "switch$map", ec.Module.CounterSwitchTypes++), loc), null);
5386                         if (!field.Define ())
5387                                 return;
5388                         ctype.AddField (field);
5389
5390                         var init = new List<Expression> ();
5391                         int counter = -1;
5392                         labels = new Dictionary<long, SwitchLabel> (string_labels.Count);
5393                         string value = null;
5394
5395                         foreach (SwitchLabel sl in case_labels) {
5396
5397                                 if (sl.SectionStart)
5398                                         labels.Add (++counter, sl);
5399
5400                                 if (sl == case_default || sl == case_null)
5401                                         continue;
5402
5403                                 value = (string) sl.Converted.GetValue ();
5404                                 var init_args = new List<Expression> (2);
5405                                 init_args.Add (new StringLiteral (ec.BuiltinTypes, value, sl.Location));
5406
5407                                 sl.Converted = new IntConstant (ec.BuiltinTypes, counter, loc);
5408                                 init_args.Add (sl.Converted);
5409
5410                                 init.Add (new CollectionElementInitializer (init_args, loc));
5411                         }
5412         
5413                         Arguments args = new Arguments (1);
5414                         args.Add (new Argument (new IntConstant (ec.BuiltinTypes, init.Count, loc)));
5415                         Expression initializer = new NewInitialize (string_dictionary_type, args,
5416                                 new CollectionOrObjectInitializers (init, loc), loc);
5417
5418                         switch_cache_field = new FieldExpr (field, loc);
5419                         string_dictionary = new SimpleAssign (switch_cache_field, initializer.Resolve (ec));
5420                 }
5421
5422                 void DoEmitStringSwitch (EmitContext ec)
5423                 {
5424                         Label l_initialized = ec.DefineLabel ();
5425
5426                         //
5427                         // Skip initialization when value is null
5428                         //
5429                         value.EmitBranchable (ec, nullLabel, false);
5430
5431                         //
5432                         // Check if string dictionary is initialized and initialize
5433                         //
5434                         switch_cache_field.EmitBranchable (ec, l_initialized, true);
5435                         using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
5436                                 string_dictionary.EmitStatement (ec);
5437                         }
5438                         ec.MarkLabel (l_initialized);
5439
5440                         LocalTemporary string_switch_variable = new LocalTemporary (ec.BuiltinTypes.Int);
5441
5442                         ResolveContext rc = new ResolveContext (ec.MemberContext);
5443
5444                         if (switch_cache_field.Type.IsGeneric) {
5445                                 Arguments get_value_args = new Arguments (2);
5446                                 get_value_args.Add (new Argument (value));
5447                                 get_value_args.Add (new Argument (string_switch_variable, Argument.AType.Out));
5448                                 Expression get_item = new Invocation (new MemberAccess (switch_cache_field, "TryGetValue", loc), get_value_args).Resolve (rc);
5449                                 if (get_item == null)
5450                                         return;
5451
5452                                 //
5453                                 // A value was not found, go to default case
5454                                 //
5455                                 get_item.EmitBranchable (ec, defaultLabel, false);
5456                         } else {
5457                                 Arguments get_value_args = new Arguments (1);
5458                                 get_value_args.Add (new Argument (value));
5459
5460                                 Expression get_item = new ElementAccess (switch_cache_field, get_value_args, loc).Resolve (rc);
5461                                 if (get_item == null)
5462                                         return;
5463
5464                                 LocalTemporary get_item_object = new LocalTemporary (ec.BuiltinTypes.Object);
5465                                 get_item_object.EmitAssign (ec, get_item, true, false);
5466                                 ec.Emit (OpCodes.Brfalse, defaultLabel);
5467
5468                                 ExpressionStatement get_item_int = (ExpressionStatement) new SimpleAssign (string_switch_variable,
5469                                         new Cast (new TypeExpression (ec.BuiltinTypes.Int, loc), get_item_object, loc)).Resolve (rc);
5470
5471                                 get_item_int.EmitStatement (ec);
5472                                 get_item_object.Release (ec);
5473                         }
5474
5475                         EmitTableSwitch (ec, string_switch_variable);
5476                         string_switch_variable.Release (ec);
5477                 }
5478
5479                 //
5480                 // Emits switch using simple if/else comparison for small label count (4 + optional default)
5481                 //
5482                 void EmitShortSwitch (EmitContext ec)
5483                 {
5484                         MethodSpec equal_method = null;
5485                         if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String) {
5486                                 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (loc);
5487                         }
5488
5489                         if (equal_method != null) {
5490                                 value.EmitBranchable (ec, nullLabel, false);
5491                         }
5492
5493                         for (int i = 0; i < case_labels.Count; ++i) {
5494                                 var label = case_labels [i];
5495                                 if (label == case_default || label == case_null)
5496                                         continue;
5497
5498                                 var constant = label.Converted;
5499
5500                                 if (constant == null) {
5501                                         label.Label.EmitBranchable (ec, label.GetILLabel (ec), true);
5502                                         continue;
5503                                 }
5504
5505                                 if (equal_method != null) {
5506                                         value.Emit (ec);
5507                                         constant.Emit (ec);
5508
5509                                         var call = new CallEmitter ();
5510                                         call.EmitPredefined (ec, equal_method, new Arguments (0));
5511                                         ec.Emit (OpCodes.Brtrue, label.GetILLabel (ec));
5512                                         continue;
5513                                 }
5514
5515                                 if (constant.IsZeroInteger && constant.Type.BuiltinType != BuiltinTypeSpec.Type.Long && constant.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
5516                                         value.EmitBranchable (ec, label.GetILLabel (ec), false);
5517                                         continue;
5518                                 }
5519
5520                                 value.Emit (ec);
5521                                 constant.Emit (ec);
5522                                 ec.Emit (OpCodes.Beq, label.GetILLabel (ec));
5523                         }
5524
5525                         ec.Emit (OpCodes.Br, defaultLabel);
5526                 }
5527
5528                 void EmitDispatch (EmitContext ec)
5529                 {
5530                         if (IsPatternMatching) {
5531                                 EmitShortSwitch (ec);
5532                                 return;
5533                         }
5534
5535                         if (value == null) {
5536                                 //
5537                                 // Constant switch, we've already done the work if there is only 1 label
5538                                 // referenced
5539                                 //
5540                                 int reachable = 0;
5541                                 foreach (var sl in case_labels) {
5542                                         if (sl.IsUnreachable)
5543                                                 continue;
5544
5545                                         if (reachable++ > 0) {
5546                                                 var constant = (Constant) new_expr;
5547                                                 var constant_label = FindLabel (constant) ?? case_default;
5548
5549                                                 ec.Emit (OpCodes.Br, constant_label.GetILLabel (ec));
5550                                                 break;
5551                                         }
5552                                 }
5553
5554                                 return;
5555                         }
5556
5557                         if (string_dictionary != null) {
5558                                 DoEmitStringSwitch (ec);
5559                         } else if (case_labels.Count < 4 || string_labels != null) {
5560                                 EmitShortSwitch (ec);
5561                         } else {
5562                                 EmitTableSwitch (ec, value);
5563                         }
5564                 }
5565
5566                 protected override void DoEmit (EmitContext ec)
5567                 {
5568                         //
5569                         // Setup the codegen context
5570                         //
5571                         Label old_end = ec.LoopEnd;
5572                         Switch old_switch = ec.Switch;
5573
5574                         ec.LoopEnd = ec.DefineLabel ();
5575                         ec.Switch = this;
5576
5577                         defaultLabel = case_default == null ? ec.LoopEnd : case_default.GetILLabel (ec);
5578                         nullLabel = case_null == null ? defaultLabel : case_null.GetILLabel (ec);
5579
5580                         if (value != null) {
5581                                 ec.Mark (loc);
5582
5583                                 var switch_expr = new_expr ?? Expr;
5584                                 if (IsNullable) {
5585                                         unwrap.EmitCheck (ec);
5586                                         ec.Emit (OpCodes.Brfalse, nullLabel);
5587                                         value.EmitAssign (ec, switch_expr, false, false);
5588                                 } else if (switch_expr != value) {
5589                                         value.EmitAssign (ec, switch_expr, false, false);
5590                                 }
5591
5592
5593                                 //
5594                                 // Next statement is compiler generated we don't need extra
5595                                 // nop when we can use the statement for sequence point
5596                                 //
5597                                 ec.Mark (block.StartLocation);
5598                                 block.IsCompilerGenerated = true;
5599                         } else {
5600                                 new_expr.EmitSideEffect (ec);
5601                         }
5602
5603                         block.Emit (ec);
5604
5605                         // Restore context state. 
5606                         ec.MarkLabel (ec.LoopEnd);
5607
5608                         //
5609                         // Restore the previous context
5610                         //
5611                         ec.LoopEnd = old_end;
5612                         ec.Switch = old_switch;
5613                 }
5614
5615                 protected override void CloneTo (CloneContext clonectx, Statement t)
5616                 {
5617                         Switch target = (Switch) t;
5618
5619                         target.Expr = Expr.Clone (clonectx);
5620                         target.Statement = target.block = (ExplicitBlock) block.Clone (clonectx);
5621                 }
5622                 
5623                 public override object Accept (StructuralVisitor visitor)
5624                 {
5625                         return visitor.Visit (this);
5626                 }
5627
5628                 public override void AddEndDefiniteAssignment (FlowAnalysisContext fc)
5629                 {
5630                         if (case_default == null && !(new_expr is Constant))
5631                                 return;
5632
5633                         if (end_reachable_das == null)
5634                                 end_reachable_das = new List<DefiniteAssignmentBitSet> ();
5635
5636                         end_reachable_das.Add (fc.DefiniteAssignment);
5637                 }
5638
5639                 public override void SetEndReachable ()
5640                 {
5641                         end_reachable = true;
5642                 }
5643         }
5644
5645         // A place where execution can restart in a state machine
5646         public abstract class ResumableStatement : Statement
5647         {
5648                 bool prepared;
5649                 protected Label resume_point;
5650
5651                 public Label PrepareForEmit (EmitContext ec)
5652                 {
5653                         if (!prepared) {
5654                                 prepared = true;
5655                                 resume_point = ec.DefineLabel ();
5656                         }
5657                         return resume_point;
5658                 }
5659
5660                 public virtual Label PrepareForDispose (EmitContext ec, Label end)
5661                 {
5662                         return end;
5663                 }
5664
5665                 public virtual void EmitForDispose (EmitContext ec, LocalBuilder pc, Label end, bool have_dispatcher)
5666                 {
5667                 }
5668         }
5669
5670         public abstract class TryFinallyBlock : ExceptionStatement
5671         {
5672                 protected Statement stmt;
5673                 Label dispose_try_block;
5674                 bool prepared_for_dispose, emitted_dispose;
5675                 Method finally_host;
5676
5677                 protected TryFinallyBlock (Statement stmt, Location loc)
5678                         : base (loc)
5679                 {
5680                         this.stmt = stmt;
5681                 }
5682
5683                 #region Properties
5684
5685                 public Statement Statement {
5686                         get {
5687                                 return stmt;
5688                         }
5689                 }
5690
5691                 #endregion
5692
5693                 protected abstract void EmitTryBody (EmitContext ec);
5694                 public abstract void EmitFinallyBody (EmitContext ec);
5695
5696                 public override Label PrepareForDispose (EmitContext ec, Label end)
5697                 {
5698                         if (!prepared_for_dispose) {
5699                                 prepared_for_dispose = true;
5700                                 dispose_try_block = ec.DefineLabel ();
5701                         }
5702                         return dispose_try_block;
5703                 }
5704
5705                 protected sealed override void DoEmit (EmitContext ec)
5706                 {
5707                         EmitTryBodyPrepare (ec);
5708                         EmitTryBody (ec);
5709
5710                         bool beginFinally = EmitBeginFinallyBlock (ec);
5711
5712                         Label start_finally = ec.DefineLabel ();
5713                         if (resume_points != null && beginFinally) {
5714                                 var state_machine = (StateMachineInitializer) ec.CurrentAnonymousMethod;
5715
5716                                 ec.Emit (OpCodes.Ldloc, state_machine.SkipFinally);
5717                                 ec.Emit (OpCodes.Brfalse_S, start_finally);
5718                                 ec.Emit (OpCodes.Endfinally);
5719                         }
5720
5721                         ec.MarkLabel (start_finally);
5722
5723                         if (finally_host != null) {
5724                                 finally_host.Define ();
5725                                 finally_host.PrepareEmit ();
5726                                 finally_host.Emit ();
5727
5728                                 // Now it's safe to add, to close it properly and emit sequence points
5729                                 finally_host.Parent.AddMember (finally_host);
5730
5731                                 var ce = new CallEmitter ();
5732                                 ce.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, loc);
5733                                 ce.EmitPredefined (ec, finally_host.Spec, new Arguments (0), true);
5734                         } else {
5735                                 EmitFinallyBody (ec);
5736                         }
5737
5738                         if (beginFinally)
5739                                 ec.EndExceptionBlock ();
5740                 }
5741
5742                 public override void EmitForDispose (EmitContext ec, LocalBuilder pc, Label end, bool have_dispatcher)
5743                 {
5744                         if (emitted_dispose)
5745                                 return;
5746
5747                         emitted_dispose = true;
5748
5749                         Label end_of_try = ec.DefineLabel ();
5750
5751                         // Ensure that the only way we can get into this code is through a dispatcher
5752                         if (have_dispatcher)
5753                                 ec.Emit (OpCodes.Br, end);
5754
5755                         ec.BeginExceptionBlock ();
5756
5757                         ec.MarkLabel (dispose_try_block);
5758
5759                         Label[] labels = null;
5760                         for (int i = 0; i < resume_points.Count; ++i) {
5761                                 ResumableStatement s = resume_points[i];
5762                                 Label ret = s.PrepareForDispose (ec, end_of_try);
5763                                 if (ret.Equals (end_of_try) && labels == null)
5764                                         continue;
5765                                 if (labels == null) {
5766                                         labels = new Label[resume_points.Count];
5767                                         for (int j = 0; j < i; ++j)
5768                                                 labels[j] = end_of_try;
5769                                 }
5770                                 labels[i] = ret;
5771                         }
5772
5773                         if (labels != null) {
5774                                 int j;
5775                                 for (j = 1; j < labels.Length; ++j)
5776                                         if (!labels[0].Equals (labels[j]))
5777                                                 break;
5778                                 bool emit_dispatcher = j < labels.Length;
5779
5780                                 if (emit_dispatcher) {
5781                                         ec.Emit (OpCodes.Ldloc, pc);
5782                                         ec.EmitInt (first_resume_pc);
5783                                         ec.Emit (OpCodes.Sub);
5784                                         ec.Emit (OpCodes.Switch, labels);
5785                                 }
5786
5787                                 foreach (ResumableStatement s in resume_points)
5788                                         s.EmitForDispose (ec, pc, end_of_try, emit_dispatcher);
5789                         }
5790
5791                         ec.MarkLabel (end_of_try);
5792
5793                         ec.BeginFinallyBlock ();
5794
5795                         if (finally_host != null) {
5796                                 var ce = new CallEmitter ();
5797                                 ce.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, loc);
5798                                 ce.EmitPredefined (ec, finally_host.Spec, new Arguments (0), true);
5799                         } else {
5800                                 EmitFinallyBody (ec);
5801                         }
5802
5803                         ec.EndExceptionBlock ();
5804                 }
5805
5806                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
5807                 {
5808                         var res = stmt.FlowAnalysis (fc);
5809                         parent = null;
5810                         return res;
5811                 }
5812
5813                 protected virtual bool EmitBeginFinallyBlock (EmitContext ec)
5814                 {
5815                         ec.BeginFinallyBlock ();
5816                         return true;
5817                 }
5818
5819                 public override Reachability MarkReachable (Reachability rc)
5820                 {
5821                         base.MarkReachable (rc);
5822                         return Statement.MarkReachable (rc);
5823                 }
5824
5825                 public override bool Resolve (BlockContext bc)
5826                 {
5827                         bool ok;
5828
5829                         parent = bc.CurrentTryBlock;
5830                         bc.CurrentTryBlock = this;
5831
5832                         using (bc.Set (ResolveContext.Options.TryScope)) {
5833                                 ok = stmt.Resolve (bc);
5834                         }
5835
5836                         bc.CurrentTryBlock = parent;
5837
5838                         //
5839                         // Finally block inside iterator is called from MoveNext and
5840                         // Dispose methods that means we need to lift the block into
5841                         // newly created host method to emit the body only once. The
5842                         // original block then simply calls the newly generated method.
5843                         //
5844                         if (bc.CurrentIterator != null && !bc.IsInProbingMode) {
5845                                 var b = stmt as Block;
5846                                 if (b != null && b.Explicit.HasYield) {
5847                                         finally_host = bc.CurrentIterator.CreateFinallyHost (this);
5848                                 }
5849                         }
5850
5851                         return base.Resolve (bc) && ok;
5852                 }
5853         }
5854
5855         //
5856         // Base class for blocks using exception handling
5857         //
5858         public abstract class ExceptionStatement : ResumableStatement
5859         {
5860                 protected List<ResumableStatement> resume_points;
5861                 protected int first_resume_pc;
5862                 protected ExceptionStatement parent;
5863
5864                 protected ExceptionStatement (Location loc)
5865                 {
5866                         this.loc = loc;
5867                 }
5868
5869                 protected virtual void EmitBeginException (EmitContext ec)
5870                 {
5871                         ec.BeginExceptionBlock ();
5872                 }
5873
5874                 protected virtual void EmitTryBodyPrepare (EmitContext ec)
5875                 {
5876                         StateMachineInitializer state_machine = null;
5877                         if (resume_points != null) {
5878                                 state_machine = (StateMachineInitializer) ec.CurrentAnonymousMethod;
5879
5880                                 ec.EmitInt ((int) IteratorStorey.State.Running);
5881                                 ec.Emit (OpCodes.Stloc, state_machine.CurrentPC);
5882                         }
5883
5884                         EmitBeginException (ec);
5885
5886                         if (resume_points != null) {
5887                                 ec.MarkLabel (resume_point);
5888
5889                                 // For normal control flow, we want to fall-through the Switch
5890                                 // So, we use CurrentPC rather than the $PC field, and initialize it to an outside value above
5891                                 ec.Emit (OpCodes.Ldloc, state_machine.CurrentPC);
5892                                 ec.EmitInt (first_resume_pc);
5893                                 ec.Emit (OpCodes.Sub);
5894
5895                                 Label[] labels = new Label[resume_points.Count];
5896                                 for (int i = 0; i < resume_points.Count; ++i)
5897                                         labels[i] = resume_points[i].PrepareForEmit (ec);
5898                                 ec.Emit (OpCodes.Switch, labels);
5899                         }
5900                 }
5901
5902                 public virtual int AddResumePoint (ResumableStatement stmt, int pc, StateMachineInitializer stateMachine)
5903                 {
5904                         if (parent != null) {
5905                                 // TODO: MOVE to virtual TryCatch
5906                                 var tc = this as TryCatch;
5907                                 var s = tc != null && tc.IsTryCatchFinally ? stmt : this;
5908
5909                                 pc = parent.AddResumePoint (s, pc, stateMachine);
5910                         } else {
5911                                 pc = stateMachine.AddResumePoint (this);
5912                         }
5913
5914                         if (resume_points == null) {
5915                                 resume_points = new List<ResumableStatement> ();
5916                                 first_resume_pc = pc;
5917                         }
5918
5919                         if (pc != first_resume_pc + resume_points.Count)
5920                                 throw new InternalErrorException ("missed an intervening AddResumePoint?");
5921
5922                         resume_points.Add (stmt);
5923                         return pc;
5924                 }
5925         }
5926
5927         public class Lock : TryFinallyBlock
5928         {
5929                 Expression expr;
5930                 TemporaryVariableReference expr_copy;
5931                 TemporaryVariableReference lock_taken;
5932                         
5933                 public Lock (Expression expr, Statement stmt, Location loc)
5934                         : base (stmt, loc)
5935                 {
5936                         this.expr = expr;
5937                 }
5938
5939                 public Expression Expr {
5940                         get {
5941                                 return this.expr;
5942                         }
5943                 }
5944
5945                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
5946                 {
5947                         expr.FlowAnalysis (fc);
5948                         return base.DoFlowAnalysis (fc);
5949                 }
5950
5951                 public override bool Resolve (BlockContext ec)
5952                 {
5953                         expr = expr.Resolve (ec);
5954                         if (expr == null)
5955                                 return false;
5956
5957                         if (!TypeSpec.IsReferenceType (expr.Type) && expr.Type != InternalType.ErrorType) {
5958                                 ec.Report.Error (185, loc,
5959                                         "`{0}' is not a reference type as required by the lock statement",
5960                                         expr.Type.GetSignatureForError ());
5961                         }
5962
5963                         if (expr.Type.IsGenericParameter) {
5964                                 expr = Convert.ImplicitTypeParameterConversion (expr, (TypeParameterSpec)expr.Type, ec.BuiltinTypes.Object);
5965                         }
5966
5967                         VariableReference lv = expr as VariableReference;
5968                         bool locked;
5969                         if (lv != null) {
5970                                 locked = lv.IsLockedByStatement;
5971                                 lv.IsLockedByStatement = true;
5972                         } else {
5973                                 lv = null;
5974                                 locked = false;
5975                         }
5976
5977                         //
5978                         // Have to keep original lock value around to unlock same location
5979                         // in the case of original value has changed or is null
5980                         //
5981                         expr_copy = TemporaryVariableReference.Create (ec.BuiltinTypes.Object, ec.CurrentBlock, loc);
5982                         expr_copy.Resolve (ec);
5983
5984                         //
5985                         // Ensure Monitor methods are available
5986                         //
5987                         if (ResolvePredefinedMethods (ec) > 1) {
5988                                 lock_taken = TemporaryVariableReference.Create (ec.BuiltinTypes.Bool, ec.CurrentBlock, loc);
5989                                 lock_taken.Resolve (ec);
5990                         }
5991
5992                         using (ec.Set (ResolveContext.Options.LockScope)) {
5993                                 base.Resolve (ec);
5994                         }
5995
5996                         if (lv != null) {
5997                                 lv.IsLockedByStatement = locked;
5998                         }
5999
6000                         return true;
6001                 }
6002                 
6003                 protected override void EmitTryBodyPrepare (EmitContext ec)
6004                 {
6005                         expr_copy.EmitAssign (ec, expr);
6006
6007                         if (lock_taken != null) {
6008                                 //
6009                                 // Initialize ref variable
6010                                 //
6011                                 lock_taken.EmitAssign (ec, new BoolLiteral (ec.BuiltinTypes, false, loc));
6012                         } else {
6013                                 //
6014                                 // Monitor.Enter (expr_copy)
6015                                 //
6016                                 expr_copy.Emit (ec);
6017                                 ec.Emit (OpCodes.Call, ec.Module.PredefinedMembers.MonitorEnter.Get ());
6018                         }
6019
6020                         base.EmitTryBodyPrepare (ec);
6021                 }
6022
6023                 protected override void EmitTryBody (EmitContext ec)
6024                 {
6025                         //
6026                         // Monitor.Enter (expr_copy, ref lock_taken)
6027                         //
6028                         if (lock_taken != null) {
6029                                 expr_copy.Emit (ec);
6030                                 lock_taken.LocalInfo.CreateBuilder (ec);
6031                                 lock_taken.AddressOf (ec, AddressOp.Load);
6032                                 ec.Emit (OpCodes.Call, ec.Module.PredefinedMembers.MonitorEnter_v4.Get ());
6033                         }
6034
6035                         Statement.Emit (ec);
6036                 }
6037
6038                 public override void EmitFinallyBody (EmitContext ec)
6039                 {
6040                         //
6041                         // if (lock_taken) Monitor.Exit (expr_copy)
6042                         //
6043                         Label skip = ec.DefineLabel ();
6044
6045                         if (lock_taken != null) {
6046                                 lock_taken.Emit (ec);
6047                                 ec.Emit (OpCodes.Brfalse_S, skip);
6048                         }
6049
6050                         expr_copy.Emit (ec);
6051                         var m = ec.Module.PredefinedMembers.MonitorExit.Resolve (loc);
6052                         if (m != null)
6053                                 ec.Emit (OpCodes.Call, m);
6054
6055                         ec.MarkLabel (skip);
6056                 }
6057
6058                 int ResolvePredefinedMethods (ResolveContext rc)
6059                 {
6060                         // Try 4.0 Monitor.Enter (object, ref bool) overload first
6061                         var m = rc.Module.PredefinedMembers.MonitorEnter_v4.Get ();
6062                         if (m != null)
6063                                 return 4;
6064
6065                         m = rc.Module.PredefinedMembers.MonitorEnter.Get ();
6066                         if (m != null)
6067                                 return 1;
6068
6069                         rc.Module.PredefinedMembers.MonitorEnter_v4.Resolve (loc);
6070                         return 0;
6071                 }
6072
6073                 protected override void CloneTo (CloneContext clonectx, Statement t)
6074                 {
6075                         Lock target = (Lock) t;
6076
6077                         target.expr = expr.Clone (clonectx);
6078                         target.stmt = Statement.Clone (clonectx);
6079                 }
6080                 
6081                 public override object Accept (StructuralVisitor visitor)
6082                 {
6083                         return visitor.Visit (this);
6084                 }
6085
6086         }
6087
6088         public class Unchecked : Statement {
6089                 public Block Block;
6090                 
6091                 public Unchecked (Block b, Location loc)
6092                 {
6093                         Block = b;
6094                         b.Unchecked = true;
6095                         this.loc = loc;
6096                 }
6097
6098                 public override bool Resolve (BlockContext ec)
6099                 {
6100                         using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
6101                                 return Block.Resolve (ec);
6102                 }
6103                 
6104                 protected override void DoEmit (EmitContext ec)
6105                 {
6106                         using (ec.With (EmitContext.Options.CheckedScope, false))
6107                                 Block.Emit (ec);
6108                 }
6109
6110                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6111                 {
6112                         return Block.FlowAnalysis (fc);
6113                 }
6114
6115                 public override Reachability MarkReachable (Reachability rc)
6116                 {
6117                         base.MarkReachable (rc);
6118                         return Block.MarkReachable (rc);
6119                 }
6120
6121                 protected override void CloneTo (CloneContext clonectx, Statement t)
6122                 {
6123                         Unchecked target = (Unchecked) t;
6124
6125                         target.Block = clonectx.LookupBlock (Block);
6126                 }
6127                 
6128                 public override object Accept (StructuralVisitor visitor)
6129                 {
6130                         return visitor.Visit (this);
6131                 }
6132         }
6133
6134         public class Checked : Statement {
6135                 public Block Block;
6136                 
6137                 public Checked (Block b, Location loc)
6138                 {
6139                         Block = b;
6140                         b.Unchecked = false;
6141                         this.loc = loc;
6142                 }
6143
6144                 public override bool Resolve (BlockContext ec)
6145                 {
6146                         using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
6147                                 return Block.Resolve (ec);
6148                 }
6149
6150                 protected override void DoEmit (EmitContext ec)
6151                 {
6152                         using (ec.With (EmitContext.Options.CheckedScope, true))
6153                                 Block.Emit (ec);
6154                 }
6155
6156                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6157                 {
6158                         return Block.FlowAnalysis (fc);
6159                 }
6160
6161                 public override Reachability MarkReachable (Reachability rc)
6162                 {
6163                         base.MarkReachable (rc);
6164                         return Block.MarkReachable (rc);
6165                 }
6166
6167                 protected override void CloneTo (CloneContext clonectx, Statement t)
6168                 {
6169                         Checked target = (Checked) t;
6170
6171                         target.Block = clonectx.LookupBlock (Block);
6172                 }
6173                 
6174                 public override object Accept (StructuralVisitor visitor)
6175                 {
6176                         return visitor.Visit (this);
6177                 }
6178         }
6179
6180         public class Unsafe : Statement {
6181                 public Block Block;
6182
6183                 public Unsafe (Block b, Location loc)
6184                 {
6185                         Block = b;
6186                         Block.Unsafe = true;
6187                         this.loc = loc;
6188                 }
6189
6190                 public override bool Resolve (BlockContext ec)
6191                 {
6192                         if (ec.CurrentIterator != null)
6193                                 ec.Report.Error (1629, loc, "Unsafe code may not appear in iterators");
6194
6195                         using (ec.Set (ResolveContext.Options.UnsafeScope))
6196                                 return Block.Resolve (ec);
6197                 }
6198                 
6199                 protected override void DoEmit (EmitContext ec)
6200                 {
6201                         Block.Emit (ec);
6202                 }
6203
6204                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6205                 {
6206                         return Block.FlowAnalysis (fc);
6207                 }
6208
6209                 public override Reachability MarkReachable (Reachability rc)
6210                 {
6211                         base.MarkReachable (rc);
6212                         return Block.MarkReachable (rc);
6213                 }
6214
6215                 protected override void CloneTo (CloneContext clonectx, Statement t)
6216                 {
6217                         Unsafe target = (Unsafe) t;
6218
6219                         target.Block = clonectx.LookupBlock (Block);
6220                 }
6221                 
6222                 public override object Accept (StructuralVisitor visitor)
6223                 {
6224                         return visitor.Visit (this);
6225                 }
6226         }
6227
6228         // 
6229         // Fixed statement
6230         //
6231         public class Fixed : Statement
6232         {
6233                 abstract class Emitter : ShimExpression
6234                 {
6235                         protected LocalVariable vi;
6236
6237                         protected Emitter (Expression expr, LocalVariable li)
6238                                 : base (expr)
6239                         {
6240                                 vi = li;
6241                         }
6242
6243                         public abstract void EmitExit (EmitContext ec);
6244
6245                         public override void FlowAnalysis (FlowAnalysisContext fc)
6246                         {
6247                                 expr.FlowAnalysis (fc);
6248                         }
6249                 }
6250
6251                 class ExpressionEmitter : Emitter {
6252                         public ExpressionEmitter (Expression converted, LocalVariable li) :
6253                                 base (converted, li)
6254                         {
6255                         }
6256
6257                         protected override Expression DoResolve (ResolveContext rc)
6258                         {
6259                                 throw new NotImplementedException ();
6260                         }
6261
6262                         public override void Emit (EmitContext ec) {
6263                                 //
6264                                 // Store pointer in pinned location
6265                                 //
6266                                 expr.Emit (ec);
6267                                 vi.EmitAssign (ec);
6268                         }
6269
6270                         public override void EmitExit (EmitContext ec)
6271                         {
6272                                 ec.EmitInt (0);
6273                                 ec.Emit (OpCodes.Conv_U);
6274                                 vi.EmitAssign (ec);
6275                         }
6276                 }
6277
6278                 class StringEmitter : Emitter
6279                 {
6280                         LocalVariable pinned_string;
6281
6282                         public StringEmitter (Expression expr, LocalVariable li)
6283                                 : base (expr, li)
6284                         {
6285                         }
6286
6287                         protected override Expression DoResolve (ResolveContext rc)
6288                         {
6289                                 pinned_string = new LocalVariable (vi.Block, "$pinned",
6290                                         LocalVariable.Flags.FixedVariable | LocalVariable.Flags.CompilerGenerated | LocalVariable.Flags.Used,
6291                                         vi.Location);
6292                                 pinned_string.Type = rc.BuiltinTypes.String;
6293
6294                                 eclass = ExprClass.Variable;
6295                                 type = rc.BuiltinTypes.Int;
6296                                 return this;
6297                         }
6298
6299                         public override void Emit (EmitContext ec)
6300                         {
6301                                 pinned_string.CreateBuilder (ec);
6302
6303                                 expr.Emit (ec);
6304                                 pinned_string.EmitAssign (ec);
6305
6306                                 // TODO: Should use Binary::Add
6307                                 pinned_string.Emit (ec);
6308                                 ec.Emit (OpCodes.Conv_I);
6309
6310                                 var m = ec.Module.PredefinedMembers.RuntimeHelpersOffsetToStringData.Resolve (loc);
6311                                 if (m == null)
6312                                         return;
6313
6314                                 PropertyExpr pe = new PropertyExpr (m, pinned_string.Location);
6315                                 //pe.InstanceExpression = pinned_string;
6316                                 pe.Resolve (new ResolveContext (ec.MemberContext)).Emit (ec);
6317
6318                                 ec.Emit (OpCodes.Add);
6319                                 vi.EmitAssign (ec);
6320                         }
6321
6322                         public override void EmitExit (EmitContext ec)
6323                         {
6324                                 ec.EmitNull ();
6325                                 pinned_string.EmitAssign (ec);
6326                         }
6327                 }
6328
6329                 public class VariableDeclaration : BlockVariable
6330                 {
6331                         public VariableDeclaration (FullNamedExpression type, LocalVariable li)
6332                                 : base (type, li)
6333                         {
6334                         }
6335
6336                         protected override Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
6337                         {
6338                                 if (!Variable.Type.IsPointer && li == Variable) {
6339                                         bc.Report.Error (209, TypeExpression.Location,
6340                                                 "The type of locals declared in a fixed statement must be a pointer type");
6341                                         return null;
6342                                 }
6343
6344                                 var res = initializer.Resolve (bc);
6345                                 if (res == null)
6346                                         return null;
6347
6348                                 //
6349                                 // Case 1: Array
6350                                 //
6351                                 if (res.Type.IsArray) {
6352                                         TypeSpec array_type = TypeManager.GetElementType (res.Type);
6353
6354                                         //
6355                                         // Provided that array_type is unmanaged,
6356                                         //
6357                                         if (!TypeManager.VerifyUnmanaged (bc.Module, array_type, loc))
6358                                                 return null;
6359
6360                                         //
6361                                         // and T* is implicitly convertible to the
6362                                         // pointer type given in the fixed statement.
6363                                         //
6364                                         ArrayPtr array_ptr = new ArrayPtr (res, array_type, loc);
6365
6366                                         Expression converted = Convert.ImplicitConversionRequired (bc, array_ptr.Resolve (bc), li.Type, loc);
6367                                         if (converted == null)
6368                                                 return null;
6369
6370                                         //
6371                                         // fixed (T* e_ptr = (e == null || e.Length == 0) ? null : converted [0])
6372                                         //
6373                                         converted = new Conditional (new BooleanExpression (new Binary (Binary.Operator.LogicalOr,
6374                                                 new Binary (Binary.Operator.Equality, res, new NullLiteral (loc)),
6375                                                 new Binary (Binary.Operator.Equality, new MemberAccess (res, "Length"), new IntConstant (bc.BuiltinTypes, 0, loc)))),
6376                                                         new NullLiteral (loc),
6377                                                         converted, loc);
6378
6379                                         converted = converted.Resolve (bc);
6380
6381                                         return new ExpressionEmitter (converted, li);
6382                                 }
6383
6384                                 //
6385                                 // Case 2: string
6386                                 //
6387                                 if (res.Type.BuiltinType == BuiltinTypeSpec.Type.String) {
6388                                         return new StringEmitter (res, li).Resolve (bc);
6389                                 }
6390
6391                                 // Case 3: fixed buffer
6392                                 if (res is FixedBufferPtr) {
6393                                         return new ExpressionEmitter (res, li);
6394                                 }
6395
6396                                 bool already_fixed = true;
6397
6398                                 //
6399                                 // Case 4: & object.
6400                                 //
6401                                 Unary u = res as Unary;
6402                                 if (u != null) {
6403                                         if (u.Oper == Unary.Operator.AddressOf) {
6404                                                 IVariableReference vr = u.Expr as IVariableReference;
6405                                                 if (vr == null || !vr.IsFixed) {
6406                                                         already_fixed = false;
6407                                                 }
6408                                         }
6409                                 } else if (initializer is Cast) {
6410                                         bc.Report.Error (254, initializer.Location, "The right hand side of a fixed statement assignment may not be a cast expression");
6411                                         return null;
6412                                 }
6413
6414                                 if (already_fixed) {
6415                                         bc.Report.Error (213, loc, "You cannot use the fixed statement to take the address of an already fixed expression");
6416                                 }
6417
6418                                 res = Convert.ImplicitConversionRequired (bc, res, li.Type, loc);
6419                                 return new ExpressionEmitter (res, li);
6420                         }
6421                 }
6422
6423
6424                 VariableDeclaration decl;
6425                 Statement statement;
6426                 bool has_ret;
6427
6428                 public Fixed (VariableDeclaration decl, Statement stmt, Location l)
6429                 {
6430                         this.decl = decl;
6431                         statement = stmt;
6432                         loc = l;
6433                 }
6434
6435                 #region Properties
6436
6437                 public Statement Statement {
6438                         get {
6439                                 return statement;
6440                         }
6441                 }
6442
6443                 public BlockVariable Variables {
6444                         get {
6445                                 return decl;
6446                         }
6447                 }
6448
6449                 #endregion
6450
6451                 public override bool Resolve (BlockContext bc)
6452                 {
6453                         using (bc.Set (ResolveContext.Options.FixedInitializerScope)) {
6454                                 if (!decl.Resolve (bc))
6455                                         return false;
6456                         }
6457
6458                         return statement.Resolve (bc);
6459                 }
6460
6461                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6462                 {
6463                         decl.FlowAnalysis (fc);
6464                         return statement.FlowAnalysis (fc);
6465                 }
6466                 
6467                 protected override void DoEmit (EmitContext ec)
6468                 {
6469                         decl.Variable.CreateBuilder (ec);
6470                         decl.Initializer.Emit (ec);
6471                         if (decl.Declarators != null) {
6472                                 foreach (var d in decl.Declarators) {
6473                                         d.Variable.CreateBuilder (ec);
6474                                         d.Initializer.Emit (ec);
6475                                 }
6476                         }
6477
6478                         statement.Emit (ec);
6479
6480                         if (has_ret)
6481                                 return;
6482
6483                         //
6484                         // Clear the pinned variable
6485                         //
6486                         ((Emitter) decl.Initializer).EmitExit (ec);
6487                         if (decl.Declarators != null) {
6488                                 foreach (var d in decl.Declarators) {
6489                                         ((Emitter)d.Initializer).EmitExit (ec);
6490                                 }
6491                         }
6492                 }
6493
6494                 public override Reachability MarkReachable (Reachability rc)
6495                 {
6496                         base.MarkReachable (rc);
6497
6498                         decl.MarkReachable (rc);
6499
6500                         rc = statement.MarkReachable (rc);
6501
6502                         // TODO: What if there is local exit?
6503                         has_ret = rc.IsUnreachable;
6504                         return rc;
6505                 }
6506
6507                 protected override void CloneTo (CloneContext clonectx, Statement t)
6508                 {
6509                         Fixed target = (Fixed) t;
6510
6511                         target.decl = (VariableDeclaration) decl.Clone (clonectx);
6512                         target.statement = statement.Clone (clonectx);
6513                 }
6514                 
6515                 public override object Accept (StructuralVisitor visitor)
6516                 {
6517                         return visitor.Visit (this);
6518                 }
6519         }
6520
6521         public class Catch : Statement
6522         {
6523                 class CatchVariableStore : Statement
6524                 {
6525                         readonly Catch ctch;
6526
6527                         public CatchVariableStore (Catch ctch)
6528                         {
6529                                 this.ctch = ctch;
6530                         }
6531
6532                         protected override void CloneTo (CloneContext clonectx, Statement target)
6533                         {
6534                         }
6535
6536                         protected override void DoEmit (EmitContext ec)
6537                         {
6538                                 // Emits catch variable debug information inside correct block
6539                                 ctch.EmitCatchVariableStore (ec);
6540                         }
6541
6542                         protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6543                         {
6544                                 return true;
6545                         }
6546                 }
6547
6548                 class FilterStatement : Statement
6549                 {
6550                         readonly Catch ctch;
6551
6552                         public FilterStatement (Catch ctch)
6553                         {
6554                                 this.ctch = ctch;
6555                         }
6556
6557                         protected override void CloneTo (CloneContext clonectx, Statement target)
6558                         {
6559                         }
6560
6561                         protected override void DoEmit (EmitContext ec)
6562                         {
6563                                 if (ctch.li != null) {
6564                                         if (ctch.hoisted_temp != null)
6565                                                 ctch.hoisted_temp.Emit (ec);
6566                                         else
6567                                                 ctch.li.Emit (ec);
6568
6569                                         if (!ctch.IsGeneral && ctch.type.Kind == MemberKind.TypeParameter)
6570                                                 ec.Emit (OpCodes.Box, ctch.type);
6571                                 }
6572
6573                                 var expr_start = ec.DefineLabel ();
6574                                 var end = ec.DefineLabel ();
6575
6576                                 ec.Emit (OpCodes.Brtrue_S, expr_start);
6577                                 ec.EmitInt (0);
6578                                 ec.Emit (OpCodes.Br, end);
6579                                 ec.MarkLabel (expr_start);
6580
6581                                 ctch.Filter.Emit (ec);
6582
6583                                 ec.MarkLabel (end);
6584                                 ec.Emit (OpCodes.Endfilter);
6585                                 ec.BeginFilterHandler ();
6586                                 ec.Emit (OpCodes.Pop);
6587                         }
6588
6589                         protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6590                         {
6591                                 ctch.Filter.FlowAnalysis (fc);
6592                                 return true;
6593                         }
6594
6595                         public override bool Resolve (BlockContext bc)
6596                         {
6597                                 ctch.Filter = ctch.Filter.Resolve (bc);
6598
6599                                 if (ctch.Filter != null) {
6600                                         if (ctch.Filter.ContainsEmitWithAwait ()) {
6601                                                 bc.Report.Error (7094, ctch.Filter.Location, "The `await' operator cannot be used in the filter expression of a catch clause");
6602                                         }
6603
6604                                         var c = ctch.Filter as Constant;
6605                                         if (c != null && !c.IsDefaultValue) {
6606                                                 bc.Report.Warning (7095, 1, ctch.Filter.Location, "Exception filter expression is a constant");
6607                                         }
6608                                 }
6609
6610                                 return true;
6611                         }
6612                 }
6613
6614                 ExplicitBlock block;
6615                 LocalVariable li;
6616                 FullNamedExpression type_expr;
6617                 CompilerAssign assign;
6618                 TypeSpec type;
6619                 LocalTemporary hoisted_temp;
6620
6621                 public Catch (ExplicitBlock block, Location loc)
6622                 {
6623                         this.block = block;
6624                         this.loc = loc;
6625                 }
6626
6627                 #region Properties
6628
6629                 public ExplicitBlock Block {
6630                         get {
6631                                 return block;
6632                         }
6633                 }
6634
6635                 public TypeSpec CatchType {
6636                         get {
6637                                 return type;
6638                         }
6639                 }
6640
6641                 public Expression Filter {
6642                         get; set;
6643                 }
6644
6645                 public bool IsGeneral {
6646                         get {
6647                                 return type_expr == null;
6648                         }
6649                 }
6650
6651                 public FullNamedExpression TypeExpression {
6652                         get {
6653                                 return type_expr;
6654                         }
6655                         set {
6656                                 type_expr = value;
6657                         }
6658                 }
6659
6660                 public LocalVariable Variable {
6661                         get {
6662                                 return li;
6663                         }
6664                         set {
6665                                 li = value;
6666                         }
6667                 }
6668
6669                 #endregion
6670
6671                 protected override void DoEmit (EmitContext ec)
6672                 {
6673                         if (Filter != null) {
6674                                 ec.BeginExceptionFilterBlock ();
6675                                 ec.Emit (OpCodes.Isinst, IsGeneral ? ec.BuiltinTypes.Object : CatchType);
6676
6677                                 if (Block.HasAwait) {
6678                                         Block.EmitScopeInitialization (ec);
6679                                 } else {
6680                                         Block.Emit (ec);
6681                                 }
6682
6683                                 return;
6684                         }
6685
6686                         if (IsGeneral)
6687                                 ec.BeginCatchBlock (ec.BuiltinTypes.Object);
6688                         else
6689                                 ec.BeginCatchBlock (CatchType);
6690
6691                         if (li == null)
6692                                 ec.Emit (OpCodes.Pop);
6693
6694                         if (Block.HasAwait) {
6695                                 if (li != null)
6696                                         EmitCatchVariableStore (ec);
6697                         } else {
6698                                 Block.Emit (ec);
6699                         }
6700                 }
6701
6702                 void EmitCatchVariableStore (EmitContext ec)
6703                 {
6704                         li.CreateBuilder (ec);
6705
6706                         //
6707                         // For hoisted catch variable we have to use a temporary local variable
6708                         // for captured variable initialization during storey setup because variable
6709                         // needs to be on the stack after storey instance for stfld operation
6710                         //
6711                         if (li.HoistedVariant != null) {
6712                                 hoisted_temp = new LocalTemporary (li.Type);
6713                                 hoisted_temp.Store (ec);
6714
6715                                 // switch to assignment from temporary variable and not from top of the stack
6716                                 assign.UpdateSource (hoisted_temp);
6717                         }
6718                 }
6719
6720                 public override bool Resolve (BlockContext bc)
6721                 {
6722                         using (bc.Set (ResolveContext.Options.CatchScope)) {
6723                                 if (type_expr == null) {
6724                                         if (CreateExceptionVariable (bc.Module.Compiler.BuiltinTypes.Object)) {
6725                                                 if (!block.HasAwait || Filter != null)
6726                                                         block.AddScopeStatement (new CatchVariableStore (this));
6727
6728                                                 Expression source = new EmptyExpression (li.Type);
6729                                                 assign = new CompilerAssign (new LocalVariableReference (li, Location.Null), source, Location.Null);
6730                                                 Block.AddScopeStatement (new StatementExpression (assign, Location.Null));
6731                                         }
6732                                 } else {
6733                                         type = type_expr.ResolveAsType (bc);
6734                                         if (type == null)
6735                                                 return false;
6736
6737                                         if (li == null)
6738                                                 CreateExceptionVariable (type);
6739
6740                                         if (type.BuiltinType != BuiltinTypeSpec.Type.Exception && !TypeSpec.IsBaseClass (type, bc.BuiltinTypes.Exception, false)) {
6741                                                 bc.Report.Error (155, loc, "The type caught or thrown must be derived from System.Exception");
6742                                         } else if (li != null) {
6743                                                 li.Type = type;
6744                                                 li.PrepareAssignmentAnalysis (bc);
6745
6746                                                 // source variable is at the top of the stack
6747                                                 Expression source = new EmptyExpression (li.Type);
6748                                                 if (li.Type.IsGenericParameter)
6749                                                         source = new UnboxCast (source, li.Type);
6750
6751                                                 if (!block.HasAwait || Filter != null)
6752                                                         block.AddScopeStatement (new CatchVariableStore (this));
6753
6754                                                 //
6755                                                 // Uses Location.Null to hide from symbol file
6756                                                 //
6757                                                 assign = new CompilerAssign (new LocalVariableReference (li, Location.Null), source, Location.Null);
6758                                                 Block.AddScopeStatement (new StatementExpression (assign, Location.Null));
6759                                         }
6760                                 }
6761
6762                                 if (Filter != null) {
6763                                         Block.AddScopeStatement (new FilterStatement (this));
6764                                 }
6765
6766                                 Block.SetCatchBlock ();
6767                                 return Block.Resolve (bc);
6768                         }
6769                 }
6770
6771                 bool CreateExceptionVariable (TypeSpec type)
6772                 {
6773                         if (!Block.HasAwait)
6774                                 return false;
6775
6776                         // TODO: Scan the block for rethrow expression
6777                         //if (!Block.HasRethrow)
6778                         //      return;
6779
6780                         li = LocalVariable.CreateCompilerGenerated (type, block, Location.Null);
6781                         return true;
6782                 }
6783
6784                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6785                 {
6786                         if (li != null && !li.IsCompilerGenerated) {
6787                                 fc.SetVariableAssigned (li.VariableInfo, true);
6788                         }
6789
6790                         return block.FlowAnalysis (fc);
6791                 }
6792
6793                 public override Reachability MarkReachable (Reachability rc)
6794                 {
6795                         base.MarkReachable (rc);
6796
6797                         var c = Filter as Constant;
6798                         if (c != null && c.IsDefaultValue)
6799                                 return Reachability.CreateUnreachable ();
6800
6801                         return block.MarkReachable (rc);
6802                 }
6803
6804                 protected override void CloneTo (CloneContext clonectx, Statement t)
6805                 {
6806                         Catch target = (Catch) t;
6807
6808                         if (type_expr != null)
6809                                 target.type_expr = (FullNamedExpression) type_expr.Clone (clonectx);
6810
6811                         if (Filter != null)
6812                                 target.Filter = Filter.Clone (clonectx);
6813
6814                         target.block = (ExplicitBlock) clonectx.LookupBlock (block);
6815                 }
6816         }
6817
6818         public class TryFinally : TryFinallyBlock
6819         {
6820                 ExplicitBlock fini;
6821                 List<DefiniteAssignmentBitSet> try_exit_dat;
6822                 List<Label> redirected_jumps;
6823                 Label? start_fin_label;
6824
6825                 public TryFinally (Statement stmt, ExplicitBlock fini, Location loc)
6826                          : base (stmt, loc)
6827                 {
6828                         this.fini = fini;
6829                 }
6830
6831                 public ExplicitBlock FinallyBlock {
6832                         get {
6833                                 return fini;
6834                         }
6835                 }
6836
6837                 public void RegisterForControlExitCheck (DefiniteAssignmentBitSet vector)
6838                 {
6839                         if (try_exit_dat == null)
6840                                 try_exit_dat = new List<DefiniteAssignmentBitSet> ();
6841
6842                         try_exit_dat.Add (vector);
6843                 }
6844
6845                 public override bool Resolve (BlockContext bc)
6846                 {
6847                         bool ok = base.Resolve (bc);
6848
6849                         fini.SetFinallyBlock ();
6850                         using (bc.Set (ResolveContext.Options.FinallyScope)) {
6851                                 ok &= fini.Resolve (bc);
6852                         }
6853
6854                         return ok;
6855                 }
6856
6857                 protected override void EmitBeginException (EmitContext ec)
6858                 {
6859                         if (fini.HasAwait && stmt is TryCatch)
6860                                 ec.BeginExceptionBlock ();
6861
6862                         base.EmitBeginException (ec);
6863                 }
6864
6865                 protected override void EmitTryBody (EmitContext ec)
6866                 {
6867                         if (fini.HasAwait) {
6868                                 if (ec.TryFinallyUnwind == null)
6869                                         ec.TryFinallyUnwind = new List<TryFinally> ();
6870
6871                                 ec.TryFinallyUnwind.Add (this);
6872                                 stmt.Emit (ec);
6873
6874                                 if (stmt is TryCatch)
6875                                         ec.EndExceptionBlock ();
6876
6877                                 ec.TryFinallyUnwind.Remove (this);
6878
6879                                 if (start_fin_label != null)
6880                                         ec.MarkLabel (start_fin_label.Value);
6881
6882                                 return;
6883                         }
6884
6885                         stmt.Emit (ec);
6886                 }
6887
6888                 protected override bool EmitBeginFinallyBlock (EmitContext ec)
6889                 {
6890                         if (fini.HasAwait)
6891                                 return false;
6892
6893                         return base.EmitBeginFinallyBlock (ec);
6894                 }
6895
6896                 public override void EmitFinallyBody (EmitContext ec)
6897                 {
6898                         if (!fini.HasAwait) {
6899                                 fini.Emit (ec);
6900                                 return;
6901                         }
6902
6903                         //
6904                         // Emits catch block like
6905                         //
6906                         // catch (object temp) {
6907                         //      this.exception_field = temp;
6908                         // }
6909                         //
6910                         var type = ec.BuiltinTypes.Object;
6911                         ec.BeginCatchBlock (type);
6912
6913                         var temp = ec.GetTemporaryLocal (type);
6914                         ec.Emit (OpCodes.Stloc, temp);
6915
6916                         var exception_field = ec.GetTemporaryField (type);
6917                         ec.EmitThis ();
6918                         ec.Emit (OpCodes.Ldloc, temp);
6919                         exception_field.EmitAssignFromStack (ec);
6920
6921                         ec.EndExceptionBlock ();
6922
6923                         ec.FreeTemporaryLocal (temp, type);
6924
6925                         fini.Emit (ec);
6926
6927                         //
6928                         // Emits exception rethrow
6929                         //
6930                         // if (this.exception_field != null)
6931                         //      throw this.exception_field;
6932                         //
6933                         exception_field.Emit (ec);
6934                         var skip_throw = ec.DefineLabel ();
6935                         ec.Emit (OpCodes.Brfalse_S, skip_throw);
6936                         exception_field.Emit (ec);
6937                         ec.Emit (OpCodes.Throw);
6938                         ec.MarkLabel (skip_throw);
6939
6940                         exception_field.IsAvailableForReuse = true;
6941
6942                         EmitUnwindFinallyTable (ec);
6943                 }
6944
6945                 bool IsParentBlock (Block block)
6946                 {
6947                         for (Block b = fini; b != null; b = b.Parent) {
6948                                 if (b == block)
6949                                         return true;
6950                         }
6951
6952                         return false;
6953                 }
6954
6955                 public static Label EmitRedirectedJump (EmitContext ec, AsyncInitializer initializer, Label label, Block labelBlock)
6956                 {
6957                         int idx;
6958                         if (labelBlock != null) {
6959                                 for (idx = ec.TryFinallyUnwind.Count; idx != 0; --idx) {
6960                                         var fin = ec.TryFinallyUnwind [idx - 1];
6961                                         if (!fin.IsParentBlock (labelBlock))
6962                                                 break;
6963                                 }
6964                         } else {
6965                                 idx = 0;
6966                         }
6967
6968                         bool set_return_state = true;
6969
6970                         for (; idx < ec.TryFinallyUnwind.Count; ++idx) {
6971                                 var fin = ec.TryFinallyUnwind [idx];
6972                                 if (labelBlock != null && !fin.IsParentBlock (labelBlock))
6973                                         break;
6974
6975                                 fin.EmitRedirectedExit (ec, label, initializer, set_return_state);
6976                                 set_return_state = false;
6977
6978                                 if (fin.start_fin_label == null) {
6979                                         fin.start_fin_label = ec.DefineLabel ();
6980                                 }
6981
6982                                 label = fin.start_fin_label.Value;
6983                         }
6984
6985                         return label;
6986                 }
6987
6988                 public static Label EmitRedirectedReturn (EmitContext ec, AsyncInitializer initializer)
6989                 {
6990                         return EmitRedirectedJump (ec, initializer, initializer.BodyEnd, null);
6991                 }
6992
6993                 void EmitRedirectedExit (EmitContext ec, Label label, AsyncInitializer initializer, bool setReturnState)
6994                 {
6995                         if (redirected_jumps == null) {
6996                                 redirected_jumps = new List<Label> ();
6997
6998                                 // Add fallthrough label
6999                                 redirected_jumps.Add (ec.DefineLabel ());
7000
7001                                 if (setReturnState)
7002                                         initializer.HoistedReturnState = ec.GetTemporaryField (ec.Module.Compiler.BuiltinTypes.Int, true);
7003                         }
7004
7005                         int index = redirected_jumps.IndexOf (label);
7006                         if (index < 0) {
7007                                 redirected_jumps.Add (label);
7008                                 index = redirected_jumps.Count - 1;
7009                         }
7010
7011                         //
7012                         // Indicates we have captured exit jump
7013                         //
7014                         if (setReturnState) {
7015                                 var value = new IntConstant (initializer.HoistedReturnState.Type, index, Location.Null);
7016                                 initializer.HoistedReturnState.EmitAssign (ec, value, false, false);
7017                         }
7018                 }
7019
7020                 //
7021                 // Emits state table of jumps outside of try block and reload of return
7022                 // value when try block returns value
7023                 //
7024                 void EmitUnwindFinallyTable (EmitContext ec)
7025                 {
7026                         if (redirected_jumps == null)
7027                                 return;
7028
7029                         var initializer = (AsyncInitializer)ec.CurrentAnonymousMethod;
7030                         initializer.HoistedReturnState.EmitLoad (ec);
7031                         ec.Emit (OpCodes.Switch, redirected_jumps.ToArray ());
7032
7033                         // Mark fallthrough label
7034                         ec.MarkLabel (redirected_jumps [0]);
7035                 }
7036
7037                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7038                 {
7039                         var da = fc.BranchDefiniteAssignment ();
7040
7041                         var tf = fc.TryFinally;
7042                         fc.TryFinally = this;
7043
7044                         var res_stmt = Statement.FlowAnalysis (fc);
7045
7046                         fc.TryFinally = tf;
7047
7048                         var try_da = fc.DefiniteAssignment;
7049                         fc.DefiniteAssignment = da;
7050
7051                         var res_fin = fini.FlowAnalysis (fc);
7052
7053                         if (try_exit_dat != null) {
7054                                 //
7055                                 // try block has global exit but we need to run definite assignment check
7056                                 // for parameter block out parameter after finally block because it's always
7057                                 // executed before exit
7058                                 //
7059                                 foreach (var try_da_part in try_exit_dat)
7060                                         fc.ParametersBlock.CheckControlExit (fc, fc.DefiniteAssignment | try_da_part);
7061
7062                                 try_exit_dat = null;
7063                         }
7064
7065                         fc.DefiniteAssignment |= try_da;
7066                         return res_stmt | res_fin;
7067                 }
7068
7069                 public override Reachability MarkReachable (Reachability rc)
7070                 {
7071                         //
7072                         // Mark finally block first for any exit statement in try block
7073                         // to know whether the code which follows finally is reachable
7074                         //
7075                         return fini.MarkReachable (rc) | base.MarkReachable (rc);
7076                 }
7077
7078                 protected override void CloneTo (CloneContext clonectx, Statement t)
7079                 {
7080                         TryFinally target = (TryFinally) t;
7081
7082                         target.stmt = stmt.Clone (clonectx);
7083                         if (fini != null)
7084                                 target.fini = (ExplicitBlock) clonectx.LookupBlock (fini);
7085                 }
7086                 
7087                 public override object Accept (StructuralVisitor visitor)
7088                 {
7089                         return visitor.Visit (this);
7090                 }
7091         }
7092
7093         public class TryCatch : ExceptionStatement
7094         {
7095                 public Block Block;
7096                 List<Catch> clauses;
7097                 readonly bool inside_try_finally;
7098                 List<Catch> catch_sm;
7099
7100                 public TryCatch (Block block, List<Catch> catch_clauses, Location l, bool inside_try_finally)
7101                         : base (l)
7102                 {
7103                         this.Block = block;
7104                         this.clauses = catch_clauses;
7105                         this.inside_try_finally = inside_try_finally;
7106                 }
7107
7108                 public List<Catch> Clauses {
7109                         get {
7110                                 return clauses;
7111                         }
7112                 }
7113
7114                 public bool IsTryCatchFinally {
7115                         get {
7116                                 return inside_try_finally;
7117                         }
7118                 }
7119
7120                 public override bool Resolve (BlockContext bc)
7121                 {
7122                         bool ok;
7123
7124                         using (bc.Set (ResolveContext.Options.TryScope)) {
7125                                 parent = bc.CurrentTryBlock;
7126
7127                                 if (IsTryCatchFinally) {
7128                                         ok = Block.Resolve (bc);
7129                                 } else {
7130                                         using (bc.Set (ResolveContext.Options.TryWithCatchScope)) {
7131                                                 bc.CurrentTryBlock = this;
7132                                                 ok = Block.Resolve (bc);
7133                                                 bc.CurrentTryBlock = parent;
7134                                         }
7135                                 }
7136                         }
7137
7138                         for (int i = 0; i < clauses.Count; ++i) {
7139                                 var c = clauses[i];
7140
7141                                 ok &= c.Resolve (bc);
7142
7143                                 if (c.Block.HasAwait) {
7144                                         if (catch_sm == null)
7145                                                 catch_sm = new List<Catch> ();
7146
7147                                         catch_sm.Add (c);
7148                                 }
7149
7150                                 if (c.Filter != null)
7151                                         continue;
7152
7153                                 TypeSpec resolved_type = c.CatchType;
7154                                 if (resolved_type == null)
7155                                         continue;
7156
7157                                 for (int ii = 0; ii < clauses.Count; ++ii) {
7158                                         if (ii == i)
7159                                                 continue;
7160
7161                                         if (clauses[ii].Filter != null)
7162                                                 continue;
7163
7164                                         if (clauses[ii].IsGeneral) {
7165                                                 if (resolved_type.BuiltinType != BuiltinTypeSpec.Type.Exception)
7166                                                         continue;
7167
7168                                                 if (!bc.Module.DeclaringAssembly.WrapNonExceptionThrows)
7169                                                         continue;
7170
7171                                                 if (!bc.Module.PredefinedAttributes.RuntimeCompatibility.IsDefined)
7172                                                         continue;
7173
7174                                                 bc.Report.Warning (1058, 1, c.loc,
7175                                                         "A previous catch clause already catches all exceptions. All non-exceptions thrown will be wrapped in a `System.Runtime.CompilerServices.RuntimeWrappedException'");
7176
7177                                                 continue;
7178                                         }
7179
7180                                         if (ii >= i)
7181                                                 continue;
7182
7183                                         var ct = clauses[ii].CatchType;
7184                                         if (ct == null)
7185                                                 continue;
7186
7187                                         if (resolved_type == ct || TypeSpec.IsBaseClass (resolved_type, ct, true)) {
7188                                                 bc.Report.Error (160, c.loc,
7189                                                         "A previous catch clause already catches all exceptions of this or a super type `{0}'",
7190                                                         ct.GetSignatureForError ());
7191                                                 ok = false;
7192                                         }
7193                                 }
7194                         }
7195
7196                         return base.Resolve (bc) && ok;
7197                 }
7198
7199                 protected sealed override void DoEmit (EmitContext ec)
7200                 {
7201                         if (!inside_try_finally)
7202                                 EmitTryBodyPrepare (ec);
7203
7204                         Block.Emit (ec);
7205
7206                         LocalBuilder state_variable = null;
7207                         foreach (Catch c in clauses) {
7208                                 c.Emit (ec);
7209
7210                                 if (catch_sm != null) {
7211                                         if (state_variable == null) {
7212                                                 //
7213                                                 // Cannot reuse temp variable because non-catch path assumes the value is 0
7214                                                 // which may not be true for reused local variable
7215                                                 //
7216                                                 state_variable = ec.DeclareLocal (ec.Module.Compiler.BuiltinTypes.Int, false);
7217                                         }
7218
7219                                         var index = catch_sm.IndexOf (c);
7220                                         if (index < 0)
7221                                                 continue;
7222
7223                                         ec.EmitInt (index + 1);
7224                                         ec.Emit (OpCodes.Stloc, state_variable);
7225                                 }
7226                         }
7227
7228                         if (!inside_try_finally)
7229                                 ec.EndExceptionBlock ();
7230
7231                         if (state_variable != null) {
7232                                 ec.Emit (OpCodes.Ldloc, state_variable);
7233
7234                                 var labels = new Label [catch_sm.Count + 1];
7235                                 for (int i = 0; i < labels.Length; ++i) {
7236                                         labels [i] = ec.DefineLabel ();
7237                                 }
7238
7239                                 var end = ec.DefineLabel ();
7240                                 ec.Emit (OpCodes.Switch, labels);
7241
7242                                 // 0 value is default label
7243                                 ec.MarkLabel (labels [0]);
7244                                 ec.Emit (OpCodes.Br, end);
7245
7246                                 var atv = ec.AsyncThrowVariable;
7247                                 Catch c = null;
7248                                 for (int i = 0; i < catch_sm.Count; ++i) {
7249                                         if (c != null && c.Block.HasReachableClosingBrace)
7250                                                 ec.Emit (OpCodes.Br, end);
7251
7252                                         ec.MarkLabel (labels [i + 1]);
7253                                         c = catch_sm [i];
7254                                         ec.AsyncThrowVariable = c.Variable;
7255                                         c.Block.Emit (ec);
7256                                 }
7257                                 ec.AsyncThrowVariable = atv;
7258
7259                                 ec.MarkLabel (end);
7260                         }
7261                 }
7262
7263                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7264                 {
7265                         var start_fc = fc.BranchDefiniteAssignment ();
7266                         var res = Block.FlowAnalysis (fc);
7267
7268                         DefiniteAssignmentBitSet try_fc = res ? null : fc.DefiniteAssignment;
7269
7270                         foreach (var c in clauses) {
7271                                 fc.BranchDefiniteAssignment (start_fc);
7272                                 if (!c.FlowAnalysis (fc)) {
7273                                         if (try_fc == null)
7274                                                 try_fc = fc.DefiniteAssignment;
7275                                         else
7276                                                 try_fc &= fc.DefiniteAssignment;
7277
7278                                         res = false;
7279                                 }
7280                         }
7281
7282                         fc.DefiniteAssignment = try_fc ?? start_fc;
7283                         parent = null;
7284                         return res;
7285                 }
7286
7287                 public override Reachability MarkReachable (Reachability rc)
7288                 {
7289                         if (rc.IsUnreachable)
7290                                 return rc;
7291
7292                         base.MarkReachable (rc);
7293
7294                         var tc_rc = Block.MarkReachable (rc);
7295
7296                         foreach (var c in clauses)
7297                                 tc_rc &= c.MarkReachable (rc);
7298
7299                         return tc_rc;
7300                 }
7301
7302                 protected override void CloneTo (CloneContext clonectx, Statement t)
7303                 {
7304                         TryCatch target = (TryCatch) t;
7305
7306                         target.Block = clonectx.LookupBlock (Block);
7307                         if (clauses != null){
7308                                 target.clauses = new List<Catch> ();
7309                                 foreach (Catch c in clauses)
7310                                         target.clauses.Add ((Catch) c.Clone (clonectx));
7311                         }
7312                 }
7313
7314                 public override object Accept (StructuralVisitor visitor)
7315                 {
7316                         return visitor.Visit (this);
7317                 }
7318         }
7319
7320         public class Using : TryFinallyBlock
7321         {
7322                 public class VariableDeclaration : BlockVariable
7323                 {
7324                         Statement dispose_call;
7325
7326                         public VariableDeclaration (FullNamedExpression type, LocalVariable li)
7327                                 : base (type, li)
7328                         {
7329                         }
7330
7331                         public VariableDeclaration (LocalVariable li, Location loc)
7332                                 : base (li)
7333                         {
7334                                 reachable = true;
7335                                 this.loc = loc;
7336                         }
7337
7338                         public VariableDeclaration (Expression expr)
7339                                 : base (null)
7340                         {
7341                                 loc = expr.Location;
7342                                 Initializer = expr;
7343                         }
7344
7345                         #region Properties
7346
7347                         public bool IsNested { get; private set; }
7348
7349                         #endregion
7350
7351                         public void EmitDispose (EmitContext ec)
7352                         {
7353                                 dispose_call.Emit (ec);
7354                         }
7355
7356                         public override bool Resolve (BlockContext bc)
7357                         {
7358                                 if (IsNested)
7359                                         return true;
7360
7361                                 return base.Resolve (bc, false);
7362                         }
7363
7364                         public Expression ResolveExpression (BlockContext bc)
7365                         {
7366                                 var e = Initializer.Resolve (bc);
7367                                 if (e == null)
7368                                         return null;
7369
7370                                 li = LocalVariable.CreateCompilerGenerated (e.Type, bc.CurrentBlock, loc);
7371                                 Initializer = ResolveInitializer (bc, Variable, e);
7372                                 return e;
7373                         }
7374
7375                         protected override Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
7376                         {
7377                                 if (li.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
7378                                         initializer = initializer.Resolve (bc);
7379                                         if (initializer == null)
7380                                                 return null;
7381
7382                                         // Once there is dynamic used defer conversion to runtime even if we know it will never succeed
7383                                         Arguments args = new Arguments (1);
7384                                         args.Add (new Argument (initializer));
7385                                         initializer = new DynamicConversion (bc.BuiltinTypes.IDisposable, 0, args, initializer.Location).Resolve (bc);
7386                                         if (initializer == null)
7387                                                 return null;
7388
7389                                         var var = LocalVariable.CreateCompilerGenerated (initializer.Type, bc.CurrentBlock, loc);
7390                                         dispose_call = CreateDisposeCall (bc, var);
7391                                         dispose_call.Resolve (bc);
7392
7393                                         return base.ResolveInitializer (bc, li, new SimpleAssign (var.CreateReferenceExpression (bc, loc), initializer, loc));
7394                                 }
7395
7396                                 if (li == Variable) {
7397                                         CheckIDiposableConversion (bc, li, initializer);
7398                                         dispose_call = CreateDisposeCall (bc, li);
7399                                         dispose_call.Resolve (bc);
7400                                 }
7401
7402                                 return base.ResolveInitializer (bc, li, initializer);
7403                         }
7404
7405                         protected virtual void CheckIDiposableConversion (BlockContext bc, LocalVariable li, Expression initializer)
7406                         {
7407                                 var type = li.Type;
7408
7409                                 if (type.BuiltinType != BuiltinTypeSpec.Type.IDisposable && !CanConvertToIDisposable (bc, type)) {
7410                                         if (type.IsNullableType) {
7411                                                 // it's handled in CreateDisposeCall
7412                                                 return;
7413                                         }
7414
7415                                         if (type != InternalType.ErrorType) {
7416                                                 bc.Report.SymbolRelatedToPreviousError (type);
7417                                                 var loc = type_expr == null ? initializer.Location : type_expr.Location;
7418                                                 bc.Report.Error (1674, loc, "`{0}': type used in a using statement must be implicitly convertible to `System.IDisposable'",
7419                                                         type.GetSignatureForError ());
7420                                         }
7421
7422                                         return;
7423                                 }
7424                         }
7425
7426                         static bool CanConvertToIDisposable (BlockContext bc, TypeSpec type)
7427                         {
7428                                 var target = bc.BuiltinTypes.IDisposable;
7429                                 var tp = type as TypeParameterSpec;
7430                                 if (tp != null)
7431                                         return Convert.ImplicitTypeParameterConversion (null, tp, target) != null;
7432
7433                                 return type.ImplementsInterface (target, false);
7434                         }
7435
7436                         protected virtual Statement CreateDisposeCall (BlockContext bc, LocalVariable lv)
7437                         {
7438                                 var lvr = lv.CreateReferenceExpression (bc, lv.Location);
7439                                 var type = lv.Type;
7440                                 var loc = lv.Location;
7441
7442                                 var idt = bc.BuiltinTypes.IDisposable;
7443                                 var m = bc.Module.PredefinedMembers.IDisposableDispose.Resolve (loc);
7444
7445                                 var dispose_mg = MethodGroupExpr.CreatePredefined (m, idt, loc);
7446                                 dispose_mg.InstanceExpression = type.IsNullableType ?
7447                                         new Cast (new TypeExpression (idt, loc), lvr, loc).Resolve (bc) :
7448                                         lvr;
7449
7450                                 //
7451                                 // Hide it from symbol file via null location
7452                                 //
7453                                 Statement dispose = new StatementExpression (new Invocation (dispose_mg, null), Location.Null);
7454
7455                                 // Add conditional call when disposing possible null variable
7456                                 if (!TypeSpec.IsValueType (type) || type.IsNullableType)
7457                                         dispose = new If (new Binary (Binary.Operator.Inequality, lvr, new NullLiteral (loc)), dispose, dispose.loc);
7458
7459                                 return dispose;
7460                         }
7461
7462                         public void ResolveDeclaratorInitializer (BlockContext bc)
7463                         {
7464                                 Initializer = base.ResolveInitializer (bc, Variable, Initializer);
7465                         }
7466
7467                         public Statement RewriteUsingDeclarators (BlockContext bc, Statement stmt)
7468                         {
7469                                 for (int i = declarators.Count - 1; i >= 0; --i) {
7470                                         var d = declarators [i];
7471                                         var vd = new VariableDeclaration (d.Variable, d.Variable.Location);
7472                                         vd.Initializer = d.Initializer;
7473                                         vd.IsNested = true;
7474                                         vd.dispose_call = CreateDisposeCall (bc, d.Variable);
7475                                         vd.dispose_call.Resolve (bc);
7476
7477                                         stmt = new Using (vd, stmt, d.Variable.Location);
7478                                 }
7479
7480                                 declarators = null;
7481                                 return stmt;
7482                         }       
7483
7484                         public override object Accept (StructuralVisitor visitor)
7485                         {
7486                                 return visitor.Visit (this);
7487                         }       
7488                 }
7489
7490                 VariableDeclaration decl;
7491
7492                 public Using (VariableDeclaration decl, Statement stmt, Location loc)
7493                         : base (stmt, loc)
7494                 {
7495                         this.decl = decl;
7496                 }
7497
7498                 public Using (Expression expr, Statement stmt, Location loc)
7499                         : base (stmt, loc)
7500                 {
7501                         this.decl = new VariableDeclaration (expr);
7502                 }
7503
7504                 #region Properties
7505
7506                 public Expression Expr {
7507                         get {
7508                                 return decl.Variable == null ? decl.Initializer : null;
7509                         }
7510                 }
7511
7512                 public BlockVariable Variables {
7513                         get {
7514                                 return decl;
7515                         }
7516                 }
7517
7518                 #endregion
7519
7520                 public override void Emit (EmitContext ec)
7521                 {
7522                         //
7523                         // Don't emit sequence point it will be set on variable declaration
7524                         //
7525                         DoEmit (ec);
7526                 }
7527
7528                 protected override void EmitTryBodyPrepare (EmitContext ec)
7529                 {
7530                         decl.Emit (ec);
7531                         base.EmitTryBodyPrepare (ec);
7532                 }
7533
7534                 protected override void EmitTryBody (EmitContext ec)
7535                 {
7536                         stmt.Emit (ec);
7537                 }
7538
7539                 public override void EmitFinallyBody (EmitContext ec)
7540                 {
7541                         decl.EmitDispose (ec);
7542                 }
7543
7544                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7545                 {
7546                         decl.FlowAnalysis (fc);
7547                         return stmt.FlowAnalysis (fc);
7548                 }
7549
7550                 public override Reachability MarkReachable (Reachability rc)
7551                 {
7552                         decl.MarkReachable (rc);
7553                         return base.MarkReachable (rc);
7554                 }
7555
7556                 public override bool Resolve (BlockContext ec)
7557                 {
7558                         VariableReference vr;
7559                         bool vr_locked = false;
7560
7561                         using (ec.Set (ResolveContext.Options.UsingInitializerScope)) {
7562                                 if (decl.Variable == null) {
7563                                         vr = decl.ResolveExpression (ec) as VariableReference;
7564                                         if (vr != null) {
7565                                                 vr_locked = vr.IsLockedByStatement;
7566                                                 vr.IsLockedByStatement = true;
7567                                         }
7568                                 } else {
7569                                         if (decl.IsNested) {
7570                                                 decl.ResolveDeclaratorInitializer (ec);
7571                                         } else {
7572                                                 if (!decl.Resolve (ec))
7573                                                         return false;
7574
7575                                                 if (decl.Declarators != null) {
7576                                                         stmt = decl.RewriteUsingDeclarators (ec, stmt);
7577                                                 }
7578                                         }
7579
7580                                         vr = null;
7581                                 }
7582                         }
7583
7584                         var ok = base.Resolve (ec);
7585
7586                         if (vr != null)
7587                                 vr.IsLockedByStatement = vr_locked;
7588
7589                         return ok;
7590                 }
7591
7592                 protected override void CloneTo (CloneContext clonectx, Statement t)
7593                 {
7594                         Using target = (Using) t;
7595
7596                         target.decl = (VariableDeclaration) decl.Clone (clonectx);
7597                         target.stmt = stmt.Clone (clonectx);
7598                 }
7599
7600                 public override object Accept (StructuralVisitor visitor)
7601                 {
7602                         return visitor.Visit (this);
7603                 }
7604         }
7605
7606         /// <summary>
7607         ///   Implementation of the foreach C# statement
7608         /// </summary>
7609         public class Foreach : LoopStatement
7610         {
7611                 abstract class IteratorStatement : Statement
7612                 {
7613                         protected readonly Foreach for_each;
7614
7615                         protected IteratorStatement (Foreach @foreach)
7616                         {
7617                                 this.for_each = @foreach;
7618                                 this.loc = @foreach.expr.Location;
7619                         }
7620
7621                         protected override void CloneTo (CloneContext clonectx, Statement target)
7622                         {
7623                                 throw new NotImplementedException ();
7624                         }
7625
7626                         public override void Emit (EmitContext ec)
7627                         {
7628                                 if (ec.EmitAccurateDebugInfo) {
7629                                         ec.Emit (OpCodes.Nop);
7630                                 }
7631
7632                                 base.Emit (ec);
7633                         }
7634
7635                         protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7636                         {
7637                                 throw new NotImplementedException ();
7638                         }
7639                 }
7640
7641                 sealed class ArrayForeach : IteratorStatement
7642                 {
7643                         TemporaryVariableReference[] lengths;
7644                         Expression [] length_exprs;
7645                         StatementExpression[] counter;
7646                         TemporaryVariableReference[] variables;
7647
7648                         TemporaryVariableReference copy;
7649
7650                         public ArrayForeach (Foreach @foreach, int rank)
7651                                 : base (@foreach)
7652                         {
7653                                 counter = new StatementExpression[rank];
7654                                 variables = new TemporaryVariableReference[rank];
7655                                 length_exprs = new Expression [rank];
7656
7657                                 //
7658                                 // Only use temporary length variables when dealing with
7659                                 // multi-dimensional arrays
7660                                 //
7661                                 if (rank > 1)
7662                                         lengths = new TemporaryVariableReference [rank];
7663                         }
7664
7665                         public override bool Resolve (BlockContext ec)
7666                         {
7667                                 Block variables_block = for_each.variable.Block;
7668                                 copy = TemporaryVariableReference.Create (for_each.expr.Type, variables_block, loc);
7669                                 copy.Resolve (ec);
7670
7671                                 int rank = length_exprs.Length;
7672                                 Arguments list = new Arguments (rank);
7673                                 for (int i = 0; i < rank; i++) {
7674                                         var v = TemporaryVariableReference.Create (ec.BuiltinTypes.Int, variables_block, loc);
7675                                         variables[i] = v;
7676                                         counter[i] = new StatementExpression (new UnaryMutator (UnaryMutator.Mode.PostIncrement, v, Location.Null));
7677                                         counter[i].Resolve (ec);
7678
7679                                         if (rank == 1) {
7680                                                 length_exprs [i] = new MemberAccess (copy, "Length").Resolve (ec);
7681                                         } else {
7682                                                 lengths[i] = TemporaryVariableReference.Create (ec.BuiltinTypes.Int, variables_block, loc);
7683                                                 lengths[i].Resolve (ec);
7684
7685                                                 Arguments args = new Arguments (1);
7686                                                 args.Add (new Argument (new IntConstant (ec.BuiltinTypes, i, loc)));
7687                                                 length_exprs [i] = new Invocation (new MemberAccess (copy, "GetLength"), args).Resolve (ec);
7688                                         }
7689
7690                                         list.Add (new Argument (v));
7691                                 }
7692
7693                                 var access = new ElementAccess (copy, list, loc).Resolve (ec);
7694                                 if (access == null)
7695                                         return false;
7696
7697                                 TypeSpec var_type;
7698                                 if (for_each.type is VarExpr) {
7699                                         // Infer implicitly typed local variable from foreach array type
7700                                         var_type = access.Type;
7701                                 } else {
7702                                         var_type = for_each.type.ResolveAsType (ec);
7703
7704                                         if (var_type == null)
7705                                                 return false;
7706
7707                                         access = Convert.ExplicitConversion (ec, access, var_type, loc);
7708                                         if (access == null)
7709                                                 return false;
7710                                 }
7711
7712                                 for_each.variable.Type = var_type;
7713
7714                                 var variable_ref = new LocalVariableReference (for_each.variable, loc).Resolve (ec);
7715                                 if (variable_ref == null)
7716                                         return false;
7717
7718                                 for_each.body.AddScopeStatement (new StatementExpression (new CompilerAssign (variable_ref, access, Location.Null), for_each.type.Location));
7719
7720                                 return for_each.body.Resolve (ec);
7721                         }
7722
7723                         protected override void DoEmit (EmitContext ec)
7724                         {
7725                                 copy.EmitAssign (ec, for_each.expr);
7726
7727                                 int rank = length_exprs.Length;
7728                                 Label[] test = new Label [rank];
7729                                 Label[] loop = new Label [rank];
7730
7731                                 for (int i = 0; i < rank; i++) {
7732                                         test [i] = ec.DefineLabel ();
7733                                         loop [i] = ec.DefineLabel ();
7734
7735                                         if (lengths != null)
7736                                                 lengths [i].EmitAssign (ec, length_exprs [i]);
7737                                 }
7738
7739                                 IntConstant zero = new IntConstant (ec.BuiltinTypes, 0, loc);
7740                                 for (int i = 0; i < rank; i++) {
7741                                         variables [i].EmitAssign (ec, zero);
7742
7743                                         ec.Emit (OpCodes.Br, test [i]);
7744                                         ec.MarkLabel (loop [i]);
7745                                 }
7746
7747                                 for_each.body.Emit (ec);
7748
7749                                 ec.MarkLabel (ec.LoopBegin);
7750                                 ec.Mark (for_each.expr.Location);
7751
7752                                 for (int i = rank - 1; i >= 0; i--){
7753                                         counter [i].Emit (ec);
7754
7755                                         ec.MarkLabel (test [i]);
7756                                         variables [i].Emit (ec);
7757
7758                                         if (lengths != null)
7759                                                 lengths [i].Emit (ec);
7760                                         else
7761                                                 length_exprs [i].Emit (ec);
7762
7763                                         ec.Emit (OpCodes.Blt, loop [i]);
7764                                 }
7765
7766                                 ec.MarkLabel (ec.LoopEnd);
7767                         }
7768                 }
7769
7770                 sealed class CollectionForeach : IteratorStatement, OverloadResolver.IErrorHandler
7771                 {
7772                         class RuntimeDispose : Using.VariableDeclaration
7773                         {
7774                                 public RuntimeDispose (LocalVariable lv, Location loc)
7775                                         : base (lv, loc)
7776                                 {
7777                                         reachable = true;
7778                                 }
7779
7780                                 protected override void CheckIDiposableConversion (BlockContext bc, LocalVariable li, Expression initializer)
7781                                 {
7782                                         // Defered to runtime check
7783                                 }
7784
7785                                 protected override Statement CreateDisposeCall (BlockContext bc, LocalVariable lv)
7786                                 {
7787                                         var idt = bc.BuiltinTypes.IDisposable;
7788
7789                                         //
7790                                         // Fabricates code like
7791                                         //
7792                                         // if ((temp = vr as IDisposable) != null) temp.Dispose ();
7793                                         //
7794
7795                                         var dispose_variable = LocalVariable.CreateCompilerGenerated (idt, bc.CurrentBlock, loc);
7796
7797                                         var idisaposable_test = new Binary (Binary.Operator.Inequality, new CompilerAssign (
7798                                                 dispose_variable.CreateReferenceExpression (bc, loc),
7799                                                 new As (lv.CreateReferenceExpression (bc, loc), new TypeExpression (dispose_variable.Type, loc), loc),
7800                                                 loc), new NullLiteral (loc));
7801
7802                                         var m = bc.Module.PredefinedMembers.IDisposableDispose.Resolve (loc);
7803
7804                                         var dispose_mg = MethodGroupExpr.CreatePredefined (m, idt, loc);
7805                                         dispose_mg.InstanceExpression = dispose_variable.CreateReferenceExpression (bc, loc);
7806
7807                                         Statement dispose = new StatementExpression (new Invocation (dispose_mg, null));
7808                                         return new If (idisaposable_test, dispose, loc);
7809                                 }
7810                         }
7811
7812                         LocalVariable variable;
7813                         Expression expr;
7814                         Statement statement;
7815                         ExpressionStatement init;
7816                         TemporaryVariableReference enumerator_variable;
7817                         bool ambiguous_getenumerator_name;
7818
7819                         public CollectionForeach (Foreach @foreach, LocalVariable var, Expression expr)
7820                                 : base (@foreach)
7821                         {
7822                                 this.variable = var;
7823                                 this.expr = expr;
7824                         }
7825
7826                         void Error_WrongEnumerator (ResolveContext rc, MethodSpec enumerator)
7827                         {
7828                                 rc.Report.SymbolRelatedToPreviousError (enumerator);
7829                                 rc.Report.Error (202, loc,
7830                                         "foreach statement requires that the return type `{0}' of `{1}' must have a suitable public MoveNext method and public Current property",
7831                                                 enumerator.ReturnType.GetSignatureForError (), enumerator.GetSignatureForError ());
7832                         }
7833
7834                         MethodGroupExpr ResolveGetEnumerator (ResolveContext rc)
7835                         {
7836                                 //
7837                                 // Option 1: Try to match by name GetEnumerator first
7838                                 //
7839                                 var mexpr = Expression.MemberLookup (rc, false, expr.Type,
7840                                         "GetEnumerator", 0, Expression.MemberLookupRestrictions.ExactArity, loc);               // TODO: What if CS0229 ?
7841
7842                                 var mg = mexpr as MethodGroupExpr;
7843                                 if (mg != null) {
7844                                         mg.InstanceExpression = expr;
7845                                         Arguments args = new Arguments (0);
7846                                         mg = mg.OverloadResolve (rc, ref args, this, OverloadResolver.Restrictions.ProbingOnly | OverloadResolver.Restrictions.GetEnumeratorLookup);
7847
7848                                         // For ambiguous GetEnumerator name warning CS0278 was reported, but Option 2 could still apply
7849                                         if (ambiguous_getenumerator_name)
7850                                                 mg = null;
7851
7852                                         if (mg != null && !mg.BestCandidate.IsStatic && mg.BestCandidate.IsPublic) {
7853                                                 return mg;
7854                                         }
7855                                 }
7856
7857                                 //
7858                                 // Option 2: Try to match using IEnumerable interfaces with preference of generic version
7859                                 //
7860                                 var t = expr.Type;
7861                                 PredefinedMember<MethodSpec> iface_candidate = null;
7862                                 var ptypes = rc.Module.PredefinedTypes;
7863                                 var gen_ienumerable = ptypes.IEnumerableGeneric;
7864                                 if (!gen_ienumerable.Define ())
7865                                         gen_ienumerable = null;
7866
7867                                 var ifaces = t.Interfaces;
7868                                 if (ifaces != null) {
7869                                         foreach (var iface in ifaces) {
7870                                                 if (gen_ienumerable != null && iface.MemberDefinition == gen_ienumerable.TypeSpec.MemberDefinition) {
7871                                                         if (iface_candidate != null && iface_candidate != rc.Module.PredefinedMembers.IEnumerableGetEnumerator) {
7872                                                                 rc.Report.SymbolRelatedToPreviousError (expr.Type);
7873                                                                 rc.Report.Error (1640, loc,
7874                                                                         "foreach statement cannot operate on variables of type `{0}' because it contains multiple implementation of `{1}'. Try casting to a specific implementation",
7875                                                                         expr.Type.GetSignatureForError (), gen_ienumerable.TypeSpec.GetSignatureForError ());
7876
7877                                                                 return null;
7878                                                         }
7879
7880                                                         // TODO: Cache this somehow
7881                                                         iface_candidate = new PredefinedMember<MethodSpec> (rc.Module, iface,
7882                                                                 MemberFilter.Method ("GetEnumerator", 0, ParametersCompiled.EmptyReadOnlyParameters, null));
7883
7884                                                         continue;
7885                                                 }
7886
7887                                                 if (iface.BuiltinType == BuiltinTypeSpec.Type.IEnumerable && iface_candidate == null) {
7888                                                         iface_candidate = rc.Module.PredefinedMembers.IEnumerableGetEnumerator;
7889                                                 }
7890                                         }
7891                                 }
7892
7893                                 if (iface_candidate == null) {
7894                                         if (expr.Type != InternalType.ErrorType) {
7895                                                 rc.Report.Error (1579, loc,
7896                                                         "foreach statement cannot operate on variables of type `{0}' because it does not contain a definition for `{1}' or is inaccessible",
7897                                                         expr.Type.GetSignatureForError (), "GetEnumerator");
7898                                         }
7899
7900                                         return null;
7901                                 }
7902
7903                                 var method = iface_candidate.Resolve (loc);
7904                                 if (method == null)
7905                                         return null;
7906
7907                                 mg = MethodGroupExpr.CreatePredefined (method, expr.Type, loc);
7908                                 mg.InstanceExpression = expr;
7909                                 return mg;
7910                         }
7911
7912                         MethodGroupExpr ResolveMoveNext (ResolveContext rc, MethodSpec enumerator)
7913                         {
7914                                 var ms = MemberCache.FindMember (enumerator.ReturnType,
7915                                         MemberFilter.Method ("MoveNext", 0, ParametersCompiled.EmptyReadOnlyParameters, rc.BuiltinTypes.Bool),
7916                                         BindingRestriction.InstanceOnly) as MethodSpec;
7917
7918                                 if (ms == null || !ms.IsPublic) {
7919                                         Error_WrongEnumerator (rc, enumerator);
7920                                         return null;
7921                                 }
7922
7923                                 return MethodGroupExpr.CreatePredefined (ms, enumerator.ReturnType, expr.Location);
7924                         }
7925
7926                         PropertySpec ResolveCurrent (ResolveContext rc, MethodSpec enumerator)
7927                         {
7928                                 var ps = MemberCache.FindMember (enumerator.ReturnType,
7929                                         MemberFilter.Property ("Current", null),
7930                                         BindingRestriction.InstanceOnly) as PropertySpec;
7931
7932                                 if (ps == null || !ps.IsPublic) {
7933                                         Error_WrongEnumerator (rc, enumerator);
7934                                         return null;
7935                                 }
7936
7937                                 return ps;
7938                         }
7939
7940                         public override bool Resolve (BlockContext ec)
7941                         {
7942                                 bool is_dynamic = expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
7943
7944                                 if (is_dynamic) {
7945                                         expr = Convert.ImplicitConversionRequired (ec, expr, ec.BuiltinTypes.IEnumerable, loc);
7946                                 } else if (expr.Type.IsNullableType) {
7947                                         expr = new Nullable.UnwrapCall (expr).Resolve (ec);
7948                                 }
7949
7950                                 var get_enumerator_mg = ResolveGetEnumerator (ec);
7951                                 if (get_enumerator_mg == null) {
7952                                         return false;
7953                                 }
7954
7955                                 var get_enumerator = get_enumerator_mg.BestCandidate;
7956                                 enumerator_variable = TemporaryVariableReference.Create (get_enumerator.ReturnType, variable.Block, loc);
7957                                 enumerator_variable.Resolve (ec);
7958
7959                                 // Prepare bool MoveNext ()
7960                                 var move_next_mg = ResolveMoveNext (ec, get_enumerator);
7961                                 if (move_next_mg == null) {
7962                                         return false;
7963                                 }
7964
7965                                 move_next_mg.InstanceExpression = enumerator_variable;
7966
7967                                 // Prepare ~T~ Current { get; }
7968                                 var current_prop = ResolveCurrent (ec, get_enumerator);
7969                                 if (current_prop == null) {
7970                                         return false;
7971                                 }
7972
7973                                 var current_pe = new PropertyExpr (current_prop, loc) { InstanceExpression = enumerator_variable }.Resolve (ec);
7974                                 if (current_pe == null)
7975                                         return false;
7976
7977                                 VarExpr ve = for_each.type as VarExpr;
7978
7979                                 if (ve != null) {
7980                                         if (is_dynamic) {
7981                                                 // Source type is dynamic, set element type to dynamic too
7982                                                 variable.Type = ec.BuiltinTypes.Dynamic;
7983                                         } else {
7984                                                 // Infer implicitly typed local variable from foreach enumerable type
7985                                                 variable.Type = current_pe.Type;
7986                                         }
7987                                 } else {
7988                                         if (is_dynamic) {
7989                                                 // Explicit cast of dynamic collection elements has to be done at runtime
7990                                                 current_pe = EmptyCast.Create (current_pe, ec.BuiltinTypes.Dynamic);
7991                                         }
7992
7993                                         variable.Type = for_each.type.ResolveAsType (ec);
7994
7995                                         if (variable.Type == null)
7996                                                 return false;
7997
7998                                         current_pe = Convert.ExplicitConversion (ec, current_pe, variable.Type, loc);
7999                                         if (current_pe == null)
8000                                                 return false;
8001                                 }
8002
8003                                 var variable_ref = new LocalVariableReference (variable, loc).Resolve (ec);
8004                                 if (variable_ref == null)
8005                                         return false;
8006
8007                                 for_each.body.AddScopeStatement (new StatementExpression (new CompilerAssign (variable_ref, current_pe, Location.Null), for_each.type.Location));
8008
8009                                 var init = new Invocation.Predefined (get_enumerator_mg, null);
8010
8011                                 statement = new While (new BooleanExpression (new Invocation (move_next_mg, null)),
8012                                          for_each.body, Location.Null);
8013
8014                                 var enum_type = enumerator_variable.Type;
8015
8016                                 //
8017                                 // Add Dispose method call when enumerator can be IDisposable
8018                                 //
8019                                 if (!enum_type.ImplementsInterface (ec.BuiltinTypes.IDisposable, false)) {
8020                                         if (!enum_type.IsSealed && !TypeSpec.IsValueType (enum_type)) {
8021                                                 //
8022                                                 // Runtime Dispose check
8023                                                 //
8024                                                 var vd = new RuntimeDispose (enumerator_variable.LocalInfo, Location.Null);
8025                                                 vd.Initializer = init;
8026                                                 statement = new Using (vd, statement, Location.Null);
8027                                         } else {
8028                                                 //
8029                                                 // No Dispose call needed
8030                                                 //
8031                                                 this.init = new SimpleAssign (enumerator_variable, init, Location.Null);
8032                                                 this.init.Resolve (ec);
8033                                         }
8034                                 } else {
8035                                         //
8036                                         // Static Dispose check
8037                                         //
8038                                         var vd = new Using.VariableDeclaration (enumerator_variable.LocalInfo, Location.Null);
8039                                         vd.Initializer = init;
8040                                         statement = new Using (vd, statement, Location.Null);
8041                                 }
8042
8043                                 return statement.Resolve (ec);
8044                         }
8045
8046                         protected override void DoEmit (EmitContext ec)
8047                         {
8048                                 enumerator_variable.LocalInfo.CreateBuilder (ec);
8049
8050                                 if (init != null)
8051                                         init.EmitStatement (ec);
8052
8053                                 statement.Emit (ec);
8054                         }
8055
8056                         #region IErrorHandler Members
8057
8058                         bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext ec, MemberSpec best, MemberSpec ambiguous)
8059                         {
8060                                 ec.Report.SymbolRelatedToPreviousError (best);
8061                                 ec.Report.Warning (278, 2, expr.Location,
8062                                         "`{0}' contains ambiguous implementation of `{1}' pattern. Method `{2}' is ambiguous with method `{3}'",
8063                                         expr.Type.GetSignatureForError (), "enumerable",
8064                                         best.GetSignatureForError (), ambiguous.GetSignatureForError ());
8065
8066                                 ambiguous_getenumerator_name = true;
8067                                 return true;
8068                         }
8069
8070                         bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
8071                         {
8072                                 return false;
8073                         }
8074
8075                         bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
8076                         {
8077                                 return false;
8078                         }
8079
8080                         bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
8081                         {
8082                                 return false;
8083                         }
8084
8085                         #endregion
8086                 }
8087
8088                 Expression type;
8089                 LocalVariable variable;
8090                 Expression expr;
8091                 Block body;
8092
8093                 public Foreach (Expression type, LocalVariable var, Expression expr, Statement stmt, Block body, Location l)
8094                         : base (stmt)
8095                 {
8096                         this.type = type;
8097                         this.variable = var;
8098                         this.expr = expr;
8099                         this.body = body;
8100                         loc = l;
8101                 }
8102
8103                 public Expression Expr {
8104                         get { return expr; }
8105                 }
8106
8107                 public Expression TypeExpression {
8108                         get { return type; }
8109                 }
8110
8111                 public LocalVariable Variable {
8112                         get { return variable; }
8113                 }
8114
8115                 public override Reachability MarkReachable (Reachability rc)
8116                 {
8117                         base.MarkReachable (rc);
8118
8119                         body.MarkReachable (rc);
8120
8121                         return rc;
8122                 }
8123
8124                 public override bool Resolve (BlockContext ec)
8125                 {
8126                         expr = expr.Resolve (ec);
8127                         if (expr == null)
8128                                 return false;
8129
8130                         if (expr.IsNull) {
8131                                 ec.Report.Error (186, loc, "Use of null is not valid in this context");
8132                                 return false;
8133                         }
8134
8135                         body.AddStatement (Statement);
8136
8137                         if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.String) {
8138                                 Statement = new ArrayForeach (this, 1);
8139                         } else if (expr.Type is ArrayContainer) {
8140                                 Statement = new ArrayForeach (this, ((ArrayContainer) expr.Type).Rank);
8141                         } else {
8142                                 if (expr.eclass == ExprClass.MethodGroup || expr is AnonymousMethodExpression) {
8143                                         ec.Report.Error (446, expr.Location, "Foreach statement cannot operate on a `{0}'",
8144                                                 expr.ExprClassName);
8145                                         return false;
8146                                 }
8147
8148                                 Statement = new CollectionForeach (this, variable, expr);
8149                         }
8150
8151                         return base.Resolve (ec);
8152                 }
8153
8154                 protected override void DoEmit (EmitContext ec)
8155                 {
8156                         Label old_begin = ec.LoopBegin, old_end = ec.LoopEnd;
8157                         ec.LoopBegin = ec.DefineLabel ();
8158                         ec.LoopEnd = ec.DefineLabel ();
8159
8160                         if (!(Statement is Block))
8161                                 ec.BeginCompilerScope ();
8162
8163                         variable.CreateBuilder (ec);
8164
8165                         Statement.Emit (ec);
8166
8167                         if (!(Statement is Block))
8168                                 ec.EndScope ();
8169
8170                         ec.LoopBegin = old_begin;
8171                         ec.LoopEnd = old_end;
8172                 }
8173
8174                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
8175                 {
8176                         expr.FlowAnalysis (fc);
8177
8178                         var da = fc.BranchDefiniteAssignment ();
8179                         body.FlowAnalysis (fc);
8180                         fc.DefiniteAssignment = da;
8181                         return false;
8182                 }
8183
8184                 protected override void CloneTo (CloneContext clonectx, Statement t)
8185                 {
8186                         Foreach target = (Foreach) t;
8187
8188                         target.type = type.Clone (clonectx);
8189                         target.expr = expr.Clone (clonectx);
8190                         target.body = (Block) body.Clone (clonectx);
8191                         target.Statement = Statement.Clone (clonectx);
8192                 }
8193                 
8194                 public override object Accept (StructuralVisitor visitor)
8195                 {
8196                         return visitor.Visit (this);
8197                 }
8198         }
8199 }