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