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