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