Merge pull request #901 from Blewzman/FixAggregateExceptionGetBaseException
[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)
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                         base.MarkReachable (rc);
2821
2822                         if (scope_initializers != null) {
2823                                 foreach (var si in scope_initializers)
2824                                         si.MarkReachable (rc);
2825                         }
2826
2827                         foreach (var s in statements) {
2828                                 rc = s.MarkReachable (rc);
2829                                 if (rc.IsUnreachable) {
2830                                         if ((flags & Flags.ReachableEnd) != 0)
2831                                                 return new Reachability ();
2832
2833                                         return rc;
2834                                 }
2835                         }
2836
2837                         flags |= Flags.ReachableEnd;
2838
2839                         return rc;
2840                 }
2841
2842                 public override bool Resolve (BlockContext bc)
2843                 {
2844                         if ((flags & Flags.Resolved) != 0)
2845                                 return true;
2846
2847                         Block prev_block = bc.CurrentBlock;
2848                         bc.CurrentBlock = this;
2849
2850                         //
2851                         // Compiler generated scope statements
2852                         //
2853                         if (scope_initializers != null) {
2854                                 for (resolving_init_idx = 0; resolving_init_idx < scope_initializers.Count; ++resolving_init_idx) {
2855                                         scope_initializers[resolving_init_idx.Value].Resolve (bc);
2856                                 }
2857
2858                                 resolving_init_idx = null;
2859                         }
2860
2861                         bool ok = true;
2862                         int statement_count = statements.Count;
2863                         for (int ix = 0; ix < statement_count; ix++){
2864                                 Statement s = statements [ix];
2865
2866                                 if (!s.Resolve (bc)) {
2867                                         ok = false;
2868                                         if (!bc.IsInProbingMode)
2869                                                 statements [ix] = new EmptyStatement (s.loc);
2870
2871                                         continue;
2872                                 }
2873                         }
2874
2875                         bc.CurrentBlock = prev_block;
2876
2877                         flags |= Flags.Resolved;
2878                         return ok;
2879                 }
2880
2881                 protected override void DoEmit (EmitContext ec)
2882                 {
2883                         for (int ix = 0; ix < statements.Count; ix++){
2884                                 statements [ix].Emit (ec);
2885                         }
2886                 }
2887
2888                 public override void Emit (EmitContext ec)
2889                 {
2890                         if (scope_initializers != null)
2891                                 EmitScopeInitializers (ec);
2892
2893                         DoEmit (ec);
2894                 }
2895
2896                 protected void EmitScopeInitializers (EmitContext ec)
2897                 {
2898                         foreach (Statement s in scope_initializers)
2899                                 s.Emit (ec);
2900                 }
2901
2902                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
2903                 {
2904                         if (scope_initializers != null) {
2905                                 foreach (var si in scope_initializers)
2906                                         si.FlowAnalysis (fc);
2907                         }
2908
2909                         return DoFlowAnalysis (fc, 0);  
2910                 }
2911
2912                 bool DoFlowAnalysis (FlowAnalysisContext fc, int startIndex)
2913                 {
2914                         bool end_unreachable = !reachable;
2915                         for (; startIndex < statements.Count; ++startIndex) {
2916                                 var s = statements[startIndex];
2917
2918                                 end_unreachable = s.FlowAnalysis (fc);
2919                                 if (s.IsUnreachable) {
2920                                         statements[startIndex] = new EmptyStatement (s.loc);
2921                                         continue;
2922                                 }
2923
2924                                 //
2925                                 // Statement end reachability is needed mostly due to goto support. Consider
2926                                 //
2927                                 // if (cond) {
2928                                 //    goto X;
2929                                 // } else {
2930                                 //    goto Y;
2931                                 // }
2932                                 // X:
2933                                 //
2934                                 // X label is reachable only via goto not as another statement after if. We need
2935                                 // this for flow-analysis only to carry variable info correctly.
2936                                 //
2937                                 if (end_unreachable) {
2938                                         for (++startIndex; startIndex < statements.Count; ++startIndex) {
2939                                                 s = statements[startIndex];
2940                                                 if (s is SwitchLabel) {
2941                                                         s.FlowAnalysis (fc);
2942                                                         break;
2943                                                 }
2944
2945                                                 if (s.IsUnreachable) {
2946                                                         s.FlowAnalysis (fc);
2947                                                         statements[startIndex] = new EmptyStatement (s.loc);
2948                                                 }
2949                                         }
2950                                 }
2951                         }
2952
2953                         //
2954                         // The condition should be true unless there is forward jumping goto
2955                         // 
2956                         // if (this is ExplicitBlock && end_unreachable != Explicit.HasReachableClosingBrace)
2957                         //      Debug.Fail ();
2958
2959                         return !Explicit.HasReachableClosingBrace;
2960                 }
2961
2962                 public void ScanGotoJump (Statement label)
2963                 {
2964                         int i;
2965                         for (i = 0; i < statements.Count; ++i) {
2966                                 if (statements[i] == label)
2967                                         break;
2968                         }
2969
2970                         var rc = new Reachability ();
2971                         for (++i; i < statements.Count; ++i) {
2972                                 var s = statements[i];
2973                                 rc = s.MarkReachable (rc);
2974                                 if (rc.IsUnreachable)
2975                                         return;
2976                         }
2977
2978                         flags |= Flags.ReachableEnd;
2979                 }
2980
2981                 public void ScanGotoJump (Statement label, FlowAnalysisContext fc)
2982                 {
2983                         int i;
2984                         for (i = 0; i < statements.Count; ++i) {
2985                                 if (statements[i] == label)
2986                                         break;
2987                         }
2988
2989                         DoFlowAnalysis (fc, ++i);
2990                 }
2991
2992 #if DEBUG
2993                 public override string ToString ()
2994                 {
2995                         return String.Format ("{0}: ID={1} Clone={2} Location={3}", GetType (), ID, clone_id != 0, StartLocation);
2996                 }
2997 #endif
2998
2999                 protected override void CloneTo (CloneContext clonectx, Statement t)
3000                 {
3001                         Block target = (Block) t;
3002 #if DEBUG
3003                         target.clone_id = ++clone_id_counter;
3004 #endif
3005
3006                         clonectx.AddBlockMap (this, target);
3007                         if (original != this)
3008                                 clonectx.AddBlockMap (original, target);
3009
3010                         target.ParametersBlock = (ParametersBlock) (ParametersBlock == this ? target : clonectx.RemapBlockCopy (ParametersBlock));
3011                         target.Explicit = (ExplicitBlock) (Explicit == this ? target : clonectx.LookupBlock (Explicit));
3012
3013                         if (Parent != null)
3014                                 target.Parent = clonectx.RemapBlockCopy (Parent);
3015
3016                         target.statements = new List<Statement> (statements.Count);
3017                         foreach (Statement s in statements)
3018                                 target.statements.Add (s.Clone (clonectx));
3019                 }
3020
3021                 public override object Accept (StructuralVisitor visitor)
3022                 {
3023                         return visitor.Visit (this);
3024                 }
3025         }
3026
3027         public class ExplicitBlock : Block
3028         {
3029                 protected AnonymousMethodStorey am_storey;
3030
3031                 public ExplicitBlock (Block parent, Location start, Location end)
3032                         : this (parent, (Flags) 0, start, end)
3033                 {
3034                 }
3035
3036                 public ExplicitBlock (Block parent, Flags flags, Location start, Location end)
3037                         : base (parent, flags, start, end)
3038                 {
3039                         this.Explicit = this;
3040                 }
3041
3042                 #region Properties
3043
3044                 public AnonymousMethodStorey AnonymousMethodStorey {
3045                         get {
3046                                 return am_storey;
3047                         }
3048                 }
3049
3050                 public bool HasAwait {
3051                         get {
3052                                 return (flags & Flags.AwaitBlock) != 0;
3053                         }
3054                 }
3055
3056                 public bool HasCapturedThis {
3057                         set {
3058                                 flags = value ? flags | Flags.HasCapturedThis : flags & ~Flags.HasCapturedThis;
3059                         }
3060                         get {
3061                                 return (flags & Flags.HasCapturedThis) != 0;
3062                         }
3063                 }
3064
3065                 //
3066                 // Used to indicate that the block has reference to parent
3067                 // block and cannot be made static when defining anonymous method
3068                 //
3069                 public bool HasCapturedVariable {
3070                         set {
3071                                 flags = value ? flags | Flags.HasCapturedVariable : flags & ~Flags.HasCapturedVariable;
3072                         }
3073                         get {
3074                                 return (flags & Flags.HasCapturedVariable) != 0;
3075                         }
3076                 }
3077
3078                 public bool HasReachableClosingBrace {
3079                     get {
3080                         return (flags & Flags.ReachableEnd) != 0;
3081                     }
3082                         set {
3083                                 flags = value ? flags | Flags.ReachableEnd : flags & ~Flags.ReachableEnd;
3084                         }
3085                 }
3086
3087                 public bool HasYield {
3088                         get {
3089                                 return (flags & Flags.YieldBlock) != 0;
3090                         }
3091                 }
3092
3093                 #endregion
3094
3095                 //
3096                 // Creates anonymous method storey in current block
3097                 //
3098                 public AnonymousMethodStorey CreateAnonymousMethodStorey (ResolveContext ec)
3099                 {
3100                         //
3101                         // Return same story for iterator and async blocks unless we are
3102                         // in nested anonymous method
3103                         //
3104                         if (ec.CurrentAnonymousMethod is StateMachineInitializer && ParametersBlock.Original == ec.CurrentAnonymousMethod.Block.Original)
3105                                 return ec.CurrentAnonymousMethod.Storey;
3106
3107                         if (am_storey == null) {
3108                                 MemberBase mc = ec.MemberContext as MemberBase;
3109
3110                                 //
3111                                 // Creates anonymous method storey for this block
3112                                 //
3113                                 am_storey = new AnonymousMethodStorey (this, ec.CurrentMemberDefinition.Parent.PartialContainer, mc, ec.CurrentTypeParameters, "AnonStorey", MemberKind.Class);
3114                         }
3115
3116                         return am_storey;
3117                 }
3118
3119                 public override void Emit (EmitContext ec)
3120                 {
3121                         if (am_storey != null) {
3122                                 DefineStoreyContainer (ec, am_storey);
3123                                 am_storey.EmitStoreyInstantiation (ec, this);
3124                         }
3125
3126                         if (scope_initializers != null)
3127                                 EmitScopeInitializers (ec);
3128
3129                         if (ec.EmitAccurateDebugInfo && !IsCompilerGenerated && ec.Mark (StartLocation)) {
3130                                 ec.Emit (OpCodes.Nop);
3131                         }
3132
3133                         if (Parent != null)
3134                                 ec.BeginScope ();
3135
3136                         DoEmit (ec);
3137
3138                         if (Parent != null)
3139                                 ec.EndScope ();
3140
3141                         if (ec.EmitAccurateDebugInfo && HasReachableClosingBrace && !(this is ParametersBlock) &&
3142                                 !IsCompilerGenerated && ec.Mark (EndLocation)) {
3143                                 ec.Emit (OpCodes.Nop);
3144                         }
3145                 }
3146
3147                 protected void DefineStoreyContainer (EmitContext ec, AnonymousMethodStorey storey)
3148                 {
3149                         if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.Storey != null) {
3150                                 storey.SetNestedStoryParent (ec.CurrentAnonymousMethod.Storey);
3151                                 storey.Mutator = ec.CurrentAnonymousMethod.Storey.Mutator;
3152                         }
3153
3154                         //
3155                         // Creates anonymous method storey
3156                         //
3157                         storey.CreateContainer ();
3158                         storey.DefineContainer ();
3159
3160                         if (Original.Explicit.HasCapturedThis && Original.ParametersBlock.TopBlock.ThisReferencesFromChildrenBlock != null) {
3161
3162                                 //
3163                                 // Only first storey in path will hold this reference. All children blocks will
3164                                 // reference it indirectly using $ref field
3165                                 //
3166                                 for (Block b = Original.Explicit; b != null; b = b.Parent) {
3167                                         if (b.Parent != null) {
3168                                                 var s = b.Parent.Explicit.AnonymousMethodStorey;
3169                                                 if (s != null) {
3170                                                         storey.HoistedThis = s.HoistedThis;
3171                                                         break;
3172                                                 }
3173                                         }
3174
3175                                         if (b.Explicit == b.Explicit.ParametersBlock && b.Explicit.ParametersBlock.StateMachine != null) {
3176                                                 if (storey.HoistedThis == null)
3177                                                         storey.HoistedThis = b.Explicit.ParametersBlock.StateMachine.HoistedThis;
3178
3179                                                 if (storey.HoistedThis != null)
3180                                                         break;
3181                                         }
3182                                 }
3183                                 
3184                                 //
3185                                 // We are the first storey on path and 'this' has to be hoisted
3186                                 //
3187                                 if (storey.HoistedThis == null) {
3188                                         foreach (ExplicitBlock ref_block in Original.ParametersBlock.TopBlock.ThisReferencesFromChildrenBlock) {
3189                                                 //
3190                                                 // ThisReferencesFromChildrenBlock holds all reference even if they
3191                                                 // are not on this path. It saves some memory otherwise it'd have to
3192                                                 // be in every explicit block. We run this check to see if the reference
3193                                                 // is valid for this storey
3194                                                 //
3195                                                 Block block_on_path = ref_block;
3196                                                 for (; block_on_path != null && block_on_path != Original; block_on_path = block_on_path.Parent);
3197
3198                                                 if (block_on_path == null)
3199                                                         continue;
3200
3201                                                 if (storey.HoistedThis == null) {
3202                                                         storey.AddCapturedThisField (ec, null);
3203                                                 }
3204
3205                                                 for (ExplicitBlock b = ref_block; b.AnonymousMethodStorey != storey; b = b.Parent.Explicit) {
3206                                                         ParametersBlock pb;
3207
3208                                                         if (b.AnonymousMethodStorey != null) {
3209                                                                 //
3210                                                                 // Don't add storey cross reference for `this' when the storey ends up not
3211                                                                 // beeing attached to any parent
3212                                                                 //
3213                                                                 if (b.ParametersBlock.StateMachine == null) {
3214                                                                         AnonymousMethodStorey s = null;
3215                                                                         for (Block ab = b.AnonymousMethodStorey.OriginalSourceBlock.Parent; ab != null; ab = ab.Parent) {
3216                                                                                 s = ab.Explicit.AnonymousMethodStorey;
3217                                                                                 if (s != null)
3218                                                                                         break;
3219                                                                         }
3220
3221                                                                         // Needs to be in sync with AnonymousMethodBody::DoCreateMethodHost
3222                                                                         if (s == null) {
3223                                                                                 var parent = storey == null || storey.Kind == MemberKind.Struct ? null : storey;
3224                                                                                 b.AnonymousMethodStorey.AddCapturedThisField (ec, parent);
3225                                                                                 break;
3226                                                                         }
3227                                                                 }
3228
3229                                                                 b.AnonymousMethodStorey.AddParentStoreyReference (ec, storey);
3230                                                                 b.AnonymousMethodStorey.HoistedThis = storey.HoistedThis;
3231
3232                                                                 //
3233                                                                 // Stop propagation inside same top block
3234                                                                 //
3235                                                                 if (b.ParametersBlock == ParametersBlock.Original)
3236                                                                         break;
3237
3238                                                                 b = b.ParametersBlock;
3239                                                         }
3240
3241                                                         pb = b as ParametersBlock;
3242                                                         if (pb != null && pb.StateMachine != null) {
3243                                                                 if (pb.StateMachine == storey)
3244                                                                         break;
3245
3246                                                                 //
3247                                                                 // If we are state machine with no parent. We can hook into parent without additional
3248                                                                 // reference and capture this directly
3249                                                                 //
3250                                                                 ExplicitBlock parent_storey_block = pb;
3251                                                                 while (parent_storey_block.Parent != null) {
3252                                                                         parent_storey_block = parent_storey_block.Parent.Explicit;
3253                                                                         if (parent_storey_block.AnonymousMethodStorey != null) {
3254                                                                                 break;
3255                                                                         }
3256                                                                 }
3257
3258                                                                 if (parent_storey_block.AnonymousMethodStorey == null) {
3259                                                                         pb.StateMachine.AddCapturedThisField (ec, null);
3260                                                                         b.HasCapturedThis = true;
3261                                                                         continue;
3262                                                                 }
3263
3264                                                                 pb.StateMachine.AddParentStoreyReference (ec, storey);
3265                                                         }
3266                                                         
3267                                                         b.HasCapturedVariable = true;
3268                                                 }
3269                                         }
3270                                 }
3271                         }
3272
3273                         var ref_blocks = storey.ReferencesFromChildrenBlock;
3274                         if (ref_blocks != null) {
3275                                 foreach (ExplicitBlock ref_block in ref_blocks) {
3276                                         for (ExplicitBlock b = ref_block; b.AnonymousMethodStorey != storey; b = b.Parent.Explicit) {
3277                                                 if (b.AnonymousMethodStorey != null) {
3278                                                         b.AnonymousMethodStorey.AddParentStoreyReference (ec, storey);
3279
3280                                                         //
3281                                                         // Stop propagation inside same top block
3282                                                         //
3283                                                         if (b.ParametersBlock == ParametersBlock.Original)
3284                                                                 break;
3285
3286                                                         b = b.ParametersBlock;
3287                                                 }
3288
3289                                                 var pb = b as ParametersBlock;
3290                                                 if (pb != null && pb.StateMachine != null) {
3291                                                         if (pb.StateMachine == storey)
3292                                                                 break;
3293
3294                                                         pb.StateMachine.AddParentStoreyReference (ec, storey);
3295                                                 }
3296
3297                                                 b.HasCapturedVariable = true;
3298                                         }
3299                                 }
3300                         }
3301
3302                         storey.Define ();
3303                         storey.PrepareEmit ();
3304                         storey.Parent.PartialContainer.AddCompilerGeneratedClass (storey);
3305                 }
3306
3307                 public void RegisterAsyncAwait ()
3308                 {
3309                         var block = this;
3310                         while ((block.flags & Flags.AwaitBlock) == 0) {
3311                                 block.flags |= Flags.AwaitBlock;
3312
3313                                 if (block is ParametersBlock)
3314                                         return;
3315
3316                                 block = block.Parent.Explicit;
3317                         }
3318                 }
3319
3320                 public void RegisterIteratorYield ()
3321                 {
3322                         ParametersBlock.TopBlock.IsIterator = true;
3323
3324                         var block = this;
3325                         while ((block.flags & Flags.YieldBlock) == 0) {
3326                                 block.flags |= Flags.YieldBlock;
3327
3328                                 if (block.Parent == null)
3329                                         return;
3330
3331                                 block = block.Parent.Explicit;
3332                         }
3333                 }
3334
3335                 public void SetCatchBlock ()
3336                 {
3337                         flags |= Flags.CatchBlock;
3338                 }
3339
3340                 public void SetFinallyBlock ()
3341                 {
3342                         flags |= Flags.FinallyBlock;
3343                 }
3344
3345                 public void WrapIntoDestructor (TryFinally tf, ExplicitBlock tryBlock)
3346                 {
3347                         tryBlock.statements = statements;
3348                         statements = new List<Statement> (1);
3349                         statements.Add (tf);
3350                 }
3351         }
3352
3353         //
3354         // ParametersBlock was introduced to support anonymous methods
3355         // and lambda expressions
3356         // 
3357         public class ParametersBlock : ExplicitBlock
3358         {
3359                 public class ParameterInfo : INamedBlockVariable
3360                 {
3361                         readonly ParametersBlock block;
3362                         readonly int index;
3363                         public VariableInfo VariableInfo;
3364                         bool is_locked;
3365
3366                         public ParameterInfo (ParametersBlock block, int index)
3367                         {
3368                                 this.block = block;
3369                                 this.index = index;
3370                         }
3371
3372                         #region Properties
3373
3374                         public ParametersBlock Block {
3375                                 get {
3376                                         return block;
3377                                 }
3378                         }
3379
3380                         Block INamedBlockVariable.Block {
3381                                 get {
3382                                         return block;
3383                                 }
3384                         }
3385
3386                         public bool IsDeclared {
3387                                 get {
3388                                         return true;
3389                                 }
3390                         }
3391
3392                         public bool IsParameter {
3393                                 get {
3394                                         return true;
3395                                 }
3396                         }
3397
3398                         public bool IsLocked {
3399                                 get {
3400                                         return is_locked;
3401                                 }
3402                                 set {
3403                                         is_locked = value;
3404                                 }
3405                         }
3406
3407                         public Location Location {
3408                                 get {
3409                                         return Parameter.Location;
3410                                 }
3411                         }
3412
3413                         public Parameter Parameter {
3414                                 get {
3415                                         return block.Parameters [index];
3416                                 }
3417                         }
3418
3419                         public TypeSpec ParameterType {
3420                                 get {
3421                                         return Parameter.Type;
3422                                 }
3423                         }
3424
3425                         #endregion
3426
3427                         public Expression CreateReferenceExpression (ResolveContext rc, Location loc)
3428                         {
3429                                 return new ParameterReference (this, loc);
3430                         }
3431                 }
3432
3433                 // 
3434                 // Block is converted into an expression
3435                 //
3436                 sealed class BlockScopeExpression : Expression
3437                 {
3438                         Expression child;
3439                         readonly ParametersBlock block;
3440
3441                         public BlockScopeExpression (Expression child, ParametersBlock block)
3442                         {
3443                                 this.child = child;
3444                                 this.block = block;
3445                         }
3446
3447                         public override bool ContainsEmitWithAwait ()
3448                         {
3449                                 return child.ContainsEmitWithAwait ();
3450                         }
3451
3452                         public override Expression CreateExpressionTree (ResolveContext ec)
3453                         {
3454                                 throw new NotSupportedException ();
3455                         }
3456
3457                         protected override Expression DoResolve (ResolveContext ec)
3458                         {
3459                                 if (child == null)
3460                                         return null;
3461
3462                                 child = child.Resolve (ec);
3463                                 if (child == null)
3464                                         return null;
3465
3466                                 eclass = child.eclass;
3467                                 type = child.Type;
3468                                 return this;
3469                         }
3470
3471                         public override void Emit (EmitContext ec)
3472                         {
3473                                 block.EmitScopeInitializers (ec);
3474                                 child.Emit (ec);
3475                         }
3476                 }
3477
3478                 protected ParametersCompiled parameters;
3479                 protected ParameterInfo[] parameter_info;
3480                 protected bool resolved;
3481                 protected ToplevelBlock top_block;
3482                 protected StateMachine state_machine;
3483                 protected Dictionary<string, object> labels;
3484
3485                 public ParametersBlock (Block parent, ParametersCompiled parameters, Location start, Flags flags = 0)
3486                         : base (parent, 0, start, start)
3487                 {
3488                         if (parameters == null)
3489                                 throw new ArgumentNullException ("parameters");
3490
3491                         this.parameters = parameters;
3492                         ParametersBlock = this;
3493
3494                         this.flags |= flags | (parent.ParametersBlock.flags & (Flags.YieldBlock | Flags.AwaitBlock));
3495
3496                         this.top_block = parent.ParametersBlock.top_block;
3497                         ProcessParameters ();
3498                 }
3499
3500                 protected ParametersBlock (ParametersCompiled parameters, Location start)
3501                         : base (null, 0, start, start)
3502                 {
3503                         if (parameters == null)
3504                                 throw new ArgumentNullException ("parameters");
3505
3506                         this.parameters = parameters;
3507                         ParametersBlock = this;
3508                 }
3509
3510                 //
3511                 // It's supposed to be used by method body implementation of anonymous methods
3512                 //
3513                 protected ParametersBlock (ParametersBlock source, ParametersCompiled parameters)
3514                         : base (null, 0, source.StartLocation, source.EndLocation)
3515                 {
3516                         this.parameters = parameters;
3517                         this.statements = source.statements;
3518                         this.scope_initializers = source.scope_initializers;
3519
3520                         this.resolved = true;
3521                         this.reachable = source.reachable;
3522                         this.am_storey = source.am_storey;
3523                         this.state_machine = source.state_machine;
3524                         this.flags = source.flags & Flags.ReachableEnd;
3525
3526                         ParametersBlock = this;
3527
3528                         //
3529                         // Overwrite original for comparison purposes when linking cross references
3530                         // between anonymous methods
3531                         //
3532                         Original = source.Original;
3533                 }
3534
3535                 #region Properties
3536
3537                 public bool IsAsync {
3538                         get {
3539                                 return (flags & Flags.HasAsyncModifier) != 0;
3540                         }
3541                         set {
3542                                 flags = value ? flags | Flags.HasAsyncModifier : flags & ~Flags.HasAsyncModifier;
3543                         }
3544                 }
3545
3546                 //
3547                 // Block has been converted to expression tree
3548                 //
3549                 public bool IsExpressionTree {
3550                         get {
3551                                 return (flags & Flags.IsExpressionTree) != 0;
3552                         }
3553                 }
3554
3555                 //
3556                 // The parameters for the block.
3557                 //
3558                 public ParametersCompiled Parameters {
3559                         get {
3560                                 return parameters;
3561                         }
3562                 }
3563
3564                 public StateMachine StateMachine {
3565                         get {
3566                                 return state_machine;
3567                         }
3568                 }
3569
3570                 public ToplevelBlock TopBlock {
3571                         get {
3572                                 return top_block;
3573                         }
3574                 }
3575
3576                 public bool Resolved {
3577                         get {
3578                                 return (flags & Flags.Resolved) != 0;
3579                         }
3580                 }
3581
3582                 public int TemporaryLocalsCount { get; set; }
3583
3584                 #endregion
3585
3586                 //
3587                 // Checks whether all `out' parameters have been assigned.
3588                 //
3589                 public void CheckControlExit (FlowAnalysisContext fc)
3590                 {
3591                         CheckControlExit (fc, fc.DefiniteAssignment);
3592                 }
3593
3594                 public virtual void CheckControlExit (FlowAnalysisContext fc, DefiniteAssignmentBitSet dat)
3595                 {
3596                         if (parameter_info == null)
3597                                 return;
3598
3599                         foreach (var p in parameter_info) {
3600                                 if (p.VariableInfo == null)
3601                                         continue;
3602
3603                                 if (p.VariableInfo.IsAssigned (dat))
3604                                         continue;
3605
3606                                 fc.Report.Error (177, p.Location,
3607                                         "The out parameter `{0}' must be assigned to before control leaves the current method",
3608                                         p.Parameter.Name);
3609                         }                                       
3610                 }
3611
3612                 protected override void CloneTo (CloneContext clonectx, Statement t)
3613                 {
3614                         base.CloneTo (clonectx, t);
3615
3616                         var target = (ParametersBlock) t;
3617
3618                         //
3619                         // Clone label statements as well as they contain block reference
3620                         //
3621                         var pb = this;
3622                         while (true) {
3623                                 if (pb.labels != null) {
3624                                         target.labels = new Dictionary<string, object> ();
3625
3626                                         foreach (var entry in pb.labels) {
3627                                                 var list = entry.Value as List<LabeledStatement>;
3628
3629                                                 if (list != null) {
3630                                                         var list_clone = new List<LabeledStatement> ();
3631                                                         foreach (var lentry in list) {
3632                                                                 list_clone.Add (RemapLabeledStatement (lentry, lentry.Block, clonectx.RemapBlockCopy (lentry.Block)));
3633                                                         }
3634
3635                                                         target.labels.Add (entry.Key, list_clone);
3636                                                 } else {
3637                                                         var labeled = (LabeledStatement) entry.Value;
3638                                                         target.labels.Add (entry.Key, RemapLabeledStatement (labeled, labeled.Block, clonectx.RemapBlockCopy (labeled.Block)));
3639                                                 }
3640                                         }
3641
3642                                         break;
3643                                 }
3644
3645                                 if (pb.Parent == null)
3646                                         break;
3647
3648                                 pb = pb.Parent.ParametersBlock;
3649                         }
3650                 }
3651
3652                 public override Expression CreateExpressionTree (ResolveContext ec)
3653                 {
3654                         if (statements.Count == 1) {
3655                                 Expression expr = statements[0].CreateExpressionTree (ec);
3656                                 if (scope_initializers != null)
3657                                         expr = new BlockScopeExpression (expr, this);
3658
3659                                 return expr;
3660                         }
3661
3662                         return base.CreateExpressionTree (ec);
3663                 }
3664
3665                 public override void Emit (EmitContext ec)
3666                 {
3667                         if (state_machine != null && state_machine.OriginalSourceBlock != this) {
3668                                 DefineStoreyContainer (ec, state_machine);
3669                                 state_machine.EmitStoreyInstantiation (ec, this);
3670                         }
3671
3672                         base.Emit (ec);
3673                 }
3674
3675                 public void EmitEmbedded (EmitContext ec)
3676                 {
3677                         if (state_machine != null && state_machine.OriginalSourceBlock != this) {
3678                                 DefineStoreyContainer (ec, state_machine);
3679                                 state_machine.EmitStoreyInstantiation (ec, this);
3680                         }
3681
3682                         base.Emit (ec);
3683                 }
3684
3685                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
3686                 {
3687                         var res = base.DoFlowAnalysis (fc);
3688
3689                         if (HasReachableClosingBrace)
3690                                 CheckControlExit (fc);
3691
3692                         return res;
3693                 }
3694
3695                 public LabeledStatement GetLabel (string name, Block block)
3696                 {
3697                         //
3698                         // Cloned parameters blocks can have their own cloned version of top-level labels
3699                         //
3700                         if (labels == null) {
3701                                 if (Parent != null)
3702                                         return Parent.ParametersBlock.GetLabel (name, block);
3703
3704                                 return null;
3705                         }
3706
3707                         object value;
3708                         if (!labels.TryGetValue (name, out value)) {
3709                                 return null;
3710                         }
3711
3712                         var label = value as LabeledStatement;
3713                         Block b = block;
3714                         if (label != null) {
3715                                 do {
3716                                         if (label.Block == b)
3717                                                 return label;
3718                                         b = b.Parent;
3719                                 } while (b != null);
3720                         } else {
3721                                 List<LabeledStatement> list = (List<LabeledStatement>) value;
3722                                 for (int i = 0; i < list.Count; ++i) {
3723                                         label = list[i];
3724                                         if (label.Block == b)
3725                                                 return label;
3726                                 }
3727                         }
3728
3729                         return null;
3730                 }
3731
3732                 public ParameterInfo GetParameterInfo (Parameter p)
3733                 {
3734                         for (int i = 0; i < parameters.Count; ++i) {
3735                                 if (parameters[i] == p)
3736                                         return parameter_info[i];
3737                         }
3738
3739                         throw new ArgumentException ("Invalid parameter");
3740                 }
3741
3742                 public ParameterReference GetParameterReference (int index, Location loc)
3743                 {
3744                         return new ParameterReference (parameter_info[index], loc);
3745                 }
3746
3747                 public Statement PerformClone ()
3748                 {
3749                         CloneContext clonectx = new CloneContext ();
3750                         return Clone (clonectx);
3751                 }
3752
3753                 protected void ProcessParameters ()
3754                 {
3755                         if (parameters.Count == 0)
3756                                 return;
3757
3758                         parameter_info = new ParameterInfo[parameters.Count];
3759                         for (int i = 0; i < parameter_info.Length; ++i) {
3760                                 var p = parameters.FixedParameters[i];
3761                                 if (p == null)
3762                                         continue;
3763
3764                                 // TODO: Should use Parameter only and more block there
3765                                 parameter_info[i] = new ParameterInfo (this, i);
3766                                 if (p.Name != null)
3767                                         AddLocalName (p.Name, parameter_info[i]);
3768                         }
3769                 }
3770
3771                 static LabeledStatement RemapLabeledStatement (LabeledStatement stmt, Block src, Block dst)
3772                 {
3773                         var src_stmts = src.Statements;
3774                         for (int i = 0; i < src_stmts.Count; ++i) {
3775                                 if (src_stmts[i] == stmt)
3776                                         return (LabeledStatement) dst.Statements[i];
3777                         }
3778
3779                         throw new InternalErrorException ("Should never be reached");
3780                 }
3781
3782                 public override bool Resolve (BlockContext bc)
3783                 {
3784                         // TODO: if ((flags & Flags.Resolved) != 0)
3785
3786                         if (resolved)
3787                                 return true;
3788
3789                         resolved = true;
3790
3791                         if (bc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
3792                                 flags |= Flags.IsExpressionTree;
3793
3794                         try {
3795                                 PrepareAssignmentAnalysis (bc);
3796
3797                                 if (!base.Resolve (bc))
3798                                         return false;
3799
3800                         } catch (Exception e) {
3801                                 if (e is CompletionResult || bc.Report.IsDisabled || e is FatalException || bc.Report.Printer is NullReportPrinter || bc.Module.Compiler.Settings.BreakOnInternalError)
3802                                         throw;
3803
3804                                 if (bc.CurrentBlock != null) {
3805                                         bc.Report.Error (584, bc.CurrentBlock.StartLocation, "Internal compiler error: {0}", e.Message);
3806                                 } else {
3807                                         bc.Report.Error (587, "Internal compiler error: {0}", e.Message);
3808                                 }
3809                         }
3810
3811                         //
3812                         // If an asynchronous body of F is either an expression classified as nothing, or a 
3813                         // statement block where no return statements have expressions, the inferred return type is Task
3814                         //
3815                         if (IsAsync) {
3816                                 var am = bc.CurrentAnonymousMethod as AnonymousMethodBody;
3817                                 if (am != null && am.ReturnTypeInference != null && !am.ReturnTypeInference.HasBounds (0)) {
3818                                         am.ReturnTypeInference = null;
3819                                         am.ReturnType = bc.Module.PredefinedTypes.Task.TypeSpec;
3820                                         return true;
3821                                 }
3822                         }
3823
3824                         return true;
3825                 }
3826
3827                 void PrepareAssignmentAnalysis (BlockContext bc)
3828                 {
3829                         for (int i = 0; i < parameters.Count; ++i) {
3830                                 var par = parameters.FixedParameters[i];
3831
3832                                 if ((par.ModFlags & Parameter.Modifier.OUT) == 0)
3833                                         continue;
3834
3835                                 parameter_info [i].VariableInfo = VariableInfo.Create (bc, (Parameter) par);
3836                         }
3837                 }
3838
3839                 public ToplevelBlock ConvertToIterator (IMethodData method, TypeDefinition host, TypeSpec iterator_type, bool is_enumerable)
3840                 {
3841                         var iterator = new Iterator (this, method, host, iterator_type, is_enumerable);
3842                         var stateMachine = new IteratorStorey (iterator);
3843
3844                         state_machine = stateMachine;
3845                         iterator.SetStateMachine (stateMachine);
3846
3847                         var tlb = new ToplevelBlock (host.Compiler, Parameters, Location.Null, Flags.CompilerGenerated);
3848                         tlb.Original = this;
3849                         tlb.state_machine = stateMachine;
3850                         tlb.AddStatement (new Return (iterator, iterator.Location));
3851                         return tlb;
3852                 }
3853
3854                 public ParametersBlock ConvertToAsyncTask (IMemberContext context, TypeDefinition host, ParametersCompiled parameters, TypeSpec returnType, TypeSpec delegateType, Location loc)
3855                 {
3856                         for (int i = 0; i < parameters.Count; i++) {
3857                                 Parameter p = parameters[i];
3858                                 Parameter.Modifier mod = p.ModFlags;
3859                                 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
3860                                         host.Compiler.Report.Error (1988, p.Location,
3861                                                 "Async methods cannot have ref or out parameters");
3862                                         return this;
3863                                 }
3864
3865                                 if (p is ArglistParameter) {
3866                                         host.Compiler.Report.Error (4006, p.Location,
3867                                                 "__arglist is not allowed in parameter list of async methods");
3868                                         return this;
3869                                 }
3870
3871                                 if (parameters.Types[i].IsPointer) {
3872                                         host.Compiler.Report.Error (4005, p.Location,
3873                                                 "Async methods cannot have unsafe parameters");
3874                                         return this;
3875                                 }
3876                         }
3877
3878                         if (!HasAwait) {
3879                                 host.Compiler.Report.Warning (1998, 1, loc,
3880                                         "Async block lacks `await' operator and will run synchronously");
3881                         }
3882
3883                         var block_type = host.Module.Compiler.BuiltinTypes.Void;
3884                         var initializer = new AsyncInitializer (this, host, block_type);
3885                         initializer.Type = block_type;
3886                         initializer.DelegateType = delegateType;
3887
3888                         var stateMachine = new AsyncTaskStorey (this, context, initializer, returnType);
3889
3890                         state_machine = stateMachine;
3891                         initializer.SetStateMachine (stateMachine);
3892
3893                         const Flags flags = Flags.CompilerGenerated;
3894
3895                         var b = this is ToplevelBlock ?
3896                                 new ToplevelBlock (host.Compiler, Parameters, Location.Null, flags) :
3897                                 new ParametersBlock (Parent, parameters, Location.Null, flags | Flags.HasAsyncModifier);
3898
3899                         b.Original = this;
3900                         b.state_machine = stateMachine;
3901                         b.AddStatement (new AsyncInitializerStatement (initializer));
3902                         return b;
3903                 }
3904         }
3905
3906         //
3907         //
3908         //
3909         public class ToplevelBlock : ParametersBlock
3910         {
3911                 LocalVariable this_variable;
3912                 CompilerContext compiler;
3913                 Dictionary<string, object> names;
3914
3915                 List<ExplicitBlock> this_references;
3916
3917                 public ToplevelBlock (CompilerContext ctx, Location loc)
3918                         : this (ctx, ParametersCompiled.EmptyReadOnlyParameters, loc)
3919                 {
3920                 }
3921
3922                 public ToplevelBlock (CompilerContext ctx, ParametersCompiled parameters, Location start, Flags flags = 0)
3923                         : base (parameters, start)
3924                 {
3925                         this.compiler = ctx;
3926                         this.flags = flags;
3927                         top_block = this;
3928
3929                         ProcessParameters ();
3930                 }
3931
3932                 //
3933                 // Recreates a top level block from parameters block. Used for
3934                 // compiler generated methods where the original block comes from
3935                 // explicit child block. This works for already resolved blocks
3936                 // only to ensure we resolve them in the correct flow order
3937                 //
3938                 public ToplevelBlock (ParametersBlock source, ParametersCompiled parameters)
3939                         : base (source, parameters)
3940                 {
3941                         this.compiler = source.TopBlock.compiler;
3942                         top_block = this;
3943                 }
3944
3945                 public bool IsIterator {
3946                         get {
3947                                 return (flags & Flags.Iterator) != 0;
3948                         }
3949                         set {
3950                                 flags = value ? flags | Flags.Iterator : flags & ~Flags.Iterator;
3951                         }
3952                 }
3953
3954                 public Report Report {
3955                         get {
3956                                 return compiler.Report;
3957                         }
3958                 }
3959
3960                 //
3961                 // Used by anonymous blocks to track references of `this' variable
3962                 //
3963                 public List<ExplicitBlock> ThisReferencesFromChildrenBlock {
3964                         get {
3965                                 return this_references;
3966                         }
3967                 }
3968
3969                 //
3970                 // Returns the "this" instance variable of this block.
3971                 // See AddThisVariable() for more information.
3972                 //
3973                 public LocalVariable ThisVariable {
3974                         get {
3975                                 return this_variable;
3976                         }
3977                 }
3978
3979                 public void AddLocalName (string name, INamedBlockVariable li, bool ignoreChildrenBlocks)
3980                 {
3981                         if (names == null)
3982                                 names = new Dictionary<string, object> ();
3983
3984                         object value;
3985                         if (!names.TryGetValue (name, out value)) {
3986                                 names.Add (name, li);
3987                                 return;
3988                         }
3989
3990                         INamedBlockVariable existing = value as INamedBlockVariable;
3991                         List<INamedBlockVariable> existing_list;
3992                         if (existing != null) {
3993                                 existing_list = new List<INamedBlockVariable> ();
3994                                 existing_list.Add (existing);
3995                                 names[name] = existing_list;
3996                         } else {
3997                                 existing_list = (List<INamedBlockVariable>) value;
3998                         }
3999
4000                         //
4001                         // A collision checking between local names
4002                         //
4003                         var variable_block = li.Block.Explicit;
4004                         for (int i = 0; i < existing_list.Count; ++i) {
4005                                 existing = existing_list[i];
4006                                 Block b = existing.Block.Explicit;
4007
4008                                 // Collision at same level
4009                                 if (variable_block == b) {
4010                                         li.Block.Error_AlreadyDeclared (name, li);
4011                                         break;
4012                                 }
4013
4014                                 // Collision with parent
4015                                 Block parent = variable_block;
4016                                 while ((parent = parent.Parent) != null) {
4017                                         if (parent == b) {
4018                                                 li.Block.Error_AlreadyDeclared (name, li, "parent or current");
4019                                                 i = existing_list.Count;
4020                                                 break;
4021                                         }
4022                                 }
4023
4024                                 if (!ignoreChildrenBlocks && variable_block.Parent != b.Parent) {
4025                                         // Collision with children
4026                                         while ((b = b.Parent) != null) {
4027                                                 if (variable_block == b) {
4028                                                         li.Block.Error_AlreadyDeclared (name, li, "child");
4029                                                         i = existing_list.Count;
4030                                                         break;
4031                                                 }
4032                                         }
4033                                 }
4034                         }
4035
4036                         existing_list.Add (li);
4037                 }
4038
4039                 public void AddLabel (string name, LabeledStatement label)
4040                 {
4041                         if (labels == null)
4042                                 labels = new Dictionary<string, object> ();
4043
4044                         object value;
4045                         if (!labels.TryGetValue (name, out value)) {
4046                                 labels.Add (name, label);
4047                                 return;
4048                         }
4049
4050                         LabeledStatement existing = value as LabeledStatement;
4051                         List<LabeledStatement> existing_list;
4052                         if (existing != null) {
4053                                 existing_list = new List<LabeledStatement> ();
4054                                 existing_list.Add (existing);
4055                                 labels[name] = existing_list;
4056                         } else {
4057                                 existing_list = (List<LabeledStatement>) value;
4058                         }
4059
4060                         //
4061                         // A collision checking between labels
4062                         //
4063                         for (int i = 0; i < existing_list.Count; ++i) {
4064                                 existing = existing_list[i];
4065                                 Block b = existing.Block;
4066
4067                                 // Collision at same level
4068                                 if (label.Block == b) {
4069                                         Report.SymbolRelatedToPreviousError (existing.loc, name);
4070                                         Report.Error (140, label.loc, "The label `{0}' is a duplicate", name);
4071                                         break;
4072                                 }
4073
4074                                 // Collision with parent
4075                                 b = label.Block;
4076                                 while ((b = b.Parent) != null) {
4077                                         if (existing.Block == b) {
4078                                                 Report.Error (158, label.loc,
4079                                                         "The label `{0}' shadows another label by the same name in a contained scope", name);
4080                                                 i = existing_list.Count;
4081                                                 break;
4082                                         }
4083                                 }
4084
4085                                 // Collision with with children
4086                                 b = existing.Block;
4087                                 while ((b = b.Parent) != null) {
4088                                         if (label.Block == b) {
4089                                                 Report.Error (158, label.loc,
4090                                                         "The label `{0}' shadows another label by the same name in a contained scope", name);
4091                                                 i = existing_list.Count;
4092                                                 break;
4093                                         }
4094                                 }
4095                         }
4096
4097                         existing_list.Add (label);
4098                 }
4099
4100                 public void AddThisReferenceFromChildrenBlock (ExplicitBlock block)
4101                 {
4102                         if (this_references == null)
4103                                 this_references = new List<ExplicitBlock> ();
4104
4105                         if (!this_references.Contains (block))
4106                                 this_references.Add (block);
4107                 }
4108
4109                 public void RemoveThisReferenceFromChildrenBlock (ExplicitBlock block)
4110                 {
4111                         this_references.Remove (block);
4112                 }
4113
4114                 //
4115                 // Creates an arguments set from all parameters, useful for method proxy calls
4116                 //
4117                 public Arguments GetAllParametersArguments ()
4118                 {
4119                         int count = parameters.Count;
4120                         Arguments args = new Arguments (count);
4121                         for (int i = 0; i < count; ++i) {
4122                                 var pi = parameter_info[i];
4123                                 var arg_expr = GetParameterReference (i, pi.Location);
4124
4125                                 Argument.AType atype_modifier;
4126                                 switch (pi.Parameter.ParameterModifier & Parameter.Modifier.RefOutMask) {
4127                                 case Parameter.Modifier.REF:
4128                                         atype_modifier = Argument.AType.Ref;
4129                                         break;
4130                                 case Parameter.Modifier.OUT:
4131                                         atype_modifier = Argument.AType.Out;
4132                                         break;
4133                                 default:
4134                                         atype_modifier = 0;
4135                                         break;
4136                                 }
4137
4138                                 args.Add (new Argument (arg_expr, atype_modifier));
4139                         }
4140
4141                         return args;
4142                 }
4143
4144                 //
4145                 // Lookup inside a block, the returned value can represent 3 states
4146                 //
4147                 // true+variable: A local name was found and it's valid
4148                 // false+variable: A local name was found in a child block only
4149                 // false+null: No local name was found
4150                 //
4151                 public bool GetLocalName (string name, Block block, ref INamedBlockVariable variable)
4152                 {
4153                         if (names == null)
4154                                 return false;
4155
4156                         object value;
4157                         if (!names.TryGetValue (name, out value))
4158                                 return false;
4159
4160                         variable = value as INamedBlockVariable;
4161                         Block b = block;
4162                         if (variable != null) {
4163                                 do {
4164                                         if (variable.Block == b.Original)
4165                                                 return true;
4166
4167                                         b = b.Parent;
4168                                 } while (b != null);
4169
4170                                 b = variable.Block;
4171                                 do {
4172                                         if (block == b)
4173                                                 return false;
4174
4175                                         b = b.Parent;
4176                                 } while (b != null);
4177                         } else {
4178                                 List<INamedBlockVariable> list = (List<INamedBlockVariable>) value;
4179                                 for (int i = 0; i < list.Count; ++i) {
4180                                         variable = list[i];
4181                                         do {
4182                                                 if (variable.Block == b.Original)
4183                                                         return true;
4184
4185                                                 b = b.Parent;
4186                                         } while (b != null);
4187
4188                                         b = variable.Block;
4189                                         do {
4190                                                 if (block == b)
4191                                                         return false;
4192
4193                                                 b = b.Parent;
4194                                         } while (b != null);
4195
4196                                         b = block;
4197                                 }
4198                         }
4199
4200                         variable = null;
4201                         return false;
4202                 }
4203
4204                 // <summary>
4205                 //   This is used by non-static `struct' constructors which do not have an
4206                 //   initializer - in this case, the constructor must initialize all of the
4207                 //   struct's fields.  To do this, we add a "this" variable and use the flow
4208                 //   analysis code to ensure that it's been fully initialized before control
4209                 //   leaves the constructor.
4210                 // </summary>
4211                 public void AddThisVariable (BlockContext bc)
4212                 {
4213                         if (this_variable != null)
4214                                 throw new InternalErrorException (StartLocation.ToString ());
4215
4216                         this_variable = new LocalVariable (this, "this", LocalVariable.Flags.IsThis | LocalVariable.Flags.Used, StartLocation);
4217                         this_variable.Type = bc.CurrentType;
4218                         this_variable.PrepareAssignmentAnalysis (bc);
4219                 }
4220
4221                 public override void CheckControlExit (FlowAnalysisContext fc, DefiniteAssignmentBitSet dat)
4222                 {
4223                         //
4224                         // If we're a non-static struct constructor which doesn't have an
4225                         // initializer, then we must initialize all of the struct's fields.
4226                         //
4227                         if (this_variable != null)
4228                                 this_variable.IsThisAssigned (fc, this);
4229
4230                         base.CheckControlExit (fc, dat);
4231                 }
4232
4233                 public override void Emit (EmitContext ec)
4234                 {
4235                         if (Report.Errors > 0)
4236                                 return;
4237
4238                         try {
4239                         if (IsCompilerGenerated) {
4240                                 using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
4241                                         base.Emit (ec);
4242                                 }
4243                         } else {
4244                                 base.Emit (ec);
4245                         }
4246
4247                         //
4248                         // If `HasReturnLabel' is set, then we already emitted a
4249                         // jump to the end of the method, so we must emit a `ret'
4250                         // there.
4251                         //
4252                         // Unfortunately, System.Reflection.Emit automatically emits
4253                         // a leave to the end of a finally block.  This is a problem
4254                         // if no code is following the try/finally block since we may
4255                         // jump to a point after the end of the method.
4256                         // As a workaround, we're always creating a return label in
4257                         // this case.
4258                         //
4259                         if (ec.HasReturnLabel || HasReachableClosingBrace) {
4260                                 if (ec.HasReturnLabel)
4261                                         ec.MarkLabel (ec.ReturnLabel);
4262
4263                                 if (ec.EmitAccurateDebugInfo && !IsCompilerGenerated)
4264                                         ec.Mark (EndLocation);
4265
4266                                 if (ec.ReturnType.Kind != MemberKind.Void)
4267                                         ec.Emit (OpCodes.Ldloc, ec.TemporaryReturn ());
4268
4269                                 ec.Emit (OpCodes.Ret);
4270                         }
4271
4272                         } catch (Exception e) {
4273                                 throw new InternalErrorException (e, StartLocation);
4274                         }
4275                 }
4276
4277                 public bool Resolve (BlockContext bc, IMethodData md)
4278                 {
4279                         if (resolved)
4280                                 return true;
4281
4282                         var errors = bc.Report.Errors;
4283
4284                         base.Resolve (bc);
4285
4286                         if (bc.Report.Errors > errors)
4287                                 return false;
4288
4289                         MarkReachable (new Reachability ());
4290
4291                         if (HasReachableClosingBrace && bc.ReturnType.Kind != MemberKind.Void) {
4292                                 // TODO: var md = bc.CurrentMemberDefinition;
4293                                 bc.Report.Error (161, md.Location, "`{0}': not all code paths return a value", md.GetSignatureForError ());
4294                         }
4295
4296                         if ((flags & Flags.NoFlowAnalysis) != 0)
4297                                 return true;
4298
4299                         var fc = new FlowAnalysisContext (bc.Module.Compiler, this, bc.AssignmentInfoOffset);
4300                         try {
4301                                 FlowAnalysis (fc);
4302                         } catch (Exception e) {
4303                                 throw new InternalErrorException (e, StartLocation);
4304                         }
4305
4306                         return true;
4307                 }
4308         }
4309         
4310         public class SwitchLabel : Statement
4311         {
4312                 Constant converted;
4313                 Expression label;
4314
4315                 Label? il_label;
4316
4317                 //
4318                 // if expr == null, then it is the default case.
4319                 //
4320                 public SwitchLabel (Expression expr, Location l)
4321                 {
4322                         label = expr;
4323                         loc = l;
4324                 }
4325
4326                 public bool IsDefault {
4327                         get {
4328                                 return label == null;
4329                         }
4330                 }
4331
4332                 public Expression Label {
4333                         get {
4334                                 return label;
4335                         }
4336                 }
4337
4338                 public Location Location {
4339                         get {
4340                                 return loc;
4341                         }
4342                 }
4343
4344                 public Constant Converted {
4345                         get {
4346                                 return converted;
4347                         }
4348                         set {
4349                                 converted = value; 
4350                         }
4351                 }
4352
4353                 public bool SectionStart { get; set; }
4354
4355                 public Label GetILLabel (EmitContext ec)
4356                 {
4357                         if (il_label == null){
4358                                 il_label = ec.DefineLabel ();
4359                         }
4360
4361                         return il_label.Value;
4362                 }
4363
4364                 protected override void DoEmit (EmitContext ec)
4365                 {
4366                         ec.MarkLabel (GetILLabel (ec));
4367                 }
4368
4369                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
4370                 {
4371                         if (!SectionStart)
4372                                 return false;
4373
4374                         fc.DefiniteAssignment = new DefiniteAssignmentBitSet (fc.SwitchInitialDefinitiveAssignment);
4375                         return false;
4376                 }
4377
4378                 public override bool Resolve (BlockContext bc)
4379                 {
4380                         if (ResolveAndReduce (bc))
4381                                 bc.Switch.RegisterLabel (bc, this);
4382
4383                         return true;
4384                 }
4385
4386                 //
4387                 // Resolves the expression, reduces it to a literal if possible
4388                 // and then converts it to the requested type.
4389                 //
4390                 bool ResolveAndReduce (BlockContext rc)
4391                 {
4392                         if (IsDefault)
4393                                 return true;
4394
4395                         var c = label.ResolveLabelConstant (rc);
4396                         if (c == null)
4397                                 return false;
4398
4399                         if (rc.Switch.IsNullable && c is NullLiteral) {
4400                                 converted = c;
4401                                 return true;
4402                         }
4403
4404                         converted = c.ImplicitConversionRequired (rc, rc.Switch.SwitchType);
4405                         return converted != null;
4406                 }
4407
4408                 public void Error_AlreadyOccurs (ResolveContext ec, SwitchLabel collision_with)
4409                 {
4410                         ec.Report.SymbolRelatedToPreviousError (collision_with.loc, null);
4411                         ec.Report.Error (152, loc, "The label `{0}' already occurs in this switch statement", GetSignatureForError ());
4412                 }
4413
4414                 protected override void CloneTo (CloneContext clonectx, Statement target)
4415                 {
4416                         var t = (SwitchLabel) target;
4417                         if (label != null)
4418                                 t.label = label.Clone (clonectx);
4419                 }
4420
4421                 public override object Accept (StructuralVisitor visitor)
4422                 {
4423                         return visitor.Visit (this);
4424                 }
4425
4426                 public string GetSignatureForError ()
4427                 {
4428                         string label;
4429                         if (converted == null)
4430                                 label = "default";
4431                         else
4432                                 label = converted.GetValueAsLiteral ();
4433
4434                         return string.Format ("case {0}:", label);
4435                 }
4436         }
4437
4438         public class Switch : LoopStatement
4439         {
4440                 // structure used to hold blocks of keys while calculating table switch
4441                 sealed class LabelsRange : IComparable<LabelsRange>
4442                 {
4443                         public readonly long min;
4444                         public long max;
4445                         public readonly List<long> label_values;
4446
4447                         public LabelsRange (long value)
4448                         {
4449                                 min = max = value;
4450                                 label_values = new List<long> ();
4451                                 label_values.Add (value);
4452                         }
4453
4454                         public LabelsRange (long min, long max, ICollection<long> values)
4455                         {
4456                                 this.min = min;
4457                                 this.max = max;
4458                                 this.label_values = new List<long> (values);
4459                         }
4460
4461                         public long Range {
4462                                 get {
4463                                         return max - min + 1;
4464                                 }
4465                         }
4466
4467                         public bool AddValue (long value)
4468                         {
4469                                 var gap = value - min + 1;
4470                                 // Ensure the range has > 50% occupancy
4471                                 if (gap > 2 * (label_values.Count + 1) || gap <= 0)
4472                                         return false;
4473
4474                                 max = value;
4475                                 label_values.Add (value);
4476                                 return true;
4477                         }
4478
4479                         public int CompareTo (LabelsRange other)
4480                         {
4481                                 int nLength = label_values.Count;
4482                                 int nLengthOther = other.label_values.Count;
4483                                 if (nLengthOther == nLength)
4484                                         return (int) (other.min - min);
4485
4486                                 return nLength - nLengthOther;
4487                         }
4488                 }
4489
4490                 sealed class DispatchStatement : Statement
4491                 {
4492                         readonly Switch body;
4493
4494                         public DispatchStatement (Switch body)
4495                         {
4496                                 this.body = body;
4497                         }
4498
4499                         protected override void CloneTo (CloneContext clonectx, Statement target)
4500                         {
4501                                 throw new NotImplementedException ();
4502                         }
4503
4504                         protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
4505                         {
4506                                 return false;
4507                         }
4508
4509                         protected override void DoEmit (EmitContext ec)
4510                         {
4511                                 body.EmitDispatch (ec);
4512                         }
4513                 }
4514
4515                 class MissingBreak : Statement
4516                 {
4517                         SwitchLabel label;
4518
4519                         public MissingBreak (SwitchLabel sl)
4520                         {
4521                                 this.label = sl;
4522                                 this.loc = sl.loc;
4523                         }
4524
4525                         protected override void DoEmit (EmitContext ec)
4526                         {
4527                         }
4528
4529                         protected override void CloneTo (CloneContext clonectx, Statement target)
4530                         {
4531                         }
4532
4533                         protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
4534                         {
4535                                 fc.Report.Error (163, loc, "Control cannot fall through from one case label `{0}' to another",
4536                                         label.GetSignatureForError ());
4537
4538                                 return true;
4539                         }
4540                 }
4541
4542                 public Expression Expr;
4543
4544                 //
4545                 // Mapping of all labels to their SwitchLabels
4546                 //
4547                 Dictionary<long, SwitchLabel> labels;
4548                 Dictionary<string, SwitchLabel> string_labels;
4549                 List<SwitchLabel> case_labels;
4550
4551                 List<Tuple<GotoCase, Constant>> goto_cases;
4552                 List<DefiniteAssignmentBitSet> end_reachable_das;
4553
4554                 /// <summary>
4555                 ///   The governing switch type
4556                 /// </summary>
4557                 public TypeSpec SwitchType;
4558
4559                 Expression new_expr;
4560
4561                 SwitchLabel case_null;
4562                 SwitchLabel case_default;
4563
4564                 Label defaultLabel, nullLabel;
4565                 VariableReference value;
4566                 ExpressionStatement string_dictionary;
4567                 FieldExpr switch_cache_field;
4568                 ExplicitBlock block;
4569                 bool end_reachable;
4570
4571                 //
4572                 // Nullable Types support
4573                 //
4574                 Nullable.Unwrap unwrap;
4575
4576                 public Switch (Expression e, ExplicitBlock block, Location l)
4577                         : base (block)
4578                 {
4579                         Expr = e;
4580                         this.block = block;
4581                         loc = l;
4582                 }
4583
4584                 public SwitchLabel ActiveLabel { get; set; }
4585
4586                 public ExplicitBlock Block {
4587                         get {
4588                                 return block;
4589                         }
4590                 }
4591
4592                 public SwitchLabel DefaultLabel {
4593                         get {
4594                                 return case_default;
4595                         }
4596                 }
4597
4598                 public bool IsNullable {
4599                         get {
4600                                 return unwrap != null;
4601                         }
4602                 }
4603
4604                 public List<SwitchLabel> RegisteredLabels {
4605                         get {
4606                                 return case_labels;
4607                         }
4608                 }
4609
4610                 //
4611                 // Determines the governing type for a switch.  The returned
4612                 // expression might be the expression from the switch, or an
4613                 // expression that includes any potential conversions to
4614                 //
4615                 Expression SwitchGoverningType (ResolveContext ec, Expression expr)
4616                 {
4617                         switch (expr.Type.BuiltinType) {
4618                         case BuiltinTypeSpec.Type.Byte:
4619                         case BuiltinTypeSpec.Type.SByte:
4620                         case BuiltinTypeSpec.Type.UShort:
4621                         case BuiltinTypeSpec.Type.Short:
4622                         case BuiltinTypeSpec.Type.UInt:
4623                         case BuiltinTypeSpec.Type.Int:
4624                         case BuiltinTypeSpec.Type.ULong:
4625                         case BuiltinTypeSpec.Type.Long:
4626                         case BuiltinTypeSpec.Type.Char:
4627                         case BuiltinTypeSpec.Type.String:
4628                         case BuiltinTypeSpec.Type.Bool:
4629                                 return expr;
4630                         }
4631
4632                         if (expr.Type.IsEnum)
4633                                 return expr;
4634
4635                         //
4636                         // Try to find a *user* defined implicit conversion.
4637                         //
4638                         // If there is no implicit conversion, or if there are multiple
4639                         // conversions, we have to report an error
4640                         //
4641                         Expression converted = null;
4642                         foreach (TypeSpec tt in ec.BuiltinTypes.SwitchUserTypes) {
4643                                 Expression e;
4644                                 
4645                                 e = Convert.ImplicitUserConversion (ec, expr, tt, loc);
4646                                 if (e == null)
4647                                         continue;
4648
4649                                 //
4650                                 // Ignore over-worked ImplicitUserConversions that do
4651                                 // an implicit conversion in addition to the user conversion.
4652                                 // 
4653                                 if (!(e is UserCast))
4654                                         continue;
4655
4656                                 if (converted != null){
4657                                         ec.Report.ExtraInformation (loc, "(Ambiguous implicit user defined conversion in previous ");
4658                                         return null;
4659                                 }
4660
4661                                 converted = e;
4662                         }
4663                         return converted;
4664                 }
4665
4666                 public static TypeSpec[] CreateSwitchUserTypes (BuiltinTypes types)
4667                 {
4668                         // LAMESPEC: For some reason it does not contain bool which looks like csc bug
4669                         return new[] {
4670                                 types.SByte,
4671                                 types.Byte,
4672                                 types.Short,
4673                                 types.UShort,
4674                                 types.Int,
4675                                 types.UInt,
4676                                 types.Long,
4677                                 types.ULong,
4678                                 types.Char,
4679                                 types.String
4680                         };
4681                 }
4682
4683                 public void RegisterLabel (BlockContext rc, SwitchLabel sl)
4684                 {
4685                         case_labels.Add (sl);
4686
4687                         if (sl.IsDefault) {
4688                                 if (case_default != null) {
4689                                         sl.Error_AlreadyOccurs (rc, case_default);
4690                                 } else {
4691                                         case_default = sl;
4692                                 }
4693
4694                                 return;
4695                         }
4696
4697                         try {
4698                                 if (string_labels != null) {
4699                                         string string_value = sl.Converted.GetValue () as string;
4700                                         if (string_value == null)
4701                                                 case_null = sl;
4702                                         else
4703                                                 string_labels.Add (string_value, sl);
4704                                 } else {
4705                                         if (sl.Converted is NullLiteral) {
4706                                                 case_null = sl;
4707                                         } else {
4708                                                 labels.Add (sl.Converted.GetValueAsLong (), sl);
4709                                         }
4710                                 }
4711                         } catch (ArgumentException) {
4712                                 if (string_labels != null)
4713                                         sl.Error_AlreadyOccurs (rc, string_labels[(string) sl.Converted.GetValue ()]);
4714                                 else
4715                                         sl.Error_AlreadyOccurs (rc, labels[sl.Converted.GetValueAsLong ()]);
4716                         }
4717                 }
4718                 
4719                 //
4720                 // This method emits code for a lookup-based switch statement (non-string)
4721                 // Basically it groups the cases into blocks that are at least half full,
4722                 // and then spits out individual lookup opcodes for each block.
4723                 // It emits the longest blocks first, and short blocks are just
4724                 // handled with direct compares.
4725                 //
4726                 void EmitTableSwitch (EmitContext ec, Expression val)
4727                 {
4728                         if (labels != null && labels.Count > 0) {
4729                                 List<LabelsRange> ranges;
4730                                 if (string_labels != null) {
4731                                         // We have done all hard work for string already
4732                                         // setup single range only
4733                                         ranges = new List<LabelsRange> (1);
4734                                         ranges.Add (new LabelsRange (0, labels.Count - 1, labels.Keys));
4735                                 } else {
4736                                         var element_keys = new long[labels.Count];
4737                                         labels.Keys.CopyTo (element_keys, 0);
4738                                         Array.Sort (element_keys);
4739
4740                                         //
4741                                         // Build possible ranges of switch labes to reduce number
4742                                         // of comparisons
4743                                         //
4744                                         ranges = new List<LabelsRange> (element_keys.Length);
4745                                         var range = new LabelsRange (element_keys[0]);
4746                                         ranges.Add (range);
4747                                         for (int i = 1; i < element_keys.Length; ++i) {
4748                                                 var l = element_keys[i];
4749                                                 if (range.AddValue (l))
4750                                                         continue;
4751
4752                                                 range = new LabelsRange (l);
4753                                                 ranges.Add (range);
4754                                         }
4755
4756                                         // sort the blocks so we can tackle the largest ones first
4757                                         ranges.Sort ();
4758                                 }
4759
4760                                 Label lbl_default = defaultLabel;
4761                                 TypeSpec compare_type = SwitchType.IsEnum ? EnumSpec.GetUnderlyingType (SwitchType) : SwitchType;
4762
4763                                 for (int range_index = ranges.Count - 1; range_index >= 0; --range_index) {
4764                                         LabelsRange kb = ranges[range_index];
4765                                         lbl_default = (range_index == 0) ? defaultLabel : ec.DefineLabel ();
4766
4767                                         // Optimize small ranges using simple equality check
4768                                         if (kb.Range <= 2) {
4769                                                 foreach (var key in kb.label_values) {
4770                                                         SwitchLabel sl = labels[key];
4771                                                         if (sl == case_default || sl == case_null)
4772                                                                 continue;
4773
4774                                                         if (sl.Converted.IsZeroInteger) {
4775                                                                 val.EmitBranchable (ec, sl.GetILLabel (ec), false);
4776                                                         } else {
4777                                                                 val.Emit (ec);
4778                                                                 sl.Converted.Emit (ec);
4779                                                                 ec.Emit (OpCodes.Beq, sl.GetILLabel (ec));
4780                                                         }
4781                                                 }
4782                                         } else {
4783                                                 // TODO: if all the keys in the block are the same and there are
4784                                                 //       no gaps/defaults then just use a range-check.
4785                                                 if (compare_type.BuiltinType == BuiltinTypeSpec.Type.Long || compare_type.BuiltinType == BuiltinTypeSpec.Type.ULong) {
4786                                                         // TODO: optimize constant/I4 cases
4787
4788                                                         // check block range (could be > 2^31)
4789                                                         val.Emit (ec);
4790                                                         ec.EmitLong (kb.min);
4791                                                         ec.Emit (OpCodes.Blt, lbl_default);
4792
4793                                                         val.Emit (ec);
4794                                                         ec.EmitLong (kb.max);
4795                                                         ec.Emit (OpCodes.Bgt, lbl_default);
4796
4797                                                         // normalize range
4798                                                         val.Emit (ec);
4799                                                         if (kb.min != 0) {
4800                                                                 ec.EmitLong (kb.min);
4801                                                                 ec.Emit (OpCodes.Sub);
4802                                                         }
4803
4804                                                         ec.Emit (OpCodes.Conv_I4);      // assumes < 2^31 labels!
4805                                                 } else {
4806                                                         // normalize range
4807                                                         val.Emit (ec);
4808                                                         int first = (int) kb.min;
4809                                                         if (first > 0) {
4810                                                                 ec.EmitInt (first);
4811                                                                 ec.Emit (OpCodes.Sub);
4812                                                         } else if (first < 0) {
4813                                                                 ec.EmitInt (-first);
4814                                                                 ec.Emit (OpCodes.Add);
4815                                                         }
4816                                                 }
4817
4818                                                 // first, build the list of labels for the switch
4819                                                 int iKey = 0;
4820                                                 long cJumps = kb.Range;
4821                                                 Label[] switch_labels = new Label[cJumps];
4822                                                 for (int iJump = 0; iJump < cJumps; iJump++) {
4823                                                         var key = kb.label_values[iKey];
4824                                                         if (key == kb.min + iJump) {
4825                                                                 switch_labels[iJump] = labels[key].GetILLabel (ec);
4826                                                                 iKey++;
4827                                                         } else {
4828                                                                 switch_labels[iJump] = lbl_default;
4829                                                         }
4830                                                 }
4831
4832                                                 // emit the switch opcode
4833                                                 ec.Emit (OpCodes.Switch, switch_labels);
4834                                         }
4835
4836                                         // mark the default for this block
4837                                         if (range_index != 0)
4838                                                 ec.MarkLabel (lbl_default);
4839                                 }
4840
4841                                 // the last default just goes to the end
4842                                 if (ranges.Count > 0)
4843                                         ec.Emit (OpCodes.Br, lbl_default);
4844                         }
4845                 }
4846                 
4847                 public SwitchLabel FindLabel (Constant value)
4848                 {
4849                         SwitchLabel sl = null;
4850
4851                         if (string_labels != null) {
4852                                 string s = value.GetValue () as string;
4853                                 if (s == null) {
4854                                         if (case_null != null)
4855                                                 sl = case_null;
4856                                         else if (case_default != null)
4857                                                 sl = case_default;
4858                                 } else {
4859                                         string_labels.TryGetValue (s, out sl);
4860                                 }
4861                         } else {
4862                                 if (value is NullLiteral) {
4863                                         sl = case_null;
4864                                 } else {
4865                                         labels.TryGetValue (value.GetValueAsLong (), out sl);
4866                                 }
4867                         }
4868
4869                         return sl;
4870                 }
4871
4872                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
4873                 {
4874                         Expr.FlowAnalysis (fc);
4875
4876                         var prev_switch = fc.SwitchInitialDefinitiveAssignment;
4877                         var InitialDefinitiveAssignment = fc.DefiniteAssignment;
4878                         fc.SwitchInitialDefinitiveAssignment = InitialDefinitiveAssignment;
4879
4880                         block.FlowAnalysis (fc);
4881
4882                         fc.SwitchInitialDefinitiveAssignment = prev_switch;
4883
4884                         if (end_reachable_das != null) {
4885                                 var sections_das = DefiniteAssignmentBitSet.And (end_reachable_das);
4886                                 InitialDefinitiveAssignment |= sections_das;
4887                                 end_reachable_das = null;
4888                         }
4889
4890                         fc.DefiniteAssignment = InitialDefinitiveAssignment;
4891
4892                         return case_default != null && !end_reachable;
4893                 }
4894
4895                 public override bool Resolve (BlockContext ec)
4896                 {
4897                         Expr = Expr.Resolve (ec);
4898                         if (Expr == null)
4899                                 return false;
4900
4901                         new_expr = SwitchGoverningType (ec, Expr);
4902
4903                         if (new_expr == null && Expr.Type.IsNullableType) {
4904                                 unwrap = Nullable.Unwrap.Create (Expr, false);
4905                                 if (unwrap == null)
4906                                         return false;
4907
4908                                 new_expr = SwitchGoverningType (ec, unwrap);
4909                         }
4910
4911                         if (new_expr == null) {
4912                                 if (Expr.Type != InternalType.ErrorType) {
4913                                         ec.Report.Error (151, loc,
4914                                                 "A switch expression of type `{0}' cannot be converted to an integral type, bool, char, string, enum or nullable type",
4915                                                 Expr.Type.GetSignatureForError ());
4916                                 }
4917
4918                                 return false;
4919                         }
4920
4921                         // Validate switch.
4922                         SwitchType = new_expr.Type;
4923
4924                         if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.Bool && ec.Module.Compiler.Settings.Version == LanguageVersion.ISO_1) {
4925                                 ec.Report.FeatureIsNotAvailable (ec.Module.Compiler, loc, "switch expression of boolean type");
4926                                 return false;
4927                         }
4928
4929                         if (block.Statements.Count == 0)
4930                                 return true;
4931
4932                         if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String) {
4933                                 string_labels = new Dictionary<string, SwitchLabel> ();
4934                         } else {
4935                                 labels = new Dictionary<long, SwitchLabel> ();
4936                         }
4937
4938                         case_labels = new List<SwitchLabel> ();
4939
4940                         var constant = new_expr as Constant;
4941
4942                         //
4943                         // Don't need extra variable for constant switch or switch with
4944                         // only default case
4945                         //
4946                         if (constant == null) {
4947                                 //
4948                                 // Store switch expression for comparison purposes
4949                                 //
4950                                 value = new_expr as VariableReference;
4951                                 if (value == null && !HasOnlyDefaultSection ()) {
4952                                         var current_block = ec.CurrentBlock;
4953                                         ec.CurrentBlock = Block;
4954                                         // Create temporary variable inside switch scope
4955                                         value = TemporaryVariableReference.Create (SwitchType, ec.CurrentBlock, loc);
4956                                         value.Resolve (ec);
4957                                         ec.CurrentBlock = current_block;
4958                                 }
4959                         }
4960
4961                         Switch old_switch = ec.Switch;
4962                         ec.Switch = this;
4963                         var parent_los = ec.EnclosingLoopOrSwitch;
4964                         ec.EnclosingLoopOrSwitch = this;
4965
4966                         var ok = Statement.Resolve (ec);
4967
4968                         ec.EnclosingLoopOrSwitch = parent_los;
4969                         ec.Switch = old_switch;
4970
4971                         //
4972                         // Check if all goto cases are valid. Needs to be done after switch
4973                         // is resolved because goto can jump forward in the scope.
4974                         //
4975                         if (goto_cases != null) {
4976                                 foreach (var gc in goto_cases) {
4977                                         if (gc.Item1 == null) {
4978                                                 if (DefaultLabel == null) {
4979                                                         Goto.Error_UnknownLabel (ec, "default", loc);
4980                                                 }
4981
4982                                                 continue;
4983                                         }
4984
4985                                         var sl = FindLabel (gc.Item2);
4986                                         if (sl == null) {
4987                                                 Goto.Error_UnknownLabel (ec, "case " + gc.Item2.GetValueAsLiteral (), loc);
4988                                         } else {
4989                                                 gc.Item1.Label = sl;
4990                                         }
4991                                 }
4992                         }
4993
4994                         if (!ok)
4995                                 return false;
4996
4997                         if (constant == null && SwitchType.BuiltinType == BuiltinTypeSpec.Type.String && string_labels.Count > 6) {
4998                                 ResolveStringSwitchMap (ec);
4999                         }
5000
5001                         //
5002                         // Anonymous storey initialization has to happen before
5003                         // any generated switch dispatch
5004                         //
5005                         block.InsertStatement (0, new DispatchStatement (this));
5006
5007                         return true;
5008                 }
5009
5010                 bool HasOnlyDefaultSection ()
5011                 {
5012                         for (int i = 0; i < block.Statements.Count; ++i) {
5013                                 var s = block.Statements[i] as SwitchLabel;
5014
5015                                 if (s == null || s.IsDefault)
5016                                         continue;
5017
5018                                 return false;
5019                         }
5020
5021                         return true;
5022                 }
5023
5024                 public override Reachability MarkReachable (Reachability rc)
5025                 {
5026                         if (rc.IsUnreachable)
5027                                 return rc;
5028
5029                         base.MarkReachable (rc);
5030
5031                         if (block.Statements.Count == 0)
5032                                 return rc;
5033
5034                         SwitchLabel constant_label = null;
5035                         var constant = new_expr as Constant;
5036
5037                         if (constant != null) {
5038                                 constant_label = FindLabel (constant) ?? case_default;
5039                                 if (constant_label == null) {
5040                                         block.Statements.RemoveAt (0);
5041                                         return rc;
5042                                 }
5043                         }
5044
5045                         var section_rc = new Reachability ();
5046                         SwitchLabel prev_label = null;
5047
5048                         for (int i = 0; i < block.Statements.Count; ++i) {
5049                                 var s = block.Statements[i];
5050                                 var sl = s as SwitchLabel;
5051
5052                                 if (sl != null && sl.SectionStart) {
5053                                         //
5054                                         // Section is marked already via constant switch or goto case
5055                                         //
5056                                         if (!sl.IsUnreachable) {
5057                                                 section_rc = new Reachability ();
5058                                                 continue;
5059                                         }
5060
5061                                         if (section_rc.IsUnreachable) {
5062                                                 section_rc = new Reachability ();
5063                                         } else {
5064                                                 if (prev_label != null) {
5065                                                         sl.SectionStart = false;
5066                                                         s = new MissingBreak (prev_label);
5067                                                         s.MarkReachable (rc);
5068                                                         block.Statements.Insert (i - 1, s);
5069                                                         ++i;
5070                                                 }
5071                                         }
5072
5073                                         prev_label = sl;
5074
5075                                         if (constant_label != null && constant_label != sl)
5076                                                 section_rc = Reachability.CreateUnreachable ();
5077                                 }
5078
5079                                 section_rc = s.MarkReachable (section_rc);
5080                         }
5081
5082                         if (!section_rc.IsUnreachable && prev_label != null) {
5083                                 prev_label.SectionStart = false;
5084                                 var s = new MissingBreak (prev_label);
5085                                 s.MarkReachable (rc);
5086                                 block.Statements.Add (s);
5087                         }
5088
5089                         //
5090                         // Reachability can affect parent only when all possible paths are handled but
5091                         // we still need to run reachability check on switch body to check for fall-through
5092                         //
5093                         if (case_default == null && constant_label == null)
5094                                 return rc;
5095
5096                         //
5097                         // We have at least one local exit from the switch
5098                         //
5099                         if (end_reachable)
5100                                 return rc;
5101
5102                         return Reachability.CreateUnreachable ();
5103                 }
5104
5105                 public void RegisterGotoCase (GotoCase gotoCase, Constant value)
5106                 {
5107                         if (goto_cases == null)
5108                                 goto_cases = new List<Tuple<GotoCase, Constant>> ();
5109
5110                         goto_cases.Add (Tuple.Create (gotoCase, value));
5111                 }
5112
5113                 //
5114                 // Converts string switch into string hashtable
5115                 //
5116                 void ResolveStringSwitchMap (ResolveContext ec)
5117                 {
5118                         FullNamedExpression string_dictionary_type;
5119                         if (ec.Module.PredefinedTypes.Dictionary.Define ()) {
5120                                 string_dictionary_type = new TypeExpression (
5121                                         ec.Module.PredefinedTypes.Dictionary.TypeSpec.MakeGenericType (ec,
5122                                                 new [] { ec.BuiltinTypes.String, ec.BuiltinTypes.Int }),
5123                                         loc);
5124                         } else if (ec.Module.PredefinedTypes.Hashtable.Define ()) {
5125                                 string_dictionary_type = new TypeExpression (ec.Module.PredefinedTypes.Hashtable.TypeSpec, loc);
5126                         } else {
5127                                 ec.Module.PredefinedTypes.Dictionary.Resolve ();
5128                                 return;
5129                         }
5130
5131                         var ctype = ec.CurrentMemberDefinition.Parent.PartialContainer;
5132                         Field field = new Field (ctype, string_dictionary_type,
5133                                 Modifiers.STATIC | Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED,
5134                                 new MemberName (CompilerGeneratedContainer.MakeName (null, "f", "switch$map", ec.Module.CounterSwitchTypes++), loc), null);
5135                         if (!field.Define ())
5136                                 return;
5137                         ctype.AddField (field);
5138
5139                         var init = new List<Expression> ();
5140                         int counter = -1;
5141                         labels = new Dictionary<long, SwitchLabel> (string_labels.Count);
5142                         string value = null;
5143
5144                         foreach (SwitchLabel sl in case_labels) {
5145
5146                                 if (sl.SectionStart)
5147                                         labels.Add (++counter, sl);
5148
5149                                 if (sl == case_default || sl == case_null)
5150                                         continue;
5151
5152                                 value = (string) sl.Converted.GetValue ();
5153                                 var init_args = new List<Expression> (2);
5154                                 init_args.Add (new StringLiteral (ec.BuiltinTypes, value, sl.Location));
5155
5156                                 sl.Converted = new IntConstant (ec.BuiltinTypes, counter, loc);
5157                                 init_args.Add (sl.Converted);
5158
5159                                 init.Add (new CollectionElementInitializer (init_args, loc));
5160                         }
5161         
5162                         Arguments args = new Arguments (1);
5163                         args.Add (new Argument (new IntConstant (ec.BuiltinTypes, init.Count, loc)));
5164                         Expression initializer = new NewInitialize (string_dictionary_type, args,
5165                                 new CollectionOrObjectInitializers (init, loc), loc);
5166
5167                         switch_cache_field = new FieldExpr (field, loc);
5168                         string_dictionary = new SimpleAssign (switch_cache_field, initializer.Resolve (ec));
5169                 }
5170
5171                 void DoEmitStringSwitch (EmitContext ec)
5172                 {
5173                         Label l_initialized = ec.DefineLabel ();
5174
5175                         //
5176                         // Skip initialization when value is null
5177                         //
5178                         value.EmitBranchable (ec, nullLabel, false);
5179
5180                         //
5181                         // Check if string dictionary is initialized and initialize
5182                         //
5183                         switch_cache_field.EmitBranchable (ec, l_initialized, true);
5184                         using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
5185                                 string_dictionary.EmitStatement (ec);
5186                         }
5187                         ec.MarkLabel (l_initialized);
5188
5189                         LocalTemporary string_switch_variable = new LocalTemporary (ec.BuiltinTypes.Int);
5190
5191                         ResolveContext rc = new ResolveContext (ec.MemberContext);
5192
5193                         if (switch_cache_field.Type.IsGeneric) {
5194                                 Arguments get_value_args = new Arguments (2);
5195                                 get_value_args.Add (new Argument (value));
5196                                 get_value_args.Add (new Argument (string_switch_variable, Argument.AType.Out));
5197                                 Expression get_item = new Invocation (new MemberAccess (switch_cache_field, "TryGetValue", loc), get_value_args).Resolve (rc);
5198                                 if (get_item == null)
5199                                         return;
5200
5201                                 //
5202                                 // A value was not found, go to default case
5203                                 //
5204                                 get_item.EmitBranchable (ec, defaultLabel, false);
5205                         } else {
5206                                 Arguments get_value_args = new Arguments (1);
5207                                 get_value_args.Add (new Argument (value));
5208
5209                                 Expression get_item = new ElementAccess (switch_cache_field, get_value_args, loc).Resolve (rc);
5210                                 if (get_item == null)
5211                                         return;
5212
5213                                 LocalTemporary get_item_object = new LocalTemporary (ec.BuiltinTypes.Object);
5214                                 get_item_object.EmitAssign (ec, get_item, true, false);
5215                                 ec.Emit (OpCodes.Brfalse, defaultLabel);
5216
5217                                 ExpressionStatement get_item_int = (ExpressionStatement) new SimpleAssign (string_switch_variable,
5218                                         new Cast (new TypeExpression (ec.BuiltinTypes.Int, loc), get_item_object, loc)).Resolve (rc);
5219
5220                                 get_item_int.EmitStatement (ec);
5221                                 get_item_object.Release (ec);
5222                         }
5223
5224                         EmitTableSwitch (ec, string_switch_variable);
5225                         string_switch_variable.Release (ec);
5226                 }
5227
5228                 //
5229                 // Emits switch using simple if/else comparison for small label count (4 + optional default)
5230                 //
5231                 void EmitShortSwitch (EmitContext ec)
5232                 {
5233                         MethodSpec equal_method = null;
5234                         if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String) {
5235                                 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (loc);
5236                         }
5237
5238                         if (equal_method != null) {
5239                                 value.EmitBranchable (ec, nullLabel, false);
5240                         }
5241
5242                         for (int i = 0; i < case_labels.Count; ++i) {
5243                                 var label = case_labels [i];
5244                                 if (label == case_default || label == case_null)
5245                                         continue;
5246
5247                                 var constant = label.Converted;
5248
5249                                 if (equal_method != null) {
5250                                         value.Emit (ec);
5251                                         constant.Emit (ec);
5252
5253                                         var call = new CallEmitter ();
5254                                         call.EmitPredefined (ec, equal_method, new Arguments (0));
5255                                         ec.Emit (OpCodes.Brtrue, label.GetILLabel (ec));
5256                                         continue;
5257                                 }
5258
5259                                 if (constant.IsZeroInteger && constant.Type.BuiltinType != BuiltinTypeSpec.Type.Long && constant.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
5260                                         value.EmitBranchable (ec, label.GetILLabel (ec), false);
5261                                         continue;
5262                                 }
5263
5264                                 value.Emit (ec);
5265                                 constant.Emit (ec);
5266                                 ec.Emit (OpCodes.Beq, label.GetILLabel (ec));
5267                         }
5268
5269                         ec.Emit (OpCodes.Br, defaultLabel);
5270                 }
5271
5272                 void EmitDispatch (EmitContext ec)
5273                 {
5274                         if (value == null) {
5275                                 //
5276                                 // Constant switch, we've already done the work if there is only 1 label
5277                                 // referenced
5278                                 //
5279                                 int reachable = 0;
5280                                 foreach (var sl in case_labels) {
5281                                         if (sl.IsUnreachable)
5282                                                 continue;
5283
5284                                         if (reachable++ > 0) {
5285                                                 var constant = (Constant) new_expr;
5286                                                 var constant_label = FindLabel (constant) ?? case_default;
5287
5288                                                 ec.Emit (OpCodes.Br, constant_label.GetILLabel (ec));
5289                                                 break;
5290                                         }
5291                                 }
5292
5293                                 return;
5294                         }
5295
5296                         if (string_dictionary != null) {
5297                                 DoEmitStringSwitch (ec);
5298                         } else if (case_labels.Count < 4 || string_labels != null) {
5299                                 EmitShortSwitch (ec);
5300                         } else {
5301                                 EmitTableSwitch (ec, value);
5302                         }
5303                 }
5304
5305                 protected override void DoEmit (EmitContext ec)
5306                 {
5307                         //
5308                         // Setup the codegen context
5309                         //
5310                         Label old_end = ec.LoopEnd;
5311                         Switch old_switch = ec.Switch;
5312
5313                         ec.LoopEnd = ec.DefineLabel ();
5314                         ec.Switch = this;
5315
5316                         defaultLabel = case_default == null ? ec.LoopEnd : case_default.GetILLabel (ec);
5317                         nullLabel = case_null == null ? defaultLabel : case_null.GetILLabel (ec);
5318
5319                         if (value != null) {
5320                                 ec.Mark (loc);
5321                                 if (IsNullable) {
5322                                         unwrap.EmitCheck (ec);
5323                                         ec.Emit (OpCodes.Brfalse, nullLabel);
5324                                         value.EmitAssign (ec, new_expr, false, false);
5325                                 } else if (new_expr != value) {
5326                                         value.EmitAssign (ec, new_expr, false, false);
5327                                 }
5328
5329
5330                                 //
5331                                 // Next statement is compiler generated we don't need extra
5332                                 // nop when we can use the statement for sequence point
5333                                 //
5334                                 ec.Mark (block.StartLocation);
5335                                 block.IsCompilerGenerated = true;
5336                         }
5337
5338                         block.Emit (ec);
5339
5340                         // Restore context state. 
5341                         ec.MarkLabel (ec.LoopEnd);
5342
5343                         //
5344                         // Restore the previous context
5345                         //
5346                         ec.LoopEnd = old_end;
5347                         ec.Switch = old_switch;
5348                 }
5349
5350                 protected override void CloneTo (CloneContext clonectx, Statement t)
5351                 {
5352                         Switch target = (Switch) t;
5353
5354                         target.Expr = Expr.Clone (clonectx);
5355                         target.Statement = target.block = (ExplicitBlock) block.Clone (clonectx);
5356                 }
5357                 
5358                 public override object Accept (StructuralVisitor visitor)
5359                 {
5360                         return visitor.Visit (this);
5361                 }
5362
5363                 public override void AddEndDefiniteAssignment (FlowAnalysisContext fc)
5364                 {
5365                         if (case_default == null)
5366                                 return;
5367
5368                         if (end_reachable_das == null)
5369                                 end_reachable_das = new List<DefiniteAssignmentBitSet> ();
5370
5371                         end_reachable_das.Add (fc.DefiniteAssignment);
5372                 }
5373
5374                 public override void SetEndReachable ()
5375                 {
5376                         end_reachable = true;
5377                 }
5378         }
5379
5380         // A place where execution can restart in a state machine
5381         public abstract class ResumableStatement : Statement
5382         {
5383                 bool prepared;
5384                 protected Label resume_point;
5385
5386                 public Label PrepareForEmit (EmitContext ec)
5387                 {
5388                         if (!prepared) {
5389                                 prepared = true;
5390                                 resume_point = ec.DefineLabel ();
5391                         }
5392                         return resume_point;
5393                 }
5394
5395                 public virtual Label PrepareForDispose (EmitContext ec, Label end)
5396                 {
5397                         return end;
5398                 }
5399
5400                 public virtual void EmitForDispose (EmitContext ec, LocalBuilder pc, Label end, bool have_dispatcher)
5401                 {
5402                 }
5403         }
5404
5405         public abstract class TryFinallyBlock : ExceptionStatement
5406         {
5407                 protected Statement stmt;
5408                 Label dispose_try_block;
5409                 bool prepared_for_dispose, emitted_dispose;
5410                 Method finally_host;
5411
5412                 protected TryFinallyBlock (Statement stmt, Location loc)
5413                         : base (loc)
5414                 {
5415                         this.stmt = stmt;
5416                 }
5417
5418                 #region Properties
5419
5420                 public Statement Statement {
5421                         get {
5422                                 return stmt;
5423                         }
5424                 }
5425
5426                 #endregion
5427
5428                 protected abstract void EmitTryBody (EmitContext ec);
5429                 public abstract void EmitFinallyBody (EmitContext ec);
5430
5431                 public override Label PrepareForDispose (EmitContext ec, Label end)
5432                 {
5433                         if (!prepared_for_dispose) {
5434                                 prepared_for_dispose = true;
5435                                 dispose_try_block = ec.DefineLabel ();
5436                         }
5437                         return dispose_try_block;
5438                 }
5439
5440                 protected sealed override void DoEmit (EmitContext ec)
5441                 {
5442                         EmitTryBodyPrepare (ec);
5443                         EmitTryBody (ec);
5444
5445                         ec.BeginFinallyBlock ();
5446
5447                         Label start_finally = ec.DefineLabel ();
5448                         if (resume_points != null) {
5449                                 var state_machine = (StateMachineInitializer) ec.CurrentAnonymousMethod;
5450
5451                                 ec.Emit (OpCodes.Ldloc, state_machine.SkipFinally);
5452                                 ec.Emit (OpCodes.Brfalse_S, start_finally);
5453                                 ec.Emit (OpCodes.Endfinally);
5454                         }
5455
5456                         ec.MarkLabel (start_finally);
5457
5458                         if (finally_host != null) {
5459                                 finally_host.Define ();
5460                                 finally_host.PrepareEmit ();
5461                                 finally_host.Emit ();
5462
5463                                 // Now it's safe to add, to close it properly and emit sequence points
5464                                 finally_host.Parent.AddMember (finally_host);
5465
5466                                 var ce = new CallEmitter ();
5467                                 ce.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, loc);
5468                                 ce.EmitPredefined (ec, finally_host.Spec, new Arguments (0));
5469                         } else {
5470                                 EmitFinallyBody (ec);
5471                         }
5472
5473                         ec.EndExceptionBlock ();
5474                 }
5475
5476                 public override void EmitForDispose (EmitContext ec, LocalBuilder pc, Label end, bool have_dispatcher)
5477                 {
5478                         if (emitted_dispose)
5479                                 return;
5480
5481                         emitted_dispose = true;
5482
5483                         Label end_of_try = ec.DefineLabel ();
5484
5485                         // Ensure that the only way we can get into this code is through a dispatcher
5486                         if (have_dispatcher)
5487                                 ec.Emit (OpCodes.Br, end);
5488
5489                         ec.BeginExceptionBlock ();
5490
5491                         ec.MarkLabel (dispose_try_block);
5492
5493                         Label[] labels = null;
5494                         for (int i = 0; i < resume_points.Count; ++i) {
5495                                 ResumableStatement s = resume_points[i];
5496                                 Label ret = s.PrepareForDispose (ec, end_of_try);
5497                                 if (ret.Equals (end_of_try) && labels == null)
5498                                         continue;
5499                                 if (labels == null) {
5500                                         labels = new Label[resume_points.Count];
5501                                         for (int j = 0; j < i; ++j)
5502                                                 labels[j] = end_of_try;
5503                                 }
5504                                 labels[i] = ret;
5505                         }
5506
5507                         if (labels != null) {
5508                                 int j;
5509                                 for (j = 1; j < labels.Length; ++j)
5510                                         if (!labels[0].Equals (labels[j]))
5511                                                 break;
5512                                 bool emit_dispatcher = j < labels.Length;
5513
5514                                 if (emit_dispatcher) {
5515                                         ec.Emit (OpCodes.Ldloc, pc);
5516                                         ec.EmitInt (first_resume_pc);
5517                                         ec.Emit (OpCodes.Sub);
5518                                         ec.Emit (OpCodes.Switch, labels);
5519                                 }
5520
5521                                 foreach (ResumableStatement s in resume_points)
5522                                         s.EmitForDispose (ec, pc, end_of_try, emit_dispatcher);
5523                         }
5524
5525                         ec.MarkLabel (end_of_try);
5526
5527                         ec.BeginFinallyBlock ();
5528
5529                         if (finally_host != null) {
5530                                 var ce = new CallEmitter ();
5531                                 ce.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, loc);
5532                                 ce.EmitPredefined (ec, finally_host.Spec, new Arguments (0));
5533                         } else {
5534                                 EmitFinallyBody (ec);
5535                         }
5536
5537                         ec.EndExceptionBlock ();
5538                 }
5539
5540                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
5541                 {
5542                         var res = stmt.FlowAnalysis (fc);
5543                         parent = null;
5544                         return res;
5545                 }
5546
5547                 public override Reachability MarkReachable (Reachability rc)
5548                 {
5549                         base.MarkReachable (rc);
5550                         return Statement.MarkReachable (rc);
5551                 }
5552
5553                 public override bool Resolve (BlockContext bc)
5554                 {
5555                         bool ok;
5556
5557                         parent = bc.CurrentTryBlock;
5558                         bc.CurrentTryBlock = this;
5559
5560                         using (bc.Set (ResolveContext.Options.TryScope)) {
5561                                 ok = stmt.Resolve (bc);
5562                         }
5563
5564                         bc.CurrentTryBlock = parent;
5565
5566                         //
5567                         // Finally block inside iterator is called from MoveNext and
5568                         // Dispose methods that means we need to lift the block into
5569                         // newly created host method to emit the body only once. The
5570                         // original block then simply calls the newly generated method.
5571                         //
5572                         if (bc.CurrentIterator != null && !bc.IsInProbingMode) {
5573                                 var b = stmt as Block;
5574                                 if (b != null && b.Explicit.HasYield) {
5575                                         finally_host = bc.CurrentIterator.CreateFinallyHost (this);
5576                                 }
5577                         }
5578
5579                         return base.Resolve (bc) && ok;
5580                 }
5581         }
5582
5583         //
5584         // Base class for blocks using exception handling
5585         //
5586         public abstract class ExceptionStatement : ResumableStatement
5587         {
5588                 protected List<ResumableStatement> resume_points;
5589                 protected int first_resume_pc;
5590                 protected ExceptionStatement parent;
5591
5592                 protected ExceptionStatement (Location loc)
5593                 {
5594                         this.loc = loc;
5595                 }
5596
5597                 protected virtual void EmitTryBodyPrepare (EmitContext ec)
5598                 {
5599                         StateMachineInitializer state_machine = null;
5600                         if (resume_points != null) {
5601                                 state_machine = (StateMachineInitializer) ec.CurrentAnonymousMethod;
5602
5603                                 ec.EmitInt ((int) IteratorStorey.State.Running);
5604                                 ec.Emit (OpCodes.Stloc, state_machine.CurrentPC);
5605                         }
5606
5607                         ec.BeginExceptionBlock ();
5608
5609                         if (resume_points != null) {
5610                                 ec.MarkLabel (resume_point);
5611
5612                                 // For normal control flow, we want to fall-through the Switch
5613                                 // So, we use CurrentPC rather than the $PC field, and initialize it to an outside value above
5614                                 ec.Emit (OpCodes.Ldloc, state_machine.CurrentPC);
5615                                 ec.EmitInt (first_resume_pc);
5616                                 ec.Emit (OpCodes.Sub);
5617
5618                                 Label[] labels = new Label[resume_points.Count];
5619                                 for (int i = 0; i < resume_points.Count; ++i)
5620                                         labels[i] = resume_points[i].PrepareForEmit (ec);
5621                                 ec.Emit (OpCodes.Switch, labels);
5622                         }
5623                 }
5624
5625                 public virtual int AddResumePoint (ResumableStatement stmt, int pc, StateMachineInitializer stateMachine)
5626                 {
5627                         if (parent != null) {
5628                                 // TODO: MOVE to virtual TryCatch
5629                                 var tc = this as TryCatch;
5630                                 var s = tc != null && tc.IsTryCatchFinally ? stmt : this;
5631
5632                                 pc = parent.AddResumePoint (s, pc, stateMachine);
5633                         } else {
5634                                 pc = stateMachine.AddResumePoint (this);
5635                         }
5636
5637                         if (resume_points == null) {
5638                                 resume_points = new List<ResumableStatement> ();
5639                                 first_resume_pc = pc;
5640                         }
5641
5642                         if (pc != first_resume_pc + resume_points.Count)
5643                                 throw new InternalErrorException ("missed an intervening AddResumePoint?");
5644
5645                         resume_points.Add (stmt);
5646                         return pc;
5647                 }
5648         }
5649
5650         public class Lock : TryFinallyBlock
5651         {
5652                 Expression expr;
5653                 TemporaryVariableReference expr_copy;
5654                 TemporaryVariableReference lock_taken;
5655                         
5656                 public Lock (Expression expr, Statement stmt, Location loc)
5657                         : base (stmt, loc)
5658                 {
5659                         this.expr = expr;
5660                 }
5661
5662                 public Expression Expr {
5663                         get {
5664                                 return this.expr;
5665                         }
5666                 }
5667
5668                 public override bool Resolve (BlockContext ec)
5669                 {
5670                         expr = expr.Resolve (ec);
5671                         if (expr == null)
5672                                 return false;
5673
5674                         if (!TypeSpec.IsReferenceType (expr.Type)) {
5675                                 ec.Report.Error (185, loc,
5676                                         "`{0}' is not a reference type as required by the lock statement",
5677                                         expr.Type.GetSignatureForError ());
5678                         }
5679
5680                         if (expr.Type.IsGenericParameter) {
5681                                 expr = Convert.ImplicitTypeParameterConversion (expr, (TypeParameterSpec)expr.Type, ec.BuiltinTypes.Object);
5682                         }
5683
5684                         VariableReference lv = expr as VariableReference;
5685                         bool locked;
5686                         if (lv != null) {
5687                                 locked = lv.IsLockedByStatement;
5688                                 lv.IsLockedByStatement = true;
5689                         } else {
5690                                 lv = null;
5691                                 locked = false;
5692                         }
5693
5694                         //
5695                         // Have to keep original lock value around to unlock same location
5696                         // in the case of original value has changed or is null
5697                         //
5698                         expr_copy = TemporaryVariableReference.Create (ec.BuiltinTypes.Object, ec.CurrentBlock, loc);
5699                         expr_copy.Resolve (ec);
5700
5701                         //
5702                         // Ensure Monitor methods are available
5703                         //
5704                         if (ResolvePredefinedMethods (ec) > 1) {
5705                                 lock_taken = TemporaryVariableReference.Create (ec.BuiltinTypes.Bool, ec.CurrentBlock, loc);
5706                                 lock_taken.Resolve (ec);
5707                         }
5708
5709                         using (ec.Set (ResolveContext.Options.LockScope)) {
5710                                 base.Resolve (ec);
5711                         }
5712
5713                         if (lv != null) {
5714                                 lv.IsLockedByStatement = locked;
5715                         }
5716
5717                         return true;
5718                 }
5719                 
5720                 protected override void EmitTryBodyPrepare (EmitContext ec)
5721                 {
5722                         expr_copy.EmitAssign (ec, expr);
5723
5724                         if (lock_taken != null) {
5725                                 //
5726                                 // Initialize ref variable
5727                                 //
5728                                 lock_taken.EmitAssign (ec, new BoolLiteral (ec.BuiltinTypes, false, loc));
5729                         } else {
5730                                 //
5731                                 // Monitor.Enter (expr_copy)
5732                                 //
5733                                 expr_copy.Emit (ec);
5734                                 ec.Emit (OpCodes.Call, ec.Module.PredefinedMembers.MonitorEnter.Get ());
5735                         }
5736
5737                         base.EmitTryBodyPrepare (ec);
5738                 }
5739
5740                 protected override void EmitTryBody (EmitContext ec)
5741                 {
5742                         //
5743                         // Monitor.Enter (expr_copy, ref lock_taken)
5744                         //
5745                         if (lock_taken != null) {
5746                                 expr_copy.Emit (ec);
5747                                 lock_taken.LocalInfo.CreateBuilder (ec);
5748                                 lock_taken.AddressOf (ec, AddressOp.Load);
5749                                 ec.Emit (OpCodes.Call, ec.Module.PredefinedMembers.MonitorEnter_v4.Get ());
5750                         }
5751
5752                         Statement.Emit (ec);
5753                 }
5754
5755                 public override void EmitFinallyBody (EmitContext ec)
5756                 {
5757                         //
5758                         // if (lock_taken) Monitor.Exit (expr_copy)
5759                         //
5760                         Label skip = ec.DefineLabel ();
5761
5762                         if (lock_taken != null) {
5763                                 lock_taken.Emit (ec);
5764                                 ec.Emit (OpCodes.Brfalse_S, skip);
5765                         }
5766
5767                         expr_copy.Emit (ec);
5768                         var m = ec.Module.PredefinedMembers.MonitorExit.Resolve (loc);
5769                         if (m != null)
5770                                 ec.Emit (OpCodes.Call, m);
5771
5772                         ec.MarkLabel (skip);
5773                 }
5774
5775                 int ResolvePredefinedMethods (ResolveContext rc)
5776                 {
5777                         // Try 4.0 Monitor.Enter (object, ref bool) overload first
5778                         var m = rc.Module.PredefinedMembers.MonitorEnter_v4.Get ();
5779                         if (m != null)
5780                                 return 4;
5781
5782                         m = rc.Module.PredefinedMembers.MonitorEnter.Get ();
5783                         if (m != null)
5784                                 return 1;
5785
5786                         rc.Module.PredefinedMembers.MonitorEnter_v4.Resolve (loc);
5787                         return 0;
5788                 }
5789
5790                 protected override void CloneTo (CloneContext clonectx, Statement t)
5791                 {
5792                         Lock target = (Lock) t;
5793
5794                         target.expr = expr.Clone (clonectx);
5795                         target.stmt = Statement.Clone (clonectx);
5796                 }
5797                 
5798                 public override object Accept (StructuralVisitor visitor)
5799                 {
5800                         return visitor.Visit (this);
5801                 }
5802
5803         }
5804
5805         public class Unchecked : Statement {
5806                 public Block Block;
5807                 
5808                 public Unchecked (Block b, Location loc)
5809                 {
5810                         Block = b;
5811                         b.Unchecked = true;
5812                         this.loc = loc;
5813                 }
5814
5815                 public override bool Resolve (BlockContext ec)
5816                 {
5817                         using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
5818                                 return Block.Resolve (ec);
5819                 }
5820                 
5821                 protected override void DoEmit (EmitContext ec)
5822                 {
5823                         using (ec.With (EmitContext.Options.CheckedScope, false))
5824                                 Block.Emit (ec);
5825                 }
5826
5827                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
5828                 {
5829                         return Block.FlowAnalysis (fc);
5830                 }
5831
5832                 public override Reachability MarkReachable (Reachability rc)
5833                 {
5834                         base.MarkReachable (rc);
5835                         return Block.MarkReachable (rc);
5836                 }
5837
5838                 protected override void CloneTo (CloneContext clonectx, Statement t)
5839                 {
5840                         Unchecked target = (Unchecked) t;
5841
5842                         target.Block = clonectx.LookupBlock (Block);
5843                 }
5844                 
5845                 public override object Accept (StructuralVisitor visitor)
5846                 {
5847                         return visitor.Visit (this);
5848                 }
5849         }
5850
5851         public class Checked : Statement {
5852                 public Block Block;
5853                 
5854                 public Checked (Block b, Location loc)
5855                 {
5856                         Block = b;
5857                         b.Unchecked = false;
5858                         this.loc = loc;
5859                 }
5860
5861                 public override bool Resolve (BlockContext ec)
5862                 {
5863                         using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
5864                                 return Block.Resolve (ec);
5865                 }
5866
5867                 protected override void DoEmit (EmitContext ec)
5868                 {
5869                         using (ec.With (EmitContext.Options.CheckedScope, true))
5870                                 Block.Emit (ec);
5871                 }
5872
5873                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
5874                 {
5875                         return Block.FlowAnalysis (fc);
5876                 }
5877
5878                 public override Reachability MarkReachable (Reachability rc)
5879                 {
5880                         base.MarkReachable (rc);
5881                         return Block.MarkReachable (rc);
5882                 }
5883
5884                 protected override void CloneTo (CloneContext clonectx, Statement t)
5885                 {
5886                         Checked target = (Checked) t;
5887
5888                         target.Block = clonectx.LookupBlock (Block);
5889                 }
5890                 
5891                 public override object Accept (StructuralVisitor visitor)
5892                 {
5893                         return visitor.Visit (this);
5894                 }
5895         }
5896
5897         public class Unsafe : Statement {
5898                 public Block Block;
5899
5900                 public Unsafe (Block b, Location loc)
5901                 {
5902                         Block = b;
5903                         Block.Unsafe = true;
5904                         this.loc = loc;
5905                 }
5906
5907                 public override bool Resolve (BlockContext ec)
5908                 {
5909                         if (ec.CurrentIterator != null)
5910                                 ec.Report.Error (1629, loc, "Unsafe code may not appear in iterators");
5911
5912                         using (ec.Set (ResolveContext.Options.UnsafeScope))
5913                                 return Block.Resolve (ec);
5914                 }
5915                 
5916                 protected override void DoEmit (EmitContext ec)
5917                 {
5918                         Block.Emit (ec);
5919                 }
5920
5921                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
5922                 {
5923                         return Block.FlowAnalysis (fc);
5924                 }
5925
5926                 public override Reachability MarkReachable (Reachability rc)
5927                 {
5928                         base.MarkReachable (rc);
5929                         return Block.MarkReachable (rc);
5930                 }
5931
5932                 protected override void CloneTo (CloneContext clonectx, Statement t)
5933                 {
5934                         Unsafe target = (Unsafe) t;
5935
5936                         target.Block = clonectx.LookupBlock (Block);
5937                 }
5938                 
5939                 public override object Accept (StructuralVisitor visitor)
5940                 {
5941                         return visitor.Visit (this);
5942                 }
5943         }
5944
5945         // 
5946         // Fixed statement
5947         //
5948         public class Fixed : Statement
5949         {
5950                 abstract class Emitter : ShimExpression
5951                 {
5952                         protected LocalVariable vi;
5953
5954                         protected Emitter (Expression expr, LocalVariable li)
5955                                 : base (expr)
5956                         {
5957                                 vi = li;
5958                         }
5959
5960                         public abstract void EmitExit (EmitContext ec);
5961
5962                         public override void FlowAnalysis (FlowAnalysisContext fc)
5963                         {
5964                                 expr.FlowAnalysis (fc);
5965                         }
5966                 }
5967
5968                 class ExpressionEmitter : Emitter {
5969                         public ExpressionEmitter (Expression converted, LocalVariable li) :
5970                                 base (converted, li)
5971                         {
5972                         }
5973
5974                         protected override Expression DoResolve (ResolveContext rc)
5975                         {
5976                                 throw new NotImplementedException ();
5977                         }
5978
5979                         public override void Emit (EmitContext ec) {
5980                                 //
5981                                 // Store pointer in pinned location
5982                                 //
5983                                 expr.Emit (ec);
5984                                 vi.EmitAssign (ec);
5985                         }
5986
5987                         public override void EmitExit (EmitContext ec)
5988                         {
5989                                 ec.EmitInt (0);
5990                                 ec.Emit (OpCodes.Conv_U);
5991                                 vi.EmitAssign (ec);
5992                         }
5993                 }
5994
5995                 class StringEmitter : Emitter
5996                 {
5997                         LocalVariable pinned_string;
5998
5999                         public StringEmitter (Expression expr, LocalVariable li)
6000                                 : base (expr, li)
6001                         {
6002                         }
6003
6004                         protected override Expression DoResolve (ResolveContext rc)
6005                         {
6006                                 pinned_string = new LocalVariable (vi.Block, "$pinned",
6007                                         LocalVariable.Flags.FixedVariable | LocalVariable.Flags.CompilerGenerated | LocalVariable.Flags.Used,
6008                                         vi.Location);
6009                                 pinned_string.Type = rc.BuiltinTypes.String;
6010
6011                                 eclass = ExprClass.Variable;
6012                                 type = rc.BuiltinTypes.Int;
6013                                 return this;
6014                         }
6015
6016                         public override void Emit (EmitContext ec)
6017                         {
6018                                 pinned_string.CreateBuilder (ec);
6019
6020                                 expr.Emit (ec);
6021                                 pinned_string.EmitAssign (ec);
6022
6023                                 // TODO: Should use Binary::Add
6024                                 pinned_string.Emit (ec);
6025                                 ec.Emit (OpCodes.Conv_I);
6026
6027                                 var m = ec.Module.PredefinedMembers.RuntimeHelpersOffsetToStringData.Resolve (loc);
6028                                 if (m == null)
6029                                         return;
6030
6031                                 PropertyExpr pe = new PropertyExpr (m, pinned_string.Location);
6032                                 //pe.InstanceExpression = pinned_string;
6033                                 pe.Resolve (new ResolveContext (ec.MemberContext)).Emit (ec);
6034
6035                                 ec.Emit (OpCodes.Add);
6036                                 vi.EmitAssign (ec);
6037                         }
6038
6039                         public override void EmitExit (EmitContext ec)
6040                         {
6041                                 ec.EmitNull ();
6042                                 pinned_string.EmitAssign (ec);
6043                         }
6044                 }
6045
6046                 public class VariableDeclaration : BlockVariable
6047                 {
6048                         public VariableDeclaration (FullNamedExpression type, LocalVariable li)
6049                                 : base (type, li)
6050                         {
6051                         }
6052
6053                         protected override Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
6054                         {
6055                                 if (!Variable.Type.IsPointer && li == Variable) {
6056                                         bc.Report.Error (209, TypeExpression.Location,
6057                                                 "The type of locals declared in a fixed statement must be a pointer type");
6058                                         return null;
6059                                 }
6060
6061                                 //
6062                                 // The rules for the possible declarators are pretty wise,
6063                                 // but the production on the grammar is more concise.
6064                                 //
6065                                 // So we have to enforce these rules here.
6066                                 //
6067                                 // We do not resolve before doing the case 1 test,
6068                                 // because the grammar is explicit in that the token &
6069                                 // is present, so we need to test for this particular case.
6070                                 //
6071
6072                                 if (initializer is Cast) {
6073                                         bc.Report.Error (254, initializer.Location, "The right hand side of a fixed statement assignment may not be a cast expression");
6074                                         return null;
6075                                 }
6076
6077                                 initializer = initializer.Resolve (bc);
6078
6079                                 if (initializer == null)
6080                                         return null;
6081
6082                                 //
6083                                 // Case 1: Array
6084                                 //
6085                                 if (initializer.Type.IsArray) {
6086                                         TypeSpec array_type = TypeManager.GetElementType (initializer.Type);
6087
6088                                         //
6089                                         // Provided that array_type is unmanaged,
6090                                         //
6091                                         if (!TypeManager.VerifyUnmanaged (bc.Module, array_type, loc))
6092                                                 return null;
6093
6094                                         //
6095                                         // and T* is implicitly convertible to the
6096                                         // pointer type given in the fixed statement.
6097                                         //
6098                                         ArrayPtr array_ptr = new ArrayPtr (initializer, array_type, loc);
6099
6100                                         Expression converted = Convert.ImplicitConversionRequired (bc, array_ptr.Resolve (bc), li.Type, loc);
6101                                         if (converted == null)
6102                                                 return null;
6103
6104                                         //
6105                                         // fixed (T* e_ptr = (e == null || e.Length == 0) ? null : converted [0])
6106                                         //
6107                                         converted = new Conditional (new BooleanExpression (new Binary (Binary.Operator.LogicalOr,
6108                                                 new Binary (Binary.Operator.Equality, initializer, new NullLiteral (loc)),
6109                                                 new Binary (Binary.Operator.Equality, new MemberAccess (initializer, "Length"), new IntConstant (bc.BuiltinTypes, 0, loc)))),
6110                                                         new NullLiteral (loc),
6111                                                         converted, loc);
6112
6113                                         converted = converted.Resolve (bc);
6114
6115                                         return new ExpressionEmitter (converted, li);
6116                                 }
6117
6118                                 //
6119                                 // Case 2: string
6120                                 //
6121                                 if (initializer.Type.BuiltinType == BuiltinTypeSpec.Type.String) {
6122                                         return new StringEmitter (initializer, li).Resolve (bc);
6123                                 }
6124
6125                                 // Case 3: fixed buffer
6126                                 if (initializer is FixedBufferPtr) {
6127                                         return new ExpressionEmitter (initializer, li);
6128                                 }
6129
6130                                 //
6131                                 // Case 4: & object.
6132                                 //
6133                                 bool already_fixed = true;
6134                                 Unary u = initializer as Unary;
6135                                 if (u != null && u.Oper == Unary.Operator.AddressOf) {
6136                                         IVariableReference vr = u.Expr as IVariableReference;
6137                                         if (vr == null || !vr.IsFixed) {
6138                                                 already_fixed = false;
6139                                         }
6140                                 }
6141
6142                                 if (already_fixed) {
6143                                         bc.Report.Error (213, loc, "You cannot use the fixed statement to take the address of an already fixed expression");
6144                                 }
6145
6146                                 initializer = Convert.ImplicitConversionRequired (bc, initializer, li.Type, loc);
6147                                 return new ExpressionEmitter (initializer, li);
6148                         }
6149                 }
6150
6151
6152                 VariableDeclaration decl;
6153                 Statement statement;
6154                 bool has_ret;
6155
6156                 public Fixed (VariableDeclaration decl, Statement stmt, Location l)
6157                 {
6158                         this.decl = decl;
6159                         statement = stmt;
6160                         loc = l;
6161                 }
6162
6163                 #region Properties
6164
6165                 public Statement Statement {
6166                         get {
6167                                 return statement;
6168                         }
6169                 }
6170
6171                 public BlockVariable Variables {
6172                         get {
6173                                 return decl;
6174                         }
6175                 }
6176
6177                 #endregion
6178
6179                 public override bool Resolve (BlockContext bc)
6180                 {
6181                         using (bc.Set (ResolveContext.Options.FixedInitializerScope)) {
6182                                 if (!decl.Resolve (bc))
6183                                         return false;
6184                         }
6185
6186                         return statement.Resolve (bc);
6187                 }
6188
6189                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6190                 {
6191                         decl.FlowAnalysis (fc);
6192                         return statement.FlowAnalysis (fc);
6193                 }
6194                 
6195                 protected override void DoEmit (EmitContext ec)
6196                 {
6197                         decl.Variable.CreateBuilder (ec);
6198                         decl.Initializer.Emit (ec);
6199                         if (decl.Declarators != null) {
6200                                 foreach (var d in decl.Declarators) {
6201                                         d.Variable.CreateBuilder (ec);
6202                                         d.Initializer.Emit (ec);
6203                                 }
6204                         }
6205
6206                         statement.Emit (ec);
6207
6208                         if (has_ret)
6209                                 return;
6210
6211                         //
6212                         // Clear the pinned variable
6213                         //
6214                         ((Emitter) decl.Initializer).EmitExit (ec);
6215                         if (decl.Declarators != null) {
6216                                 foreach (var d in decl.Declarators) {
6217                                         ((Emitter)d.Initializer).EmitExit (ec);
6218                                 }
6219                         }
6220                 }
6221
6222                 public override Reachability MarkReachable (Reachability rc)
6223                 {
6224                         base.MarkReachable (rc);
6225
6226                         decl.MarkReachable (rc);
6227
6228                         rc = statement.MarkReachable (rc);
6229
6230                         // TODO: What if there is local exit?
6231                         has_ret = rc.IsUnreachable;
6232                         return rc;
6233                 }
6234
6235                 protected override void CloneTo (CloneContext clonectx, Statement t)
6236                 {
6237                         Fixed target = (Fixed) t;
6238
6239                         target.decl = (VariableDeclaration) decl.Clone (clonectx);
6240                         target.statement = statement.Clone (clonectx);
6241                 }
6242                 
6243                 public override object Accept (StructuralVisitor visitor)
6244                 {
6245                         return visitor.Visit (this);
6246                 }
6247         }
6248
6249         public class Catch : Statement
6250         {
6251                 ExplicitBlock block;
6252                 LocalVariable li;
6253                 FullNamedExpression type_expr;
6254                 CompilerAssign assign;
6255                 TypeSpec type;
6256                 
6257                 public Catch (ExplicitBlock block, Location loc)
6258                 {
6259                         this.block = block;
6260                         this.loc = loc;
6261                 }
6262
6263                 #region Properties
6264
6265                 public ExplicitBlock Block {
6266                         get {
6267                                 return block;
6268                         }
6269                 }
6270
6271                 public TypeSpec CatchType {
6272                         get {
6273                                 return type;
6274                         }
6275                 }
6276
6277                 public bool IsGeneral {
6278                         get {
6279                                 return type_expr == null;
6280                         }
6281                 }
6282
6283                 public FullNamedExpression TypeExpression {
6284                         get {
6285                                 return type_expr;
6286                         }
6287                         set {
6288                                 type_expr = value;
6289                         }
6290                 }
6291
6292                 public LocalVariable Variable {
6293                         get {
6294                                 return li;
6295                         }
6296                         set {
6297                                 li = value;
6298                         }
6299                 }
6300
6301                 #endregion
6302
6303                 protected override void DoEmit (EmitContext ec)
6304                 {
6305                         if (IsGeneral)
6306                                 ec.BeginCatchBlock (ec.BuiltinTypes.Object);
6307                         else
6308                                 ec.BeginCatchBlock (CatchType);
6309
6310                         if (li != null) {
6311                                 li.CreateBuilder (ec);
6312
6313                                 //
6314                                 // Special case hoisted catch variable, we have to use a temporary variable
6315                                 // to pass via anonymous storey initialization with the value still on top
6316                                 // of the stack
6317                                 //
6318                                 if (li.HoistedVariant != null) {
6319                                         LocalTemporary lt = new LocalTemporary (li.Type);
6320                                         lt.Store (ec);
6321
6322                                         // switch to assigning from the temporary variable and not from top of the stack
6323                                         assign.UpdateSource (lt);
6324                                 }
6325                         } else {
6326                                 ec.Emit (OpCodes.Pop);
6327                         }
6328
6329                         Block.Emit (ec);
6330                 }
6331
6332                 public override bool Resolve (BlockContext ec)
6333                 {
6334                         using (ec.Set (ResolveContext.Options.CatchScope)) {
6335                                 if (type_expr != null) {
6336                                         type = type_expr.ResolveAsType (ec);
6337                                         if (type == null)
6338                                                 return false;
6339
6340                                         if (type.BuiltinType != BuiltinTypeSpec.Type.Exception && !TypeSpec.IsBaseClass (type, ec.BuiltinTypes.Exception, false)) {
6341                                                 ec.Report.Error (155, loc, "The type caught or thrown must be derived from System.Exception");
6342                                         } else if (li != null) {
6343                                                 li.Type = type;
6344                                                 li.PrepareAssignmentAnalysis (ec);
6345
6346                                                 // source variable is at the top of the stack
6347                                                 Expression source = new EmptyExpression (li.Type);
6348                                                 if (li.Type.IsGenericParameter)
6349                                                         source = new UnboxCast (source, li.Type);
6350
6351                                                 //
6352                                                 // Uses Location.Null to hide from symbol file
6353                                                 //
6354                                                 assign = new CompilerAssign (new LocalVariableReference (li, Location.Null), source, Location.Null);
6355                                                 Block.AddScopeStatement (new StatementExpression (assign, Location.Null));
6356                                         }
6357                                 }
6358
6359                                 Block.SetCatchBlock ();
6360                                 return Block.Resolve (ec);
6361                         }
6362                 }
6363
6364                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6365                 {
6366                         if (li != null) {
6367                                 fc.SetVariableAssigned (li.VariableInfo, true);
6368                         }
6369
6370                         return block.FlowAnalysis (fc);
6371                 }
6372
6373                 public override Reachability MarkReachable (Reachability rc)
6374                 {
6375                         base.MarkReachable (rc);
6376
6377                         return block.MarkReachable (rc);
6378                 }
6379
6380                 protected override void CloneTo (CloneContext clonectx, Statement t)
6381                 {
6382                         Catch target = (Catch) t;
6383
6384                         if (type_expr != null)
6385                                 target.type_expr = (FullNamedExpression) type_expr.Clone (clonectx);
6386
6387                         target.block = (ExplicitBlock) clonectx.LookupBlock (block);
6388                 }
6389         }
6390
6391         public class TryFinally : TryFinallyBlock
6392         {
6393                 ExplicitBlock fini;
6394                 List<DefiniteAssignmentBitSet> try_exit_dat;
6395
6396                 public TryFinally (Statement stmt, ExplicitBlock fini, Location loc)
6397                          : base (stmt, loc)
6398                 {
6399                         this.fini = fini;
6400                 }
6401
6402                 public ExplicitBlock FinallyBlock {
6403                         get {
6404                                 return fini;
6405                         }
6406                 }
6407
6408                 public void RegisterForControlExitCheck (DefiniteAssignmentBitSet vector)
6409                 {
6410                         if (try_exit_dat == null)
6411                                 try_exit_dat = new List<DefiniteAssignmentBitSet> ();
6412
6413                         try_exit_dat.Add (vector);
6414                 }
6415
6416                 public override bool Resolve (BlockContext bc)
6417                 {
6418                         bool ok = base.Resolve (bc);
6419
6420                         fini.SetFinallyBlock ();
6421                         using (bc.Set (ResolveContext.Options.FinallyScope)) {
6422                                 ok &= fini.Resolve (bc);
6423                         }
6424
6425                         return ok;
6426                 }
6427
6428                 protected override void EmitTryBody (EmitContext ec)
6429                 {
6430                         stmt.Emit (ec);
6431                 }
6432
6433                 public override void EmitFinallyBody (EmitContext ec)
6434                 {
6435                         fini.Emit (ec);
6436                 }
6437
6438                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6439                 {
6440                         var da = fc.BranchDefiniteAssignment ();
6441
6442                         var tf = fc.TryFinally;
6443                         fc.TryFinally = this;
6444
6445                         var res_stmt = Statement.FlowAnalysis (fc);
6446
6447                         fc.TryFinally = tf;
6448
6449                         var try_da = fc.DefiniteAssignment;
6450                         fc.DefiniteAssignment = da;
6451
6452                         var res_fin = fini.FlowAnalysis (fc);
6453
6454                         if (try_exit_dat != null) {
6455                                 //
6456                                 // try block has global exit but we need to run definite assignment check
6457                                 // for parameter block out parameter after finally block because it's always
6458                                 // executed before exit
6459                                 //
6460                                 foreach (var try_da_part in try_exit_dat)
6461                                         fc.ParametersBlock.CheckControlExit (fc, fc.DefiniteAssignment | try_da_part);
6462
6463                                 try_exit_dat = null;
6464                         }
6465
6466                         fc.DefiniteAssignment |= try_da;
6467                         return res_stmt | res_fin;
6468                 }
6469
6470                 public override Reachability MarkReachable (Reachability rc)
6471                 {
6472                         //
6473                         // Mark finally block first for any exit statement in try block
6474                         // to know whether the code which follows finally is reachable
6475                         //
6476                         return fini.MarkReachable (rc) | base.MarkReachable (rc);
6477                 }
6478
6479                 protected override void CloneTo (CloneContext clonectx, Statement t)
6480                 {
6481                         TryFinally target = (TryFinally) t;
6482
6483                         target.stmt = stmt.Clone (clonectx);
6484                         if (fini != null)
6485                                 target.fini = (ExplicitBlock) clonectx.LookupBlock (fini);
6486                 }
6487                 
6488                 public override object Accept (StructuralVisitor visitor)
6489                 {
6490                         return visitor.Visit (this);
6491                 }
6492         }
6493
6494         public class TryCatch : ExceptionStatement
6495         {
6496                 public Block Block;
6497                 List<Catch> clauses;
6498                 readonly bool inside_try_finally;
6499
6500                 public TryCatch (Block block, List<Catch> catch_clauses, Location l, bool inside_try_finally)
6501                         : base (l)
6502                 {
6503                         this.Block = block;
6504                         this.clauses = catch_clauses;
6505                         this.inside_try_finally = inside_try_finally;
6506                 }
6507
6508                 public List<Catch> Clauses {
6509                         get {
6510                                 return clauses;
6511                         }
6512                 }
6513
6514                 public bool IsTryCatchFinally {
6515                         get {
6516                                 return inside_try_finally;
6517                         }
6518                 }
6519
6520                 public override bool Resolve (BlockContext bc)
6521                 {
6522                         bool ok;
6523
6524                         using (bc.Set (ResolveContext.Options.TryScope)) {
6525                                 parent = bc.CurrentTryBlock;
6526
6527                                 if (IsTryCatchFinally) {
6528                                         ok = Block.Resolve (bc);
6529                                 } else {
6530                                         using (bc.Set (ResolveContext.Options.TryWithCatchScope)) {
6531                                                 bc.CurrentTryBlock = this;
6532                                                 ok = Block.Resolve (bc);
6533                                                 bc.CurrentTryBlock = parent;
6534                                         }
6535                                 }
6536                         }
6537
6538                         for (int i = 0; i < clauses.Count; ++i) {
6539                                 var c = clauses[i];
6540
6541                                 ok &= c.Resolve (bc);
6542
6543                                 TypeSpec resolved_type = c.CatchType;
6544                                 for (int ii = 0; ii < clauses.Count; ++ii) {
6545                                         if (ii == i)
6546                                                 continue;
6547
6548                                         if (clauses[ii].IsGeneral) {
6549                                                 if (resolved_type.BuiltinType != BuiltinTypeSpec.Type.Exception)
6550                                                         continue;
6551
6552                                                 if (!bc.Module.DeclaringAssembly.WrapNonExceptionThrows)
6553                                                         continue;
6554
6555                                                 if (!bc.Module.PredefinedAttributes.RuntimeCompatibility.IsDefined)
6556                                                         continue;
6557
6558                                                 bc.Report.Warning (1058, 1, c.loc,
6559                                                         "A previous catch clause already catches all exceptions. All non-exceptions thrown will be wrapped in a `System.Runtime.CompilerServices.RuntimeWrappedException'");
6560
6561                                                 continue;
6562                                         }
6563
6564                                         if (ii >= i)
6565                                                 continue;
6566
6567                                         var ct = clauses[ii].CatchType;
6568                                         if (ct == null)
6569                                                 continue;
6570
6571                                         if (resolved_type == ct || TypeSpec.IsBaseClass (resolved_type, ct, true)) {
6572                                                 bc.Report.Error (160, c.loc,
6573                                                         "A previous catch clause already catches all exceptions of this or a super type `{0}'",
6574                                                         ct.GetSignatureForError ());
6575                                                 ok = false;
6576                                         }
6577                                 }
6578                         }
6579
6580                         return base.Resolve (bc) && ok;
6581                 }
6582
6583                 protected sealed override void DoEmit (EmitContext ec)
6584                 {
6585                         if (!inside_try_finally)
6586                                 EmitTryBodyPrepare (ec);
6587
6588                         Block.Emit (ec);
6589
6590                         foreach (Catch c in clauses)
6591                                 c.Emit (ec);
6592
6593                         if (!inside_try_finally)
6594                                 ec.EndExceptionBlock ();
6595                 }
6596
6597                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6598                 {
6599                         var start_fc = fc.BranchDefiniteAssignment ();
6600                         var res = Block.FlowAnalysis (fc);
6601
6602                         DefiniteAssignmentBitSet try_fc = res ? null : fc.DefiniteAssignment;
6603
6604                         foreach (var c in clauses) {
6605                                 fc.DefiniteAssignment = new DefiniteAssignmentBitSet (start_fc);
6606                                 if (!c.FlowAnalysis (fc)) {
6607                                         if (try_fc == null)
6608                                                 try_fc = fc.DefiniteAssignment;
6609                                         else
6610                                                 try_fc &= fc.DefiniteAssignment;
6611
6612                                         res = false;
6613                                 }
6614                         }
6615
6616                         fc.DefiniteAssignment = try_fc ?? start_fc;
6617                         parent = null;
6618                         return res;
6619                 }
6620
6621                 public override Reachability MarkReachable (Reachability rc)
6622                 {
6623                         if (rc.IsUnreachable)
6624                                 return rc;
6625
6626                         base.MarkReachable (rc);
6627
6628                         var tc_rc = Block.MarkReachable (rc);
6629
6630                         foreach (var c in clauses)
6631                                 tc_rc &= c.MarkReachable (rc);
6632
6633                         return tc_rc;
6634                 }
6635
6636                 protected override void CloneTo (CloneContext clonectx, Statement t)
6637                 {
6638                         TryCatch target = (TryCatch) t;
6639
6640                         target.Block = clonectx.LookupBlock (Block);
6641                         if (clauses != null){
6642                                 target.clauses = new List<Catch> ();
6643                                 foreach (Catch c in clauses)
6644                                         target.clauses.Add ((Catch) c.Clone (clonectx));
6645                         }
6646                 }
6647
6648                 public override object Accept (StructuralVisitor visitor)
6649                 {
6650                         return visitor.Visit (this);
6651                 }
6652         }
6653
6654         public class Using : TryFinallyBlock
6655         {
6656                 public class VariableDeclaration : BlockVariable
6657                 {
6658                         Statement dispose_call;
6659
6660                         public VariableDeclaration (FullNamedExpression type, LocalVariable li)
6661                                 : base (type, li)
6662                         {
6663                         }
6664
6665                         public VariableDeclaration (LocalVariable li, Location loc)
6666                                 : base (li)
6667                         {
6668                                 this.loc = loc;
6669                         }
6670
6671                         public VariableDeclaration (Expression expr)
6672                                 : base (null)
6673                         {
6674                                 loc = expr.Location;
6675                                 Initializer = expr;
6676                         }
6677
6678                         #region Properties
6679
6680                         public bool IsNested { get; private set; }
6681
6682                         #endregion
6683
6684                         public void EmitDispose (EmitContext ec)
6685                         {
6686                                 dispose_call.Emit (ec);
6687                         }
6688
6689                         public override bool Resolve (BlockContext bc)
6690                         {
6691                                 if (IsNested)
6692                                         return true;
6693
6694                                 return base.Resolve (bc, false);
6695                         }
6696
6697                         public Expression ResolveExpression (BlockContext bc)
6698                         {
6699                                 var e = Initializer.Resolve (bc);
6700                                 if (e == null)
6701                                         return null;
6702
6703                                 li = LocalVariable.CreateCompilerGenerated (e.Type, bc.CurrentBlock, loc);
6704                                 Initializer = ResolveInitializer (bc, Variable, e);
6705                                 return e;
6706                         }
6707
6708                         protected override Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
6709                         {
6710                                 if (li.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
6711                                         initializer = initializer.Resolve (bc);
6712                                         if (initializer == null)
6713                                                 return null;
6714
6715                                         // Once there is dynamic used defer conversion to runtime even if we know it will never succeed
6716                                         Arguments args = new Arguments (1);
6717                                         args.Add (new Argument (initializer));
6718                                         initializer = new DynamicConversion (bc.BuiltinTypes.IDisposable, 0, args, initializer.Location).Resolve (bc);
6719                                         if (initializer == null)
6720                                                 return null;
6721
6722                                         var var = LocalVariable.CreateCompilerGenerated (initializer.Type, bc.CurrentBlock, loc);
6723                                         dispose_call = CreateDisposeCall (bc, var);
6724                                         dispose_call.Resolve (bc);
6725
6726                                         return base.ResolveInitializer (bc, li, new SimpleAssign (var.CreateReferenceExpression (bc, loc), initializer, loc));
6727                                 }
6728
6729                                 if (li == Variable) {
6730                                         CheckIDiposableConversion (bc, li, initializer);
6731                                         dispose_call = CreateDisposeCall (bc, li);
6732                                         dispose_call.Resolve (bc);
6733                                 }
6734
6735                                 return base.ResolveInitializer (bc, li, initializer);
6736                         }
6737
6738                         protected virtual void CheckIDiposableConversion (BlockContext bc, LocalVariable li, Expression initializer)
6739                         {
6740                                 var type = li.Type;
6741
6742                                 if (type.BuiltinType != BuiltinTypeSpec.Type.IDisposable && !type.ImplementsInterface (bc.BuiltinTypes.IDisposable, false)) {
6743                                         if (type.IsNullableType) {
6744                                                 // it's handled in CreateDisposeCall
6745                                                 return;
6746                                         }
6747
6748                                         if (type != InternalType.ErrorType) {
6749                                                 bc.Report.SymbolRelatedToPreviousError (type);
6750                                                 var loc = type_expr == null ? initializer.Location : type_expr.Location;
6751                                                 bc.Report.Error (1674, loc, "`{0}': type used in a using statement must be implicitly convertible to `System.IDisposable'",
6752                                                         type.GetSignatureForError ());
6753                                         }
6754
6755                                         return;
6756                                 }
6757                         }
6758
6759                         protected virtual Statement CreateDisposeCall (BlockContext bc, LocalVariable lv)
6760                         {
6761                                 var lvr = lv.CreateReferenceExpression (bc, lv.Location);
6762                                 var type = lv.Type;
6763                                 var loc = lv.Location;
6764
6765                                 var idt = bc.BuiltinTypes.IDisposable;
6766                                 var m = bc.Module.PredefinedMembers.IDisposableDispose.Resolve (loc);
6767
6768                                 var dispose_mg = MethodGroupExpr.CreatePredefined (m, idt, loc);
6769                                 dispose_mg.InstanceExpression = type.IsNullableType ?
6770                                         new Cast (new TypeExpression (idt, loc), lvr, loc).Resolve (bc) :
6771                                         lvr;
6772
6773                                 //
6774                                 // Hide it from symbol file via null location
6775                                 //
6776                                 Statement dispose = new StatementExpression (new Invocation (dispose_mg, null), Location.Null);
6777
6778                                 // Add conditional call when disposing possible null variable
6779                                 if (!type.IsStruct || type.IsNullableType)
6780                                         dispose = new If (new Binary (Binary.Operator.Inequality, lvr, new NullLiteral (loc)), dispose, dispose.loc);
6781
6782                                 return dispose;
6783                         }
6784
6785                         public void ResolveDeclaratorInitializer (BlockContext bc)
6786                         {
6787                                 Initializer = base.ResolveInitializer (bc, Variable, Initializer);
6788                         }
6789
6790                         public Statement RewriteUsingDeclarators (BlockContext bc, Statement stmt)
6791                         {
6792                                 for (int i = declarators.Count - 1; i >= 0; --i) {
6793                                         var d = declarators [i];
6794                                         var vd = new VariableDeclaration (d.Variable, d.Variable.Location);
6795                                         vd.Initializer = d.Initializer;
6796                                         vd.IsNested = true;
6797                                         vd.dispose_call = CreateDisposeCall (bc, d.Variable);
6798                                         vd.dispose_call.Resolve (bc);
6799
6800                                         stmt = new Using (vd, stmt, d.Variable.Location);
6801                                 }
6802
6803                                 declarators = null;
6804                                 return stmt;
6805                         }       
6806
6807                         public override object Accept (StructuralVisitor visitor)
6808                         {
6809                                 return visitor.Visit (this);
6810                         }       
6811                 }
6812
6813                 VariableDeclaration decl;
6814
6815                 public Using (VariableDeclaration decl, Statement stmt, Location loc)
6816                         : base (stmt, loc)
6817                 {
6818                         this.decl = decl;
6819                 }
6820
6821                 public Using (Expression expr, Statement stmt, Location loc)
6822                         : base (stmt, loc)
6823                 {
6824                         this.decl = new VariableDeclaration (expr);
6825                 }
6826
6827                 #region Properties
6828
6829                 public Expression Expr {
6830                         get {
6831                                 return decl.Variable == null ? decl.Initializer : null;
6832                         }
6833                 }
6834
6835                 public BlockVariable Variables {
6836                         get {
6837                                 return decl;
6838                         }
6839                 }
6840
6841                 #endregion
6842
6843                 public override void Emit (EmitContext ec)
6844                 {
6845                         //
6846                         // Don't emit sequence point it will be set on variable declaration
6847                         //
6848                         DoEmit (ec);
6849                 }
6850
6851                 protected override void EmitTryBodyPrepare (EmitContext ec)
6852                 {
6853                         decl.Emit (ec);
6854                         base.EmitTryBodyPrepare (ec);
6855                 }
6856
6857                 protected override void EmitTryBody (EmitContext ec)
6858                 {
6859                         stmt.Emit (ec);
6860                 }
6861
6862                 public override void EmitFinallyBody (EmitContext ec)
6863                 {
6864                         decl.EmitDispose (ec);
6865                 }
6866
6867                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6868                 {
6869                         decl.FlowAnalysis (fc);
6870                         return stmt.FlowAnalysis (fc);
6871                 }
6872
6873                 public override Reachability MarkReachable (Reachability rc)
6874                 {
6875                         decl.MarkReachable (rc);
6876                         return base.MarkReachable (rc);
6877                 }
6878
6879                 public override bool Resolve (BlockContext ec)
6880                 {
6881                         VariableReference vr;
6882                         bool vr_locked = false;
6883
6884                         using (ec.Set (ResolveContext.Options.UsingInitializerScope)) {
6885                                 if (decl.Variable == null) {
6886                                         vr = decl.ResolveExpression (ec) as VariableReference;
6887                                         if (vr != null) {
6888                                                 vr_locked = vr.IsLockedByStatement;
6889                                                 vr.IsLockedByStatement = true;
6890                                         }
6891                                 } else {
6892                                         if (decl.IsNested) {
6893                                                 decl.ResolveDeclaratorInitializer (ec);
6894                                         } else {
6895                                                 if (!decl.Resolve (ec))
6896                                                         return false;
6897
6898                                                 if (decl.Declarators != null) {
6899                                                         stmt = decl.RewriteUsingDeclarators (ec, stmt);
6900                                                 }
6901                                         }
6902
6903                                         vr = null;
6904                                 }
6905                         }
6906
6907                         base.Resolve (ec);
6908
6909                         if (vr != null)
6910                                 vr.IsLockedByStatement = vr_locked;
6911
6912                         return true;
6913                 }
6914
6915                 protected override void CloneTo (CloneContext clonectx, Statement t)
6916                 {
6917                         Using target = (Using) t;
6918
6919                         target.decl = (VariableDeclaration) decl.Clone (clonectx);
6920                         target.stmt = stmt.Clone (clonectx);
6921                 }
6922
6923                 public override object Accept (StructuralVisitor visitor)
6924                 {
6925                         return visitor.Visit (this);
6926                 }
6927         }
6928
6929         /// <summary>
6930         ///   Implementation of the foreach C# statement
6931         /// </summary>
6932         public class Foreach : LoopStatement
6933         {
6934                 abstract class IteratorStatement : Statement
6935                 {
6936                         protected readonly Foreach for_each;
6937
6938                         protected IteratorStatement (Foreach @foreach)
6939                         {
6940                                 this.for_each = @foreach;
6941                                 this.loc = @foreach.expr.Location;
6942                         }
6943
6944                         protected override void CloneTo (CloneContext clonectx, Statement target)
6945                         {
6946                                 throw new NotImplementedException ();
6947                         }
6948
6949                         public override void Emit (EmitContext ec)
6950                         {
6951                                 if (ec.EmitAccurateDebugInfo) {
6952                                         ec.Emit (OpCodes.Nop);
6953                                 }
6954
6955                                 base.Emit (ec);
6956                         }
6957
6958                         protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6959                         {
6960                                 throw new NotImplementedException ();
6961                         }
6962                 }
6963
6964                 sealed class ArrayForeach : IteratorStatement
6965                 {
6966                         TemporaryVariableReference[] lengths;
6967                         Expression [] length_exprs;
6968                         StatementExpression[] counter;
6969                         TemporaryVariableReference[] variables;
6970
6971                         TemporaryVariableReference copy;
6972
6973                         public ArrayForeach (Foreach @foreach, int rank)
6974                                 : base (@foreach)
6975                         {
6976                                 counter = new StatementExpression[rank];
6977                                 variables = new TemporaryVariableReference[rank];
6978                                 length_exprs = new Expression [rank];
6979
6980                                 //
6981                                 // Only use temporary length variables when dealing with
6982                                 // multi-dimensional arrays
6983                                 //
6984                                 if (rank > 1)
6985                                         lengths = new TemporaryVariableReference [rank];
6986                         }
6987
6988                         public override bool Resolve (BlockContext ec)
6989                         {
6990                                 Block variables_block = for_each.variable.Block;
6991                                 copy = TemporaryVariableReference.Create (for_each.expr.Type, variables_block, loc);
6992                                 copy.Resolve (ec);
6993
6994                                 int rank = length_exprs.Length;
6995                                 Arguments list = new Arguments (rank);
6996                                 for (int i = 0; i < rank; i++) {
6997                                         var v = TemporaryVariableReference.Create (ec.BuiltinTypes.Int, variables_block, loc);
6998                                         variables[i] = v;
6999                                         counter[i] = new StatementExpression (new UnaryMutator (UnaryMutator.Mode.PostIncrement, v, Location.Null));
7000                                         counter[i].Resolve (ec);
7001
7002                                         if (rank == 1) {
7003                                                 length_exprs [i] = new MemberAccess (copy, "Length").Resolve (ec);
7004                                         } else {
7005                                                 lengths[i] = TemporaryVariableReference.Create (ec.BuiltinTypes.Int, variables_block, loc);
7006                                                 lengths[i].Resolve (ec);
7007
7008                                                 Arguments args = new Arguments (1);
7009                                                 args.Add (new Argument (new IntConstant (ec.BuiltinTypes, i, loc)));
7010                                                 length_exprs [i] = new Invocation (new MemberAccess (copy, "GetLength"), args).Resolve (ec);
7011                                         }
7012
7013                                         list.Add (new Argument (v));
7014                                 }
7015
7016                                 var access = new ElementAccess (copy, list, loc).Resolve (ec);
7017                                 if (access == null)
7018                                         return false;
7019
7020                                 TypeSpec var_type;
7021                                 if (for_each.type is VarExpr) {
7022                                         // Infer implicitly typed local variable from foreach array type
7023                                         var_type = access.Type;
7024                                 } else {
7025                                         var_type = for_each.type.ResolveAsType (ec);
7026
7027                                         if (var_type == null)
7028                                                 return false;
7029
7030                                         access = Convert.ExplicitConversion (ec, access, var_type, loc);
7031                                         if (access == null)
7032                                                 return false;
7033                                 }
7034
7035                                 for_each.variable.Type = var_type;
7036
7037                                 var variable_ref = new LocalVariableReference (for_each.variable, loc).Resolve (ec);
7038                                 if (variable_ref == null)
7039                                         return false;
7040
7041                                 for_each.body.AddScopeStatement (new StatementExpression (new CompilerAssign (variable_ref, access, Location.Null), for_each.type.Location));
7042
7043                                 return for_each.body.Resolve (ec);
7044                         }
7045
7046                         protected override void DoEmit (EmitContext ec)
7047                         {
7048                                 copy.EmitAssign (ec, for_each.expr);
7049
7050                                 int rank = length_exprs.Length;
7051                                 Label[] test = new Label [rank];
7052                                 Label[] loop = new Label [rank];
7053
7054                                 for (int i = 0; i < rank; i++) {
7055                                         test [i] = ec.DefineLabel ();
7056                                         loop [i] = ec.DefineLabel ();
7057
7058                                         if (lengths != null)
7059                                                 lengths [i].EmitAssign (ec, length_exprs [i]);
7060                                 }
7061
7062                                 IntConstant zero = new IntConstant (ec.BuiltinTypes, 0, loc);
7063                                 for (int i = 0; i < rank; i++) {
7064                                         variables [i].EmitAssign (ec, zero);
7065
7066                                         ec.Emit (OpCodes.Br, test [i]);
7067                                         ec.MarkLabel (loop [i]);
7068                                 }
7069
7070                                 for_each.body.Emit (ec);
7071
7072                                 ec.MarkLabel (ec.LoopBegin);
7073                                 ec.Mark (for_each.expr.Location);
7074
7075                                 for (int i = rank - 1; i >= 0; i--){
7076                                         counter [i].Emit (ec);
7077
7078                                         ec.MarkLabel (test [i]);
7079                                         variables [i].Emit (ec);
7080
7081                                         if (lengths != null)
7082                                                 lengths [i].Emit (ec);
7083                                         else
7084                                                 length_exprs [i].Emit (ec);
7085
7086                                         ec.Emit (OpCodes.Blt, loop [i]);
7087                                 }
7088
7089                                 ec.MarkLabel (ec.LoopEnd);
7090                         }
7091                 }
7092
7093                 sealed class CollectionForeach : IteratorStatement, OverloadResolver.IErrorHandler
7094                 {
7095                         class RuntimeDispose : Using.VariableDeclaration
7096                         {
7097                                 public RuntimeDispose (LocalVariable lv, Location loc)
7098                                         : base (lv, loc)
7099                                 {
7100                                 }
7101
7102                                 protected override void CheckIDiposableConversion (BlockContext bc, LocalVariable li, Expression initializer)
7103                                 {
7104                                         // Defered to runtime check
7105                                 }
7106
7107                                 protected override Statement CreateDisposeCall (BlockContext bc, LocalVariable lv)
7108                                 {
7109                                         var idt = bc.BuiltinTypes.IDisposable;
7110
7111                                         //
7112                                         // Fabricates code like
7113                                         //
7114                                         // if ((temp = vr as IDisposable) != null) temp.Dispose ();
7115                                         //
7116
7117                                         var dispose_variable = LocalVariable.CreateCompilerGenerated (idt, bc.CurrentBlock, loc);
7118
7119                                         var idisaposable_test = new Binary (Binary.Operator.Inequality, new CompilerAssign (
7120                                                 dispose_variable.CreateReferenceExpression (bc, loc),
7121                                                 new As (lv.CreateReferenceExpression (bc, loc), new TypeExpression (dispose_variable.Type, loc), loc),
7122                                                 loc), new NullLiteral (loc));
7123
7124                                         var m = bc.Module.PredefinedMembers.IDisposableDispose.Resolve (loc);
7125
7126                                         var dispose_mg = MethodGroupExpr.CreatePredefined (m, idt, loc);
7127                                         dispose_mg.InstanceExpression = dispose_variable.CreateReferenceExpression (bc, loc);
7128
7129                                         Statement dispose = new StatementExpression (new Invocation (dispose_mg, null));
7130                                         return new If (idisaposable_test, dispose, loc);
7131                                 }
7132                         }
7133
7134                         LocalVariable variable;
7135                         Expression expr;
7136                         Statement statement;
7137                         ExpressionStatement init;
7138                         TemporaryVariableReference enumerator_variable;
7139                         bool ambiguous_getenumerator_name;
7140
7141                         public CollectionForeach (Foreach @foreach, LocalVariable var, Expression expr)
7142                                 : base (@foreach)
7143                         {
7144                                 this.variable = var;
7145                                 this.expr = expr;
7146                         }
7147
7148                         void Error_WrongEnumerator (ResolveContext rc, MethodSpec enumerator)
7149                         {
7150                                 rc.Report.SymbolRelatedToPreviousError (enumerator);
7151                                 rc.Report.Error (202, loc,
7152                                         "foreach statement requires that the return type `{0}' of `{1}' must have a suitable public MoveNext method and public Current property",
7153                                                 enumerator.ReturnType.GetSignatureForError (), enumerator.GetSignatureForError ());
7154                         }
7155
7156                         MethodGroupExpr ResolveGetEnumerator (ResolveContext rc)
7157                         {
7158                                 //
7159                                 // Option 1: Try to match by name GetEnumerator first
7160                                 //
7161                                 var mexpr = Expression.MemberLookup (rc, false, expr.Type,
7162                                         "GetEnumerator", 0, Expression.MemberLookupRestrictions.ExactArity, loc);               // TODO: What if CS0229 ?
7163
7164                                 var mg = mexpr as MethodGroupExpr;
7165                                 if (mg != null) {
7166                                         mg.InstanceExpression = expr;
7167                                         Arguments args = new Arguments (0);
7168                                         mg = mg.OverloadResolve (rc, ref args, this, OverloadResolver.Restrictions.ProbingOnly);
7169
7170                                         // For ambiguous GetEnumerator name warning CS0278 was reported, but Option 2 could still apply
7171                                         if (ambiguous_getenumerator_name)
7172                                                 mg = null;
7173
7174                                         if (mg != null && args.Count == 0 && !mg.BestCandidate.IsStatic && mg.BestCandidate.IsPublic) {
7175                                                 return mg;
7176                                         }
7177                                 }
7178
7179                                 //
7180                                 // Option 2: Try to match using IEnumerable interfaces with preference of generic version
7181                                 //
7182                                 var t = expr.Type;
7183                                 PredefinedMember<MethodSpec> iface_candidate = null;
7184                                 var ptypes = rc.Module.PredefinedTypes;
7185                                 var gen_ienumerable = ptypes.IEnumerableGeneric;
7186                                 if (!gen_ienumerable.Define ())
7187                                         gen_ienumerable = null;
7188
7189                                 var ifaces = t.Interfaces;
7190                                 if (ifaces != null) {
7191                                         foreach (var iface in ifaces) {
7192                                                 if (gen_ienumerable != null && iface.MemberDefinition == gen_ienumerable.TypeSpec.MemberDefinition) {
7193                                                         if (iface_candidate != null && iface_candidate != rc.Module.PredefinedMembers.IEnumerableGetEnumerator) {
7194                                                                 rc.Report.SymbolRelatedToPreviousError (expr.Type);
7195                                                                 rc.Report.Error (1640, loc,
7196                                                                         "foreach statement cannot operate on variables of type `{0}' because it contains multiple implementation of `{1}'. Try casting to a specific implementation",
7197                                                                         expr.Type.GetSignatureForError (), gen_ienumerable.TypeSpec.GetSignatureForError ());
7198
7199                                                                 return null;
7200                                                         }
7201
7202                                                         // TODO: Cache this somehow
7203                                                         iface_candidate = new PredefinedMember<MethodSpec> (rc.Module, iface,
7204                                                                 MemberFilter.Method ("GetEnumerator", 0, ParametersCompiled.EmptyReadOnlyParameters, null));
7205
7206                                                         continue;
7207                                                 }
7208
7209                                                 if (iface.BuiltinType == BuiltinTypeSpec.Type.IEnumerable && iface_candidate == null) {
7210                                                         iface_candidate = rc.Module.PredefinedMembers.IEnumerableGetEnumerator;
7211                                                 }
7212                                         }
7213                                 }
7214
7215                                 if (iface_candidate == null) {
7216                                         if (expr.Type != InternalType.ErrorType) {
7217                                                 rc.Report.Error (1579, loc,
7218                                                         "foreach statement cannot operate on variables of type `{0}' because it does not contain a definition for `{1}' or is inaccessible",
7219                                                         expr.Type.GetSignatureForError (), "GetEnumerator");
7220                                         }
7221
7222                                         return null;
7223                                 }
7224
7225                                 var method = iface_candidate.Resolve (loc);
7226                                 if (method == null)
7227                                         return null;
7228
7229                                 mg = MethodGroupExpr.CreatePredefined (method, expr.Type, loc);
7230                                 mg.InstanceExpression = expr;
7231                                 return mg;
7232                         }
7233
7234                         MethodGroupExpr ResolveMoveNext (ResolveContext rc, MethodSpec enumerator)
7235                         {
7236                                 var ms = MemberCache.FindMember (enumerator.ReturnType,
7237                                         MemberFilter.Method ("MoveNext", 0, ParametersCompiled.EmptyReadOnlyParameters, rc.BuiltinTypes.Bool),
7238                                         BindingRestriction.InstanceOnly) as MethodSpec;
7239
7240                                 if (ms == null || !ms.IsPublic) {
7241                                         Error_WrongEnumerator (rc, enumerator);
7242                                         return null;
7243                                 }
7244
7245                                 return MethodGroupExpr.CreatePredefined (ms, enumerator.ReturnType, expr.Location);
7246                         }
7247
7248                         PropertySpec ResolveCurrent (ResolveContext rc, MethodSpec enumerator)
7249                         {
7250                                 var ps = MemberCache.FindMember (enumerator.ReturnType,
7251                                         MemberFilter.Property ("Current", null),
7252                                         BindingRestriction.InstanceOnly) as PropertySpec;
7253
7254                                 if (ps == null || !ps.IsPublic) {
7255                                         Error_WrongEnumerator (rc, enumerator);
7256                                         return null;
7257                                 }
7258
7259                                 return ps;
7260                         }
7261
7262                         public override bool Resolve (BlockContext ec)
7263                         {
7264                                 bool is_dynamic = expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
7265
7266                                 if (is_dynamic) {
7267                                         expr = Convert.ImplicitConversionRequired (ec, expr, ec.BuiltinTypes.IEnumerable, loc);
7268                                 } else if (expr.Type.IsNullableType) {
7269                                         expr = new Nullable.UnwrapCall (expr).Resolve (ec);
7270                                 }
7271
7272                                 var get_enumerator_mg = ResolveGetEnumerator (ec);
7273                                 if (get_enumerator_mg == null) {
7274                                         return false;
7275                                 }
7276
7277                                 var get_enumerator = get_enumerator_mg.BestCandidate;
7278                                 enumerator_variable = TemporaryVariableReference.Create (get_enumerator.ReturnType, variable.Block, loc);
7279                                 enumerator_variable.Resolve (ec);
7280
7281                                 // Prepare bool MoveNext ()
7282                                 var move_next_mg = ResolveMoveNext (ec, get_enumerator);
7283                                 if (move_next_mg == null) {
7284                                         return false;
7285                                 }
7286
7287                                 move_next_mg.InstanceExpression = enumerator_variable;
7288
7289                                 // Prepare ~T~ Current { get; }
7290                                 var current_prop = ResolveCurrent (ec, get_enumerator);
7291                                 if (current_prop == null) {
7292                                         return false;
7293                                 }
7294
7295                                 var current_pe = new PropertyExpr (current_prop, loc) { InstanceExpression = enumerator_variable }.Resolve (ec);
7296                                 if (current_pe == null)
7297                                         return false;
7298
7299                                 VarExpr ve = for_each.type as VarExpr;
7300
7301                                 if (ve != null) {
7302                                         if (is_dynamic) {
7303                                                 // Source type is dynamic, set element type to dynamic too
7304                                                 variable.Type = ec.BuiltinTypes.Dynamic;
7305                                         } else {
7306                                                 // Infer implicitly typed local variable from foreach enumerable type
7307                                                 variable.Type = current_pe.Type;
7308                                         }
7309                                 } else {
7310                                         if (is_dynamic) {
7311                                                 // Explicit cast of dynamic collection elements has to be done at runtime
7312                                                 current_pe = EmptyCast.Create (current_pe, ec.BuiltinTypes.Dynamic);
7313                                         }
7314
7315                                         variable.Type = for_each.type.ResolveAsType (ec);
7316
7317                                         if (variable.Type == null)
7318                                                 return false;
7319
7320                                         current_pe = Convert.ExplicitConversion (ec, current_pe, variable.Type, loc);
7321                                         if (current_pe == null)
7322                                                 return false;
7323                                 }
7324
7325                                 var variable_ref = new LocalVariableReference (variable, loc).Resolve (ec);
7326                                 if (variable_ref == null)
7327                                         return false;
7328
7329                                 for_each.body.AddScopeStatement (new StatementExpression (new CompilerAssign (variable_ref, current_pe, Location.Null), for_each.type.Location));
7330
7331                                 var init = new Invocation (get_enumerator_mg, null);
7332
7333                                 statement = new While (new BooleanExpression (new Invocation (move_next_mg, null)),
7334                                          for_each.body, Location.Null);
7335
7336                                 var enum_type = enumerator_variable.Type;
7337
7338                                 //
7339                                 // Add Dispose method call when enumerator can be IDisposable
7340                                 //
7341                                 if (!enum_type.ImplementsInterface (ec.BuiltinTypes.IDisposable, false)) {
7342                                         if (!enum_type.IsSealed && !TypeSpec.IsValueType (enum_type)) {
7343                                                 //
7344                                                 // Runtime Dispose check
7345                                                 //
7346                                                 var vd = new RuntimeDispose (enumerator_variable.LocalInfo, Location.Null);
7347                                                 vd.Initializer = init;
7348                                                 statement = new Using (vd, statement, Location.Null);
7349                                         } else {
7350                                                 //
7351                                                 // No Dispose call needed
7352                                                 //
7353                                                 this.init = new SimpleAssign (enumerator_variable, init, Location.Null);
7354                                                 this.init.Resolve (ec);
7355                                         }
7356                                 } else {
7357                                         //
7358                                         // Static Dispose check
7359                                         //
7360                                         var vd = new Using.VariableDeclaration (enumerator_variable.LocalInfo, Location.Null);
7361                                         vd.Initializer = init;
7362                                         statement = new Using (vd, statement, Location.Null);
7363                                 }
7364
7365                                 return statement.Resolve (ec);
7366                         }
7367
7368                         protected override void DoEmit (EmitContext ec)
7369                         {
7370                                 enumerator_variable.LocalInfo.CreateBuilder (ec);
7371
7372                                 if (init != null)
7373                                         init.EmitStatement (ec);
7374
7375                                 statement.Emit (ec);
7376                         }
7377
7378                         #region IErrorHandler Members
7379
7380                         bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext ec, MemberSpec best, MemberSpec ambiguous)
7381                         {
7382                                 ec.Report.SymbolRelatedToPreviousError (best);
7383                                 ec.Report.Warning (278, 2, expr.Location,
7384                                         "`{0}' contains ambiguous implementation of `{1}' pattern. Method `{2}' is ambiguous with method `{3}'",
7385                                         expr.Type.GetSignatureForError (), "enumerable",
7386                                         best.GetSignatureForError (), ambiguous.GetSignatureForError ());
7387
7388                                 ambiguous_getenumerator_name = true;
7389                                 return true;
7390                         }
7391
7392                         bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
7393                         {
7394                                 return false;
7395                         }
7396
7397                         bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
7398                         {
7399                                 return false;
7400                         }
7401
7402                         bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
7403                         {
7404                                 return false;
7405                         }
7406
7407                         #endregion
7408                 }
7409
7410                 Expression type;
7411                 LocalVariable variable;
7412                 Expression expr;
7413                 Block body;
7414
7415                 public Foreach (Expression type, LocalVariable var, Expression expr, Statement stmt, Block body, Location l)
7416                         : base (stmt)
7417                 {
7418                         this.type = type;
7419                         this.variable = var;
7420                         this.expr = expr;
7421                         this.body = body;
7422                         loc = l;
7423                 }
7424
7425                 public Expression Expr {
7426                         get { return expr; }
7427                 }
7428
7429                 public Expression TypeExpression {
7430                         get { return type; }
7431                 }
7432
7433                 public LocalVariable Variable {
7434                         get { return variable; }
7435                 }
7436
7437                 public override Reachability MarkReachable (Reachability rc)
7438                 {
7439                         base.MarkReachable (rc);
7440
7441                         body.MarkReachable (rc);
7442
7443                         return rc;
7444                 }
7445
7446                 public override bool Resolve (BlockContext ec)
7447                 {
7448                         expr = expr.Resolve (ec);
7449                         if (expr == null)
7450                                 return false;
7451
7452                         if (expr.IsNull) {
7453                                 ec.Report.Error (186, loc, "Use of null is not valid in this context");
7454                                 return false;
7455                         }
7456
7457                         body.AddStatement (Statement);
7458
7459                         if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.String) {
7460                                 Statement = new ArrayForeach (this, 1);
7461                         } else if (expr.Type is ArrayContainer) {
7462                                 Statement = new ArrayForeach (this, ((ArrayContainer) expr.Type).Rank);
7463                         } else {
7464                                 if (expr.eclass == ExprClass.MethodGroup || expr is AnonymousMethodExpression) {
7465                                         ec.Report.Error (446, expr.Location, "Foreach statement cannot operate on a `{0}'",
7466                                                 expr.ExprClassName);
7467                                         return false;
7468                                 }
7469
7470                                 Statement = new CollectionForeach (this, variable, expr);
7471                         }
7472
7473                         base.Resolve (ec);
7474                         return true;
7475                 }
7476
7477                 protected override void DoEmit (EmitContext ec)
7478                 {
7479                         Label old_begin = ec.LoopBegin, old_end = ec.LoopEnd;
7480                         ec.LoopBegin = ec.DefineLabel ();
7481                         ec.LoopEnd = ec.DefineLabel ();
7482
7483                         if (!(Statement is Block))
7484                                 ec.BeginCompilerScope ();
7485
7486                         variable.CreateBuilder (ec);
7487
7488                         Statement.Emit (ec);
7489
7490                         if (!(Statement is Block))
7491                                 ec.EndScope ();
7492
7493                         ec.LoopBegin = old_begin;
7494                         ec.LoopEnd = old_end;
7495                 }
7496
7497                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7498                 {
7499                         expr.FlowAnalysis (fc);
7500
7501                         var da = fc.BranchDefiniteAssignment ();
7502                         body.FlowAnalysis (fc);
7503                         fc.DefiniteAssignment = da;
7504                         return false;
7505                 }
7506
7507                 protected override void CloneTo (CloneContext clonectx, Statement t)
7508                 {
7509                         Foreach target = (Foreach) t;
7510
7511                         target.type = type.Clone (clonectx);
7512                         target.expr = expr.Clone (clonectx);
7513                         target.body = (Block) body.Clone (clonectx);
7514                         target.Statement = Statement.Clone (clonectx);
7515                 }
7516                 
7517                 public override object Accept (StructuralVisitor visitor)
7518                 {
7519                         return visitor.Visit (this);
7520                 }
7521         }
7522 }