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