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