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