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