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