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