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