Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.NRefactory/5.5.0/NRefactory.CSharp-5.5.0/Parser/mcs/statement.cs @ 13397

Last change on this file since 13397 was 11700, checked in by jkarder, 9 years ago

#2077: created branch and added first version

File size: 191.3 KB
Line 
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
14using System;
15using System.Collections.Generic;
16
17#if STATIC
18using IKVM.Reflection.Emit;
19#else
20using System.Reflection.Emit;
21#endif
22
23namespace 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 SectionStart { get; set; }
4475
4476    public Label GetILLabel (EmitContext ec)
4477    {
4478      if (il_label == null){
4479        il_label = ec.DefineLabel ();
4480      }
4481
4482      return il_label.Value;
4483    }
4484
4485    protected override void DoEmit (EmitContext ec)
4486    {
4487      ec.MarkLabel (GetILLabel (ec));
4488    }
4489
4490    protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
4491    {
4492      if (!SectionStart)
4493        return false;
4494
4495      fc.DefiniteAssignment = new DefiniteAssignmentBitSet (fc.SwitchInitialDefinitiveAssignment);
4496      return false;
4497    }
4498
4499    public override bool Resolve (BlockContext bc)
4500    {
4501      if (ResolveAndReduce (bc))
4502        bc.Switch.RegisterLabel (bc, this);
4503
4504      return true;
4505    }
4506
4507    //
4508    // Resolves the expression, reduces it to a literal if possible
4509    // and then converts it to the requested type.
4510    //
4511    bool ResolveAndReduce (BlockContext rc)
4512    {
4513      if (IsDefault)
4514        return true;
4515
4516      var c = label.ResolveLabelConstant (rc);
4517      if (c == null)
4518        return false;
4519
4520      if (rc.Switch.IsNullable && c is NullLiteral) {
4521        converted = c;
4522        return true;
4523      }
4524
4525      converted = c.ImplicitConversionRequired (rc, rc.Switch.SwitchType);
4526      return converted != null;
4527    }
4528
4529    public void Error_AlreadyOccurs (ResolveContext ec, SwitchLabel collision_with)
4530    {
4531      ec.Report.SymbolRelatedToPreviousError (collision_with.loc, null);
4532      ec.Report.Error (152, loc, "The label `{0}' already occurs in this switch statement", GetSignatureForError ());
4533    }
4534
4535    protected override void CloneTo (CloneContext clonectx, Statement target)
4536    {
4537      var t = (SwitchLabel) target;
4538      if (label != null)
4539        t.label = label.Clone (clonectx);
4540    }
4541
4542    public override object Accept (StructuralVisitor visitor)
4543    {
4544      return visitor.Visit (this);
4545    }
4546
4547    public string GetSignatureForError ()
4548    {
4549      string label;
4550      if (converted == null)
4551        label = "default";
4552      else
4553        label = converted.GetValueAsLiteral ();
4554
4555      return string.Format ("case {0}:", label);
4556    }
4557  }
4558
4559  public class Switch : LoopStatement
4560  {
4561    // structure used to hold blocks of keys while calculating table switch
4562    sealed class LabelsRange : IComparable<LabelsRange>
4563    {
4564      public readonly long min;
4565      public long max;
4566      public readonly List<long> label_values;
4567
4568      public LabelsRange (long value)
4569      {
4570        min = max = value;
4571        label_values = new List<long> ();
4572        label_values.Add (value);
4573      }
4574
4575      public LabelsRange (long min, long max, ICollection<long> values)
4576      {
4577        this.min = min;
4578        this.max = max;
4579        this.label_values = new List<long> (values);
4580      }
4581
4582      public long Range {
4583        get {
4584          return max - min + 1;
4585        }
4586      }
4587
4588      public bool AddValue (long value)
4589      {
4590        var gap = value - min + 1;
4591        // Ensure the range has > 50% occupancy
4592        if (gap > 2 * (label_values.Count + 1) || gap <= 0)
4593          return false;
4594
4595        max = value;
4596        label_values.Add (value);
4597        return true;
4598      }
4599
4600      public int CompareTo (LabelsRange other)
4601      {
4602        int nLength = label_values.Count;
4603        int nLengthOther = other.label_values.Count;
4604        if (nLengthOther == nLength)
4605          return (int) (other.min - min);
4606
4607        return nLength - nLengthOther;
4608      }
4609    }
4610
4611    sealed class DispatchStatement : Statement
4612    {
4613      readonly Switch body;
4614
4615      public DispatchStatement (Switch body)
4616      {
4617        this.body = body;
4618      }
4619
4620      protected override void CloneTo (CloneContext clonectx, Statement target)
4621      {
4622        throw new NotImplementedException ();
4623      }
4624
4625      protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
4626      {
4627        return false;
4628      }
4629
4630      protected override void DoEmit (EmitContext ec)
4631      {
4632        body.EmitDispatch (ec);
4633      }
4634    }
4635
4636    class MissingBreak : Statement
4637    {
4638      readonly SwitchLabel label;
4639
4640      public MissingBreak (SwitchLabel sl)
4641      {
4642        this.label = sl;
4643        this.loc = sl.loc;
4644      }
4645
4646      public bool FallOut { get; set; }
4647
4648      protected override void DoEmit (EmitContext ec)
4649      {
4650      }
4651
4652      protected override void CloneTo (CloneContext clonectx, Statement target)
4653      {
4654      }
4655
4656      protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
4657      {
4658        if (FallOut) {
4659          fc.Report.Error (8070, loc, "Control cannot fall out of switch statement through final case label `{0}'",
4660            label.GetSignatureForError ());
4661        } else {
4662          fc.Report.Error (163, loc, "Control cannot fall through from one case label `{0}' to another",
4663            label.GetSignatureForError ());
4664        }
4665        return true;
4666      }
4667    }
4668
4669    public Expression Expr;
4670
4671    //
4672    // Mapping of all labels to their SwitchLabels
4673    //
4674    Dictionary<long, SwitchLabel> labels;
4675    Dictionary<string, SwitchLabel> string_labels;
4676    List<SwitchLabel> case_labels;
4677
4678    List<Tuple<GotoCase, Constant>> goto_cases;
4679    List<DefiniteAssignmentBitSet> end_reachable_das;
4680
4681    /// <summary>
4682    ///   The governing switch type
4683    /// </summary>
4684    public TypeSpec SwitchType;
4685
4686    Expression new_expr;
4687
4688    SwitchLabel case_null;
4689    SwitchLabel case_default;
4690
4691    Label defaultLabel, nullLabel;
4692    VariableReference value;
4693    ExpressionStatement string_dictionary;
4694    FieldExpr switch_cache_field;
4695    ExplicitBlock block;
4696    bool end_reachable;
4697
4698    //
4699    // Nullable Types support
4700    //
4701    Nullable.Unwrap unwrap;
4702
4703    public Switch (Expression e, ExplicitBlock block, Location l)
4704      : base (block)
4705    {
4706      Expr = e;
4707      this.block = block;
4708      loc = l;
4709    }
4710
4711    public SwitchLabel ActiveLabel { get; set; }
4712
4713    public ExplicitBlock Block {
4714      get {
4715        return block;
4716      }
4717    }
4718
4719    public SwitchLabel DefaultLabel {
4720      get {
4721        return case_default;
4722      }
4723    }
4724
4725    public bool IsNullable {
4726      get {
4727        return unwrap != null;
4728      }
4729    }
4730
4731    public List<SwitchLabel> RegisteredLabels {
4732      get {
4733        return case_labels;
4734      }
4735    }
4736
4737    //
4738    // Determines the governing type for a switch.  The returned
4739    // expression might be the expression from the switch, or an
4740    // expression that includes any potential conversions to
4741    //
4742    static Expression SwitchGoverningType (ResolveContext rc, Expression expr, bool unwrapExpr)
4743    {
4744      switch (expr.Type.BuiltinType) {
4745      case BuiltinTypeSpec.Type.Byte:
4746      case BuiltinTypeSpec.Type.SByte:
4747      case BuiltinTypeSpec.Type.UShort:
4748      case BuiltinTypeSpec.Type.Short:
4749      case BuiltinTypeSpec.Type.UInt:
4750      case BuiltinTypeSpec.Type.Int:
4751      case BuiltinTypeSpec.Type.ULong:
4752      case BuiltinTypeSpec.Type.Long:
4753      case BuiltinTypeSpec.Type.Char:
4754      case BuiltinTypeSpec.Type.String:
4755      case BuiltinTypeSpec.Type.Bool:
4756        return expr;
4757      }
4758
4759      if (expr.Type.IsEnum)
4760        return expr;
4761
4762      //
4763      // Try to find a *user* defined implicit conversion.
4764      //
4765      // If there is no implicit conversion, or if there are multiple
4766      // conversions, we have to report an error
4767      //
4768      Expression converted = null;
4769      foreach (TypeSpec tt in rc.Module.PredefinedTypes.SwitchUserTypes) {
4770
4771        if (!unwrapExpr && tt.IsNullableType && expr.Type.IsNullableType)
4772          break;
4773
4774        var restr = Convert.UserConversionRestriction.ImplicitOnly |
4775          Convert.UserConversionRestriction.ProbingOnly;
4776
4777        if (unwrapExpr)
4778          restr |= Convert.UserConversionRestriction.NullableSourceOnly;
4779
4780        var e = Convert.UserDefinedConversion (rc, expr, tt, restr, Location.Null);
4781        if (e == null)
4782          continue;
4783
4784        //
4785        // Ignore over-worked ImplicitUserConversions that do
4786        // an implicit conversion in addition to the user conversion.
4787        //
4788        var uc = e as UserCast;
4789        if (uc == null)
4790          continue;
4791
4792        if (converted != null){
4793//          rc.Report.ExtraInformation (loc, "(Ambiguous implicit user defined conversion in previous ");
4794          return null;
4795        }
4796
4797        converted = e;
4798      }
4799      return converted;
4800    }
4801
4802    public static TypeSpec[] CreateSwitchUserTypes (ModuleContainer module, TypeSpec nullable)
4803    {
4804      var types = module.Compiler.BuiltinTypes;
4805
4806      // LAMESPEC: For some reason it does not contain bool which looks like csc bug
4807      TypeSpec[] stypes = new[] {
4808        types.SByte,
4809        types.Byte,
4810        types.Short,
4811        types.UShort,
4812        types.Int,
4813        types.UInt,
4814        types.Long,
4815        types.ULong,
4816        types.Char,
4817        types.String
4818      };
4819
4820      if (nullable != null) {
4821
4822        Array.Resize (ref stypes, stypes.Length + 9);
4823
4824        for (int i = 0; i < 9; ++i) {
4825          stypes [10 + i] = nullable.MakeGenericType (module, new [] { stypes [i] });
4826        }
4827      }
4828
4829      return stypes;
4830    }
4831
4832    public void RegisterLabel (BlockContext rc, SwitchLabel sl)
4833    {
4834      case_labels.Add (sl);
4835
4836      if (sl.IsDefault) {
4837        if (case_default != null) {
4838          sl.Error_AlreadyOccurs (rc, case_default);
4839        } else {
4840          case_default = sl;
4841        }
4842
4843        return;
4844      }
4845
4846      try {
4847        if (string_labels != null) {
4848          string string_value = sl.Converted.GetValue () as string;
4849          if (string_value == null)
4850            case_null = sl;
4851          else
4852            string_labels.Add (string_value, sl);
4853        } else {
4854          if (sl.Converted is NullLiteral) {
4855            case_null = sl;
4856          } else {
4857            labels.Add (sl.Converted.GetValueAsLong (), sl);
4858          }
4859        }
4860      } catch (ArgumentException) {
4861        if (string_labels != null)
4862          sl.Error_AlreadyOccurs (rc, string_labels[(string) sl.Converted.GetValue ()]);
4863        else
4864          sl.Error_AlreadyOccurs (rc, labels[sl.Converted.GetValueAsLong ()]);
4865      }
4866    }
4867   
4868    //
4869    // This method emits code for a lookup-based switch statement (non-string)
4870    // Basically it groups the cases into blocks that are at least half full,
4871    // and then spits out individual lookup opcodes for each block.
4872    // It emits the longest blocks first, and short blocks are just
4873    // handled with direct compares.
4874    //
4875    void EmitTableSwitch (EmitContext ec, Expression val)
4876    {
4877      if (labels != null && labels.Count > 0) {
4878        List<LabelsRange> ranges;
4879        if (string_labels != null) {
4880          // We have done all hard work for string already
4881          // setup single range only
4882          ranges = new List<LabelsRange> (1);
4883          ranges.Add (new LabelsRange (0, labels.Count - 1, labels.Keys));
4884        } else {
4885          var element_keys = new long[labels.Count];
4886          labels.Keys.CopyTo (element_keys, 0);
4887          Array.Sort (element_keys);
4888
4889          //
4890          // Build possible ranges of switch labes to reduce number
4891          // of comparisons
4892          //
4893          ranges = new List<LabelsRange> (element_keys.Length);
4894          var range = new LabelsRange (element_keys[0]);
4895          ranges.Add (range);
4896          for (int i = 1; i < element_keys.Length; ++i) {
4897            var l = element_keys[i];
4898            if (range.AddValue (l))
4899              continue;
4900
4901            range = new LabelsRange (l);
4902            ranges.Add (range);
4903          }
4904
4905          // sort the blocks so we can tackle the largest ones first
4906          ranges.Sort ();
4907        }
4908
4909        Label lbl_default = defaultLabel;
4910        TypeSpec compare_type = SwitchType.IsEnum ? EnumSpec.GetUnderlyingType (SwitchType) : SwitchType;
4911
4912        for (int range_index = ranges.Count - 1; range_index >= 0; --range_index) {
4913          LabelsRange kb = ranges[range_index];
4914          lbl_default = (range_index == 0) ? defaultLabel : ec.DefineLabel ();
4915
4916          // Optimize small ranges using simple equality check
4917          if (kb.Range <= 2) {
4918            foreach (var key in kb.label_values) {
4919              SwitchLabel sl = labels[key];
4920              if (sl == case_default || sl == case_null)
4921                continue;
4922
4923              if (sl.Converted.IsZeroInteger) {
4924                val.EmitBranchable (ec, sl.GetILLabel (ec), false);
4925              } else {
4926                val.Emit (ec);
4927                sl.Converted.Emit (ec);
4928                ec.Emit (OpCodes.Beq, sl.GetILLabel (ec));
4929              }
4930            }
4931          } else {
4932            // TODO: if all the keys in the block are the same and there are
4933            //       no gaps/defaults then just use a range-check.
4934            if (compare_type.BuiltinType == BuiltinTypeSpec.Type.Long || compare_type.BuiltinType == BuiltinTypeSpec.Type.ULong) {
4935              // TODO: optimize constant/I4 cases
4936
4937              // check block range (could be > 2^31)
4938              val.Emit (ec);
4939              ec.EmitLong (kb.min);
4940              ec.Emit (OpCodes.Blt, lbl_default);
4941
4942              val.Emit (ec);
4943              ec.EmitLong (kb.max);
4944              ec.Emit (OpCodes.Bgt, lbl_default);
4945
4946              // normalize range
4947              val.Emit (ec);
4948              if (kb.min != 0) {
4949                ec.EmitLong (kb.min);
4950                ec.Emit (OpCodes.Sub);
4951              }
4952
4953              ec.Emit (OpCodes.Conv_I4);  // assumes < 2^31 labels!
4954            } else {
4955              // normalize range
4956              val.Emit (ec);
4957              int first = (int) kb.min;
4958              if (first > 0) {
4959                ec.EmitInt (first);
4960                ec.Emit (OpCodes.Sub);
4961              } else if (first < 0) {
4962                ec.EmitInt (-first);
4963                ec.Emit (OpCodes.Add);
4964              }
4965            }
4966
4967            // first, build the list of labels for the switch
4968            int iKey = 0;
4969            long cJumps = kb.Range;
4970            Label[] switch_labels = new Label[cJumps];
4971            for (int iJump = 0; iJump < cJumps; iJump++) {
4972              var key = kb.label_values[iKey];
4973              if (key == kb.min + iJump) {
4974                switch_labels[iJump] = labels[key].GetILLabel (ec);
4975                iKey++;
4976              } else {
4977                switch_labels[iJump] = lbl_default;
4978              }
4979            }
4980
4981            // emit the switch opcode
4982            ec.Emit (OpCodes.Switch, switch_labels);
4983          }
4984
4985          // mark the default for this block
4986          if (range_index != 0)
4987            ec.MarkLabel (lbl_default);
4988        }
4989
4990        // the last default just goes to the end
4991        if (ranges.Count > 0)
4992          ec.Emit (OpCodes.Br, lbl_default);
4993      }
4994    }
4995   
4996    public SwitchLabel FindLabel (Constant value)
4997    {
4998      SwitchLabel sl = null;
4999
5000      if (string_labels != null) {
5001        string s = value.GetValue () as string;
5002        if (s == null) {
5003          if (case_null != null)
5004            sl = case_null;
5005          else if (case_default != null)
5006            sl = case_default;
5007        } else {
5008          string_labels.TryGetValue (s, out sl);
5009        }
5010      } else {
5011        if (value is NullLiteral) {
5012          sl = case_null;
5013        } else {
5014          labels.TryGetValue (value.GetValueAsLong (), out sl);
5015        }
5016      }
5017
5018      return sl;
5019    }
5020
5021    protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
5022    {
5023      Expr.FlowAnalysis (fc);
5024
5025      var prev_switch = fc.SwitchInitialDefinitiveAssignment;
5026      var InitialDefinitiveAssignment = fc.DefiniteAssignment;
5027      fc.SwitchInitialDefinitiveAssignment = InitialDefinitiveAssignment;
5028
5029      block.FlowAnalysis (fc);
5030
5031      fc.SwitchInitialDefinitiveAssignment = prev_switch;
5032
5033      if (end_reachable_das != null) {
5034        var sections_das = DefiniteAssignmentBitSet.And (end_reachable_das);
5035        InitialDefinitiveAssignment |= sections_das;
5036        end_reachable_das = null;
5037      }
5038
5039      fc.DefiniteAssignment = InitialDefinitiveAssignment;
5040
5041      return case_default != null && !end_reachable;
5042    }
5043
5044    public override bool Resolve (BlockContext ec)
5045    {
5046      Expr = Expr.Resolve (ec);
5047      if (Expr == null)
5048        return false;
5049
5050      //
5051      // LAMESPEC: User conversion from non-nullable governing type has a priority
5052      //
5053      new_expr = SwitchGoverningType (ec, Expr, false);
5054
5055      if (new_expr == null) {
5056        if (Expr.Type.IsNullableType) {
5057          unwrap = Nullable.Unwrap.Create (Expr, false);
5058          if (unwrap == null)
5059            return false;
5060
5061          //
5062          // Unwrap + user conversion using non-nullable type is not allowed but user operator
5063          // involving nullable Expr and nullable governing type is
5064          //
5065          new_expr = SwitchGoverningType (ec, unwrap, true);
5066        }
5067      }
5068
5069      if (new_expr == null) {
5070        if (Expr.Type != InternalType.ErrorType) {
5071          ec.Report.Error (151, loc,
5072            "A switch expression of type `{0}' cannot be converted to an integral type, bool, char, string, enum or nullable type",
5073            Expr.Type.GetSignatureForError ());
5074        }
5075
5076        return false;
5077      }
5078
5079      SwitchType = new_expr.Type;
5080      if (SwitchType.IsNullableType) {
5081        new_expr = unwrap = Nullable.Unwrap.Create (new_expr, true);
5082        SwitchType = Nullable.NullableInfo.GetUnderlyingType (SwitchType);
5083      }
5084
5085      if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.Bool && ec.Module.Compiler.Settings.Version == LanguageVersion.ISO_1) {
5086        ec.Report.FeatureIsNotAvailable (ec.Module.Compiler, loc, "switch expression of boolean type");
5087        return false;
5088      }
5089
5090      if (block.Statements.Count == 0)
5091        return true;
5092
5093      if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String) {
5094        string_labels = new Dictionary<string, SwitchLabel> ();
5095      } else {
5096        labels = new Dictionary<long, SwitchLabel> ();
5097      }
5098
5099      case_labels = new List<SwitchLabel> ();
5100
5101      var constant = new_expr as Constant;
5102
5103      //
5104      // Don't need extra variable for constant switch or switch with
5105      // only default case
5106      //
5107      if (constant == null) {
5108        //
5109        // Store switch expression for comparison purposes
5110        //
5111        value = new_expr as VariableReference;
5112        if (value == null && !HasOnlyDefaultSection ()) {
5113          var current_block = ec.CurrentBlock;
5114          ec.CurrentBlock = Block;
5115          // Create temporary variable inside switch scope
5116          value = TemporaryVariableReference.Create (SwitchType, ec.CurrentBlock, loc);
5117          value.Resolve (ec);
5118          ec.CurrentBlock = current_block;
5119        }
5120      }
5121
5122      Switch old_switch = ec.Switch;
5123      ec.Switch = this;
5124      var parent_los = ec.EnclosingLoopOrSwitch;
5125      ec.EnclosingLoopOrSwitch = this;
5126
5127      var ok = Statement.Resolve (ec);
5128
5129      ec.EnclosingLoopOrSwitch = parent_los;
5130      ec.Switch = old_switch;
5131
5132      //
5133      // Check if all goto cases are valid. Needs to be done after switch
5134      // is resolved because goto can jump forward in the scope.
5135      //
5136      if (goto_cases != null) {
5137        foreach (var gc in goto_cases) {
5138          if (gc.Item1 == null) {
5139            if (DefaultLabel == null) {
5140              Goto.Error_UnknownLabel (ec, "default", loc);
5141            }
5142
5143            continue;
5144          }
5145
5146          var sl = FindLabel (gc.Item2);
5147          if (sl == null) {
5148            Goto.Error_UnknownLabel (ec, "case " + gc.Item2.GetValueAsLiteral (), loc);
5149          } else {
5150            gc.Item1.Label = sl;
5151          }
5152        }
5153      }
5154
5155      if (!ok)
5156        return false;
5157
5158      if (constant == null && SwitchType.BuiltinType == BuiltinTypeSpec.Type.String && string_labels.Count > 6) {
5159        ResolveStringSwitchMap (ec);
5160      }
5161
5162      //
5163      // Anonymous storey initialization has to happen before
5164      // any generated switch dispatch
5165      //
5166      block.InsertStatement (0, new DispatchStatement (this));
5167
5168      return true;
5169    }
5170
5171    bool HasOnlyDefaultSection ()
5172    {
5173      for (int i = 0; i < block.Statements.Count; ++i) {
5174        var s = block.Statements[i] as SwitchLabel;
5175
5176        if (s == null || s.IsDefault)
5177          continue;
5178
5179        return false;
5180      }
5181
5182      return true;
5183    }
5184
5185    public override Reachability MarkReachable (Reachability rc)
5186    {
5187      if (rc.IsUnreachable)
5188        return rc;
5189
5190      base.MarkReachable (rc);
5191
5192      block.MarkReachableScope (rc);
5193
5194      if (block.Statements.Count == 0)
5195        return rc;
5196
5197      SwitchLabel constant_label = null;
5198      var constant = new_expr as Constant;
5199
5200      if (constant != null) {
5201        constant_label = FindLabel (constant) ?? case_default;
5202        if (constant_label == null) {
5203          block.Statements.RemoveAt (0);
5204          return rc;
5205        }
5206      }
5207
5208      var section_rc = new Reachability ();
5209      SwitchLabel prev_label = null;
5210
5211      for (int i = 0; i < block.Statements.Count; ++i) {
5212        var s = block.Statements[i];
5213        var sl = s as SwitchLabel;
5214
5215        if (sl != null && sl.SectionStart) {
5216          //
5217          // Section is marked already via goto case
5218          //
5219          if (!sl.IsUnreachable) {
5220            section_rc = new Reachability ();
5221            continue;
5222          }
5223
5224          if (constant_label != null && constant_label != sl)
5225            section_rc = Reachability.CreateUnreachable ();
5226          else if (section_rc.IsUnreachable) {
5227            section_rc = new Reachability ();
5228          } else {
5229            if (prev_label != null) {
5230              sl.SectionStart = false;
5231              s = new MissingBreak (prev_label);
5232              s.MarkReachable (rc);
5233              block.Statements.Insert (i - 1, s);
5234              ++i;
5235            }
5236          }
5237
5238          prev_label = sl;
5239        }
5240
5241        section_rc = s.MarkReachable (section_rc);
5242      }
5243
5244      if (!section_rc.IsUnreachable && prev_label != null) {
5245        prev_label.SectionStart = false;
5246        var s = new MissingBreak (prev_label) {
5247          FallOut = true
5248        };
5249
5250        s.MarkReachable (rc);
5251        block.Statements.Add (s);
5252      }
5253
5254      //
5255      // Reachability can affect parent only when all possible paths are handled but
5256      // we still need to run reachability check on switch body to check for fall-through
5257      //
5258      if (case_default == null && constant_label == null)
5259        return rc;
5260
5261      //
5262      // We have at least one local exit from the switch
5263      //
5264      if (end_reachable)
5265        return rc;
5266
5267      return Reachability.CreateUnreachable ();
5268    }
5269
5270    public void RegisterGotoCase (GotoCase gotoCase, Constant value)
5271    {
5272      if (goto_cases == null)
5273        goto_cases = new List<Tuple<GotoCase, Constant>> ();
5274
5275      goto_cases.Add (Tuple.Create (gotoCase, value));
5276    }
5277
5278    //
5279    // Converts string switch into string hashtable
5280    //
5281    void ResolveStringSwitchMap (ResolveContext ec)
5282    {
5283      FullNamedExpression string_dictionary_type;
5284      if (ec.Module.PredefinedTypes.Dictionary.Define ()) {
5285        string_dictionary_type = new TypeExpression (
5286          ec.Module.PredefinedTypes.Dictionary.TypeSpec.MakeGenericType (ec,
5287            new [] { ec.BuiltinTypes.String, ec.BuiltinTypes.Int }),
5288          loc);
5289      } else if (ec.Module.PredefinedTypes.Hashtable.Define ()) {
5290        string_dictionary_type = new TypeExpression (ec.Module.PredefinedTypes.Hashtable.TypeSpec, loc);
5291      } else {
5292        ec.Module.PredefinedTypes.Dictionary.Resolve ();
5293        return;
5294      }
5295
5296      var ctype = ec.CurrentMemberDefinition.Parent.PartialContainer;
5297      Field field = new Field (ctype, string_dictionary_type,
5298        Modifiers.STATIC | Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED,
5299        new MemberName (CompilerGeneratedContainer.MakeName (null, "f", "switch$map", ec.Module.CounterSwitchTypes++), loc), null);
5300      if (!field.Define ())
5301        return;
5302      ctype.AddField (field);
5303
5304      var init = new List<Expression> ();
5305      int counter = -1;
5306      labels = new Dictionary<long, SwitchLabel> (string_labels.Count);
5307      string value = null;
5308
5309      foreach (SwitchLabel sl in case_labels) {
5310
5311        if (sl.SectionStart)
5312          labels.Add (++counter, sl);
5313
5314        if (sl == case_default || sl == case_null)
5315          continue;
5316
5317        value = (string) sl.Converted.GetValue ();
5318        var init_args = new List<Expression> (2);
5319        init_args.Add (new StringLiteral (ec.BuiltinTypes, value, sl.Location));
5320
5321        sl.Converted = new IntConstant (ec.BuiltinTypes, counter, loc);
5322        init_args.Add (sl.Converted);
5323
5324        init.Add (new CollectionElementInitializer (init_args, loc));
5325      }
5326 
5327      Arguments args = new Arguments (1);
5328      args.Add (new Argument (new IntConstant (ec.BuiltinTypes, init.Count, loc)));
5329      Expression initializer = new NewInitialize (string_dictionary_type, args,
5330        new CollectionOrObjectInitializers (init, loc), loc);
5331
5332      switch_cache_field = new FieldExpr (field, loc);
5333      string_dictionary = new SimpleAssign (switch_cache_field, initializer.Resolve (ec));
5334    }
5335
5336    void DoEmitStringSwitch (EmitContext ec)
5337    {
5338      Label l_initialized = ec.DefineLabel ();
5339
5340      //
5341      // Skip initialization when value is null
5342      //
5343      value.EmitBranchable (ec, nullLabel, false);
5344
5345      //
5346      // Check if string dictionary is initialized and initialize
5347      //
5348      switch_cache_field.EmitBranchable (ec, l_initialized, true);
5349      using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
5350        string_dictionary.EmitStatement (ec);
5351      }
5352      ec.MarkLabel (l_initialized);
5353
5354      LocalTemporary string_switch_variable = new LocalTemporary (ec.BuiltinTypes.Int);
5355
5356      ResolveContext rc = new ResolveContext (ec.MemberContext);
5357
5358      if (switch_cache_field.Type.IsGeneric) {
5359        Arguments get_value_args = new Arguments (2);
5360        get_value_args.Add (new Argument (value));
5361        get_value_args.Add (new Argument (string_switch_variable, Argument.AType.Out));
5362        Expression get_item = new Invocation (new MemberAccess (switch_cache_field, "TryGetValue", loc), get_value_args).Resolve (rc);
5363        if (get_item == null)
5364          return;
5365
5366        //
5367        // A value was not found, go to default case
5368        //
5369        get_item.EmitBranchable (ec, defaultLabel, false);
5370      } else {
5371        Arguments get_value_args = new Arguments (1);
5372        get_value_args.Add (new Argument (value));
5373
5374        Expression get_item = new ElementAccess (switch_cache_field, get_value_args, loc).Resolve (rc);
5375        if (get_item == null)
5376          return;
5377
5378        LocalTemporary get_item_object = new LocalTemporary (ec.BuiltinTypes.Object);
5379        get_item_object.EmitAssign (ec, get_item, true, false);
5380        ec.Emit (OpCodes.Brfalse, defaultLabel);
5381
5382        ExpressionStatement get_item_int = (ExpressionStatement) new SimpleAssign (string_switch_variable,
5383          new Cast (new TypeExpression (ec.BuiltinTypes.Int, loc), get_item_object, loc)).Resolve (rc);
5384
5385        get_item_int.EmitStatement (ec);
5386        get_item_object.Release (ec);
5387      }
5388
5389      EmitTableSwitch (ec, string_switch_variable);
5390      string_switch_variable.Release (ec);
5391    }
5392
5393    //
5394    // Emits switch using simple if/else comparison for small label count (4 + optional default)
5395    //
5396    void EmitShortSwitch (EmitContext ec)
5397    {
5398      MethodSpec equal_method = null;
5399      if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String) {
5400        equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (loc);
5401      }
5402
5403      if (equal_method != null) {
5404        value.EmitBranchable (ec, nullLabel, false);
5405      }
5406
5407      for (int i = 0; i < case_labels.Count; ++i) {
5408        var label = case_labels [i];
5409        if (label == case_default || label == case_null)
5410          continue;
5411
5412        var constant = label.Converted;
5413
5414        if (equal_method != null) {
5415          value.Emit (ec);
5416          constant.Emit (ec);
5417
5418          var call = new CallEmitter ();
5419          call.EmitPredefined (ec, equal_method, new Arguments (0));
5420          ec.Emit (OpCodes.Brtrue, label.GetILLabel (ec));
5421          continue;
5422        }
5423
5424        if (constant.IsZeroInteger && constant.Type.BuiltinType != BuiltinTypeSpec.Type.Long && constant.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
5425          value.EmitBranchable (ec, label.GetILLabel (ec), false);
5426          continue;
5427        }
5428
5429        value.Emit (ec);
5430        constant.Emit (ec);
5431        ec.Emit (OpCodes.Beq, label.GetILLabel (ec));
5432      }
5433
5434      ec.Emit (OpCodes.Br, defaultLabel);
5435    }
5436
5437    void EmitDispatch (EmitContext ec)
5438    {
5439      if (value == null) {
5440        //
5441        // Constant switch, we've already done the work if there is only 1 label
5442        // referenced
5443        //
5444        int reachable = 0;
5445        foreach (var sl in case_labels) {
5446          if (sl.IsUnreachable)
5447            continue;
5448
5449          if (reachable++ > 0) {
5450            var constant = (Constant) new_expr;
5451            var constant_label = FindLabel (constant) ?? case_default;
5452
5453            ec.Emit (OpCodes.Br, constant_label.GetILLabel (ec));
5454            break;
5455          }
5456        }
5457
5458        return;
5459      }
5460
5461      if (string_dictionary != null) {
5462        DoEmitStringSwitch (ec);
5463      } else if (case_labels.Count < 4 || string_labels != null) {
5464        EmitShortSwitch (ec);
5465      } else {
5466        EmitTableSwitch (ec, value);
5467      }
5468    }
5469
5470    protected override void DoEmit (EmitContext ec)
5471    {
5472      //
5473      // Setup the codegen context
5474      //
5475      Label old_end = ec.LoopEnd;
5476      Switch old_switch = ec.Switch;
5477
5478      ec.LoopEnd = ec.DefineLabel ();
5479      ec.Switch = this;
5480
5481      defaultLabel = case_default == null ? ec.LoopEnd : case_default.GetILLabel (ec);
5482      nullLabel = case_null == null ? defaultLabel : case_null.GetILLabel (ec);
5483
5484      if (value != null) {
5485        ec.Mark (loc);
5486        if (IsNullable) {
5487          unwrap.EmitCheck (ec);
5488          ec.Emit (OpCodes.Brfalse, nullLabel);
5489          value.EmitAssign (ec, new_expr, false, false);
5490        } else if (new_expr != value) {
5491          value.EmitAssign (ec, new_expr, false, false);
5492        }
5493
5494
5495        //
5496        // Next statement is compiler generated we don't need extra
5497        // nop when we can use the statement for sequence point
5498        //
5499        ec.Mark (block.StartLocation);
5500        block.IsCompilerGenerated = true;
5501      } else {
5502        new_expr.EmitSideEffect (ec);
5503      }
5504
5505      block.Emit (ec);
5506
5507      // Restore context state.
5508      ec.MarkLabel (ec.LoopEnd);
5509
5510      //
5511      // Restore the previous context
5512      //
5513      ec.LoopEnd = old_end;
5514      ec.Switch = old_switch;
5515    }
5516
5517    protected override void CloneTo (CloneContext clonectx, Statement t)
5518    {
5519      Switch target = (Switch) t;
5520
5521      target.Expr = Expr.Clone (clonectx);
5522      target.Statement = target.block = (ExplicitBlock) block.Clone (clonectx);
5523    }
5524   
5525    public override object Accept (StructuralVisitor visitor)
5526    {
5527      return visitor.Visit (this);
5528    }
5529
5530    public override void AddEndDefiniteAssignment (FlowAnalysisContext fc)
5531    {
5532      if (case_default == null && !(new_expr is Constant))
5533        return;
5534
5535      if (end_reachable_das == null)
5536        end_reachable_das = new List<DefiniteAssignmentBitSet> ();
5537
5538      end_reachable_das.Add (fc.DefiniteAssignment);
5539    }
5540
5541    public override void SetEndReachable ()
5542    {
5543      end_reachable = true;
5544    }
5545  }
5546
5547  // A place where execution can restart in a state machine
5548  public abstract class ResumableStatement : Statement
5549  {
5550    bool prepared;
5551    protected Label resume_point;
5552
5553    public Label PrepareForEmit (EmitContext ec)
5554    {
5555      if (!prepared) {
5556        prepared = true;
5557        resume_point = ec.DefineLabel ();
5558      }
5559      return resume_point;
5560    }
5561
5562    public virtual Label PrepareForDispose (EmitContext ec, Label end)
5563    {
5564      return end;
5565    }
5566
5567    public virtual void EmitForDispose (EmitContext ec, LocalBuilder pc, Label end, bool have_dispatcher)
5568    {
5569    }
5570  }
5571
5572  public abstract class TryFinallyBlock : ExceptionStatement
5573  {
5574    protected Statement stmt;
5575    Label dispose_try_block;
5576    bool prepared_for_dispose, emitted_dispose;
5577    Method finally_host;
5578
5579    protected TryFinallyBlock (Statement stmt, Location loc)
5580      : base (loc)
5581    {
5582      this.stmt = stmt;
5583    }
5584
5585    #region Properties
5586
5587    public Statement Statement {
5588      get {
5589        return stmt;
5590      }
5591    }
5592
5593    #endregion
5594
5595    protected abstract void EmitTryBody (EmitContext ec);
5596    public abstract void EmitFinallyBody (EmitContext ec);
5597
5598    public override Label PrepareForDispose (EmitContext ec, Label end)
5599    {
5600      if (!prepared_for_dispose) {
5601        prepared_for_dispose = true;
5602        dispose_try_block = ec.DefineLabel ();
5603      }
5604      return dispose_try_block;
5605    }
5606
5607    protected sealed override void DoEmit (EmitContext ec)
5608    {
5609      EmitTryBodyPrepare (ec);
5610      EmitTryBody (ec);
5611
5612      bool beginFinally = EmitBeginFinallyBlock (ec);
5613
5614      Label start_finally = ec.DefineLabel ();
5615      if (resume_points != null && beginFinally) {
5616        var state_machine = (StateMachineInitializer) ec.CurrentAnonymousMethod;
5617
5618        ec.Emit (OpCodes.Ldloc, state_machine.SkipFinally);
5619        ec.Emit (OpCodes.Brfalse_S, start_finally);
5620        ec.Emit (OpCodes.Endfinally);
5621      }
5622
5623      ec.MarkLabel (start_finally);
5624
5625      if (finally_host != null) {
5626        finally_host.Define ();
5627        finally_host.PrepareEmit ();
5628        finally_host.Emit ();
5629
5630        // Now it's safe to add, to close it properly and emit sequence points
5631        finally_host.Parent.AddMember (finally_host);
5632
5633        var ce = new CallEmitter ();
5634        ce.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, loc);
5635        ce.EmitPredefined (ec, finally_host.Spec, new Arguments (0), true);
5636      } else {
5637        EmitFinallyBody (ec);
5638      }
5639
5640      if (beginFinally)
5641        ec.EndExceptionBlock ();
5642    }
5643
5644    public override void EmitForDispose (EmitContext ec, LocalBuilder pc, Label end, bool have_dispatcher)
5645    {
5646      if (emitted_dispose)
5647        return;
5648
5649      emitted_dispose = true;
5650
5651      Label end_of_try = ec.DefineLabel ();
5652
5653      // Ensure that the only way we can get into this code is through a dispatcher
5654      if (have_dispatcher)
5655        ec.Emit (OpCodes.Br, end);
5656
5657      ec.BeginExceptionBlock ();
5658
5659      ec.MarkLabel (dispose_try_block);
5660
5661      Label[] labels = null;
5662      for (int i = 0; i < resume_points.Count; ++i) {
5663        ResumableStatement s = resume_points[i];
5664        Label ret = s.PrepareForDispose (ec, end_of_try);
5665        if (ret.Equals (end_of_try) && labels == null)
5666          continue;
5667        if (labels == null) {
5668          labels = new Label[resume_points.Count];
5669          for (int j = 0; j < i; ++j)
5670            labels[j] = end_of_try;
5671        }
5672        labels[i] = ret;
5673      }
5674
5675      if (labels != null) {
5676        int j;
5677        for (j = 1; j < labels.Length; ++j)
5678          if (!labels[0].Equals (labels[j]))
5679            break;
5680        bool emit_dispatcher = j < labels.Length;
5681
5682        if (emit_dispatcher) {
5683          ec.Emit (OpCodes.Ldloc, pc);
5684          ec.EmitInt (first_resume_pc);
5685          ec.Emit (OpCodes.Sub);
5686          ec.Emit (OpCodes.Switch, labels);
5687        }
5688
5689        foreach (ResumableStatement s in resume_points)
5690          s.EmitForDispose (ec, pc, end_of_try, emit_dispatcher);
5691      }
5692
5693      ec.MarkLabel (end_of_try);
5694
5695      ec.BeginFinallyBlock ();
5696
5697      if (finally_host != null) {
5698        var ce = new CallEmitter ();
5699        ce.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, loc);
5700        ce.EmitPredefined (ec, finally_host.Spec, new Arguments (0), true);
5701      } else {
5702        EmitFinallyBody (ec);
5703      }
5704
5705      ec.EndExceptionBlock ();
5706    }
5707
5708    protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
5709    {
5710      var res = stmt.FlowAnalysis (fc);
5711      parent = null;
5712      return res;
5713    }
5714
5715    protected virtual bool EmitBeginFinallyBlock (EmitContext ec)
5716    {
5717      ec.BeginFinallyBlock ();
5718      return true;
5719    }
5720
5721    public override Reachability MarkReachable (Reachability rc)
5722    {
5723      base.MarkReachable (rc);
5724      return Statement.MarkReachable (rc);
5725    }
5726
5727    public override bool Resolve (BlockContext bc)
5728    {
5729      bool ok;
5730
5731      parent = bc.CurrentTryBlock;
5732      bc.CurrentTryBlock = this;
5733
5734      using (bc.Set (ResolveContext.Options.TryScope)) {
5735        ok = stmt.Resolve (bc);
5736      }
5737
5738      bc.CurrentTryBlock = parent;
5739
5740      //
5741      // Finally block inside iterator is called from MoveNext and
5742      // Dispose methods that means we need to lift the block into
5743      // newly created host method to emit the body only once. The
5744      // original block then simply calls the newly generated method.
5745      //
5746      if (bc.CurrentIterator != null && !bc.IsInProbingMode) {
5747        var b = stmt as Block;
5748        if (b != null && b.Explicit.HasYield) {
5749          finally_host = bc.CurrentIterator.CreateFinallyHost (this);
5750        }
5751      }
5752
5753      return base.Resolve (bc) && ok;
5754    }
5755  }
5756
5757  //
5758  // Base class for blocks using exception handling
5759  //
5760  public abstract class ExceptionStatement : ResumableStatement
5761  {
5762    protected List<ResumableStatement> resume_points;
5763    protected int first_resume_pc;
5764    protected ExceptionStatement parent;
5765
5766    protected ExceptionStatement (Location loc)
5767    {
5768      this.loc = loc;
5769    }
5770
5771    protected virtual void EmitTryBodyPrepare (EmitContext ec)
5772    {
5773      StateMachineInitializer state_machine = null;
5774      if (resume_points != null) {
5775        state_machine = (StateMachineInitializer) ec.CurrentAnonymousMethod;
5776
5777        ec.EmitInt ((int) IteratorStorey.State.Running);
5778        ec.Emit (OpCodes.Stloc, state_machine.CurrentPC);
5779      }
5780
5781      ec.BeginExceptionBlock ();
5782
5783      if (resume_points != null) {
5784        ec.MarkLabel (resume_point);
5785
5786        // For normal control flow, we want to fall-through the Switch
5787        // So, we use CurrentPC rather than the $PC field, and initialize it to an outside value above
5788        ec.Emit (OpCodes.Ldloc, state_machine.CurrentPC);
5789        ec.EmitInt (first_resume_pc);
5790        ec.Emit (OpCodes.Sub);
5791
5792        Label[] labels = new Label[resume_points.Count];
5793        for (int i = 0; i < resume_points.Count; ++i)
5794          labels[i] = resume_points[i].PrepareForEmit (ec);
5795        ec.Emit (OpCodes.Switch, labels);
5796      }
5797    }
5798
5799    public virtual int AddResumePoint (ResumableStatement stmt, int pc, StateMachineInitializer stateMachine)
5800    {
5801      if (parent != null) {
5802        // TODO: MOVE to virtual TryCatch
5803        var tc = this as TryCatch;
5804        var s = tc != null && tc.IsTryCatchFinally ? stmt : this;
5805
5806        pc = parent.AddResumePoint (s, pc, stateMachine);
5807      } else {
5808        pc = stateMachine.AddResumePoint (this);
5809      }
5810
5811      if (resume_points == null) {
5812        resume_points = new List<ResumableStatement> ();
5813        first_resume_pc = pc;
5814      }
5815
5816      if (pc != first_resume_pc + resume_points.Count)
5817        throw new InternalErrorException ("missed an intervening AddResumePoint?");
5818
5819      resume_points.Add (stmt);
5820      return pc;
5821    }
5822  }
5823
5824  public class Lock : TryFinallyBlock
5825  {
5826    Expression expr;
5827    TemporaryVariableReference expr_copy;
5828    TemporaryVariableReference lock_taken;
5829     
5830    public Lock (Expression expr, Statement stmt, Location loc)
5831      : base (stmt, loc)
5832    {
5833      this.expr = expr;
5834    }
5835
5836    public Expression Expr {
5837      get {
5838        return this.expr;
5839      }
5840    }
5841
5842    protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
5843    {
5844      expr.FlowAnalysis (fc);
5845      return base.DoFlowAnalysis (fc);
5846    }
5847
5848    public override bool Resolve (BlockContext ec)
5849    {
5850      expr = expr.Resolve (ec);
5851      if (expr == null)
5852        return false;
5853
5854      if (!TypeSpec.IsReferenceType (expr.Type)) {
5855        ec.Report.Error (185, loc,
5856          "`{0}' is not a reference type as required by the lock statement",
5857          expr.Type.GetSignatureForError ());
5858      }
5859
5860      if (expr.Type.IsGenericParameter) {
5861        expr = Convert.ImplicitTypeParameterConversion (expr, (TypeParameterSpec)expr.Type, ec.BuiltinTypes.Object);
5862      }
5863
5864      VariableReference lv = expr as VariableReference;
5865      bool locked;
5866      if (lv != null) {
5867        locked = lv.IsLockedByStatement;
5868        lv.IsLockedByStatement = true;
5869      } else {
5870        lv = null;
5871        locked = false;
5872      }
5873
5874      //
5875      // Have to keep original lock value around to unlock same location
5876      // in the case of original value has changed or is null
5877      //
5878      expr_copy = TemporaryVariableReference.Create (ec.BuiltinTypes.Object, ec.CurrentBlock, loc);
5879      expr_copy.Resolve (ec);
5880
5881      //
5882      // Ensure Monitor methods are available
5883      //
5884      if (ResolvePredefinedMethods (ec) > 1) {
5885        lock_taken = TemporaryVariableReference.Create (ec.BuiltinTypes.Bool, ec.CurrentBlock, loc);
5886        lock_taken.Resolve (ec);
5887      }
5888
5889      using (ec.Set (ResolveContext.Options.LockScope)) {
5890        base.Resolve (ec);
5891      }
5892
5893      if (lv != null) {
5894        lv.IsLockedByStatement = locked;
5895      }
5896
5897      return true;
5898    }
5899   
5900    protected override void EmitTryBodyPrepare (EmitContext ec)
5901    {
5902      expr_copy.EmitAssign (ec, expr);
5903
5904      if (lock_taken != null) {
5905        //
5906        // Initialize ref variable
5907        //
5908        lock_taken.EmitAssign (ec, new BoolLiteral (ec.BuiltinTypes, false, loc));
5909      } else {
5910        //
5911        // Monitor.Enter (expr_copy)
5912        //
5913        expr_copy.Emit (ec);
5914        ec.Emit (OpCodes.Call, ec.Module.PredefinedMembers.MonitorEnter.Get ());
5915      }
5916
5917      base.EmitTryBodyPrepare (ec);
5918    }
5919
5920    protected override void EmitTryBody (EmitContext ec)
5921    {
5922      //
5923      // Monitor.Enter (expr_copy, ref lock_taken)
5924      //
5925      if (lock_taken != null) {
5926        expr_copy.Emit (ec);
5927        lock_taken.LocalInfo.CreateBuilder (ec);
5928        lock_taken.AddressOf (ec, AddressOp.Load);
5929        ec.Emit (OpCodes.Call, ec.Module.PredefinedMembers.MonitorEnter_v4.Get ());
5930      }
5931
5932      Statement.Emit (ec);
5933    }
5934
5935    public override void EmitFinallyBody (EmitContext ec)
5936    {
5937      //
5938      // if (lock_taken) Monitor.Exit (expr_copy)
5939      //
5940      Label skip = ec.DefineLabel ();
5941
5942      if (lock_taken != null) {
5943        lock_taken.Emit (ec);
5944        ec.Emit (OpCodes.Brfalse_S, skip);
5945      }
5946
5947      expr_copy.Emit (ec);
5948      var m = ec.Module.PredefinedMembers.MonitorExit.Resolve (loc);
5949      if (m != null)
5950        ec.Emit (OpCodes.Call, m);
5951
5952      ec.MarkLabel (skip);
5953    }
5954
5955    int ResolvePredefinedMethods (ResolveContext rc)
5956    {
5957      // Try 4.0 Monitor.Enter (object, ref bool) overload first
5958      var m = rc.Module.PredefinedMembers.MonitorEnter_v4.Get ();
5959      if (m != null)
5960        return 4;
5961
5962      m = rc.Module.PredefinedMembers.MonitorEnter.Get ();
5963      if (m != null)
5964        return 1;
5965
5966      rc.Module.PredefinedMembers.MonitorEnter_v4.Resolve (loc);
5967      return 0;
5968    }
5969
5970    protected override void CloneTo (CloneContext clonectx, Statement t)
5971    {
5972      Lock target = (Lock) t;
5973
5974      target.expr = expr.Clone (clonectx);
5975      target.stmt = Statement.Clone (clonectx);
5976    }
5977   
5978    public override object Accept (StructuralVisitor visitor)
5979    {
5980      return visitor.Visit (this);
5981    }
5982
5983  }
5984
5985  public class Unchecked : Statement {
5986    public Block Block;
5987   
5988    public Unchecked (Block b, Location loc)
5989    {
5990      Block = b;
5991      b.Unchecked = true;
5992      this.loc = loc;
5993    }
5994
5995    public override bool Resolve (BlockContext ec)
5996    {
5997      using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
5998        return Block.Resolve (ec);
5999    }
6000   
6001    protected override void DoEmit (EmitContext ec)
6002    {
6003      using (ec.With (EmitContext.Options.CheckedScope, false))
6004        Block.Emit (ec);
6005    }
6006
6007    protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6008    {
6009      return Block.FlowAnalysis (fc);
6010    }
6011
6012    public override Reachability MarkReachable (Reachability rc)
6013    {
6014      base.MarkReachable (rc);
6015      return Block.MarkReachable (rc);
6016    }
6017
6018    protected override void CloneTo (CloneContext clonectx, Statement t)
6019    {
6020      Unchecked target = (Unchecked) t;
6021
6022      target.Block = clonectx.LookupBlock (Block);
6023    }
6024   
6025    public override object Accept (StructuralVisitor visitor)
6026    {
6027      return visitor.Visit (this);
6028    }
6029  }
6030
6031  public class Checked : Statement {
6032    public Block Block;
6033   
6034    public Checked (Block b, Location loc)
6035    {
6036      Block = b;
6037      b.Unchecked = false;
6038      this.loc = loc;
6039    }
6040
6041    public override bool Resolve (BlockContext ec)
6042    {
6043      using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
6044        return Block.Resolve (ec);
6045    }
6046
6047    protected override void DoEmit (EmitContext ec)
6048    {
6049      using (ec.With (EmitContext.Options.CheckedScope, true))
6050        Block.Emit (ec);
6051    }
6052
6053    protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6054    {
6055      return Block.FlowAnalysis (fc);
6056    }
6057
6058    public override Reachability MarkReachable (Reachability rc)
6059    {
6060      base.MarkReachable (rc);
6061      return Block.MarkReachable (rc);
6062    }
6063
6064    protected override void CloneTo (CloneContext clonectx, Statement t)
6065    {
6066      Checked target = (Checked) t;
6067
6068      target.Block = clonectx.LookupBlock (Block);
6069    }
6070   
6071    public override object Accept (StructuralVisitor visitor)
6072    {
6073      return visitor.Visit (this);
6074    }
6075  }
6076
6077  public class Unsafe : Statement {
6078    public Block Block;
6079
6080    public Unsafe (Block b, Location loc)
6081    {
6082      Block = b;
6083      Block.Unsafe = true;
6084      this.loc = loc;
6085    }
6086
6087    public override bool Resolve (BlockContext ec)
6088    {
6089      if (ec.CurrentIterator != null)
6090        ec.Report.Error (1629, loc, "Unsafe code may not appear in iterators");
6091
6092      using (ec.Set (ResolveContext.Options.UnsafeScope))
6093        return Block.Resolve (ec);
6094    }
6095   
6096    protected override void DoEmit (EmitContext ec)
6097    {
6098      Block.Emit (ec);
6099    }
6100
6101    protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6102    {
6103      return Block.FlowAnalysis (fc);
6104    }
6105
6106    public override Reachability MarkReachable (Reachability rc)
6107    {
6108      base.MarkReachable (rc);
6109      return Block.MarkReachable (rc);
6110    }
6111
6112    protected override void CloneTo (CloneContext clonectx, Statement t)
6113    {
6114      Unsafe target = (Unsafe) t;
6115
6116      target.Block = clonectx.LookupBlock (Block);
6117    }
6118   
6119    public override object Accept (StructuralVisitor visitor)
6120    {
6121      return visitor.Visit (this);
6122    }
6123  }
6124
6125  //
6126  // Fixed statement
6127  //
6128  public class Fixed : Statement
6129  {
6130    abstract class Emitter : ShimExpression
6131    {
6132      protected LocalVariable vi;
6133
6134      protected Emitter (Expression expr, LocalVariable li)
6135        : base (expr)
6136      {
6137        vi = li;
6138      }
6139
6140      public abstract void EmitExit (EmitContext ec);
6141
6142      public override void FlowAnalysis (FlowAnalysisContext fc)
6143      {
6144        expr.FlowAnalysis (fc);
6145      }
6146    }
6147
6148    class ExpressionEmitter : Emitter {
6149      public ExpressionEmitter (Expression converted, LocalVariable li) :
6150        base (converted, li)
6151      {
6152      }
6153
6154      protected override Expression DoResolve (ResolveContext rc)
6155      {
6156        throw new NotImplementedException ();
6157      }
6158
6159      public override void Emit (EmitContext ec) {
6160        //
6161        // Store pointer in pinned location
6162        //
6163        expr.Emit (ec);
6164        vi.EmitAssign (ec);
6165      }
6166
6167      public override void EmitExit (EmitContext ec)
6168      {
6169        ec.EmitInt (0);
6170        ec.Emit (OpCodes.Conv_U);
6171        vi.EmitAssign (ec);
6172      }
6173    }
6174
6175    class StringEmitter : Emitter
6176    {
6177      LocalVariable pinned_string;
6178
6179      public StringEmitter (Expression expr, LocalVariable li)
6180        : base (expr, li)
6181      {
6182      }
6183
6184      protected override Expression DoResolve (ResolveContext rc)
6185      {
6186        pinned_string = new LocalVariable (vi.Block, "$pinned",
6187          LocalVariable.Flags.FixedVariable | LocalVariable.Flags.CompilerGenerated | LocalVariable.Flags.Used,
6188          vi.Location);
6189        pinned_string.Type = rc.BuiltinTypes.String;
6190
6191        eclass = ExprClass.Variable;
6192        type = rc.BuiltinTypes.Int;
6193        return this;
6194      }
6195
6196      public override void Emit (EmitContext ec)
6197      {
6198        pinned_string.CreateBuilder (ec);
6199
6200        expr.Emit (ec);
6201        pinned_string.EmitAssign (ec);
6202
6203        // TODO: Should use Binary::Add
6204        pinned_string.Emit (ec);
6205        ec.Emit (OpCodes.Conv_I);
6206
6207        var m = ec.Module.PredefinedMembers.RuntimeHelpersOffsetToStringData.Resolve (loc);
6208        if (m == null)
6209          return;
6210
6211        PropertyExpr pe = new PropertyExpr (m, pinned_string.Location);
6212        //pe.InstanceExpression = pinned_string;
6213        pe.Resolve (new ResolveContext (ec.MemberContext)).Emit (ec);
6214
6215        ec.Emit (OpCodes.Add);
6216        vi.EmitAssign (ec);
6217      }
6218
6219      public override void EmitExit (EmitContext ec)
6220      {
6221        ec.EmitNull ();
6222        pinned_string.EmitAssign (ec);
6223      }
6224    }
6225
6226    public class VariableDeclaration : BlockVariable
6227    {
6228      public VariableDeclaration (FullNamedExpression type, LocalVariable li)
6229        : base (type, li)
6230      {
6231      }
6232
6233      protected override Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
6234      {
6235        if (!Variable.Type.IsPointer && li == Variable) {
6236          bc.Report.Error (209, TypeExpression.Location,
6237            "The type of locals declared in a fixed statement must be a pointer type");
6238          return null;
6239        }
6240
6241        //
6242        // The rules for the possible declarators are pretty wise,
6243        // but the production on the grammar is more concise.
6244        //
6245        // So we have to enforce these rules here.
6246        //
6247        // We do not resolve before doing the case 1 test,
6248        // because the grammar is explicit in that the token &
6249        // is present, so we need to test for this particular case.
6250        //
6251
6252        if (initializer is Cast) {
6253          bc.Report.Error (254, initializer.Location, "The right hand side of a fixed statement assignment may not be a cast expression");
6254          return null;
6255        }
6256
6257        initializer = initializer.Resolve (bc);
6258
6259        if (initializer == null)
6260          return null;
6261
6262        //
6263        // Case 1: Array
6264        //
6265        if (initializer.Type.IsArray) {
6266          TypeSpec array_type = TypeManager.GetElementType (initializer.Type);
6267
6268          //
6269          // Provided that array_type is unmanaged,
6270          //
6271          if (!TypeManager.VerifyUnmanaged (bc.Module, array_type, loc))
6272            return null;
6273
6274          //
6275          // and T* is implicitly convertible to the
6276          // pointer type given in the fixed statement.
6277          //
6278          ArrayPtr array_ptr = new ArrayPtr (initializer, array_type, loc);
6279
6280          Expression converted = Convert.ImplicitConversionRequired (bc, array_ptr.Resolve (bc), li.Type, loc);
6281          if (converted == null)
6282            return null;
6283
6284          //
6285          // fixed (T* e_ptr = (e == null || e.Length == 0) ? null : converted [0])
6286          //
6287          converted = new Conditional (new BooleanExpression (new Binary (Binary.Operator.LogicalOr,
6288            new Binary (Binary.Operator.Equality, initializer, new NullLiteral (loc)),
6289            new Binary (Binary.Operator.Equality, new MemberAccess (initializer, "Length"), new IntConstant (bc.BuiltinTypes, 0, loc)))),
6290              new NullLiteral (loc),
6291              converted, loc);
6292
6293          converted = converted.Resolve (bc);
6294
6295          return new ExpressionEmitter (converted, li);
6296        }
6297
6298        //
6299        // Case 2: string
6300        //
6301        if (initializer.Type.BuiltinType == BuiltinTypeSpec.Type.String) {
6302          return new StringEmitter (initializer, li).Resolve (bc);
6303        }
6304
6305        // Case 3: fixed buffer
6306        if (initializer is FixedBufferPtr) {
6307          return new ExpressionEmitter (initializer, li);
6308        }
6309
6310        //
6311        // Case 4: & object.
6312        //
6313        bool already_fixed = true;
6314        Unary u = initializer as Unary;
6315        if (u != null && u.Oper == Unary.Operator.AddressOf) {
6316          IVariableReference vr = u.Expr as IVariableReference;
6317          if (vr == null || !vr.IsFixed) {
6318            already_fixed = false;
6319          }
6320        }
6321
6322        if (already_fixed) {
6323          bc.Report.Error (213, loc, "You cannot use the fixed statement to take the address of an already fixed expression");
6324        }
6325
6326        initializer = Convert.ImplicitConversionRequired (bc, initializer, li.Type, loc);
6327        return new ExpressionEmitter (initializer, li);
6328      }
6329    }
6330
6331
6332    VariableDeclaration decl;
6333    Statement statement;
6334    bool has_ret;
6335
6336    public Fixed (VariableDeclaration decl, Statement stmt, Location l)
6337    {
6338      this.decl = decl;
6339      statement = stmt;
6340      loc = l;
6341    }
6342
6343    #region Properties
6344
6345    public Statement Statement {
6346      get {
6347        return statement;
6348      }
6349    }
6350
6351    public BlockVariable Variables {
6352      get {
6353        return decl;
6354      }
6355    }
6356
6357    #endregion
6358
6359    public override bool Resolve (BlockContext bc)
6360    {
6361      using (bc.Set (ResolveContext.Options.FixedInitializerScope)) {
6362        if (!decl.Resolve (bc))
6363          return false;
6364      }
6365
6366      return statement.Resolve (bc);
6367    }
6368
6369    protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6370    {
6371      decl.FlowAnalysis (fc);
6372      return statement.FlowAnalysis (fc);
6373    }
6374   
6375    protected override void DoEmit (EmitContext ec)
6376    {
6377      decl.Variable.CreateBuilder (ec);
6378      decl.Initializer.Emit (ec);
6379      if (decl.Declarators != null) {
6380        foreach (var d in decl.Declarators) {
6381          d.Variable.CreateBuilder (ec);
6382          d.Initializer.Emit (ec);
6383        }
6384      }
6385
6386      statement.Emit (ec);
6387
6388      if (has_ret)
6389        return;
6390
6391      //
6392      // Clear the pinned variable
6393      //
6394      ((Emitter) decl.Initializer).EmitExit (ec);
6395      if (decl.Declarators != null) {
6396        foreach (var d in decl.Declarators) {
6397          ((Emitter)d.Initializer).EmitExit (ec);
6398        }
6399      }
6400    }
6401
6402    public override Reachability MarkReachable (Reachability rc)
6403    {
6404      base.MarkReachable (rc);
6405
6406      decl.MarkReachable (rc);
6407
6408      rc = statement.MarkReachable (rc);
6409
6410      // TODO: What if there is local exit?
6411      has_ret = rc.IsUnreachable;
6412      return rc;
6413    }
6414
6415    protected override void CloneTo (CloneContext clonectx, Statement t)
6416    {
6417      Fixed target = (Fixed) t;
6418
6419      target.decl = (VariableDeclaration) decl.Clone (clonectx);
6420      target.statement = statement.Clone (clonectx);
6421    }
6422   
6423    public override object Accept (StructuralVisitor visitor)
6424    {
6425      return visitor.Visit (this);
6426    }
6427  }
6428
6429  public class Catch : Statement
6430  {
6431    class FilterStatement : Statement
6432    {
6433      readonly Catch ctch;
6434
6435      public FilterStatement (Catch ctch)
6436      {
6437        this.ctch = ctch;
6438      }
6439
6440      protected override void CloneTo (CloneContext clonectx, Statement target)
6441      {
6442      }
6443
6444      protected override void DoEmit (EmitContext ec)
6445      {
6446        if (ctch.li != null) {
6447          if (ctch.hoisted_temp != null)
6448            ctch.hoisted_temp.Emit (ec);
6449          else
6450            ctch.li.Emit (ec);
6451
6452          if (!ctch.IsGeneral && ctch.type.Kind == MemberKind.TypeParameter)
6453            ec.Emit (OpCodes.Box, ctch.type);
6454        }
6455
6456        var expr_start = ec.DefineLabel ();
6457        var end = ec.DefineLabel ();
6458
6459        ec.Emit (OpCodes.Brtrue_S, expr_start);
6460        ec.EmitInt (0);
6461        ec.Emit (OpCodes.Br, end);
6462        ec.MarkLabel (expr_start);
6463
6464        ctch.Filter.Emit (ec);
6465
6466        ec.MarkLabel (end);
6467        ec.Emit (OpCodes.Endfilter);
6468        ec.BeginFilterHandler ();
6469        ec.Emit (OpCodes.Pop);
6470      }
6471
6472      protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6473      {
6474        ctch.Filter.FlowAnalysis (fc);
6475        return true;
6476      }
6477
6478      public override bool Resolve (BlockContext bc)
6479      {
6480        ctch.Filter = ctch.Filter.Resolve (bc);
6481
6482        if (ctch.Filter != null) {
6483          if (ctch.Filter.ContainsEmitWithAwait ()) {
6484            bc.Report.Error (7094, ctch.Filter.Location, "The `await' operator cannot be used in the filter expression of a catch clause");
6485          }
6486
6487          var c = ctch.Filter as Constant;
6488          if (c != null && !c.IsDefaultValue) {
6489            bc.Report.Warning (7095, 1, ctch.Filter.Location, "Exception filter expression is a constant");
6490          }
6491        }
6492
6493        return true;
6494      }
6495    }
6496
6497    ExplicitBlock block;
6498    LocalVariable li;
6499    FullNamedExpression type_expr;
6500    CompilerAssign assign;
6501    TypeSpec type;
6502    LocalTemporary hoisted_temp;
6503
6504    public Catch (ExplicitBlock block, Location loc)
6505    {
6506      this.block = block;
6507      this.loc = loc;
6508    }
6509
6510    #region Properties
6511
6512    public ExplicitBlock Block {
6513      get {
6514        return block;
6515      }
6516    }
6517
6518    public TypeSpec CatchType {
6519      get {
6520        return type;
6521      }
6522    }
6523
6524    public Expression Filter {
6525      get; set;
6526    }
6527
6528    public bool IsGeneral {
6529      get {
6530        return type_expr == null;
6531      }
6532    }
6533
6534    public FullNamedExpression TypeExpression {
6535      get {
6536        return type_expr;
6537      }
6538      set {
6539        type_expr = value;
6540      }
6541    }
6542
6543    public LocalVariable Variable {
6544      get {
6545        return li;
6546      }
6547      set {
6548        li = value;
6549      }
6550    }
6551
6552    #endregion
6553
6554    protected override void DoEmit (EmitContext ec)
6555    {
6556      if (Filter != null) {
6557        ec.BeginExceptionFilterBlock ();
6558        ec.Emit (OpCodes.Isinst, IsGeneral ? ec.BuiltinTypes.Object : CatchType);
6559
6560        if (li != null)
6561          EmitCatchVariableStore (ec);
6562
6563        if (Block.HasAwait) {
6564          Block.EmitScopeInitialization (ec);
6565        } else {
6566          Block.Emit (ec);
6567        }
6568
6569        return;
6570      }
6571
6572      if (IsGeneral)
6573        ec.BeginCatchBlock (ec.BuiltinTypes.Object);
6574      else
6575        ec.BeginCatchBlock (CatchType);
6576
6577      if (li != null) {
6578        EmitCatchVariableStore (ec);
6579      } else {
6580        ec.Emit (OpCodes.Pop);
6581      }
6582
6583      if (!Block.HasAwait)
6584        Block.Emit (ec);
6585    }
6586
6587    void EmitCatchVariableStore (EmitContext ec)
6588    {
6589      li.CreateBuilder (ec);
6590
6591      //
6592      // Special case hoisted catch variable, we have to use a temporary variable
6593      // to pass via anonymous storey initialization with the value still on top
6594      // of the stack
6595      //
6596      if (li.HoistedVariant != null) {
6597        hoisted_temp = new LocalTemporary (li.Type);
6598        hoisted_temp.Store (ec);
6599
6600        // switch to assignment from temporary variable and not from top of the stack
6601        assign.UpdateSource (hoisted_temp);
6602      }
6603    }
6604
6605    public override bool Resolve (BlockContext bc)
6606    {
6607      using (bc.Set (ResolveContext.Options.CatchScope)) {
6608        if (type_expr == null) {
6609          if (CreateExceptionVariable (bc.Module.Compiler.BuiltinTypes.Object)) {
6610            Expression source = new EmptyExpression (li.Type);
6611            assign = new CompilerAssign (new LocalVariableReference (li, Location.Null), source, Location.Null);
6612            Block.AddScopeStatement (new StatementExpression (assign, Location.Null));
6613          }
6614        } else {
6615          type = type_expr.ResolveAsType (bc);
6616          if (type == null)
6617            return false;
6618
6619          if (li == null)
6620            CreateExceptionVariable (type);
6621
6622          if (type.BuiltinType != BuiltinTypeSpec.Type.Exception && !TypeSpec.IsBaseClass (type, bc.BuiltinTypes.Exception, false)) {
6623            bc.Report.Error (155, loc, "The type caught or thrown must be derived from System.Exception");
6624          } else if (li != null) {
6625            li.Type = type;
6626            li.PrepareAssignmentAnalysis (bc);
6627
6628            // source variable is at the top of the stack
6629            Expression source = new EmptyExpression (li.Type);
6630            if (li.Type.IsGenericParameter)
6631              source = new UnboxCast (source, li.Type);
6632
6633            //
6634            // Uses Location.Null to hide from symbol file
6635            //
6636            assign = new CompilerAssign (new LocalVariableReference (li, Location.Null), source, Location.Null);
6637            Block.AddScopeStatement (new StatementExpression (assign, Location.Null));
6638          }
6639        }
6640
6641        if (Filter != null) {
6642          Block.AddScopeStatement (new FilterStatement (this));
6643        }
6644
6645        Block.SetCatchBlock ();
6646        return Block.Resolve (bc);
6647      }
6648    }
6649
6650    bool CreateExceptionVariable (TypeSpec type)
6651    {
6652      if (!Block.HasAwait)
6653        return false;
6654
6655      // TODO: Scan the block for rethrow expression
6656      //if (!Block.HasRethrow)
6657      //  return;
6658
6659      li = LocalVariable.CreateCompilerGenerated (type, block, Location.Null);
6660      return true;
6661    }
6662
6663    protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6664    {
6665      if (li != null && !li.IsCompilerGenerated) {
6666        fc.SetVariableAssigned (li.VariableInfo, true);
6667      }
6668
6669      return block.FlowAnalysis (fc);
6670    }
6671
6672    public override Reachability MarkReachable (Reachability rc)
6673    {
6674      base.MarkReachable (rc);
6675
6676      var c = Filter as Constant;
6677      if (c != null && c.IsDefaultValue)
6678        return Reachability.CreateUnreachable ();
6679
6680      return block.MarkReachable (rc);
6681    }
6682
6683    protected override void CloneTo (CloneContext clonectx, Statement t)
6684    {
6685      Catch target = (Catch) t;
6686
6687      if (type_expr != null)
6688        target.type_expr = (FullNamedExpression) type_expr.Clone (clonectx);
6689
6690      if (Filter != null)
6691        target.Filter = Filter.Clone (clonectx);
6692
6693      target.block = (ExplicitBlock) clonectx.LookupBlock (block);
6694    }
6695  }
6696
6697  public class TryFinally : TryFinallyBlock
6698  {
6699    ExplicitBlock fini;
6700    List<DefiniteAssignmentBitSet> try_exit_dat;
6701    List<Label> redirected_jumps;
6702    Label? start_fin_label;
6703
6704    public Statement Stmt {
6705      get { return this.stmt; }
6706    }
6707
6708    public ExplicitBlock Fini {
6709      get { return this.fini; }
6710    }
6711
6712    public TryFinally (Statement stmt, ExplicitBlock fini, Location loc)
6713       : base (stmt, loc)
6714    {
6715      this.fini = fini;
6716    }
6717
6718    public ExplicitBlock FinallyBlock {
6719      get {
6720        return fini;
6721      }
6722    }
6723
6724    public void RegisterForControlExitCheck (DefiniteAssignmentBitSet vector)
6725    {
6726      if (try_exit_dat == null)
6727        try_exit_dat = new List<DefiniteAssignmentBitSet> ();
6728
6729      try_exit_dat.Add (vector);
6730    }
6731
6732    public override bool Resolve (BlockContext bc)
6733    {
6734      bool ok = base.Resolve (bc);
6735
6736      fini.SetFinallyBlock ();
6737      using (bc.Set (ResolveContext.Options.FinallyScope)) {
6738        ok &= fini.Resolve (bc);
6739      }
6740
6741      return ok;
6742    }
6743
6744    protected override void EmitTryBody (EmitContext ec)
6745    {
6746      if (fini.HasAwait) {
6747        if (ec.TryFinallyUnwind == null)
6748          ec.TryFinallyUnwind = new List<TryFinally> ();
6749
6750        ec.TryFinallyUnwind.Add (this);
6751        stmt.Emit (ec);
6752        ec.TryFinallyUnwind.Remove (this);
6753
6754        if (start_fin_label != null)
6755          ec.MarkLabel (start_fin_label.Value);
6756
6757        return;
6758      }
6759
6760      stmt.Emit (ec);
6761    }
6762
6763    protected override bool EmitBeginFinallyBlock (EmitContext ec)
6764    {
6765      if (fini.HasAwait)
6766        return false;
6767
6768      return base.EmitBeginFinallyBlock (ec);
6769    }
6770
6771    public override void EmitFinallyBody (EmitContext ec)
6772    {
6773      if (!fini.HasAwait) {
6774        fini.Emit (ec);
6775        return;
6776      }
6777
6778      //
6779      // Emits catch block like
6780      //
6781      // catch (object temp) {
6782      //  this.exception_field = temp;
6783      // }
6784      //
6785      var type = ec.BuiltinTypes.Object;
6786      ec.BeginCatchBlock (type);
6787
6788      var temp = ec.GetTemporaryLocal (type);
6789      ec.Emit (OpCodes.Stloc, temp);
6790
6791      var exception_field = ec.GetTemporaryField (type);
6792      ec.EmitThis ();
6793      ec.Emit (OpCodes.Ldloc, temp);
6794      exception_field.EmitAssignFromStack (ec);
6795
6796      ec.EndExceptionBlock ();
6797
6798      ec.FreeTemporaryLocal (temp, type);
6799
6800      fini.Emit (ec);
6801
6802      //
6803      // Emits exception rethrow
6804      //
6805      // if (this.exception_field != null)
6806      //  throw this.exception_field;
6807      //
6808      exception_field.Emit (ec);
6809      var skip_throw = ec.DefineLabel ();
6810      ec.Emit (OpCodes.Brfalse_S, skip_throw);
6811      exception_field.Emit (ec);
6812      ec.Emit (OpCodes.Throw);
6813      ec.MarkLabel (skip_throw);
6814
6815      exception_field.IsAvailableForReuse = true;
6816
6817      EmitUnwindFinallyTable (ec);
6818    }
6819
6820    bool IsParentBlock (Block block)
6821    {
6822      for (Block b = fini; b != null; b = b.Parent) {
6823        if (b == block)
6824          return true;
6825      }
6826
6827      return false;
6828    }
6829
6830    public static Label EmitRedirectedJump (EmitContext ec, AsyncInitializer initializer, Label label, Block labelBlock)
6831    {
6832      int idx;
6833      if (labelBlock != null) {
6834        for (idx = ec.TryFinallyUnwind.Count; idx != 0; --idx) {
6835          var fin = ec.TryFinallyUnwind [idx - 1];
6836          if (!fin.IsParentBlock (labelBlock))
6837            break;
6838        }
6839      } else {
6840        idx = 0;
6841      }
6842
6843      bool set_return_state = true;
6844
6845      for (; idx < ec.TryFinallyUnwind.Count; ++idx) {
6846        var fin = ec.TryFinallyUnwind [idx];
6847        if (labelBlock != null && !fin.IsParentBlock (labelBlock))
6848          break;
6849
6850        fin.EmitRedirectedExit (ec, label, initializer, set_return_state);
6851        set_return_state = false;
6852
6853        if (fin.start_fin_label == null) {
6854          fin.start_fin_label = ec.DefineLabel ();
6855        }
6856
6857        label = fin.start_fin_label.Value;
6858      }
6859
6860      return label;
6861    }
6862
6863    public static Label EmitRedirectedReturn (EmitContext ec, AsyncInitializer initializer)
6864    {
6865      return EmitRedirectedJump (ec, initializer, initializer.BodyEnd, null);
6866    }
6867
6868    void EmitRedirectedExit (EmitContext ec, Label label, AsyncInitializer initializer, bool setReturnState)
6869    {
6870      if (redirected_jumps == null) {
6871        redirected_jumps = new List<Label> ();
6872
6873        // Add fallthrough label
6874        redirected_jumps.Add (ec.DefineLabel ());
6875
6876        if (setReturnState)
6877          initializer.HoistedReturnState = ec.GetTemporaryField (ec.Module.Compiler.BuiltinTypes.Int, true);
6878      }
6879
6880      int index = redirected_jumps.IndexOf (label);
6881      if (index < 0) {
6882        redirected_jumps.Add (label);
6883        index = redirected_jumps.Count - 1;
6884      }
6885
6886      //
6887      // Indicates we have captured exit jump
6888      //
6889      if (setReturnState) {
6890        var value = new IntConstant (initializer.HoistedReturnState.Type, index, Location.Null);
6891        initializer.HoistedReturnState.EmitAssign (ec, value, false, false);
6892      }
6893    }
6894
6895    //
6896    // Emits state table of jumps outside of try block and reload of return
6897    // value when try block returns value
6898    //
6899    void EmitUnwindFinallyTable (EmitContext ec)
6900    {
6901      if (redirected_jumps == null)
6902        return;
6903
6904      var initializer = (AsyncInitializer)ec.CurrentAnonymousMethod;
6905      initializer.HoistedReturnState.EmitLoad (ec);
6906      ec.Emit (OpCodes.Switch, redirected_jumps.ToArray ());
6907
6908      // Mark fallthrough label
6909      ec.MarkLabel (redirected_jumps [0]);
6910    }
6911
6912    protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6913    {
6914      var da = fc.BranchDefiniteAssignment ();
6915
6916      var tf = fc.TryFinally;
6917      fc.TryFinally = this;
6918
6919      var res_stmt = Statement.FlowAnalysis (fc);
6920
6921      fc.TryFinally = tf;
6922
6923      var try_da = fc.DefiniteAssignment;
6924      fc.DefiniteAssignment = da;
6925
6926      var res_fin = fini.FlowAnalysis (fc);
6927
6928      if (try_exit_dat != null) {
6929        //
6930        // try block has global exit but we need to run definite assignment check
6931        // for parameter block out parameter after finally block because it's always
6932        // executed before exit
6933        //
6934        foreach (var try_da_part in try_exit_dat)
6935          fc.ParametersBlock.CheckControlExit (fc, fc.DefiniteAssignment | try_da_part);
6936
6937        try_exit_dat = null;
6938      }
6939
6940      fc.DefiniteAssignment |= try_da;
6941      return res_stmt | res_fin;
6942    }
6943
6944    public override Reachability MarkReachable (Reachability rc)
6945    {
6946      //
6947      // Mark finally block first for any exit statement in try block
6948      // to know whether the code which follows finally is reachable
6949      //
6950      return fini.MarkReachable (rc) | base.MarkReachable (rc);
6951    }
6952
6953    protected override void CloneTo (CloneContext clonectx, Statement t)
6954    {
6955      TryFinally target = (TryFinally) t;
6956
6957      target.stmt = stmt.Clone (clonectx);
6958      if (fini != null)
6959        target.fini = (ExplicitBlock) clonectx.LookupBlock (fini);
6960    }
6961   
6962    public override object Accept (StructuralVisitor visitor)
6963    {
6964      return visitor.Visit (this);
6965    }
6966  }
6967
6968  public class TryCatch : ExceptionStatement
6969  {
6970    public Block Block;
6971    List<Catch> clauses;
6972    readonly bool inside_try_finally;
6973    List<Catch> catch_sm;
6974
6975    public TryCatch (Block block, List<Catch> catch_clauses, Location l, bool inside_try_finally)
6976      : base (l)
6977    {
6978      this.Block = block;
6979      this.clauses = catch_clauses;
6980      this.inside_try_finally = inside_try_finally;
6981    }
6982
6983    public List<Catch> Clauses {
6984      get {
6985        return clauses;
6986      }
6987    }
6988
6989    public bool IsTryCatchFinally {
6990      get {
6991        return inside_try_finally;
6992      }
6993    }
6994
6995    public override bool Resolve (BlockContext bc)
6996    {
6997      bool ok;
6998
6999      using (bc.Set (ResolveContext.Options.TryScope)) {
7000        parent = bc.CurrentTryBlock;
7001
7002        if (IsTryCatchFinally) {
7003          ok = Block.Resolve (bc);
7004        } else {
7005          using (bc.Set (ResolveContext.Options.TryWithCatchScope)) {
7006            bc.CurrentTryBlock = this;
7007            ok = Block.Resolve (bc);
7008            bc.CurrentTryBlock = parent;
7009          }
7010        }
7011      }
7012
7013      for (int i = 0; i < clauses.Count; ++i) {
7014        var c = clauses[i];
7015
7016        ok &= c.Resolve (bc);
7017
7018        if (c.Block.HasAwait) {
7019          if (catch_sm == null)
7020            catch_sm = new List<Catch> ();
7021
7022          catch_sm.Add (c);
7023        }
7024
7025        if (c.Filter != null)
7026          continue;
7027
7028        TypeSpec resolved_type = c.CatchType;
7029        if (resolved_type == null)
7030          continue;
7031
7032        for (int ii = 0; ii < clauses.Count; ++ii) {
7033          if (ii == i)
7034            continue;
7035
7036          if (clauses[ii].Filter != null)
7037            continue;
7038
7039          if (clauses[ii].IsGeneral) {
7040            if (resolved_type.BuiltinType != BuiltinTypeSpec.Type.Exception)
7041              continue;
7042
7043            if (!bc.Module.DeclaringAssembly.WrapNonExceptionThrows)
7044              continue;
7045
7046            if (!bc.Module.PredefinedAttributes.RuntimeCompatibility.IsDefined)
7047              continue;
7048
7049            bc.Report.Warning (1058, 1, c.loc,
7050              "A previous catch clause already catches all exceptions. All non-exceptions thrown will be wrapped in a `System.Runtime.CompilerServices.RuntimeWrappedException'");
7051
7052            continue;
7053          }
7054
7055          if (ii >= i)
7056            continue;
7057
7058          var ct = clauses[ii].CatchType;
7059          if (ct == null)
7060            continue;
7061
7062          if (resolved_type == ct || TypeSpec.IsBaseClass (resolved_type, ct, true)) {
7063            bc.Report.Error (160, c.loc,
7064              "A previous catch clause already catches all exceptions of this or a super type `{0}'",
7065              ct.GetSignatureForError ());
7066            ok = false;
7067          }
7068        }
7069      }
7070
7071      return base.Resolve (bc) && ok;
7072    }
7073
7074    protected sealed override void DoEmit (EmitContext ec)
7075    {
7076      if (!inside_try_finally)
7077        EmitTryBodyPrepare (ec);
7078
7079      Block.Emit (ec);
7080
7081      LocalBuilder state_variable = null;
7082      foreach (Catch c in clauses) {
7083        c.Emit (ec);
7084
7085        if (catch_sm != null) {
7086          if (state_variable == null) {
7087            //
7088            // Cannot reuse temp variable because non-catch path assumes the value is 0
7089            // which may not be true for reused local variable
7090            //
7091            state_variable = ec.DeclareLocal (ec.Module.Compiler.BuiltinTypes.Int, false);
7092          }
7093
7094          var index = catch_sm.IndexOf (c);
7095          if (index < 0)
7096            continue;
7097
7098          ec.EmitInt (index + 1);
7099          ec.Emit (OpCodes.Stloc, state_variable);
7100        }
7101      }
7102
7103      if (!inside_try_finally)
7104        ec.EndExceptionBlock ();
7105
7106      if (state_variable != null) {
7107        ec.Emit (OpCodes.Ldloc, state_variable);
7108
7109        var labels = new Label [catch_sm.Count + 1];
7110        for (int i = 0; i < labels.Length; ++i) {
7111          labels [i] = ec.DefineLabel ();
7112        }
7113
7114        var end = ec.DefineLabel ();
7115        ec.Emit (OpCodes.Switch, labels);
7116
7117        // 0 value is default label
7118        ec.MarkLabel (labels [0]);
7119        ec.Emit (OpCodes.Br, end);
7120
7121        var atv = ec.AsyncThrowVariable;
7122        Catch c = null;
7123        for (int i = 0; i < catch_sm.Count; ++i) {
7124          if (c != null && c.Block.HasReachableClosingBrace)
7125            ec.Emit (OpCodes.Br, end);
7126
7127          ec.MarkLabel (labels [i + 1]);
7128          c = catch_sm [i];
7129          ec.AsyncThrowVariable = c.Variable;
7130          c.Block.Emit (ec);
7131        }
7132        ec.AsyncThrowVariable = atv;
7133
7134        ec.MarkLabel (end);
7135      }
7136    }
7137
7138    protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7139    {
7140      var start_fc = fc.BranchDefiniteAssignment ();
7141      var res = Block.FlowAnalysis (fc);
7142
7143      DefiniteAssignmentBitSet try_fc = res ? null : fc.DefiniteAssignment;
7144
7145      foreach (var c in clauses) {
7146        fc.DefiniteAssignment = new DefiniteAssignmentBitSet (start_fc);
7147        if (!c.FlowAnalysis (fc)) {
7148          if (try_fc == null)
7149            try_fc = fc.DefiniteAssignment;
7150          else
7151            try_fc &= fc.DefiniteAssignment;
7152
7153          res = false;
7154        }
7155      }
7156
7157      fc.DefiniteAssignment = try_fc ?? start_fc;
7158      parent = null;
7159      return res;
7160    }
7161
7162    public override Reachability MarkReachable (Reachability rc)
7163    {
7164      if (rc.IsUnreachable)
7165        return rc;
7166
7167      base.MarkReachable (rc);
7168
7169      var tc_rc = Block.MarkReachable (rc);
7170
7171      foreach (var c in clauses)
7172        tc_rc &= c.MarkReachable (rc);
7173
7174      return tc_rc;
7175    }
7176
7177    protected override void CloneTo (CloneContext clonectx, Statement t)
7178    {
7179      TryCatch target = (TryCatch) t;
7180
7181      target.Block = clonectx.LookupBlock (Block);
7182      if (clauses != null){
7183        target.clauses = new List<Catch> ();
7184        foreach (Catch c in clauses)
7185          target.clauses.Add ((Catch) c.Clone (clonectx));
7186      }
7187    }
7188
7189    public override object Accept (StructuralVisitor visitor)
7190    {
7191      return visitor.Visit (this);
7192    }
7193  }
7194
7195  public class Using : TryFinallyBlock
7196  {
7197    public class VariableDeclaration : BlockVariable
7198    {
7199      Statement dispose_call;
7200
7201      public VariableDeclaration (FullNamedExpression type, LocalVariable li)
7202        : base (type, li)
7203      {
7204      }
7205
7206      public VariableDeclaration (LocalVariable li, Location loc)
7207        : base (li)
7208      {
7209        reachable = true;
7210        this.loc = loc;
7211      }
7212
7213      public VariableDeclaration (Expression expr)
7214        : base (null)
7215      {
7216        loc = expr.Location;
7217        Initializer = expr;
7218      }
7219
7220      #region Properties
7221
7222      public bool IsNested { get; private set; }
7223
7224      #endregion
7225
7226      public void EmitDispose (EmitContext ec)
7227      {
7228        dispose_call.Emit (ec);
7229      }
7230
7231      public override bool Resolve (BlockContext bc)
7232      {
7233        if (IsNested)
7234          return true;
7235
7236        return base.Resolve (bc, false);
7237      }
7238
7239      public Expression ResolveExpression (BlockContext bc)
7240      {
7241        var e = Initializer.Resolve (bc);
7242        if (e == null)
7243          return null;
7244
7245        li = LocalVariable.CreateCompilerGenerated (e.Type, bc.CurrentBlock, loc);
7246        Initializer = ResolveInitializer (bc, Variable, e);
7247        return e;
7248      }
7249
7250      protected override Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
7251      {
7252        if (li.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
7253          initializer = initializer.Resolve (bc);
7254          if (initializer == null)
7255            return null;
7256
7257          // Once there is dynamic used defer conversion to runtime even if we know it will never succeed
7258          Arguments args = new Arguments (1);
7259          args.Add (new Argument (initializer));
7260          initializer = new DynamicConversion (bc.BuiltinTypes.IDisposable, 0, args, initializer.Location).Resolve (bc);
7261          if (initializer == null)
7262            return null;
7263
7264          var var = LocalVariable.CreateCompilerGenerated (initializer.Type, bc.CurrentBlock, loc);
7265          dispose_call = CreateDisposeCall (bc, var);
7266          dispose_call.Resolve (bc);
7267
7268          return base.ResolveInitializer (bc, li, new SimpleAssign (var.CreateReferenceExpression (bc, loc), initializer, loc));
7269        }
7270
7271        if (li == Variable) {
7272          CheckIDiposableConversion (bc, li, initializer);
7273          dispose_call = CreateDisposeCall (bc, li);
7274          dispose_call.Resolve (bc);
7275        }
7276
7277        return base.ResolveInitializer (bc, li, initializer);
7278      }
7279
7280      protected virtual void CheckIDiposableConversion (BlockContext bc, LocalVariable li, Expression initializer)
7281      {
7282        var type = li.Type;
7283
7284        if (type.BuiltinType != BuiltinTypeSpec.Type.IDisposable && !CanConvertToIDisposable (bc, type)) {
7285          if (type.IsNullableType) {
7286            // it's handled in CreateDisposeCall
7287            return;
7288          }
7289
7290          if (type != InternalType.ErrorType) {
7291            bc.Report.SymbolRelatedToPreviousError (type);
7292            var loc = type_expr == null ? initializer.Location : type_expr.Location;
7293            bc.Report.Error (1674, loc, "`{0}': type used in a using statement must be implicitly convertible to `System.IDisposable'",
7294              type.GetSignatureForError ());
7295          }
7296
7297          return;
7298        }
7299      }
7300
7301      static bool CanConvertToIDisposable (BlockContext bc, TypeSpec type)
7302      {
7303        var target = bc.BuiltinTypes.IDisposable;
7304        var tp = type as TypeParameterSpec;
7305        if (tp != null)
7306          return Convert.ImplicitTypeParameterConversion (null, tp, target) != null;
7307
7308        return type.ImplementsInterface (target, false);
7309      }
7310
7311      protected virtual Statement CreateDisposeCall (BlockContext bc, LocalVariable lv)
7312      {
7313        var lvr = lv.CreateReferenceExpression (bc, lv.Location);
7314        var type = lv.Type;
7315        var loc = lv.Location;
7316
7317        var idt = bc.BuiltinTypes.IDisposable;
7318        var m = bc.Module.PredefinedMembers.IDisposableDispose.Resolve (loc);
7319
7320        var dispose_mg = MethodGroupExpr.CreatePredefined (m, idt, loc);
7321        dispose_mg.InstanceExpression = type.IsNullableType ?
7322          new Cast (new TypeExpression (idt, loc), lvr, loc).Resolve (bc) :
7323          lvr;
7324
7325        //
7326        // Hide it from symbol file via null location
7327        //
7328        Statement dispose = new StatementExpression (new Invocation (dispose_mg, null), Location.Null);
7329
7330        // Add conditional call when disposing possible null variable
7331        if (!TypeSpec.IsValueType (type) || type.IsNullableType)
7332          dispose = new If (new Binary (Binary.Operator.Inequality, lvr, new NullLiteral (loc)), dispose, dispose.loc);
7333
7334        return dispose;
7335      }
7336
7337      public void ResolveDeclaratorInitializer (BlockContext bc)
7338      {
7339        Initializer = base.ResolveInitializer (bc, Variable, Initializer);
7340      }
7341
7342      public Statement RewriteUsingDeclarators (BlockContext bc, Statement stmt)
7343      {
7344        for (int i = declarators.Count - 1; i >= 0; --i) {
7345          var d = declarators [i];
7346          var vd = new VariableDeclaration (d.Variable, d.Variable.Location);
7347          vd.Initializer = d.Initializer;
7348          vd.IsNested = true;
7349          vd.dispose_call = CreateDisposeCall (bc, d.Variable);
7350          vd.dispose_call.Resolve (bc);
7351
7352          stmt = new Using (vd, stmt, d.Variable.Location);
7353        }
7354
7355        declarators = null;
7356        return stmt;
7357      }
7358
7359      public override object Accept (StructuralVisitor visitor)
7360      {
7361        return visitor.Visit (this);
7362      }
7363    }
7364
7365    VariableDeclaration decl;
7366
7367    public Using (VariableDeclaration decl, Statement stmt, Location loc)
7368      : base (stmt, loc)
7369    {
7370      this.decl = decl;
7371    }
7372
7373    public Using (Expression expr, Statement stmt, Location loc)
7374      : base (stmt, loc)
7375    {
7376      this.decl = new VariableDeclaration (expr);
7377    }
7378
7379    #region Properties
7380
7381    public Expression Expr {
7382      get {
7383        return decl.Variable == null ? decl.Initializer : null;
7384      }
7385    }
7386
7387    public BlockVariable Variables {
7388      get {
7389        return decl;
7390      }
7391    }
7392
7393    #endregion
7394
7395    public override void Emit (EmitContext ec)
7396    {
7397      //
7398      // Don't emit sequence point it will be set on variable declaration
7399      //
7400      DoEmit (ec);
7401    }
7402
7403    protected override void EmitTryBodyPrepare (EmitContext ec)
7404    {
7405      decl.Emit (ec);
7406      base.EmitTryBodyPrepare (ec);
7407    }
7408
7409    protected override void EmitTryBody (EmitContext ec)
7410    {
7411      stmt.Emit (ec);
7412    }
7413
7414    public override void EmitFinallyBody (EmitContext ec)
7415    {
7416      decl.EmitDispose (ec);
7417    }
7418
7419    protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7420    {
7421      decl.FlowAnalysis (fc);
7422      return stmt.FlowAnalysis (fc);
7423    }
7424
7425    public override Reachability MarkReachable (Reachability rc)
7426    {
7427      decl.MarkReachable (rc);
7428      return base.MarkReachable (rc);
7429    }
7430
7431    public override bool Resolve (BlockContext ec)
7432    {
7433      VariableReference vr;
7434      bool vr_locked = false;
7435
7436      using (ec.Set (ResolveContext.Options.UsingInitializerScope)) {
7437        if (decl.Variable == null) {
7438          vr = decl.ResolveExpression (ec) as VariableReference;
7439          if (vr != null) {
7440            vr_locked = vr.IsLockedByStatement;
7441            vr.IsLockedByStatement = true;
7442          }
7443        } else {
7444          if (decl.IsNested) {
7445            decl.ResolveDeclaratorInitializer (ec);
7446          } else {
7447            if (!decl.Resolve (ec))
7448              return false;
7449
7450            if (decl.Declarators != null) {
7451              stmt = decl.RewriteUsingDeclarators (ec, stmt);
7452            }
7453          }
7454
7455          vr = null;
7456        }
7457      }
7458
7459      var ok = base.Resolve (ec);
7460
7461      if (vr != null)
7462        vr.IsLockedByStatement = vr_locked;
7463
7464      return ok;
7465    }
7466
7467    protected override void CloneTo (CloneContext clonectx, Statement t)
7468    {
7469      Using target = (Using) t;
7470
7471      target.decl = (VariableDeclaration) decl.Clone (clonectx);
7472      target.stmt = stmt.Clone (clonectx);
7473    }
7474
7475    public override object Accept (StructuralVisitor visitor)
7476    {
7477      return visitor.Visit (this);
7478    }
7479  }
7480
7481  /// <summary>
7482  ///   Implementation of the foreach C# statement
7483  /// </summary>
7484  public class Foreach : LoopStatement
7485  {
7486    abstract class IteratorStatement : Statement
7487    {
7488      protected readonly Foreach for_each;
7489
7490      protected IteratorStatement (Foreach @foreach)
7491      {
7492        this.for_each = @foreach;
7493        this.loc = @foreach.expr.Location;
7494      }
7495
7496      protected override void CloneTo (CloneContext clonectx, Statement target)
7497      {
7498        throw new NotImplementedException ();
7499      }
7500
7501      public override void Emit (EmitContext ec)
7502      {
7503        if (ec.EmitAccurateDebugInfo) {
7504          ec.Emit (OpCodes.Nop);
7505        }
7506
7507        base.Emit (ec);
7508      }
7509
7510      protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7511      {
7512        throw new NotImplementedException ();
7513      }
7514    }
7515
7516    sealed class ArrayForeach : IteratorStatement
7517    {
7518      TemporaryVariableReference[] lengths;
7519      Expression [] length_exprs;
7520      StatementExpression[] counter;
7521      TemporaryVariableReference[] variables;
7522
7523      TemporaryVariableReference copy;
7524
7525      public ArrayForeach (Foreach @foreach, int rank)
7526        : base (@foreach)
7527      {
7528        counter = new StatementExpression[rank];
7529        variables = new TemporaryVariableReference[rank];
7530        length_exprs = new Expression [rank];
7531
7532        //
7533        // Only use temporary length variables when dealing with
7534        // multi-dimensional arrays
7535        //
7536        if (rank > 1)
7537          lengths = new TemporaryVariableReference [rank];
7538      }
7539
7540      public override bool Resolve (BlockContext ec)
7541      {
7542        Block variables_block = for_each.variable.Block;
7543        copy = TemporaryVariableReference.Create (for_each.expr.Type, variables_block, loc);
7544        copy.Resolve (ec);
7545
7546        int rank = length_exprs.Length;
7547        Arguments list = new Arguments (rank);
7548        for (int i = 0; i < rank; i++) {
7549          var v = TemporaryVariableReference.Create (ec.BuiltinTypes.Int, variables_block, loc);
7550          variables[i] = v;
7551          counter[i] = new StatementExpression (new UnaryMutator (UnaryMutator.Mode.PostIncrement, v, Location.Null));
7552          counter[i].Resolve (ec);
7553
7554          if (rank == 1) {
7555            length_exprs [i] = new MemberAccess (copy, "Length").Resolve (ec);
7556          } else {
7557            lengths[i] = TemporaryVariableReference.Create (ec.BuiltinTypes.Int, variables_block, loc);
7558            lengths[i].Resolve (ec);
7559
7560            Arguments args = new Arguments (1);
7561            args.Add (new Argument (new IntConstant (ec.BuiltinTypes, i, loc)));
7562            length_exprs [i] = new Invocation (new MemberAccess (copy, "GetLength"), args).Resolve (ec);
7563          }
7564
7565          list.Add (new Argument (v));
7566        }
7567
7568        var access = new ElementAccess (copy, list, loc).Resolve (ec);
7569        if (access == null)
7570          return false;
7571
7572        TypeSpec var_type;
7573        if (for_each.type is VarExpr) {
7574          // Infer implicitly typed local variable from foreach array type
7575          var_type = access.Type;
7576        } else {
7577          var_type = for_each.type.ResolveAsType (ec);
7578
7579          if (var_type == null)
7580            return false;
7581
7582          access = Convert.ExplicitConversion (ec, access, var_type, loc);
7583          if (access == null)
7584            return false;
7585        }
7586
7587        for_each.variable.Type = var_type;
7588
7589        var variable_ref = new LocalVariableReference (for_each.variable, loc).Resolve (ec);
7590        if (variable_ref == null)
7591          return false;
7592
7593        for_each.body.AddScopeStatement (new StatementExpression (new CompilerAssign (variable_ref, access, Location.Null), for_each.type.Location));
7594
7595        return for_each.body.Resolve (ec);
7596      }
7597
7598      protected override void DoEmit (EmitContext ec)
7599      {
7600        copy.EmitAssign (ec, for_each.expr);
7601
7602        int rank = length_exprs.Length;
7603        Label[] test = new Label [rank];
7604        Label[] loop = new Label [rank];
7605
7606        for (int i = 0; i < rank; i++) {
7607          test [i] = ec.DefineLabel ();
7608          loop [i] = ec.DefineLabel ();
7609
7610          if (lengths != null)
7611            lengths [i].EmitAssign (ec, length_exprs [i]);
7612        }
7613
7614        IntConstant zero = new IntConstant (ec.BuiltinTypes, 0, loc);
7615        for (int i = 0; i < rank; i++) {
7616          variables [i].EmitAssign (ec, zero);
7617
7618          ec.Emit (OpCodes.Br, test [i]);
7619          ec.MarkLabel (loop [i]);
7620        }
7621
7622        for_each.body.Emit (ec);
7623
7624        ec.MarkLabel (ec.LoopBegin);
7625        ec.Mark (for_each.expr.Location);
7626
7627        for (int i = rank - 1; i >= 0; i--){
7628          counter [i].Emit (ec);
7629
7630          ec.MarkLabel (test [i]);
7631          variables [i].Emit (ec);
7632
7633          if (lengths != null)
7634            lengths [i].Emit (ec);
7635          else
7636            length_exprs [i].Emit (ec);
7637
7638          ec.Emit (OpCodes.Blt, loop [i]);
7639        }
7640
7641        ec.MarkLabel (ec.LoopEnd);
7642      }
7643    }
7644
7645    sealed class CollectionForeach : IteratorStatement, OverloadResolver.IErrorHandler
7646    {
7647      class RuntimeDispose : Using.VariableDeclaration
7648      {
7649        public RuntimeDispose (LocalVariable lv, Location loc)
7650          : base (lv, loc)
7651        {
7652          reachable = true;
7653        }
7654
7655        protected override void CheckIDiposableConversion (BlockContext bc, LocalVariable li, Expression initializer)
7656        {
7657          // Defered to runtime check
7658        }
7659
7660        protected override Statement CreateDisposeCall (BlockContext bc, LocalVariable lv)
7661        {
7662          var idt = bc.BuiltinTypes.IDisposable;
7663
7664          //
7665          // Fabricates code like
7666          //
7667          // if ((temp = vr as IDisposable) != null) temp.Dispose ();
7668          //
7669
7670          var dispose_variable = LocalVariable.CreateCompilerGenerated (idt, bc.CurrentBlock, loc);
7671
7672          var idisaposable_test = new Binary (Binary.Operator.Inequality, new CompilerAssign (
7673            dispose_variable.CreateReferenceExpression (bc, loc),
7674            new As (lv.CreateReferenceExpression (bc, loc), new TypeExpression (dispose_variable.Type, loc), loc),
7675            loc), new NullLiteral (loc));
7676
7677          var m = bc.Module.PredefinedMembers.IDisposableDispose.Resolve (loc);
7678
7679          var dispose_mg = MethodGroupExpr.CreatePredefined (m, idt, loc);
7680          dispose_mg.InstanceExpression = dispose_variable.CreateReferenceExpression (bc, loc);
7681
7682          Statement dispose = new StatementExpression (new Invocation (dispose_mg, null));
7683          return new If (idisaposable_test, dispose, loc);
7684        }
7685      }
7686
7687      LocalVariable variable;
7688      Expression expr;
7689      Statement statement;
7690      ExpressionStatement init;
7691      TemporaryVariableReference enumerator_variable;
7692      bool ambiguous_getenumerator_name;
7693
7694      public CollectionForeach (Foreach @foreach, LocalVariable var, Expression expr)
7695        : base (@foreach)
7696      {
7697        this.variable = var;
7698        this.expr = expr;
7699      }
7700
7701      void Error_WrongEnumerator (ResolveContext rc, MethodSpec enumerator)
7702      {
7703        rc.Report.SymbolRelatedToPreviousError (enumerator);
7704        rc.Report.Error (202, loc,
7705          "foreach statement requires that the return type `{0}' of `{1}' must have a suitable public MoveNext method and public Current property",
7706            enumerator.ReturnType.GetSignatureForError (), enumerator.GetSignatureForError ());
7707      }
7708
7709      MethodGroupExpr ResolveGetEnumerator (ResolveContext rc)
7710      {
7711        //
7712        // Option 1: Try to match by name GetEnumerator first
7713        //
7714        var mexpr = Expression.MemberLookup (rc, false, expr.Type,
7715          "GetEnumerator", 0, Expression.MemberLookupRestrictions.ExactArity, loc);   // TODO: What if CS0229 ?
7716
7717        var mg = mexpr as MethodGroupExpr;
7718        if (mg != null) {
7719          mg.InstanceExpression = expr;
7720          Arguments args = new Arguments (0);
7721          mg = mg.OverloadResolve (rc, ref args, this, OverloadResolver.Restrictions.ProbingOnly | OverloadResolver.Restrictions.GetEnumeratorLookup);
7722
7723          // For ambiguous GetEnumerator name warning CS0278 was reported, but Option 2 could still apply
7724          if (ambiguous_getenumerator_name)
7725            mg = null;
7726
7727          if (mg != null && !mg.BestCandidate.IsStatic && mg.BestCandidate.IsPublic) {
7728            return mg;
7729          }
7730        }
7731
7732        //
7733        // Option 2: Try to match using IEnumerable interfaces with preference of generic version
7734        //
7735        var t = expr.Type;
7736        PredefinedMember<MethodSpec> iface_candidate = null;
7737        var ptypes = rc.Module.PredefinedTypes;
7738        var gen_ienumerable = ptypes.IEnumerableGeneric;
7739        if (!gen_ienumerable.Define ())
7740          gen_ienumerable = null;
7741
7742        var ifaces = t.Interfaces;
7743        if (ifaces != null) {
7744          foreach (var iface in ifaces) {
7745            if (gen_ienumerable != null && iface.MemberDefinition == gen_ienumerable.TypeSpec.MemberDefinition) {
7746              if (iface_candidate != null && iface_candidate != rc.Module.PredefinedMembers.IEnumerableGetEnumerator) {
7747                rc.Report.SymbolRelatedToPreviousError (expr.Type);
7748                rc.Report.Error (1640, loc,
7749                  "foreach statement cannot operate on variables of type `{0}' because it contains multiple implementation of `{1}'. Try casting to a specific implementation",
7750                  expr.Type.GetSignatureForError (), gen_ienumerable.TypeSpec.GetSignatureForError ());
7751
7752                return null;
7753              }
7754
7755              // TODO: Cache this somehow
7756              iface_candidate = new PredefinedMember<MethodSpec> (rc.Module, iface,
7757                MemberFilter.Method ("GetEnumerator", 0, ParametersCompiled.EmptyReadOnlyParameters, null));
7758
7759              continue;
7760            }
7761
7762            if (iface.BuiltinType == BuiltinTypeSpec.Type.IEnumerable && iface_candidate == null) {
7763              iface_candidate = rc.Module.PredefinedMembers.IEnumerableGetEnumerator;
7764            }
7765          }
7766        }
7767
7768        if (iface_candidate == null) {
7769          if (expr.Type != InternalType.ErrorType) {
7770            rc.Report.Error (1579, loc,
7771              "foreach statement cannot operate on variables of type `{0}' because it does not contain a definition for `{1}' or is inaccessible",
7772              expr.Type.GetSignatureForError (), "GetEnumerator");
7773          }
7774
7775          return null;
7776        }
7777
7778        var method = iface_candidate.Resolve (loc);
7779        if (method == null)
7780          return null;
7781
7782        mg = MethodGroupExpr.CreatePredefined (method, expr.Type, loc);
7783        mg.InstanceExpression = expr;
7784        return mg;
7785      }
7786
7787      MethodGroupExpr ResolveMoveNext (ResolveContext rc, MethodSpec enumerator)
7788      {
7789        var ms = MemberCache.FindMember (enumerator.ReturnType,
7790          MemberFilter.Method ("MoveNext", 0, ParametersCompiled.EmptyReadOnlyParameters, rc.BuiltinTypes.Bool),
7791          BindingRestriction.InstanceOnly) as MethodSpec;
7792
7793        if (ms == null || !ms.IsPublic) {
7794          Error_WrongEnumerator (rc, enumerator);
7795          return null;
7796        }
7797
7798        return MethodGroupExpr.CreatePredefined (ms, enumerator.ReturnType, expr.Location);
7799      }
7800
7801      PropertySpec ResolveCurrent (ResolveContext rc, MethodSpec enumerator)
7802      {
7803        var ps = MemberCache.FindMember (enumerator.ReturnType,
7804          MemberFilter.Property ("Current", null),
7805          BindingRestriction.InstanceOnly) as PropertySpec;
7806
7807        if (ps == null || !ps.IsPublic) {
7808          Error_WrongEnumerator (rc, enumerator);
7809          return null;
7810        }
7811
7812        return ps;
7813      }
7814
7815      public override bool Resolve (BlockContext ec)
7816      {
7817        bool is_dynamic = expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
7818
7819        if (is_dynamic) {
7820          expr = Convert.ImplicitConversionRequired (ec, expr, ec.BuiltinTypes.IEnumerable, loc);
7821        } else if (expr.Type.IsNullableType) {
7822          expr = new Nullable.UnwrapCall (expr).Resolve (ec);
7823        }
7824
7825        var get_enumerator_mg = ResolveGetEnumerator (ec);
7826        if (get_enumerator_mg == null) {
7827          return false;
7828        }
7829
7830        var get_enumerator = get_enumerator_mg.BestCandidate;
7831        enumerator_variable = TemporaryVariableReference.Create (get_enumerator.ReturnType, variable.Block, loc);
7832        enumerator_variable.Resolve (ec);
7833
7834        // Prepare bool MoveNext ()
7835        var move_next_mg = ResolveMoveNext (ec, get_enumerator);
7836        if (move_next_mg == null) {
7837          return false;
7838        }
7839
7840        move_next_mg.InstanceExpression = enumerator_variable;
7841
7842        // Prepare ~T~ Current { get; }
7843        var current_prop = ResolveCurrent (ec, get_enumerator);
7844        if (current_prop == null) {
7845          return false;
7846        }
7847
7848        var current_pe = new PropertyExpr (current_prop, loc) { InstanceExpression = enumerator_variable }.Resolve (ec);
7849        if (current_pe == null)
7850          return false;
7851
7852        VarExpr ve = for_each.type as VarExpr;
7853
7854        if (ve != null) {
7855          if (is_dynamic) {
7856            // Source type is dynamic, set element type to dynamic too
7857            variable.Type = ec.BuiltinTypes.Dynamic;
7858          } else {
7859            // Infer implicitly typed local variable from foreach enumerable type
7860            variable.Type = current_pe.Type;
7861          }
7862        } else {
7863          if (is_dynamic) {
7864            // Explicit cast of dynamic collection elements has to be done at runtime
7865            current_pe = EmptyCast.Create (current_pe, ec.BuiltinTypes.Dynamic);
7866          }
7867
7868          variable.Type = for_each.type.ResolveAsType (ec);
7869
7870          if (variable.Type == null)
7871            return false;
7872
7873          current_pe = Convert.ExplicitConversion (ec, current_pe, variable.Type, loc);
7874          if (current_pe == null)
7875            return false;
7876        }
7877
7878        var variable_ref = new LocalVariableReference (variable, loc).Resolve (ec);
7879        if (variable_ref == null)
7880          return false;
7881
7882        for_each.body.AddScopeStatement (new StatementExpression (new CompilerAssign (variable_ref, current_pe, Location.Null), for_each.type.Location));
7883
7884        var init = new Invocation.Predefined (get_enumerator_mg, null);
7885
7886        statement = new While (new BooleanExpression (new Invocation (move_next_mg, null)),
7887           for_each.body, Location.Null);
7888
7889        var enum_type = enumerator_variable.Type;
7890
7891        //
7892        // Add Dispose method call when enumerator can be IDisposable
7893        //
7894        if (!enum_type.ImplementsInterface (ec.BuiltinTypes.IDisposable, false)) {
7895          if (!enum_type.IsSealed && !TypeSpec.IsValueType (enum_type)) {
7896            //
7897            // Runtime Dispose check
7898            //
7899            var vd = new RuntimeDispose (enumerator_variable.LocalInfo, Location.Null);
7900            vd.Initializer = init;
7901            statement = new Using (vd, statement, Location.Null);
7902          } else {
7903            //
7904            // No Dispose call needed
7905            //
7906            this.init = new SimpleAssign (enumerator_variable, init, Location.Null);
7907            this.init.Resolve (ec);
7908          }
7909        } else {
7910          //
7911          // Static Dispose check
7912          //
7913          var vd = new Using.VariableDeclaration (enumerator_variable.LocalInfo, Location.Null);
7914          vd.Initializer = init;
7915          statement = new Using (vd, statement, Location.Null);
7916        }
7917
7918        return statement.Resolve (ec);
7919      }
7920
7921      protected override void DoEmit (EmitContext ec)
7922      {
7923        enumerator_variable.LocalInfo.CreateBuilder (ec);
7924
7925        if (init != null)
7926          init.EmitStatement (ec);
7927
7928        statement.Emit (ec);
7929      }
7930
7931      #region IErrorHandler Members
7932
7933      bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext ec, MemberSpec best, MemberSpec ambiguous)
7934      {
7935        ec.Report.SymbolRelatedToPreviousError (best);
7936        ec.Report.Warning (278, 2, expr.Location,
7937          "`{0}' contains ambiguous implementation of `{1}' pattern. Method `{2}' is ambiguous with method `{3}'",
7938          expr.Type.GetSignatureForError (), "enumerable",
7939          best.GetSignatureForError (), ambiguous.GetSignatureForError ());
7940
7941        ambiguous_getenumerator_name = true;
7942        return true;
7943      }
7944
7945      bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
7946      {
7947        return false;
7948      }
7949
7950      bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
7951      {
7952        return false;
7953      }
7954
7955      bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
7956      {
7957        return false;
7958      }
7959
7960      #endregion
7961    }
7962
7963    Expression type;
7964    LocalVariable variable;
7965    Expression expr;
7966    Block body;
7967
7968    public Foreach (Expression type, LocalVariable var, Expression expr, Statement stmt, Block body, Location l)
7969      : base (stmt)
7970    {
7971      this.type = type;
7972      this.variable = var;
7973      this.expr = expr;
7974      this.body = body;
7975      loc = l;
7976    }
7977
7978    public Expression Expr {
7979      get { return expr; }
7980    }
7981
7982    public Expression TypeExpression {
7983      get { return type; }
7984    }
7985
7986    public LocalVariable Variable {
7987      get { return variable; }
7988    }
7989
7990    public override Reachability MarkReachable (Reachability rc)
7991    {
7992      base.MarkReachable (rc);
7993
7994      body.MarkReachable (rc);
7995
7996      return rc;
7997    }
7998
7999    public override bool Resolve (BlockContext ec)
8000    {
8001      expr = expr.Resolve (ec);
8002      if (expr == null)
8003        return false;
8004
8005      if (expr.IsNull) {
8006        ec.Report.Error (186, loc, "Use of null is not valid in this context");
8007        return false;
8008      }
8009
8010      body.AddStatement (Statement);
8011
8012      if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.String) {
8013        Statement = new ArrayForeach (this, 1);
8014      } else if (expr.Type is ArrayContainer) {
8015        Statement = new ArrayForeach (this, ((ArrayContainer) expr.Type).Rank);
8016      } else {
8017        if (expr.eclass == ExprClass.MethodGroup || expr is AnonymousMethodExpression) {
8018          ec.Report.Error (446, expr.Location, "Foreach statement cannot operate on a `{0}'",
8019            expr.ExprClassName);
8020          return false;
8021        }
8022
8023        Statement = new CollectionForeach (this, variable, expr);
8024      }
8025
8026      return base.Resolve (ec);
8027    }
8028
8029    protected override void DoEmit (EmitContext ec)
8030    {
8031      Label old_begin = ec.LoopBegin, old_end = ec.LoopEnd;
8032      ec.LoopBegin = ec.DefineLabel ();
8033      ec.LoopEnd = ec.DefineLabel ();
8034
8035      if (!(Statement is Block))
8036        ec.BeginCompilerScope ();
8037
8038      variable.CreateBuilder (ec);
8039
8040      Statement.Emit (ec);
8041
8042      if (!(Statement is Block))
8043        ec.EndScope ();
8044
8045      ec.LoopBegin = old_begin;
8046      ec.LoopEnd = old_end;
8047    }
8048
8049    protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
8050    {
8051      expr.FlowAnalysis (fc);
8052
8053      var da = fc.BranchDefiniteAssignment ();
8054      body.FlowAnalysis (fc);
8055      fc.DefiniteAssignment = da;
8056      return false;
8057    }
8058
8059    protected override void CloneTo (CloneContext clonectx, Statement t)
8060    {
8061      Foreach target = (Foreach) t;
8062
8063      target.type = type.Clone (clonectx);
8064      target.expr = expr.Clone (clonectx);
8065      target.body = (Block) body.Clone (clonectx);
8066      target.Statement = Statement.Clone (clonectx);
8067    }
8068   
8069    public override object Accept (StructuralVisitor visitor)
8070    {
8071      return visitor.Visit (this);
8072    }
8073  }
8074}
Note: See TracBrowser for help on using the repository browser.