6a8f29a6d2a772c7abfe7f52cb7dc4b5017c1cfb
[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                         Iterator = 1 << 14
2064                 }
2065
2066                 public Block Parent;
2067                 public Location StartLocation;
2068                 public Location EndLocation;
2069
2070                 public ExplicitBlock Explicit;
2071                 public ParametersBlock ParametersBlock;
2072
2073                 protected Flags flags;
2074
2075                 //
2076                 // The statements in this block
2077                 //
2078                 protected List<Statement> statements;
2079
2080                 protected List<Statement> scope_initializers;
2081
2082                 int? resolving_init_idx;
2083
2084                 Block original;
2085
2086 #if DEBUG
2087                 static int id;
2088                 public int ID = id++;
2089
2090                 static int clone_id_counter;
2091                 int clone_id;
2092 #endif
2093
2094 //              int assignable_slots;
2095
2096                 public Block (Block parent, Location start, Location end)
2097                         : this (parent, 0, start, end)
2098                 {
2099                 }
2100
2101                 public Block (Block parent, Flags flags, Location start, Location end)
2102                 {
2103                         if (parent != null) {
2104                                 // the appropriate constructors will fixup these fields
2105                                 ParametersBlock = parent.ParametersBlock;
2106                                 Explicit = parent.Explicit;
2107                         }
2108                         
2109                         this.Parent = parent;
2110                         this.flags = flags;
2111                         this.StartLocation = start;
2112                         this.EndLocation = end;
2113                         this.loc = start;
2114                         statements = new List<Statement> (4);
2115
2116                         this.original = this;
2117                 }
2118
2119                 #region Properties
2120
2121                 public bool HasUnreachableClosingBrace {
2122                         get {
2123                                 return (flags & Flags.HasRet) != 0;
2124                         }
2125                         set {
2126                                 flags = value ? flags | Flags.HasRet : flags & ~Flags.HasRet;
2127                         }
2128                 }
2129
2130                 public Block Original {
2131                         get {
2132                                 return original;
2133                         }
2134                         protected set {
2135                                 original = value;
2136                         }
2137                 }
2138
2139                 public bool IsCompilerGenerated {
2140                         get { return (flags & Flags.CompilerGenerated) != 0; }
2141                         set { flags = value ? flags | Flags.CompilerGenerated : flags & ~Flags.CompilerGenerated; }
2142                 }
2143
2144                 public bool Unchecked {
2145                         get { return (flags & Flags.Unchecked) != 0; }
2146                         set { flags = value ? flags | Flags.Unchecked : flags & ~Flags.Unchecked; }
2147                 }
2148
2149                 public bool Unsafe {
2150                         get { return (flags & Flags.Unsafe) != 0; }
2151                         set { flags |= Flags.Unsafe; }
2152                 }
2153
2154                 public List<Statement> Statements {
2155                         get { return statements; }
2156                 }
2157
2158                 #endregion
2159
2160                 public void SetEndLocation (Location loc)
2161                 {
2162                         EndLocation = loc;
2163                 }
2164
2165                 public void AddLabel (LabeledStatement target)
2166                 {
2167                         ParametersBlock.TopBlock.AddLabel (target.Name, target);
2168                 }
2169
2170                 public void AddLocalName (LocalVariable li)
2171                 {
2172                         AddLocalName (li.Name, li);
2173                 }
2174
2175                 public void AddLocalName (string name, INamedBlockVariable li)
2176                 {
2177                         ParametersBlock.TopBlock.AddLocalName (name, li, false);
2178                 }
2179
2180                 public virtual void Error_AlreadyDeclared (string name, INamedBlockVariable variable, string reason)
2181                 {
2182                         if (reason == null) {
2183                                 Error_AlreadyDeclared (name, variable);
2184                                 return;
2185                         }
2186
2187                         ParametersBlock.TopBlock.Report.Error (136, variable.Location,
2188                                 "A local variable named `{0}' cannot be declared in this scope because it would give a different meaning " +
2189                                 "to `{0}', which is already used in a `{1}' scope to denote something else",
2190                                 name, reason);
2191                 }
2192
2193                 public virtual void Error_AlreadyDeclared (string name, INamedBlockVariable variable)
2194                 {
2195                         var pi = variable as ParametersBlock.ParameterInfo;
2196                         if (pi != null) {
2197                                 pi.Parameter.Error_DuplicateName (ParametersBlock.TopBlock.Report);
2198                         } else {
2199                                 ParametersBlock.TopBlock.Report.Error (128, variable.Location,
2200                                         "A local variable named `{0}' is already defined in this scope", name);
2201                         }
2202                 }
2203                                         
2204                 public virtual void Error_AlreadyDeclaredTypeParameter (string name, Location loc)
2205                 {
2206                         ParametersBlock.TopBlock.Report.Error (412, loc,
2207                                 "The type parameter name `{0}' is the same as local variable or parameter name",
2208                                 name);
2209                 }
2210
2211                 //
2212                 // It should be used by expressions which require to
2213                 // register a statement during resolve process.
2214                 //
2215                 public void AddScopeStatement (Statement s)
2216                 {
2217                         if (scope_initializers == null)
2218                                 scope_initializers = new List<Statement> ();
2219
2220                         //
2221                         // Simple recursive helper, when resolve scope initializer another
2222                         // new scope initializer can be added, this ensures it's initialized
2223                         // before existing one. For now this can happen with expression trees
2224                         // in base ctor initializer only
2225                         //
2226                         if (resolving_init_idx.HasValue) {
2227                                 scope_initializers.Insert (resolving_init_idx.Value, s);
2228                                 ++resolving_init_idx;
2229                         } else {
2230                                 scope_initializers.Add (s);
2231                         }
2232                 }
2233                 
2234                 public void AddStatement (Statement s)
2235                 {
2236                         statements.Add (s);
2237                 }
2238
2239                 public int AssignableSlots {
2240                         get {
2241                                 // FIXME: HACK, we don't know the block available variables count now, so set this high enough
2242                                 return 4096;
2243 //                              return assignable_slots;
2244                         }
2245                 }
2246
2247                 public LabeledStatement LookupLabel (string name)
2248                 {
2249                         return ParametersBlock.TopBlock.GetLabel (name, this);
2250                 }
2251
2252                 public override bool Resolve (BlockContext ec)
2253                 {
2254                         if ((flags & Flags.Resolved) != 0)
2255                                 return true;
2256
2257                         Block prev_block = ec.CurrentBlock;
2258                         bool ok = true;
2259                         bool unreachable = ec.IsUnreachable;
2260                         bool prev_unreachable = unreachable;
2261
2262                         ec.CurrentBlock = this;
2263                         ec.StartFlowBranching (this);
2264
2265                         //
2266                         // Compiler generated scope statements
2267                         //
2268                         if (scope_initializers != null) {
2269                                 for (resolving_init_idx = 0; resolving_init_idx < scope_initializers.Count; ++resolving_init_idx) {
2270                                         scope_initializers[resolving_init_idx.Value].Resolve (ec);
2271                                 }
2272
2273                                 resolving_init_idx = null;
2274                         }
2275
2276                         //
2277                         // This flag is used to notate nested statements as unreachable from the beginning of this block.
2278                         // For the purposes of this resolution, it doesn't matter that the whole block is unreachable 
2279                         // from the beginning of the function.  The outer Resolve() that detected the unreachability is
2280                         // responsible for handling the situation.
2281                         //
2282                         int statement_count = statements.Count;
2283                         for (int ix = 0; ix < statement_count; ix++){
2284                                 Statement s = statements [ix];
2285
2286                                 //
2287                                 // Warn if we detect unreachable code.
2288                                 //
2289                                 if (unreachable) {
2290                                         if (s is EmptyStatement)
2291                                                 continue;
2292
2293                                         if (!ec.UnreachableReported && !(s is LabeledStatement) && !(s is SwitchLabel)) {
2294                                                 ec.Report.Warning (162, 2, s.loc, "Unreachable code detected");
2295                                                 ec.UnreachableReported = true;
2296                                         }
2297                                 }
2298
2299                                 //
2300                                 // Note that we're not using ResolveUnreachable() for unreachable
2301                                 // statements here.  ResolveUnreachable() creates a temporary
2302                                 // flow branching and kills it afterwards.  This leads to problems
2303                                 // if you have two unreachable statements where the first one
2304                                 // assigns a variable and the second one tries to access it.
2305                                 //
2306
2307                                 if (!s.Resolve (ec)) {
2308                                         ok = false;
2309                                         if (!ec.IsInProbingMode)
2310                                                 statements [ix] = new EmptyStatement (s.loc);
2311
2312                                         continue;
2313                                 }
2314
2315                                 if (unreachable && !(s is LabeledStatement) && !(s is SwitchLabel) && !(s is Block))
2316                                         statements [ix] = new EmptyStatement (s.loc);
2317
2318                                 unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
2319                                 if (unreachable) {
2320                                         ec.IsUnreachable = true;
2321                                 } else if (ec.IsUnreachable)
2322                                         ec.IsUnreachable = false;
2323                         }
2324
2325                         if (unreachable != prev_unreachable) {
2326                                 ec.IsUnreachable = prev_unreachable;
2327                                 ec.UnreachableReported = false;
2328                         }
2329
2330                         while (ec.CurrentBranching is FlowBranchingLabeled)
2331                                 ec.EndFlowBranching ();
2332
2333                         bool flow_unreachable = ec.EndFlowBranching ();
2334
2335                         ec.CurrentBlock = prev_block;
2336
2337                         if (flow_unreachable)
2338                                 flags |= Flags.HasRet;
2339
2340                         // If we're a non-static `struct' constructor which doesn't have an
2341                         // initializer, then we must initialize all of the struct's fields.
2342                         if (this == ParametersBlock.TopBlock && !ParametersBlock.TopBlock.IsThisAssigned (ec) && !flow_unreachable)
2343                                 ok = false;
2344
2345                         flags |= Flags.Resolved;
2346                         return ok;
2347                 }
2348
2349                 public override bool ResolveUnreachable (BlockContext ec, bool warn)
2350                 {
2351                         bool unreachable = false;
2352                         if (warn && !ec.UnreachableReported) {
2353                                 ec.UnreachableReported = true;
2354                                 unreachable = true;
2355                                 ec.Report.Warning (162, 2, loc, "Unreachable code detected");
2356                         }
2357
2358                         var fb = ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc);
2359                         fb.CurrentUsageVector.IsUnreachable = true;
2360                         bool ok = Resolve (ec);
2361                         ec.KillFlowBranching ();
2362
2363                         if (unreachable)
2364                                 ec.UnreachableReported = false;
2365
2366                         return ok;
2367                 }
2368                 
2369                 protected override void DoEmit (EmitContext ec)
2370                 {
2371                         for (int ix = 0; ix < statements.Count; ix++){
2372                                 statements [ix].Emit (ec);
2373                         }
2374                 }
2375
2376                 public override void Emit (EmitContext ec)
2377                 {
2378                         if (scope_initializers != null)
2379                                 EmitScopeInitializers (ec);
2380
2381                         DoEmit (ec);
2382                 }
2383
2384                 protected void EmitScopeInitializers (EmitContext ec)
2385                 {
2386                         foreach (Statement s in scope_initializers)
2387                                 s.Emit (ec);
2388                 }
2389
2390 #if DEBUG
2391                 public override string ToString ()
2392                 {
2393                         return String.Format ("{0} ({1}:{2})", GetType (), ID, StartLocation);
2394                 }
2395 #endif
2396
2397                 protected override void CloneTo (CloneContext clonectx, Statement t)
2398                 {
2399                         Block target = (Block) t;
2400 #if DEBUG
2401                         target.clone_id = clone_id_counter++;
2402 #endif
2403
2404                         clonectx.AddBlockMap (this, target);
2405                         if (original != this)
2406                                 clonectx.AddBlockMap (original, target);
2407
2408                         target.ParametersBlock = (ParametersBlock) (ParametersBlock == this ? target : clonectx.RemapBlockCopy (ParametersBlock));
2409                         target.Explicit = (ExplicitBlock) (Explicit == this ? target : clonectx.LookupBlock (Explicit));
2410
2411                         if (Parent != null)
2412                                 target.Parent = clonectx.RemapBlockCopy (Parent);
2413
2414                         target.statements = new List<Statement> (statements.Count);
2415                         foreach (Statement s in statements)
2416                                 target.statements.Add (s.Clone (clonectx));
2417                 }
2418
2419                 public override object Accept (StructuralVisitor visitor)
2420                 {
2421                         return visitor.Visit (this);
2422                 }
2423         }
2424
2425         public class ExplicitBlock : Block
2426         {
2427                 protected AnonymousMethodStorey am_storey;
2428
2429                 public ExplicitBlock (Block parent, Location start, Location end)
2430                         : this (parent, (Flags) 0, start, end)
2431                 {
2432                 }
2433
2434                 public ExplicitBlock (Block parent, Flags flags, Location start, Location end)
2435                         : base (parent, flags, start, end)
2436                 {
2437                         this.Explicit = this;
2438                 }
2439
2440                 #region Properties
2441
2442                 public AnonymousMethodStorey AnonymousMethodStorey {
2443                         get {
2444                                 return am_storey;
2445                         }
2446                 }
2447
2448                 public bool HasAwait {
2449                         get {
2450                                 return (flags & Flags.AwaitBlock) != 0;
2451                         }
2452                 }
2453
2454                 public bool HasCapturedThis {
2455                         set {
2456                                 flags = value ? flags | Flags.HasCapturedThis : flags & ~Flags.HasCapturedThis;
2457                         }
2458                         get {
2459                                 return (flags & Flags.HasCapturedThis) != 0;
2460                         }
2461                 }
2462
2463                 //
2464                 // Used to indicate that the block has reference to parent
2465                 // block and cannot be made static when defining anonymous method
2466                 //
2467                 public bool HasCapturedVariable {
2468                         set {
2469                                 flags = value ? flags | Flags.HasCapturedVariable : flags & ~Flags.HasCapturedVariable;
2470                         }
2471                         get {
2472                                 return (flags & Flags.HasCapturedVariable) != 0;
2473                         }
2474                 }
2475
2476                 public bool HasYield {
2477                         get {
2478                                 return (flags & Flags.YieldBlock) != 0;
2479                         }
2480                 }
2481
2482                 #endregion
2483
2484                 //
2485                 // Creates anonymous method storey in current block
2486                 //
2487                 public AnonymousMethodStorey CreateAnonymousMethodStorey (ResolveContext ec)
2488                 {
2489                         //
2490                         // Return same story for iterator and async blocks unless we are
2491                         // in nested anonymous method
2492                         //
2493                         if (ec.CurrentAnonymousMethod is StateMachineInitializer && ParametersBlock.Original == ec.CurrentAnonymousMethod.Block.Original)
2494                                 return ec.CurrentAnonymousMethod.Storey;
2495
2496                         if (am_storey == null) {
2497                                 MemberBase mc = ec.MemberContext as MemberBase;
2498
2499                                 //
2500                                 // Creates anonymous method storey for this block
2501                                 //
2502                                 am_storey = new AnonymousMethodStorey (this, ec.CurrentMemberDefinition.Parent.PartialContainer, mc, ec.CurrentTypeParameters, "AnonStorey", MemberKind.Class);
2503                         }
2504
2505                         return am_storey;
2506                 }
2507
2508                 public override void Emit (EmitContext ec)
2509                 {
2510                         if (am_storey != null) {
2511                                 DefineStoreyContainer (ec, am_storey);
2512                                 am_storey.EmitStoreyInstantiation (ec, this);
2513                         }
2514
2515                         if (scope_initializers != null)
2516                                 EmitScopeInitializers (ec);
2517
2518                         if (ec.EmitAccurateDebugInfo && !IsCompilerGenerated && ec.Mark (StartLocation)) {
2519                                 ec.Emit (OpCodes.Nop);
2520                         }
2521
2522                         if (Parent != null)
2523                                 ec.BeginScope ();
2524
2525                         DoEmit (ec);
2526
2527                         if (Parent != null)
2528                                 ec.EndScope ();
2529
2530                         if (ec.EmitAccurateDebugInfo && !HasUnreachableClosingBrace && !IsCompilerGenerated && ec.Mark (EndLocation)) {
2531                                 ec.Emit (OpCodes.Nop);
2532                         }
2533                 }
2534
2535                 protected void DefineStoreyContainer (EmitContext ec, AnonymousMethodStorey storey)
2536                 {
2537                         if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.Storey != null) {
2538                                 storey.SetNestedStoryParent (ec.CurrentAnonymousMethod.Storey);
2539                                 storey.Mutator = ec.CurrentAnonymousMethod.Storey.Mutator;
2540                         }
2541
2542                         //
2543                         // Creates anonymous method storey
2544                         //
2545                         storey.CreateContainer ();
2546                         storey.DefineContainer ();
2547
2548                         if (Original.Explicit.HasCapturedThis && Original.ParametersBlock.TopBlock.ThisReferencesFromChildrenBlock != null) {
2549
2550                                 //
2551                                 // Only first storey in path will hold this reference. All children blocks will
2552                                 // reference it indirectly using $ref field
2553                                 //
2554                                 for (Block b = Original.Explicit; b != null; b = b.Parent) {
2555                                         if (b.Parent != null) {
2556                                                 var s = b.Parent.Explicit.AnonymousMethodStorey;
2557                                                 if (s != null) {
2558                                                         storey.HoistedThis = s.HoistedThis;
2559                                                         break;
2560                                                 }
2561                                         }
2562
2563                                         if (b.Explicit == b.Explicit.ParametersBlock && b.Explicit.ParametersBlock.StateMachine != null) {
2564                                                 storey.HoistedThis = b.Explicit.ParametersBlock.StateMachine.HoistedThis;
2565
2566                                                 if (storey.HoistedThis != null)
2567                                                         break;
2568                                         }
2569                                 }
2570                                 
2571                                 //
2572                                 // We are the first storey on path and 'this' has to be hoisted
2573                                 //
2574                                 if (storey.HoistedThis == null) {
2575                                         foreach (ExplicitBlock ref_block in Original.ParametersBlock.TopBlock.ThisReferencesFromChildrenBlock) {
2576                                                 //
2577                                                 // ThisReferencesFromChildrenBlock holds all reference even if they
2578                                                 // are not on this path. It saves some memory otherwise it'd have to
2579                                                 // be in every explicit block. We run this check to see if the reference
2580                                                 // is valid for this storey
2581                                                 //
2582                                                 Block block_on_path = ref_block;
2583                                                 for (; block_on_path != null && block_on_path != Original; block_on_path = block_on_path.Parent);
2584
2585                                                 if (block_on_path == null)
2586                                                         continue;
2587
2588                                                 if (storey.HoistedThis == null) {
2589                                                         storey.AddCapturedThisField (ec);
2590                                                 }
2591
2592                                                 for (ExplicitBlock b = ref_block; b.AnonymousMethodStorey != storey; b = b.Parent.Explicit) {
2593                                                         if (b.AnonymousMethodStorey != null) {
2594                                                                 b.AnonymousMethodStorey.AddParentStoreyReference (ec, storey);
2595                                                                 b.AnonymousMethodStorey.HoistedThis = storey.HoistedThis;
2596
2597                                                                 //
2598                                                                 // Stop propagation inside same top block
2599                                                                 //
2600                                                                 if (b.ParametersBlock == ParametersBlock.Original)
2601                                                                         break;
2602
2603                                                                 b = b.ParametersBlock;
2604                                                         }
2605
2606                                                         var pb = b as ParametersBlock;
2607                                                         if (pb != null && pb.StateMachine != null) {
2608                                                                 if (pb.StateMachine == storey)
2609                                                                         break;
2610
2611                                                                 pb.StateMachine.AddParentStoreyReference (ec, storey);
2612                                                         }
2613                                                         
2614                                                         b.HasCapturedVariable = true;
2615                                                 }
2616                                         }
2617                                 }
2618                         }
2619
2620                         var ref_blocks = storey.ReferencesFromChildrenBlock;
2621                         if (ref_blocks != null) {
2622                                 foreach (ExplicitBlock ref_block in ref_blocks) {
2623                                         for (ExplicitBlock b = ref_block; b.AnonymousMethodStorey != storey; b = b.Parent.Explicit) {
2624                                                 if (b.AnonymousMethodStorey != null) {
2625                                                         b.AnonymousMethodStorey.AddParentStoreyReference (ec, storey);
2626
2627                                                         //
2628                                                         // Stop propagation inside same top block
2629                                                         //
2630                                                         if (b.ParametersBlock == ParametersBlock.Original)
2631                                                                 break;
2632
2633                                                         b = b.ParametersBlock;
2634                                                 }
2635
2636                                                 var pb = b as ParametersBlock;
2637                                                 if (pb != null && pb.StateMachine != null) {
2638                                                         if (pb.StateMachine == storey)
2639                                                                 break;
2640
2641                                                         pb.StateMachine.AddParentStoreyReference (ec, storey);
2642                                                 }
2643
2644                                                 b.HasCapturedVariable = true;
2645                                         }
2646                                 }
2647                         }
2648
2649                         storey.Define ();
2650                         storey.Parent.PartialContainer.AddCompilerGeneratedClass (storey);
2651                 }
2652
2653                 public void RegisterAsyncAwait ()
2654                 {
2655                         var block = this;
2656                         while ((block.flags & Flags.AwaitBlock) == 0) {
2657                                 block.flags |= Flags.AwaitBlock;
2658
2659                                 if (block is ParametersBlock)
2660                                         return;
2661
2662                                 block = block.Parent.Explicit;
2663                         }
2664                 }
2665
2666                 public void RegisterIteratorYield ()
2667                 {
2668                         ParametersBlock.TopBlock.IsIterator = true;
2669
2670                         var block = this;
2671                         while ((block.flags & Flags.YieldBlock) == 0) {
2672                                 block.flags |= Flags.YieldBlock;
2673
2674                                 if (block.Parent == null)
2675                                         return;
2676
2677                                 block = block.Parent.Explicit;
2678                         }
2679                 }
2680
2681                 public void WrapIntoDestructor (TryFinally tf, ExplicitBlock tryBlock)
2682                 {
2683                         tryBlock.statements = statements;
2684                         statements = new List<Statement> (1);
2685                         statements.Add (tf);
2686                 }
2687         }
2688
2689         //
2690         // ParametersBlock was introduced to support anonymous methods
2691         // and lambda expressions
2692         // 
2693         public class ParametersBlock : ExplicitBlock
2694         {
2695                 public class ParameterInfo : INamedBlockVariable
2696                 {
2697                         readonly ParametersBlock block;
2698                         readonly int index;
2699                         public VariableInfo VariableInfo;
2700                         bool is_locked;
2701
2702                         public ParameterInfo (ParametersBlock block, int index)
2703                         {
2704                                 this.block = block;
2705                                 this.index = index;
2706                         }
2707
2708                         #region Properties
2709
2710                         public ParametersBlock Block {
2711                                 get {
2712                                         return block;
2713                                 }
2714                         }
2715
2716                         Block INamedBlockVariable.Block {
2717                                 get {
2718                                         return block;
2719                                 }
2720                         }
2721
2722                         public bool IsDeclared {
2723                                 get {
2724                                         return true;
2725                                 }
2726                         }
2727
2728                         public bool IsParameter {
2729                                 get {
2730                                         return true;
2731                                 }
2732                         }
2733
2734                         public bool IsLocked {
2735                                 get {
2736                                         return is_locked;
2737                                 }
2738                                 set {
2739                                         is_locked = value;
2740                                 }
2741                         }
2742
2743                         public Location Location {
2744                                 get {
2745                                         return Parameter.Location;
2746                                 }
2747                         }
2748
2749                         public Parameter Parameter {
2750                                 get {
2751                                         return block.Parameters [index];
2752                                 }
2753                         }
2754
2755                         public TypeSpec ParameterType {
2756                                 get {
2757                                         return Parameter.Type;
2758                                 }
2759                         }
2760
2761                         #endregion
2762
2763                         public Expression CreateReferenceExpression (ResolveContext rc, Location loc)
2764                         {
2765                                 return new ParameterReference (this, loc);
2766                         }
2767                 }
2768
2769                 // 
2770                 // Block is converted into an expression
2771                 //
2772                 sealed class BlockScopeExpression : Expression
2773                 {
2774                         Expression child;
2775                         readonly ParametersBlock block;
2776
2777                         public BlockScopeExpression (Expression child, ParametersBlock block)
2778                         {
2779                                 this.child = child;
2780                                 this.block = block;
2781                         }
2782
2783                         public override bool ContainsEmitWithAwait ()
2784                         {
2785                                 return child.ContainsEmitWithAwait ();
2786                         }
2787
2788                         public override Expression CreateExpressionTree (ResolveContext ec)
2789                         {
2790                                 throw new NotSupportedException ();
2791                         }
2792
2793                         protected override Expression DoResolve (ResolveContext ec)
2794                         {
2795                                 if (child == null)
2796                                         return null;
2797
2798                                 child = child.Resolve (ec);
2799                                 if (child == null)
2800                                         return null;
2801
2802                                 eclass = child.eclass;
2803                                 type = child.Type;
2804                                 return this;
2805                         }
2806
2807                         public override void Emit (EmitContext ec)
2808                         {
2809                                 block.EmitScopeInitializers (ec);
2810                                 child.Emit (ec);
2811                         }
2812                 }
2813
2814                 protected ParametersCompiled parameters;
2815                 protected ParameterInfo[] parameter_info;
2816                 bool resolved;
2817                 protected bool unreachable;
2818                 protected ToplevelBlock top_block;
2819                 protected StateMachine state_machine;
2820
2821                 public ParametersBlock (Block parent, ParametersCompiled parameters, Location start)
2822                         : base (parent, 0, start, start)
2823                 {
2824                         if (parameters == null)
2825                                 throw new ArgumentNullException ("parameters");
2826
2827                         this.parameters = parameters;
2828                         ParametersBlock = this;
2829
2830                         flags |= (parent.ParametersBlock.flags & (Flags.YieldBlock | Flags.AwaitBlock));
2831
2832                         this.top_block = parent.ParametersBlock.top_block;
2833                         ProcessParameters ();
2834                 }
2835
2836                 protected ParametersBlock (ParametersCompiled parameters, Location start)
2837                         : base (null, 0, start, start)
2838                 {
2839                         if (parameters == null)
2840                                 throw new ArgumentNullException ("parameters");
2841
2842                         this.parameters = parameters;
2843                         ParametersBlock = this;
2844                 }
2845
2846                 //
2847                 // It's supposed to be used by method body implementation of anonymous methods
2848                 //
2849                 protected ParametersBlock (ParametersBlock source, ParametersCompiled parameters)
2850                         : base (null, 0, source.StartLocation, source.EndLocation)
2851                 {
2852                         this.parameters = parameters;
2853                         this.statements = source.statements;
2854                         this.scope_initializers = source.scope_initializers;
2855
2856                         this.resolved = true;
2857                         this.unreachable = source.unreachable;
2858                         this.am_storey = source.am_storey;
2859                         this.state_machine = source.state_machine;
2860
2861                         ParametersBlock = this;
2862
2863                         //
2864                         // Overwrite original for comparison purposes when linking cross references
2865                         // between anonymous methods
2866                         //
2867                         Original = source.Original;
2868                 }
2869
2870                 #region Properties
2871
2872                 public bool IsAsync {
2873                         get {
2874                                 return (flags & Flags.HasAsyncModifier) != 0;
2875                         }
2876                         set {
2877                                 flags = value ? flags | Flags.HasAsyncModifier : flags & ~Flags.HasAsyncModifier;
2878                         }
2879                 }
2880
2881                 //
2882                 // Block has been converted to expression tree
2883                 //
2884                 public bool IsExpressionTree {
2885                         get {
2886                                 return (flags & Flags.IsExpressionTree) != 0;
2887                         }
2888                 }
2889
2890                 //
2891                 // The parameters for the block.
2892                 //
2893                 public ParametersCompiled Parameters {
2894                         get {
2895                                 return parameters;
2896                         }
2897                 }
2898
2899                 public StateMachine StateMachine {
2900                         get {
2901                                 return state_machine;
2902                         }
2903                 }
2904
2905                 public ToplevelBlock TopBlock {
2906                         get {
2907                                 return top_block;
2908                         }
2909                 }
2910
2911                 public bool Resolved {
2912                         get {
2913                                 return (flags & Flags.Resolved) != 0;
2914                         }
2915                 }
2916
2917                 public int TemporaryLocalsCount { get; set; }
2918
2919                 #endregion
2920
2921                 // <summary>
2922                 //   Check whether all `out' parameters have been assigned.
2923                 // </summary>
2924                 public void CheckOutParameters (FlowBranching.UsageVector vector)
2925                 {
2926                         if (vector.IsUnreachable)
2927                                 return;
2928
2929                         int n = parameter_info == null ? 0 : parameter_info.Length;
2930
2931                         for (int i = 0; i < n; i++) {
2932                                 VariableInfo var = parameter_info[i].VariableInfo;
2933
2934                                 if (var == null)
2935                                         continue;
2936
2937                                 if (vector.IsAssigned (var, false))
2938                                         continue;
2939
2940                                 var p = parameter_info[i].Parameter;
2941                                 TopBlock.Report.Error (177, p.Location,
2942                                         "The out parameter `{0}' must be assigned to before control leaves the current method",
2943                                         p.Name);
2944                         }
2945                 }
2946
2947                 public override Expression CreateExpressionTree (ResolveContext ec)
2948                 {
2949                         if (statements.Count == 1) {
2950                                 Expression expr = ((Statement) statements[0]).CreateExpressionTree (ec);
2951                                 if (scope_initializers != null)
2952                                         expr = new BlockScopeExpression (expr, this);
2953
2954                                 return expr;
2955                         }
2956
2957                         return base.CreateExpressionTree (ec);
2958                 }
2959
2960                 public override void Emit (EmitContext ec)
2961                 {
2962                         if (state_machine != null && state_machine.OriginalSourceBlock != this) {
2963                                 DefineStoreyContainer (ec, state_machine);
2964                                 state_machine.EmitStoreyInstantiation (ec, this);
2965                         }
2966
2967                         base.Emit (ec);
2968                 }
2969
2970                 public void EmitEmbedded (EmitContext ec)
2971                 {
2972                         if (state_machine != null && state_machine.OriginalSourceBlock != this) {
2973                                 DefineStoreyContainer (ec, state_machine);
2974                                 state_machine.EmitStoreyInstantiation (ec, this);
2975                         }
2976
2977                         base.Emit (ec);
2978                 }
2979
2980                 public ParameterInfo GetParameterInfo (Parameter p)
2981                 {
2982                         for (int i = 0; i < parameters.Count; ++i) {
2983                                 if (parameters[i] == p)
2984                                         return parameter_info[i];
2985                         }
2986
2987                         throw new ArgumentException ("Invalid parameter");
2988                 }
2989
2990                 public ParameterReference GetParameterReference (int index, Location loc)
2991                 {
2992                         return new ParameterReference (parameter_info[index], loc);
2993                 }
2994
2995                 public Statement PerformClone ()
2996                 {
2997                         CloneContext clonectx = new CloneContext ();
2998                         return Clone (clonectx);
2999                 }
3000
3001                 protected void ProcessParameters ()
3002                 {
3003                         if (parameters.Count == 0)
3004                                 return;
3005
3006                         parameter_info = new ParameterInfo[parameters.Count];
3007                         for (int i = 0; i < parameter_info.Length; ++i) {
3008                                 var p = parameters.FixedParameters[i];
3009                                 if (p == null)
3010                                         continue;
3011
3012                                 // TODO: Should use Parameter only and more block there
3013                                 parameter_info[i] = new ParameterInfo (this, i);
3014                                 if (p.Name != null)
3015                                         AddLocalName (p.Name, parameter_info[i]);
3016                         }
3017                 }
3018
3019                 public bool Resolve (FlowBranching parent, BlockContext rc, IMethodData md)
3020                 {
3021                         if (resolved)
3022                                 return true;
3023
3024                         resolved = true;
3025
3026                         if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
3027                                 flags |= Flags.IsExpressionTree;
3028
3029                         try {
3030                                 ResolveMeta (rc);
3031
3032                                 using (rc.With (ResolveContext.Options.DoFlowAnalysis, true)) {
3033                                         FlowBranchingToplevel top_level = rc.StartFlowBranching (this, parent);
3034
3035                                         if (!Resolve (rc))
3036                                                 return false;
3037
3038                                         unreachable = top_level.End ();
3039                                 }
3040                         } catch (Exception e) {
3041                                 if (e is CompletionResult || rc.Report.IsDisabled || e is FatalException)
3042                                         throw;
3043
3044                                 if (rc.CurrentBlock != null) {
3045                                         rc.Report.Error (584, rc.CurrentBlock.StartLocation, "Internal compiler error: {0}", e.Message);
3046                                 } else {
3047                                         rc.Report.Error (587, "Internal compiler error: {0}", e.Message);
3048                                 }
3049
3050                                 if (rc.Module.Compiler.Settings.DebugFlags > 0)
3051                                         throw;
3052                         }
3053
3054                         if (rc.ReturnType.Kind != MemberKind.Void && !unreachable) {
3055                                 if (rc.CurrentAnonymousMethod == null) {
3056                                         // FIXME: Missing FlowAnalysis for generated iterator MoveNext method
3057                                         if (md is StateMachineMethod) {
3058                                                 unreachable = true;
3059                                         } else {
3060                                                 rc.Report.Error (161, md.Location, "`{0}': not all code paths return a value", md.GetSignatureForError ());
3061                                                 return false;
3062                                         }
3063                                 } else {
3064                                         //
3065                                         // If an asynchronous body of F is either an expression classified as nothing, or a 
3066                                         // statement block where no return statements have expressions, the inferred return type is Task
3067                                         //
3068                                         if (IsAsync) {
3069                                                 var am = rc.CurrentAnonymousMethod as AnonymousMethodBody;
3070                                                 if (am != null && am.ReturnTypeInference != null && !am.ReturnTypeInference.HasBounds (0)) {
3071                                                         am.ReturnTypeInference = null;
3072                                                         am.ReturnType = rc.Module.PredefinedTypes.Task.TypeSpec;
3073                                                         return true;
3074                                                 }
3075                                         }
3076
3077                                         rc.Report.Error (1643, rc.CurrentAnonymousMethod.Location, "Not all code paths return a value in anonymous method of type `{0}'",
3078                                                           rc.CurrentAnonymousMethod.GetSignatureForError ());
3079                                         return false;
3080                                 }
3081                         }
3082
3083                         return true;
3084                 }
3085
3086                 void ResolveMeta (BlockContext ec)
3087                 {
3088                         int orig_count = parameters.Count;
3089
3090                         for (int i = 0; i < orig_count; ++i) {
3091                                 Parameter.Modifier mod = parameters.FixedParameters[i].ModFlags;
3092
3093                                 if ((mod & Parameter.Modifier.OUT) == 0)
3094                                         continue;
3095
3096                                 VariableInfo vi = new VariableInfo (parameters, i, ec.FlowOffset);
3097                                 parameter_info[i].VariableInfo = vi;
3098                                 ec.FlowOffset += vi.Length;
3099                         }
3100                 }
3101
3102                 public ToplevelBlock ConvertToIterator (IMethodData method, TypeDefinition host, TypeSpec iterator_type, bool is_enumerable)
3103                 {
3104                         var iterator = new Iterator (this, method, host, iterator_type, is_enumerable);
3105                         var stateMachine = new IteratorStorey (iterator);
3106
3107                         state_machine = stateMachine;
3108                         iterator.SetStateMachine (stateMachine);
3109
3110                         var tlb = new ToplevelBlock (host.Compiler, Parameters, Location.Null);
3111                         tlb.Original = this;
3112                         tlb.IsCompilerGenerated = true;
3113                         tlb.state_machine = stateMachine;
3114                         tlb.AddStatement (new Return (iterator, iterator.Location));
3115                         return tlb;
3116                 }
3117
3118                 public ParametersBlock ConvertToAsyncTask (IMemberContext context, TypeDefinition host, ParametersCompiled parameters, TypeSpec returnType, Location loc)
3119                 {
3120                         for (int i = 0; i < parameters.Count; i++) {
3121                                 Parameter p = parameters[i];
3122                                 Parameter.Modifier mod = p.ModFlags;
3123                                 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
3124                                         host.Compiler.Report.Error (1988, p.Location,
3125                                                 "Async methods cannot have ref or out parameters");
3126                                         return this;
3127                                 }
3128
3129                                 if (p is ArglistParameter) {
3130                                         host.Compiler.Report.Error (4006, p.Location,
3131                                                 "__arglist is not allowed in parameter list of async methods");
3132                                         return this;
3133                                 }
3134
3135                                 if (parameters.Types[i].IsPointer) {
3136                                         host.Compiler.Report.Error (4005, p.Location,
3137                                                 "Async methods cannot have unsafe parameters");
3138                                         return this;
3139                                 }
3140                         }
3141
3142                         if (!HasAwait) {
3143                                 host.Compiler.Report.Warning (1998, 1, loc,
3144                                         "Async block lacks `await' operator and will run synchronously");
3145                         }
3146
3147                         var block_type = host.Module.Compiler.BuiltinTypes.Void;
3148                         var initializer = new AsyncInitializer (this, host, block_type);
3149                         initializer.Type = block_type;
3150
3151                         var stateMachine = new AsyncTaskStorey (this, context, initializer, returnType);
3152
3153                         state_machine = stateMachine;
3154                         initializer.SetStateMachine (stateMachine);
3155
3156                         var b = this is ToplevelBlock ?
3157                                 new ToplevelBlock (host.Compiler, Parameters, Location.Null) :
3158                                 new ParametersBlock (Parent, parameters, Location.Null) {
3159                                         IsAsync = true,
3160                                 };
3161
3162                         b.Original = this;
3163                         b.IsCompilerGenerated = true;
3164                         b.state_machine = stateMachine;
3165                         b.AddStatement (new StatementExpression (initializer));
3166                         return b;
3167                 }
3168         }
3169
3170         //
3171         //
3172         //
3173         public class ToplevelBlock : ParametersBlock
3174         {
3175                 LocalVariable this_variable;
3176                 CompilerContext compiler;
3177                 Dictionary<string, object> names;
3178                 Dictionary<string, object> labels;
3179
3180                 List<ExplicitBlock> this_references;
3181
3182                 public ToplevelBlock (CompilerContext ctx, Location loc)
3183                         : this (ctx, ParametersCompiled.EmptyReadOnlyParameters, loc)
3184                 {
3185                 }
3186
3187                 public ToplevelBlock (CompilerContext ctx, ParametersCompiled parameters, Location start)
3188                         : base (parameters, start)
3189                 {
3190                         this.compiler = ctx;
3191                         top_block = this;
3192                         flags |= Flags.HasRet;
3193
3194                         ProcessParameters ();
3195                 }
3196
3197                 //
3198                 // Recreates a top level block from parameters block. Used for
3199                 // compiler generated methods where the original block comes from
3200                 // explicit child block. This works for already resolved blocks
3201                 // only to ensure we resolve them in the correct flow order
3202                 //
3203                 public ToplevelBlock (ParametersBlock source, ParametersCompiled parameters)
3204                         : base (source, parameters)
3205                 {
3206                         this.compiler = source.TopBlock.compiler;
3207                         top_block = this;
3208                         flags |= Flags.HasRet;
3209                 }
3210
3211                 public bool IsIterator {
3212                         get {
3213                                 return (flags & Flags.Iterator) != 0;
3214                         }
3215                         set {
3216                                 flags = value ? flags | Flags.Iterator : flags & ~Flags.Iterator;
3217                         }
3218                 }
3219
3220                 public Report Report {
3221                         get {
3222                                 return compiler.Report;
3223                         }
3224                 }
3225
3226                 //
3227                 // Used by anonymous blocks to track references of `this' variable
3228                 //
3229                 public List<ExplicitBlock> ThisReferencesFromChildrenBlock {
3230                         get {
3231                                 return this_references;
3232                         }
3233                 }
3234
3235                 //
3236                 // Returns the "this" instance variable of this block.
3237                 // See AddThisVariable() for more information.
3238                 //
3239                 public LocalVariable ThisVariable {
3240                         get {
3241                                 return this_variable;
3242                         }
3243                 }
3244
3245                 public void AddLocalName (string name, INamedBlockVariable li, bool ignoreChildrenBlocks)
3246                 {
3247                         if (names == null)
3248                                 names = new Dictionary<string, object> ();
3249
3250                         object value;
3251                         if (!names.TryGetValue (name, out value)) {
3252                                 names.Add (name, li);
3253                                 return;
3254                         }
3255
3256                         INamedBlockVariable existing = value as INamedBlockVariable;
3257                         List<INamedBlockVariable> existing_list;
3258                         if (existing != null) {
3259                                 existing_list = new List<INamedBlockVariable> ();
3260                                 existing_list.Add (existing);
3261                                 names[name] = existing_list;
3262                         } else {
3263                                 existing_list = (List<INamedBlockVariable>) value;
3264                         }
3265
3266                         //
3267                         // A collision checking between local names
3268                         //
3269                         var variable_block = li.Block.Explicit;
3270                         for (int i = 0; i < existing_list.Count; ++i) {
3271                                 existing = existing_list[i];
3272                                 Block b = existing.Block.Explicit;
3273
3274                                 // Collision at same level
3275                                 if (variable_block == b) {
3276                                         li.Block.Error_AlreadyDeclared (name, li);
3277                                         break;
3278                                 }
3279
3280                                 // Collision with parent
3281                                 Block parent = variable_block;
3282                                 while ((parent = parent.Parent) != null) {
3283                                         if (parent == b) {
3284                                                 li.Block.Error_AlreadyDeclared (name, li, "parent or current");
3285                                                 i = existing_list.Count;
3286                                                 break;
3287                                         }
3288                                 }
3289
3290                                 if (!ignoreChildrenBlocks && variable_block.Parent != b.Parent) {
3291                                         // Collision with children
3292                                         while ((b = b.Parent) != null) {
3293                                                 if (variable_block == b) {
3294                                                         li.Block.Error_AlreadyDeclared (name, li, "child");
3295                                                         i = existing_list.Count;
3296                                                         break;
3297                                                 }
3298                                         }
3299                                 }
3300                         }
3301
3302                         existing_list.Add (li);
3303                 }
3304
3305                 public void AddLabel (string name, LabeledStatement label)
3306                 {
3307                         if (labels == null)
3308                                 labels = new Dictionary<string, object> ();
3309
3310                         object value;
3311                         if (!labels.TryGetValue (name, out value)) {
3312                                 labels.Add (name, label);
3313                                 return;
3314                         }
3315
3316                         LabeledStatement existing = value as LabeledStatement;
3317                         List<LabeledStatement> existing_list;
3318                         if (existing != null) {
3319                                 existing_list = new List<LabeledStatement> ();
3320                                 existing_list.Add (existing);
3321                                 labels[name] = existing_list;
3322                         } else {
3323                                 existing_list = (List<LabeledStatement>) value;
3324                         }
3325
3326                         //
3327                         // A collision checking between labels
3328                         //
3329                         for (int i = 0; i < existing_list.Count; ++i) {
3330                                 existing = existing_list[i];
3331                                 Block b = existing.Block;
3332
3333                                 // Collision at same level
3334                                 if (label.Block == b) {
3335                                         Report.SymbolRelatedToPreviousError (existing.loc, name);
3336                                         Report.Error (140, label.loc, "The label `{0}' is a duplicate", name);
3337                                         break;
3338                                 }
3339
3340                                 // Collision with parent
3341                                 b = label.Block;
3342                                 while ((b = b.Parent) != null) {
3343                                         if (existing.Block == b) {
3344                                                 Report.Error (158, label.loc,
3345                                                         "The label `{0}' shadows another label by the same name in a contained scope", name);
3346                                                 i = existing_list.Count;
3347                                                 break;
3348                                         }
3349                                 }
3350
3351                                 // Collision with with children
3352                                 b = existing.Block;
3353                                 while ((b = b.Parent) != null) {
3354                                         if (label.Block == b) {
3355                                                 Report.Error (158, label.loc,
3356                                                         "The label `{0}' shadows another label by the same name in a contained scope", name);
3357                                                 i = existing_list.Count;
3358                                                 break;
3359                                         }
3360                                 }
3361                         }
3362
3363                         existing_list.Add (label);
3364                 }
3365
3366                 public void AddThisReferenceFromChildrenBlock (ExplicitBlock block)
3367                 {
3368                         if (this_references == null)
3369                                 this_references = new List<ExplicitBlock> ();
3370
3371                         if (!this_references.Contains (block))
3372                                 this_references.Add (block);
3373                 }
3374
3375                 public void RemoveThisReferenceFromChildrenBlock (ExplicitBlock block)
3376                 {
3377                         this_references.Remove (block);
3378                 }
3379
3380                 //
3381                 // Creates an arguments set from all parameters, useful for method proxy calls
3382                 //
3383                 public Arguments GetAllParametersArguments ()
3384                 {
3385                         int count = parameters.Count;
3386                         Arguments args = new Arguments (count);
3387                         for (int i = 0; i < count; ++i) {
3388                                 var arg_expr = GetParameterReference (i, parameter_info[i].Location);
3389                                 args.Add (new Argument (arg_expr));
3390                         }
3391
3392                         return args;
3393                 }
3394
3395                 //
3396                 // Lookup inside a block, the returned value can represent 3 states
3397                 //
3398                 // true+variable: A local name was found and it's valid
3399                 // false+variable: A local name was found in a child block only
3400                 // false+null: No local name was found
3401                 //
3402                 public bool GetLocalName (string name, Block block, ref INamedBlockVariable variable)
3403                 {
3404                         if (names == null)
3405                                 return false;
3406
3407                         object value;
3408                         if (!names.TryGetValue (name, out value))
3409                                 return false;
3410
3411                         variable = value as INamedBlockVariable;
3412                         Block b = block;
3413                         if (variable != null) {
3414                                 do {
3415                                         if (variable.Block == b.Original)
3416                                                 return true;
3417
3418                                         b = b.Parent;
3419                                 } while (b != null);
3420
3421                                 b = variable.Block;
3422                                 do {
3423                                         if (block == b)
3424                                                 return false;
3425
3426                                         b = b.Parent;
3427                                 } while (b != null);
3428                         } else {
3429                                 List<INamedBlockVariable> list = (List<INamedBlockVariable>) value;
3430                                 for (int i = 0; i < list.Count; ++i) {
3431                                         variable = list[i];
3432                                         do {
3433                                                 if (variable.Block == b.Original)
3434                                                         return true;
3435
3436                                                 b = b.Parent;
3437                                         } while (b != null);
3438
3439                                         b = variable.Block;
3440                                         do {
3441                                                 if (block == b)
3442                                                         return false;
3443
3444                                                 b = b.Parent;
3445                                         } while (b != null);
3446
3447                                         b = block;
3448                                 }
3449                         }
3450
3451                         variable = null;
3452                         return false;
3453                 }
3454
3455                 public LabeledStatement GetLabel (string name, Block block)
3456                 {
3457                         if (labels == null)
3458                                 return null;
3459
3460                         object value;
3461                         if (!labels.TryGetValue (name, out value)) {
3462                                 return null;
3463                         }
3464
3465                         var label = value as LabeledStatement;
3466                         Block b = block;
3467                         if (label != null) {
3468                                 if (label.Block == b.Original)
3469                                         return label;
3470                         } else {
3471                                 List<LabeledStatement> list = (List<LabeledStatement>) value;
3472                                 for (int i = 0; i < list.Count; ++i) {
3473                                         label = list[i];
3474                                         if (label.Block == b.Original)
3475                                                 return label;
3476                                 }
3477                         }
3478                                 
3479                         return null;
3480                 }
3481
3482                 // <summary>
3483                 //   This is used by non-static `struct' constructors which do not have an
3484                 //   initializer - in this case, the constructor must initialize all of the
3485                 //   struct's fields.  To do this, we add a "this" variable and use the flow
3486                 //   analysis code to ensure that it's been fully initialized before control
3487                 //   leaves the constructor.
3488                 // </summary>
3489                 public void AddThisVariable (BlockContext bc)
3490                 {
3491                         if (this_variable != null)
3492                                 throw new InternalErrorException (StartLocation.ToString ());
3493
3494                         this_variable = new LocalVariable (this, "this", LocalVariable.Flags.IsThis | LocalVariable.Flags.Used, StartLocation);
3495                         this_variable.Type = bc.CurrentType;
3496                         this_variable.PrepareForFlowAnalysis (bc);
3497                 }
3498
3499                 public bool IsThisAssigned (BlockContext ec)
3500                 {
3501                         return this_variable == null || this_variable.IsThisAssigned (ec, this);
3502                 }
3503
3504                 public override void Emit (EmitContext ec)
3505                 {
3506                         if (Report.Errors > 0)
3507                                 return;
3508
3509                         try {
3510                         if (IsCompilerGenerated) {
3511                                 using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
3512                                         base.Emit (ec);
3513                                 }
3514                         } else {
3515                                 base.Emit (ec);
3516                         }
3517
3518                         //
3519                         // If `HasReturnLabel' is set, then we already emitted a
3520                         // jump to the end of the method, so we must emit a `ret'
3521                         // there.
3522                         //
3523                         // Unfortunately, System.Reflection.Emit automatically emits
3524                         // a leave to the end of a finally block.  This is a problem
3525                         // if no code is following the try/finally block since we may
3526                         // jump to a point after the end of the method.
3527                         // As a workaround, we're always creating a return label in
3528                         // this case.
3529                         //
3530                         if (ec.HasReturnLabel || !unreachable) {
3531                                 if (ec.HasReturnLabel)
3532                                         ec.MarkLabel (ec.ReturnLabel);
3533
3534                                 if (ec.EmitAccurateDebugInfo && !IsCompilerGenerated)
3535                                         ec.Mark (EndLocation);
3536
3537                                 if (ec.ReturnType.Kind != MemberKind.Void)
3538                                         ec.Emit (OpCodes.Ldloc, ec.TemporaryReturn ());
3539
3540                                 ec.Emit (OpCodes.Ret);
3541                         }
3542
3543                         } catch (Exception e) {
3544                                 throw new InternalErrorException (e, StartLocation);
3545                         }
3546                 }
3547         }
3548         
3549         public class SwitchLabel : Statement
3550         {
3551                 Expression label;
3552                 Constant converted;
3553
3554                 Label? il_label;
3555
3556                 //
3557                 // if expr == null, then it is the default case.
3558                 //
3559                 public SwitchLabel (Expression expr, Location l)
3560                 {
3561                         label = expr;
3562                         loc = l;
3563                 }
3564
3565                 public bool IsDefault {
3566                         get {
3567                                 return label == null;
3568                         }
3569                 }
3570
3571                 public Expression Label {
3572                         get {
3573                                 return label;
3574                         }
3575                 }
3576
3577                 public Location Location {
3578                         get {
3579                                 return loc;
3580                         }
3581                 }
3582
3583                 public Constant Converted {
3584                         get {
3585                                 return converted;
3586                         }
3587                         set {
3588                                 converted = value;
3589                         }
3590                 }
3591
3592                 public bool SectionStart { get; set; }
3593
3594                 public Label GetILLabel (EmitContext ec)
3595                 {
3596                         if (il_label == null){
3597                                 il_label = ec.DefineLabel ();
3598                         }
3599
3600                         return il_label.Value;
3601                 }
3602
3603                 protected override void DoEmit (EmitContext ec)
3604                 {
3605                         ec.MarkLabel (GetILLabel (ec));
3606                 }
3607
3608                 public override bool Resolve (BlockContext bc)
3609                 {
3610                         bc.CurrentBranching.CurrentUsageVector.ResetBarrier ();
3611
3612                         return base.Resolve (bc);
3613                 }
3614
3615                 //
3616                 // Resolves the expression, reduces it to a literal if possible
3617                 // and then converts it to the requested type.
3618                 //
3619                 public bool ResolveAndReduce (ResolveContext ec, TypeSpec required_type, bool allow_nullable)
3620                 {       
3621                         Expression e = label.Resolve (ec);
3622
3623                         if (e == null)
3624                                 return false;
3625
3626                         Constant c = e as Constant;
3627                         if (c == null){
3628                                 ec.Report.Error (150, loc, "A constant value is expected");
3629                                 return false;
3630                         }
3631
3632                         if (allow_nullable && c is NullLiteral) {
3633                                 converted = c;
3634                                 return true;
3635                         }
3636
3637                         converted = c.ImplicitConversionRequired (ec, required_type, loc);
3638                         return converted != null;
3639                 }
3640
3641                 public void Error_AlreadyOccurs (ResolveContext ec, TypeSpec switch_type, SwitchLabel collision_with)
3642                 {
3643                         string label;
3644                         if (converted == null)
3645                                 label = "default";
3646                         else
3647                                 label = converted.GetValueAsLiteral ();
3648                         
3649                         ec.Report.SymbolRelatedToPreviousError (collision_with.loc, null);
3650                         ec.Report.Error (152, loc, "The label `case {0}:' already occurs in this switch statement", label);
3651                 }
3652
3653                 protected override void CloneTo (CloneContext clonectx, Statement target)
3654                 {
3655                         var t = (SwitchLabel) target;
3656                         if (label != null)
3657                                 t.label = label.Clone (clonectx);
3658                 }
3659
3660                 public override object Accept (StructuralVisitor visitor)
3661                 {
3662                         return visitor.Visit (this);
3663                 }
3664         }
3665
3666         public class Switch : Statement
3667         {
3668                 // structure used to hold blocks of keys while calculating table switch
3669                 sealed class LabelsRange : IComparable<LabelsRange>
3670                 {
3671                         public readonly long min;
3672                         public long max;
3673                         public readonly List<long> label_values;
3674
3675                         public LabelsRange (long value)
3676                         {
3677                                 min = max = value;
3678                                 label_values = new List<long> ();
3679                                 label_values.Add (value);
3680                         }
3681
3682                         public LabelsRange (long min, long max, ICollection<long> values)
3683                         {
3684                                 this.min = min;
3685                                 this.max = max;
3686                                 this.label_values = new List<long> (values);
3687                         }
3688
3689                         public long Range {
3690                                 get {
3691                                         return max - min + 1;
3692                                 }
3693                         }
3694
3695                         public bool AddValue (long value)
3696                         {
3697                                 var gap = value - min + 1;
3698                                 // Ensure the range has > 50% occupancy
3699                                 if (gap > 2 * (label_values.Count + 1) || gap <= 0)
3700                                         return false;
3701
3702                                 max = value;
3703                                 label_values.Add (value);
3704                                 return true;
3705                         }
3706
3707                         public int CompareTo (LabelsRange other)
3708                         {
3709                                 int nLength = label_values.Count;
3710                                 int nLengthOther = other.label_values.Count;
3711                                 if (nLengthOther == nLength)
3712                                         return (int) (other.min - min);
3713
3714                                 return nLength - nLengthOther;
3715                         }
3716                 }
3717
3718                 sealed class DispatchStatement : Statement
3719                 {
3720                         readonly Switch body;
3721
3722                         public DispatchStatement (Switch body)
3723                         {
3724                                 this.body = body;
3725                         }
3726
3727                         protected override void CloneTo (CloneContext clonectx, Statement target)
3728                         {
3729                                 throw new NotImplementedException ();
3730                         }
3731
3732                         protected override void DoEmit (EmitContext ec)
3733                         {
3734                                 body.EmitDispatch (ec);
3735                         }
3736                 }
3737
3738                 public Expression Expr;
3739
3740                 //
3741                 // Mapping of all labels to their SwitchLabels
3742                 //
3743                 Dictionary<long, SwitchLabel> labels;
3744                 Dictionary<string, SwitchLabel> string_labels;
3745                 List<SwitchLabel> case_labels;
3746
3747                 /// <summary>
3748                 ///   The governing switch type
3749                 /// </summary>
3750                 public TypeSpec SwitchType;
3751
3752                 Expression new_expr;
3753
3754                 SwitchLabel case_null;
3755                 SwitchLabel case_default;
3756
3757                 Label defaultLabel, nullLabel;
3758                 VariableReference value;
3759                 ExpressionStatement string_dictionary;
3760                 FieldExpr switch_cache_field;
3761                 ExplicitBlock block;
3762
3763                 //
3764                 // Nullable Types support
3765                 //
3766                 Nullable.Unwrap unwrap;
3767
3768                 public Switch (Expression e, ExplicitBlock block, Location l)
3769                 {
3770                         Expr = e;
3771                         this.block = block;
3772                         loc = l;
3773                 }
3774
3775                 public ExplicitBlock Block {
3776                         get {
3777                                 return block;
3778                         }
3779                 }
3780
3781                 public SwitchLabel DefaultLabel {
3782                         get {
3783                                 return case_default;
3784                         }
3785                 }
3786
3787                 public bool IsNullable {
3788                         get {
3789                                 return unwrap != null;
3790                         }
3791                 }
3792
3793                 //
3794                 // Determines the governing type for a switch.  The returned
3795                 // expression might be the expression from the switch, or an
3796                 // expression that includes any potential conversions to
3797                 //
3798                 Expression SwitchGoverningType (ResolveContext ec, Expression expr)
3799                 {
3800                         switch (expr.Type.BuiltinType) {
3801                         case BuiltinTypeSpec.Type.Byte:
3802                         case BuiltinTypeSpec.Type.SByte:
3803                         case BuiltinTypeSpec.Type.UShort:
3804                         case BuiltinTypeSpec.Type.Short:
3805                         case BuiltinTypeSpec.Type.UInt:
3806                         case BuiltinTypeSpec.Type.Int:
3807                         case BuiltinTypeSpec.Type.ULong:
3808                         case BuiltinTypeSpec.Type.Long:
3809                         case BuiltinTypeSpec.Type.Char:
3810                         case BuiltinTypeSpec.Type.String:
3811                         case BuiltinTypeSpec.Type.Bool:
3812                                 return expr;
3813                         }
3814
3815                         if (expr.Type.IsEnum)
3816                                 return expr;
3817
3818                         //
3819                         // Try to find a *user* defined implicit conversion.
3820                         //
3821                         // If there is no implicit conversion, or if there are multiple
3822                         // conversions, we have to report an error
3823                         //
3824                         Expression converted = null;
3825                         foreach (TypeSpec tt in ec.BuiltinTypes.SwitchUserTypes) {
3826                                 Expression e;
3827                                 
3828                                 e = Convert.ImplicitUserConversion (ec, expr, tt, loc);
3829                                 if (e == null)
3830                                         continue;
3831
3832                                 //
3833                                 // Ignore over-worked ImplicitUserConversions that do
3834                                 // an implicit conversion in addition to the user conversion.
3835                                 // 
3836                                 if (!(e is UserCast))
3837                                         continue;
3838
3839                                 if (converted != null){
3840                                         ec.Report.ExtraInformation (loc, "(Ambiguous implicit user defined conversion in previous ");
3841                                         return null;
3842                                 }
3843
3844                                 converted = e;
3845                         }
3846                         return converted;
3847                 }
3848
3849                 public static TypeSpec[] CreateSwitchUserTypes (BuiltinTypes types)
3850                 {
3851                         // LAMESPEC: For some reason it does not contain bool which looks like csc bug
3852                         return new[] {
3853                                 types.SByte,
3854                                 types.Byte,
3855                                 types.Short,
3856                                 types.UShort,
3857                                 types.Int,
3858                                 types.UInt,
3859                                 types.Long,
3860                                 types.ULong,
3861                                 types.Char,
3862                                 types.String
3863                         };
3864                 }
3865
3866                 //
3867                 // Performs the basic sanity checks on the switch statement
3868                 // (looks for duplicate keys and non-constant expressions).
3869                 //
3870                 // It also returns a hashtable with the keys that we will later
3871                 // use to compute the switch tables
3872                 //
3873                 bool ResolveLabels (ResolveContext ec, Constant value)
3874                 {
3875                         bool error = false;
3876                         if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String) {
3877                                 string_labels = new Dictionary<string, SwitchLabel> ();
3878                         } else {
3879                                 labels = new Dictionary<long, SwitchLabel> ();
3880                         }
3881
3882                         case_labels = new List<SwitchLabel> ();
3883                         int default_label_index = -1;
3884                         bool constant_label_found = false;
3885
3886                         for (int i = 0; i < block.Statements.Count; ++i) {
3887                                 var s = block.Statements[i];
3888
3889                                 var sl = s as SwitchLabel;
3890                                 if (sl == null) {
3891                                         continue;
3892                                 }
3893
3894                                 case_labels.Add (sl);
3895
3896                                 if (sl.IsDefault) {
3897                                         if (case_default != null) {
3898                                                 sl.Error_AlreadyOccurs (ec, SwitchType, case_default);
3899                                                 error = true;
3900                                         }
3901
3902                                         default_label_index = i;
3903                                         case_default = sl;
3904                                         continue;
3905                                 }
3906
3907                                 if (!sl.ResolveAndReduce (ec, SwitchType, IsNullable)) {
3908                                         error = true;
3909                                         continue;
3910                                 }
3911
3912                                 try {
3913                                         if (string_labels != null) {
3914                                                 string string_value = sl.Converted.GetValue () as string;
3915                                                 if (string_value == null)
3916                                                         case_null = sl;
3917                                                 else
3918                                                         string_labels.Add (string_value, sl);
3919                                         } else {
3920                                                 if (sl.Converted is NullLiteral) {
3921                                                         case_null = sl;
3922                                                 } else {
3923                                                         labels.Add (sl.Converted.GetValueAsLong (), sl);
3924                                                 }
3925                                         }
3926                                 } catch (ArgumentException) {
3927                                         if (string_labels != null)
3928                                                 sl.Error_AlreadyOccurs (ec, SwitchType, string_labels[(string) sl.Converted.GetValue ()]);
3929                                         else
3930                                                 sl.Error_AlreadyOccurs (ec, SwitchType, labels[sl.Converted.GetValueAsLong ()]);
3931
3932                                         error = true;
3933                                 }
3934
3935                                 if (value != null) {
3936                                         var constant_label = constant_label_found ? null : FindLabel (value);
3937                                         if (constant_label == null || constant_label != sl)
3938                                                 block.Statements[i] = new EmptyStatement (s.loc);
3939                                         else
3940                                                 constant_label_found = true;
3941                                 }
3942                         }
3943
3944                         if (value != null && constant_label_found && default_label_index >= 0)
3945                                 block.Statements[default_label_index] = new EmptyStatement (case_default.loc);
3946
3947                         return !error;
3948                 }
3949                 
3950                 //
3951                 // This method emits code for a lookup-based switch statement (non-string)
3952                 // Basically it groups the cases into blocks that are at least half full,
3953                 // and then spits out individual lookup opcodes for each block.
3954                 // It emits the longest blocks first, and short blocks are just
3955                 // handled with direct compares.
3956                 //
3957                 void EmitTableSwitch (EmitContext ec, Expression val)
3958                 {
3959                         if (labels != null && labels.Count > 0) {
3960                                 List<LabelsRange> ranges;
3961                                 if (string_labels != null) {
3962                                         // We have done all hard work for string already
3963                                         // setup single range only
3964                                         ranges = new List<LabelsRange> (1);
3965                                         ranges.Add (new LabelsRange (0, labels.Count - 1, labels.Keys));
3966                                 } else {
3967                                         var element_keys = new long[labels.Count];
3968                                         labels.Keys.CopyTo (element_keys, 0);
3969                                         Array.Sort (element_keys);
3970
3971                                         //
3972                                         // Build possible ranges of switch labes to reduce number
3973                                         // of comparisons
3974                                         //
3975                                         ranges = new List<LabelsRange> (element_keys.Length);
3976                                         var range = new LabelsRange (element_keys[0]);
3977                                         ranges.Add (range);
3978                                         for (int i = 1; i < element_keys.Length; ++i) {
3979                                                 var l = element_keys[i];
3980                                                 if (range.AddValue (l))
3981                                                         continue;
3982
3983                                                 range = new LabelsRange (l);
3984                                                 ranges.Add (range);
3985                                         }
3986
3987                                         // sort the blocks so we can tackle the largest ones first
3988                                         ranges.Sort ();
3989                                 }
3990
3991                                 Label lbl_default = defaultLabel;
3992                                 TypeSpec compare_type = SwitchType.IsEnum ? EnumSpec.GetUnderlyingType (SwitchType) : SwitchType;
3993
3994                                 for (int range_index = ranges.Count - 1; range_index >= 0; --range_index) {
3995                                         LabelsRange kb = ranges[range_index];
3996                                         lbl_default = (range_index == 0) ? defaultLabel : ec.DefineLabel ();
3997
3998                                         // Optimize small ranges using simple equality check
3999                                         if (kb.Range <= 2) {
4000                                                 foreach (var key in kb.label_values) {
4001                                                         SwitchLabel sl = labels[key];
4002                                                         if (sl == case_default || sl == case_null)
4003                                                                 continue;
4004
4005                                                         if (sl.Converted.IsZeroInteger) {
4006                                                                 val.EmitBranchable (ec, sl.GetILLabel (ec), false);
4007                                                         } else {
4008                                                                 val.Emit (ec);
4009                                                                 sl.Converted.Emit (ec);
4010                                                                 ec.Emit (OpCodes.Beq, sl.GetILLabel (ec));
4011                                                         }
4012                                                 }
4013                                         } else {
4014                                                 // TODO: if all the keys in the block are the same and there are
4015                                                 //       no gaps/defaults then just use a range-check.
4016                                                 if (compare_type.BuiltinType == BuiltinTypeSpec.Type.Long || compare_type.BuiltinType == BuiltinTypeSpec.Type.ULong) {
4017                                                         // TODO: optimize constant/I4 cases
4018
4019                                                         // check block range (could be > 2^31)
4020                                                         val.Emit (ec);
4021                                                         ec.EmitLong (kb.min);
4022                                                         ec.Emit (OpCodes.Blt, lbl_default);
4023
4024                                                         val.Emit (ec);
4025                                                         ec.EmitLong (kb.max);
4026                                                         ec.Emit (OpCodes.Bgt, lbl_default);
4027
4028                                                         // normalize range
4029                                                         val.Emit (ec);
4030                                                         if (kb.min != 0) {
4031                                                                 ec.EmitLong (kb.min);
4032                                                                 ec.Emit (OpCodes.Sub);
4033                                                         }
4034
4035                                                         ec.Emit (OpCodes.Conv_I4);      // assumes < 2^31 labels!
4036                                                 } else {
4037                                                         // normalize range
4038                                                         val.Emit (ec);
4039                                                         int first = (int) kb.min;
4040                                                         if (first > 0) {
4041                                                                 ec.EmitInt (first);
4042                                                                 ec.Emit (OpCodes.Sub);
4043                                                         } else if (first < 0) {
4044                                                                 ec.EmitInt (-first);
4045                                                                 ec.Emit (OpCodes.Add);
4046                                                         }
4047                                                 }
4048
4049                                                 // first, build the list of labels for the switch
4050                                                 int iKey = 0;
4051                                                 long cJumps = kb.Range;
4052                                                 Label[] switch_labels = new Label[cJumps];
4053                                                 for (int iJump = 0; iJump < cJumps; iJump++) {
4054                                                         var key = kb.label_values[iKey];
4055                                                         if (key == kb.min + iJump) {
4056                                                                 switch_labels[iJump] = labels[key].GetILLabel (ec);
4057                                                                 iKey++;
4058                                                         } else {
4059                                                                 switch_labels[iJump] = lbl_default;
4060                                                         }
4061                                                 }
4062
4063                                                 // emit the switch opcode
4064                                                 ec.Emit (OpCodes.Switch, switch_labels);
4065                                         }
4066
4067                                         // mark the default for this block
4068                                         if (range_index != 0)
4069                                                 ec.MarkLabel (lbl_default);
4070                                 }
4071
4072                                 // the last default just goes to the end
4073                                 if (ranges.Count > 0)
4074                                         ec.Emit (OpCodes.Br, lbl_default);
4075                         }
4076                 }
4077                 
4078                 SwitchLabel FindLabel (Constant value)
4079                 {
4080                         SwitchLabel sl = null;
4081
4082                         if (string_labels != null) {
4083                                 string s = value.GetValue () as string;
4084                                 if (s == null) {
4085                                         if (case_null != null)
4086                                                 sl = case_null;
4087                                         else if (case_default != null)
4088                                                 sl = case_default;
4089                                 } else {
4090                                         string_labels.TryGetValue (s, out sl);
4091                                 }
4092                         } else {
4093                                 if (value is NullLiteral) {
4094                                         sl = case_null;
4095                                 } else {
4096                                         labels.TryGetValue (value.GetValueAsLong (), out sl);
4097                                 }
4098                         }
4099
4100                         return sl;
4101                 }
4102
4103                 public override bool Resolve (BlockContext ec)
4104                 {
4105                         Expr = Expr.Resolve (ec);
4106                         if (Expr == null)
4107                                 return false;
4108
4109                         new_expr = SwitchGoverningType (ec, Expr);
4110
4111                         if (new_expr == null && Expr.Type.IsNullableType) {
4112                                 unwrap = Nullable.Unwrap.Create (Expr, false);
4113                                 if (unwrap == null)
4114                                         return false;
4115
4116                                 new_expr = SwitchGoverningType (ec, unwrap);
4117                         }
4118
4119                         if (new_expr == null){
4120                                 ec.Report.Error (151, loc,
4121                                         "A switch expression of type `{0}' cannot be converted to an integral type, bool, char, string, enum or nullable type",
4122                                         TypeManager.CSharpName (Expr.Type));
4123                                 return false;
4124                         }
4125
4126                         // Validate switch.
4127                         SwitchType = new_expr.Type;
4128
4129                         if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.Bool && ec.Module.Compiler.Settings.Version == LanguageVersion.ISO_1) {
4130                                 ec.Report.FeatureIsNotAvailable (ec.Module.Compiler, loc, "switch expression of boolean type");
4131                                 return false;
4132                         }
4133
4134                         if (block.Statements.Count == 0)
4135                                 return true;
4136
4137                         var constant = new_expr as Constant;
4138
4139                         if (!ResolveLabels (ec, constant))
4140                                 return false;
4141
4142                         //
4143                         // Don't need extra variable for constant switch or switch with
4144                         // only default case
4145                         //
4146                         if (constant == null && (case_labels.Count - (case_default != null ? 1 : 0)) != 0) {
4147                                 //
4148                                 // Store switch expression for comparison purposes
4149                                 //
4150                                 value = new_expr as VariableReference;
4151                                 if (value == null) {
4152                                         // Create temporary variable inside switch scope
4153                                         var current_block = ec.CurrentBlock;
4154                                         ec.CurrentBlock = Block;
4155                                         value = TemporaryVariableReference.Create (SwitchType, ec.CurrentBlock, loc);
4156                                         value.Resolve (ec);
4157                                         ec.CurrentBlock = current_block;
4158                                 }
4159                         }
4160
4161                         Switch old_switch = ec.Switch;
4162                         ec.Switch = this;
4163                         ec.Switch.SwitchType = SwitchType;
4164
4165                         ec.StartFlowBranching (FlowBranching.BranchingType.Switch, loc);
4166
4167                         ec.CurrentBranching.CurrentUsageVector.Goto ();
4168
4169                         var ok = block.Resolve (ec);
4170
4171                         if (case_default == null)
4172                                 ec.CurrentBranching.CurrentUsageVector.ResetBarrier ();
4173
4174                         ec.EndFlowBranching ();
4175                         ec.Switch = old_switch;
4176
4177                         if (!ok)
4178                                 return false;
4179
4180                         if (constant == null && SwitchType.BuiltinType == BuiltinTypeSpec.Type.String && string_labels.Count > 6) {
4181                                 ResolveStringSwitchMap (ec);
4182                         }
4183
4184                         //
4185                         // Needed to emit anonymous storey initialization before
4186                         // any generated switch dispatch
4187                         //
4188                         block.AddScopeStatement (new DispatchStatement (this));
4189
4190                         return true;
4191                 }
4192
4193                 public SwitchLabel ResolveGotoCase (ResolveContext rc, Constant value)
4194                 {
4195                         var sl = FindLabel (value);
4196
4197                         if (sl == null) {
4198                                 FlowBranchingBlock.Error_UnknownLabel (loc, "case " + value.GetValueAsLiteral (), rc.Report);
4199                         }
4200
4201                         return sl;
4202                 }
4203
4204                 //
4205                 // Converts string switch into string hashtable
4206                 //
4207                 void ResolveStringSwitchMap (ResolveContext ec)
4208                 {
4209                         FullNamedExpression string_dictionary_type;
4210                         if (ec.Module.PredefinedTypes.Dictionary.Define ()) {
4211                                 string_dictionary_type = new TypeExpression (
4212                                         ec.Module.PredefinedTypes.Dictionary.TypeSpec.MakeGenericType (ec,
4213                                                 new [] { ec.BuiltinTypes.String, ec.BuiltinTypes.Int }),
4214                                         loc);
4215                         } else if (ec.Module.PredefinedTypes.Hashtable.Define ()) {
4216                                 string_dictionary_type = new TypeExpression (ec.Module.PredefinedTypes.Hashtable.TypeSpec, loc);
4217                         } else {
4218                                 ec.Module.PredefinedTypes.Dictionary.Resolve ();
4219                                 return;
4220                         }
4221
4222                         var ctype = ec.CurrentMemberDefinition.Parent.PartialContainer;
4223                         Field field = new Field (ctype, string_dictionary_type,
4224                                 Modifiers.STATIC | Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED,
4225                                 new MemberName (CompilerGeneratedContainer.MakeName (null, "f", "switch$map", ec.Module.CounterSwitchTypes++), loc), null);
4226                         if (!field.Define ())
4227                                 return;
4228                         ctype.AddField (field);
4229
4230                         var init = new List<Expression> ();
4231                         int counter = -1;
4232                         labels = new Dictionary<long, SwitchLabel> (string_labels.Count);
4233                         string value = null;
4234
4235                         foreach (SwitchLabel sl in case_labels) {
4236
4237                                 if (sl.SectionStart)
4238                                         labels.Add (++counter, sl);
4239
4240                                 if (sl == case_default || sl == case_null)
4241                                         continue;
4242
4243                                 value = (string) sl.Converted.GetValue ();
4244                                 var init_args = new List<Expression> (2);
4245                                 init_args.Add (new StringLiteral (ec.BuiltinTypes, value, sl.Location));
4246
4247                                 sl.Converted = new IntConstant (ec.BuiltinTypes, counter, loc);
4248                                 init_args.Add (sl.Converted);
4249
4250                                 init.Add (new CollectionElementInitializer (init_args, loc));
4251                         }
4252         
4253                         Arguments args = new Arguments (1);
4254                         args.Add (new Argument (new IntConstant (ec.BuiltinTypes, init.Count, loc)));
4255                         Expression initializer = new NewInitialize (string_dictionary_type, args,
4256                                 new CollectionOrObjectInitializers (init, loc), loc);
4257
4258                         switch_cache_field = new FieldExpr (field, loc);
4259                         string_dictionary = new SimpleAssign (switch_cache_field, initializer.Resolve (ec));
4260                 }
4261
4262                 void DoEmitStringSwitch (EmitContext ec)
4263                 {
4264                         Label l_initialized = ec.DefineLabel ();
4265
4266                         //
4267                         // Skip initialization when value is null
4268                         //
4269                         value.EmitBranchable (ec, nullLabel, false);
4270
4271                         //
4272                         // Check if string dictionary is initialized and initialize
4273                         //
4274                         switch_cache_field.EmitBranchable (ec, l_initialized, true);
4275                         using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
4276                                 string_dictionary.EmitStatement (ec);
4277                         }
4278                         ec.MarkLabel (l_initialized);
4279
4280                         LocalTemporary string_switch_variable = new LocalTemporary (ec.BuiltinTypes.Int);
4281
4282                         ResolveContext rc = new ResolveContext (ec.MemberContext);
4283
4284                         if (switch_cache_field.Type.IsGeneric) {
4285                                 Arguments get_value_args = new Arguments (2);
4286                                 get_value_args.Add (new Argument (value));
4287                                 get_value_args.Add (new Argument (string_switch_variable, Argument.AType.Out));
4288                                 Expression get_item = new Invocation (new MemberAccess (switch_cache_field, "TryGetValue", loc), get_value_args).Resolve (rc);
4289                                 if (get_item == null)
4290                                         return;
4291
4292                                 //
4293                                 // A value was not found, go to default case
4294                                 //
4295                                 get_item.EmitBranchable (ec, defaultLabel, false);
4296                         } else {
4297                                 Arguments get_value_args = new Arguments (1);
4298                                 get_value_args.Add (new Argument (value));
4299
4300                                 Expression get_item = new ElementAccess (switch_cache_field, get_value_args, loc).Resolve (rc);
4301                                 if (get_item == null)
4302                                         return;
4303
4304                                 LocalTemporary get_item_object = new LocalTemporary (ec.BuiltinTypes.Object);
4305                                 get_item_object.EmitAssign (ec, get_item, true, false);
4306                                 ec.Emit (OpCodes.Brfalse, defaultLabel);
4307
4308                                 ExpressionStatement get_item_int = (ExpressionStatement) new SimpleAssign (string_switch_variable,
4309                                         new Cast (new TypeExpression (ec.BuiltinTypes.Int, loc), get_item_object, loc)).Resolve (rc);
4310
4311                                 get_item_int.EmitStatement (ec);
4312                                 get_item_object.Release (ec);
4313                         }
4314
4315                         EmitTableSwitch (ec, string_switch_variable);
4316                         string_switch_variable.Release (ec);
4317                 }
4318
4319                 //
4320                 // Emits switch using simple if/else comparison for small label count (4 + optional default)
4321                 //
4322                 void EmitShortSwitch (EmitContext ec)
4323                 {
4324                         MethodSpec equal_method = null;
4325                         if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String) {
4326                                 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (loc);
4327                         }
4328
4329                         if (equal_method != null) {
4330                                 value.EmitBranchable (ec, nullLabel, false);
4331                         }
4332
4333                         for (int i = 0; i < case_labels.Count; ++i) {
4334                                 var label = case_labels [i];
4335                                 if (label == case_default || label == case_null)
4336                                         continue;
4337
4338                                 var constant = label.Converted;
4339
4340                                 if (equal_method != null) {
4341                                         value.Emit (ec);
4342                                         constant.Emit (ec);
4343
4344                                         var call = new CallEmitter ();
4345                                         call.EmitPredefined (ec, equal_method, new Arguments (0));
4346                                         ec.Emit (OpCodes.Brtrue, label.GetILLabel (ec));
4347                                         continue;
4348                                 }
4349
4350                                 if (constant.IsZeroInteger && constant.Type.BuiltinType != BuiltinTypeSpec.Type.Long && constant.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
4351                                         value.EmitBranchable (ec, label.GetILLabel (ec), false);
4352                                         continue;
4353                                 }
4354
4355                                 value.Emit (ec);
4356                                 constant.Emit (ec);
4357                                 ec.Emit (OpCodes.Beq, label.GetILLabel (ec));
4358                         }
4359
4360                         ec.Emit (OpCodes.Br, defaultLabel);
4361                 }
4362
4363                 void EmitDispatch (EmitContext ec)
4364                 {
4365                         if (value == null) {
4366                                 //
4367                                 // Constant switch, we already done the work
4368                                 //
4369                                 return;
4370                         }
4371
4372                         //
4373                         // Mark sequence point explicitly to switch
4374                         //
4375                         ec.Mark (block.StartLocation);
4376                         block.IsCompilerGenerated = true;
4377
4378                         if (string_dictionary != null) {
4379                                 DoEmitStringSwitch (ec);
4380                         } else if (case_labels.Count < 4 || string_labels != null) {
4381                                 EmitShortSwitch (ec);
4382                         } else {
4383                                 EmitTableSwitch (ec, value);
4384                         }
4385                 }
4386
4387                 protected override void DoEmit (EmitContext ec)
4388                 {
4389                         // Workaround broken flow-analysis
4390                         block.HasUnreachableClosingBrace = true;
4391
4392                         //
4393                         // Setup the codegen context
4394                         //
4395                         Label old_end = ec.LoopEnd;
4396                         Switch old_switch = ec.Switch;
4397
4398                         ec.LoopEnd = ec.DefineLabel ();
4399                         ec.Switch = this;
4400
4401                         defaultLabel = case_default == null ? ec.LoopEnd : case_default.GetILLabel (ec);
4402                         nullLabel = case_null == null ? defaultLabel : case_null.GetILLabel (ec);
4403
4404                         if (value != null) {
4405                                 ec.Mark (loc);
4406                                 if (IsNullable) {
4407                                         unwrap.EmitCheck (ec);
4408                                         ec.Emit (OpCodes.Brfalse, nullLabel);
4409                                         value.EmitAssign (ec, new_expr, false, false);
4410                                 } else if (new_expr != value) {
4411                                         value.EmitAssign (ec, new_expr, false, false);
4412                                 }
4413                         }
4414
4415                         block.Emit (ec);
4416
4417                         // Restore context state. 
4418                         ec.MarkLabel (ec.LoopEnd);
4419
4420                         //
4421                         // Restore the previous context
4422                         //
4423                         ec.LoopEnd = old_end;
4424                         ec.Switch = old_switch;
4425                 }
4426
4427                 protected override void CloneTo (CloneContext clonectx, Statement t)
4428                 {
4429                         Switch target = (Switch) t;
4430
4431                         target.Expr = Expr.Clone (clonectx);
4432                         target.block = (ExplicitBlock) block.Clone (clonectx);
4433                 }
4434                 
4435                 public override object Accept (StructuralVisitor visitor)
4436                 {
4437                         return visitor.Visit (this);
4438                 }
4439         }
4440
4441         // A place where execution can restart in an iterator
4442         public abstract class ResumableStatement : Statement
4443         {
4444                 bool prepared;
4445                 protected Label resume_point;
4446
4447                 public Label PrepareForEmit (EmitContext ec)
4448                 {
4449                         if (!prepared) {
4450                                 prepared = true;
4451                                 resume_point = ec.DefineLabel ();
4452                         }
4453                         return resume_point;
4454                 }
4455
4456                 public virtual Label PrepareForDispose (EmitContext ec, Label end)
4457                 {
4458                         return end;
4459                 }
4460
4461                 public virtual void EmitForDispose (EmitContext ec, LocalBuilder pc, Label end, bool have_dispatcher)
4462                 {
4463                 }
4464         }
4465
4466         public abstract class TryFinallyBlock : ExceptionStatement
4467         {
4468                 protected Statement stmt;
4469                 Label dispose_try_block;
4470                 bool prepared_for_dispose, emitted_dispose;
4471                 Method finally_host;
4472
4473                 protected TryFinallyBlock (Statement stmt, Location loc)
4474                         : base (loc)
4475                 {
4476                         this.stmt = stmt;
4477                 }
4478
4479                 #region Properties
4480
4481                 public Statement Statement {
4482                         get {
4483                                 return stmt;
4484                         }
4485                 }
4486
4487                 #endregion
4488
4489                 protected abstract void EmitTryBody (EmitContext ec);
4490                 public abstract void EmitFinallyBody (EmitContext ec);
4491
4492                 public override Label PrepareForDispose (EmitContext ec, Label end)
4493                 {
4494                         if (!prepared_for_dispose) {
4495                                 prepared_for_dispose = true;
4496                                 dispose_try_block = ec.DefineLabel ();
4497                         }
4498                         return dispose_try_block;
4499                 }
4500
4501                 protected sealed override void DoEmit (EmitContext ec)
4502                 {
4503                         EmitTryBodyPrepare (ec);
4504                         EmitTryBody (ec);
4505
4506                         ec.BeginFinallyBlock ();
4507
4508                         Label start_finally = ec.DefineLabel ();
4509                         if (resume_points != null) {
4510                                 var state_machine = (StateMachineInitializer) ec.CurrentAnonymousMethod;
4511
4512                                 ec.Emit (OpCodes.Ldloc, state_machine.SkipFinally);
4513                                 ec.Emit (OpCodes.Brfalse_S, start_finally);
4514                                 ec.Emit (OpCodes.Endfinally);
4515                         }
4516
4517                         ec.MarkLabel (start_finally);
4518
4519                         if (finally_host != null) {
4520                                 finally_host.Define ();
4521                                 finally_host.Emit ();
4522
4523                                 // Now it's safe to add, to close it properly and emit sequence points
4524                                 finally_host.Parent.AddMember (finally_host);
4525
4526                                 var ce = new CallEmitter ();
4527                                 ce.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, loc);
4528                                 ce.EmitPredefined (ec, finally_host.Spec, new Arguments (0));
4529                         } else {
4530                                 EmitFinallyBody (ec);
4531                         }
4532
4533                         ec.EndExceptionBlock ();
4534                 }
4535
4536                 public override void EmitForDispose (EmitContext ec, LocalBuilder pc, Label end, bool have_dispatcher)
4537                 {
4538                         if (emitted_dispose)
4539                                 return;
4540
4541                         emitted_dispose = true;
4542
4543                         Label end_of_try = ec.DefineLabel ();
4544
4545                         // Ensure that the only way we can get into this code is through a dispatcher
4546                         if (have_dispatcher)
4547                                 ec.Emit (OpCodes.Br, end);
4548
4549                         ec.BeginExceptionBlock ();
4550
4551                         ec.MarkLabel (dispose_try_block);
4552
4553                         Label[] labels = null;
4554                         for (int i = 0; i < resume_points.Count; ++i) {
4555                                 ResumableStatement s = resume_points[i];
4556                                 Label ret = s.PrepareForDispose (ec, end_of_try);
4557                                 if (ret.Equals (end_of_try) && labels == null)
4558                                         continue;
4559                                 if (labels == null) {
4560                                         labels = new Label[resume_points.Count];
4561                                         for (int j = 0; j < i; ++j)
4562                                                 labels[j] = end_of_try;
4563                                 }
4564                                 labels[i] = ret;
4565                         }
4566
4567                         if (labels != null) {
4568                                 int j;
4569                                 for (j = 1; j < labels.Length; ++j)
4570                                         if (!labels[0].Equals (labels[j]))
4571                                                 break;
4572                                 bool emit_dispatcher = j < labels.Length;
4573
4574                                 if (emit_dispatcher) {
4575                                         ec.Emit (OpCodes.Ldloc, pc);
4576                                         ec.EmitInt (first_resume_pc);
4577                                         ec.Emit (OpCodes.Sub);
4578                                         ec.Emit (OpCodes.Switch, labels);
4579                                 }
4580
4581                                 foreach (ResumableStatement s in resume_points)
4582                                         s.EmitForDispose (ec, pc, end_of_try, emit_dispatcher);
4583                         }
4584
4585                         ec.MarkLabel (end_of_try);
4586
4587                         ec.BeginFinallyBlock ();
4588
4589                         if (finally_host != null) {
4590                                 var ce = new CallEmitter ();
4591                                 ce.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, loc);
4592                                 ce.EmitPredefined (ec, finally_host.Spec, new Arguments (0));
4593                         } else {
4594                                 EmitFinallyBody (ec);
4595                         }
4596
4597                         ec.EndExceptionBlock ();
4598                 }
4599
4600                 public override bool Resolve (BlockContext bc)
4601                 {
4602                         //
4603                         // Finally block inside iterator is called from MoveNext and
4604                         // Dispose methods that means we need to lift the block into
4605                         // newly created host method to emit the body only once. The
4606                         // original block then simply calls the newly generated method.
4607                         //
4608                         if (bc.CurrentIterator != null && !bc.IsInProbingMode) {
4609                                 var b = stmt as Block;
4610                                 if (b != null && b.Explicit.HasYield) {
4611                                         finally_host = bc.CurrentIterator.CreateFinallyHost (this);
4612                                 }
4613                         }
4614
4615                         return base.Resolve (bc);
4616                 }
4617         }
4618
4619         //
4620         // Base class for blocks using exception handling
4621         //
4622         public abstract class ExceptionStatement : ResumableStatement
4623         {
4624 #if !STATIC
4625                 bool code_follows;
4626 #endif
4627                 protected List<ResumableStatement> resume_points;
4628                 protected int first_resume_pc;
4629
4630                 protected ExceptionStatement (Location loc)
4631                 {
4632                         this.loc = loc;
4633                 }
4634
4635                 protected virtual void EmitTryBodyPrepare (EmitContext ec)
4636                 {
4637                         StateMachineInitializer state_machine = null;
4638                         if (resume_points != null) {
4639                                 state_machine = (StateMachineInitializer) ec.CurrentAnonymousMethod;
4640
4641                                 ec.EmitInt ((int) IteratorStorey.State.Running);
4642                                 ec.Emit (OpCodes.Stloc, state_machine.CurrentPC);
4643                         }
4644
4645                         ec.BeginExceptionBlock ();
4646
4647                         if (resume_points != null) {
4648                                 ec.MarkLabel (resume_point);
4649
4650                                 // For normal control flow, we want to fall-through the Switch
4651                                 // So, we use CurrentPC rather than the $PC field, and initialize it to an outside value above
4652                                 ec.Emit (OpCodes.Ldloc, state_machine.CurrentPC);
4653                                 ec.EmitInt (first_resume_pc);
4654                                 ec.Emit (OpCodes.Sub);
4655
4656                                 Label[] labels = new Label[resume_points.Count];
4657                                 for (int i = 0; i < resume_points.Count; ++i)
4658                                         labels[i] = resume_points[i].PrepareForEmit (ec);
4659                                 ec.Emit (OpCodes.Switch, labels);
4660                         }
4661                 }
4662
4663                 public void SomeCodeFollows ()
4664                 {
4665 #if !STATIC
4666                         code_follows = true;
4667 #endif
4668                 }
4669
4670                 public override bool Resolve (BlockContext ec)
4671                 {
4672 #if !STATIC
4673                         // System.Reflection.Emit automatically emits a 'leave' at the end of a try clause
4674                         // So, ensure there's some IL code after this statement.
4675                         if (!code_follows && resume_points == null && ec.CurrentBranching.CurrentUsageVector.IsUnreachable)
4676                                 ec.NeedReturnLabel ();
4677 #endif
4678                         return true;
4679                 }
4680
4681                 public void AddResumePoint (ResumableStatement stmt, int pc)
4682                 {
4683                         if (resume_points == null) {
4684                                 resume_points = new List<ResumableStatement> ();
4685                                 first_resume_pc = pc;
4686                         }
4687
4688                         if (pc != first_resume_pc + resume_points.Count)
4689                                 throw new InternalErrorException ("missed an intervening AddResumePoint?");
4690
4691                         resume_points.Add (stmt);
4692                 }
4693
4694         }
4695
4696         public class Lock : TryFinallyBlock
4697         {
4698                 Expression expr;
4699                 TemporaryVariableReference expr_copy;
4700                 TemporaryVariableReference lock_taken;
4701                         
4702                 public Lock (Expression expr, Statement stmt, Location loc)
4703                         : base (stmt, loc)
4704                 {
4705                         this.expr = expr;
4706                 }
4707
4708                 public Expression Expr {
4709                         get {
4710                                 return this.expr;
4711                         }
4712                 }
4713
4714                 public override bool Resolve (BlockContext ec)
4715                 {
4716                         expr = expr.Resolve (ec);
4717                         if (expr == null)
4718                                 return false;
4719
4720                         if (!TypeSpec.IsReferenceType (expr.Type)) {
4721                                 ec.Report.Error (185, loc,
4722                                         "`{0}' is not a reference type as required by the lock statement",
4723                                         expr.Type.GetSignatureForError ());
4724                         }
4725
4726                         if (expr.Type.IsGenericParameter) {
4727                                 expr = Convert.ImplicitTypeParameterConversion (expr, (TypeParameterSpec)expr.Type, ec.BuiltinTypes.Object);
4728                         }
4729
4730                         VariableReference lv = expr as VariableReference;
4731                         bool locked;
4732                         if (lv != null) {
4733                                 locked = lv.IsLockedByStatement;
4734                                 lv.IsLockedByStatement = true;
4735                         } else {
4736                                 lv = null;
4737                                 locked = false;
4738                         }
4739
4740                         //
4741                         // Have to keep original lock value around to unlock same location
4742                         // in the case of original value has changed or is null
4743                         //
4744                         expr_copy = TemporaryVariableReference.Create (ec.BuiltinTypes.Object, ec.CurrentBlock, loc);
4745                         expr_copy.Resolve (ec);
4746
4747                         //
4748                         // Ensure Monitor methods are available
4749                         //
4750                         if (ResolvePredefinedMethods (ec) > 1) {
4751                                 lock_taken = TemporaryVariableReference.Create (ec.BuiltinTypes.Bool, ec.CurrentBlock, loc);
4752                                 lock_taken.Resolve (ec);
4753                         }
4754
4755                         using (ec.Set (ResolveContext.Options.LockScope)) {
4756                                 ec.StartFlowBranching (this);
4757                                 Statement.Resolve (ec);
4758                                 ec.EndFlowBranching ();
4759                         }
4760
4761                         if (lv != null) {
4762                                 lv.IsLockedByStatement = locked;
4763                         }
4764
4765                         base.Resolve (ec);
4766
4767                         return true;
4768                 }
4769                 
4770                 protected override void EmitTryBodyPrepare (EmitContext ec)
4771                 {
4772                         expr_copy.EmitAssign (ec, expr);
4773
4774                         if (lock_taken != null) {
4775                                 //
4776                                 // Initialize ref variable
4777                                 //
4778                                 lock_taken.EmitAssign (ec, new BoolLiteral (ec.BuiltinTypes, false, loc));
4779                         } else {
4780                                 //
4781                                 // Monitor.Enter (expr_copy)
4782                                 //
4783                                 expr_copy.Emit (ec);
4784                                 ec.Emit (OpCodes.Call, ec.Module.PredefinedMembers.MonitorEnter.Get ());
4785                         }
4786
4787                         base.EmitTryBodyPrepare (ec);
4788                 }
4789
4790                 protected override void EmitTryBody (EmitContext ec)
4791                 {
4792                         //
4793                         // Monitor.Enter (expr_copy, ref lock_taken)
4794                         //
4795                         if (lock_taken != null) {
4796                                 expr_copy.Emit (ec);
4797                                 lock_taken.LocalInfo.CreateBuilder (ec);
4798                                 lock_taken.AddressOf (ec, AddressOp.Load);
4799                                 ec.Emit (OpCodes.Call, ec.Module.PredefinedMembers.MonitorEnter_v4.Get ());
4800                         }
4801
4802                         Statement.Emit (ec);
4803                 }
4804
4805                 public override void EmitFinallyBody (EmitContext ec)
4806                 {
4807                         //
4808                         // if (lock_taken) Monitor.Exit (expr_copy)
4809                         //
4810                         Label skip = ec.DefineLabel ();
4811
4812                         if (lock_taken != null) {
4813                                 lock_taken.Emit (ec);
4814                                 ec.Emit (OpCodes.Brfalse_S, skip);
4815                         }
4816
4817                         expr_copy.Emit (ec);
4818                         var m = ec.Module.PredefinedMembers.MonitorExit.Resolve (loc);
4819                         if (m != null)
4820                                 ec.Emit (OpCodes.Call, m);
4821
4822                         ec.MarkLabel (skip);
4823                 }
4824
4825                 int ResolvePredefinedMethods (ResolveContext rc)
4826                 {
4827                         // Try 4.0 Monitor.Enter (object, ref bool) overload first
4828                         var m = rc.Module.PredefinedMembers.MonitorEnter_v4.Get ();
4829                         if (m != null)
4830                                 return 4;
4831
4832                         m = rc.Module.PredefinedMembers.MonitorEnter.Get ();
4833                         if (m != null)
4834                                 return 1;
4835
4836                         rc.Module.PredefinedMembers.MonitorEnter_v4.Resolve (loc);
4837                         return 0;
4838                 }
4839
4840                 protected override void CloneTo (CloneContext clonectx, Statement t)
4841                 {
4842                         Lock target = (Lock) t;
4843
4844                         target.expr = expr.Clone (clonectx);
4845                         target.stmt = Statement.Clone (clonectx);
4846                 }
4847                 
4848                 public override object Accept (StructuralVisitor visitor)
4849                 {
4850                         return visitor.Visit (this);
4851                 }
4852
4853         }
4854
4855         public class Unchecked : Statement {
4856                 public Block Block;
4857                 
4858                 public Unchecked (Block b, Location loc)
4859                 {
4860                         Block = b;
4861                         b.Unchecked = true;
4862                         this.loc = loc;
4863                 }
4864
4865                 public override bool Resolve (BlockContext ec)
4866                 {
4867                         using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
4868                                 return Block.Resolve (ec);
4869                 }
4870                 
4871                 protected override void DoEmit (EmitContext ec)
4872                 {
4873                         using (ec.With (EmitContext.Options.CheckedScope, false))
4874                                 Block.Emit (ec);
4875                 }
4876
4877                 protected override void CloneTo (CloneContext clonectx, Statement t)
4878                 {
4879                         Unchecked target = (Unchecked) t;
4880
4881                         target.Block = clonectx.LookupBlock (Block);
4882                 }
4883                 
4884                 public override object Accept (StructuralVisitor visitor)
4885                 {
4886                         return visitor.Visit (this);
4887                 }
4888         }
4889
4890         public class Checked : Statement {
4891                 public Block Block;
4892                 
4893                 public Checked (Block b, Location loc)
4894                 {
4895                         Block = b;
4896                         b.Unchecked = false;
4897                         this.loc = loc;
4898                 }
4899
4900                 public override bool Resolve (BlockContext ec)
4901                 {
4902                         using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
4903                                 return Block.Resolve (ec);
4904                 }
4905
4906                 protected override void DoEmit (EmitContext ec)
4907                 {
4908                         using (ec.With (EmitContext.Options.CheckedScope, true))
4909                                 Block.Emit (ec);
4910                 }
4911
4912                 protected override void CloneTo (CloneContext clonectx, Statement t)
4913                 {
4914                         Checked target = (Checked) t;
4915
4916                         target.Block = clonectx.LookupBlock (Block);
4917                 }
4918                 
4919                 public override object Accept (StructuralVisitor visitor)
4920                 {
4921                         return visitor.Visit (this);
4922                 }
4923         }
4924
4925         public class Unsafe : Statement {
4926                 public Block Block;
4927
4928                 public Unsafe (Block b, Location loc)
4929                 {
4930                         Block = b;
4931                         Block.Unsafe = true;
4932                         this.loc = loc;
4933                 }
4934
4935                 public override bool Resolve (BlockContext ec)
4936                 {
4937                         if (ec.CurrentIterator != null)
4938                                 ec.Report.Error (1629, loc, "Unsafe code may not appear in iterators");
4939
4940                         using (ec.Set (ResolveContext.Options.UnsafeScope))
4941                                 return Block.Resolve (ec);
4942                 }
4943                 
4944                 protected override void DoEmit (EmitContext ec)
4945                 {
4946                         Block.Emit (ec);
4947                 }
4948
4949                 protected override void CloneTo (CloneContext clonectx, Statement t)
4950                 {
4951                         Unsafe target = (Unsafe) t;
4952
4953                         target.Block = clonectx.LookupBlock (Block);
4954                 }
4955                 
4956                 public override object Accept (StructuralVisitor visitor)
4957                 {
4958                         return visitor.Visit (this);
4959                 }
4960         }
4961
4962         // 
4963         // Fixed statement
4964         //
4965         public class Fixed : Statement
4966         {
4967                 abstract class Emitter : ShimExpression
4968                 {
4969                         protected LocalVariable vi;
4970
4971                         protected Emitter (Expression expr, LocalVariable li)
4972                                 : base (expr)
4973                         {
4974                                 vi = li;
4975                         }
4976
4977                         public abstract void EmitExit (EmitContext ec);
4978                 }
4979
4980                 class ExpressionEmitter : Emitter {
4981                         public ExpressionEmitter (Expression converted, LocalVariable li) :
4982                                 base (converted, li)
4983                         {
4984                         }
4985
4986                         protected override Expression DoResolve (ResolveContext rc)
4987                         {
4988                                 throw new NotImplementedException ();
4989                         }
4990
4991                         public override void Emit (EmitContext ec) {
4992                                 //
4993                                 // Store pointer in pinned location
4994                                 //
4995                                 expr.Emit (ec);
4996                                 vi.EmitAssign (ec);
4997                         }
4998
4999                         public override void EmitExit (EmitContext ec)
5000                         {
5001                                 ec.EmitInt (0);
5002                                 ec.Emit (OpCodes.Conv_U);
5003                                 vi.EmitAssign (ec);
5004                         }
5005                 }
5006
5007                 class StringEmitter : Emitter
5008                 {
5009                         LocalVariable pinned_string;
5010
5011                         public StringEmitter (Expression expr, LocalVariable li, Location loc)
5012                                 : base (expr, li)
5013                         {
5014                         }
5015
5016                         protected override Expression DoResolve (ResolveContext rc)
5017                         {
5018                                 pinned_string = new LocalVariable (vi.Block, "$pinned",
5019                                         LocalVariable.Flags.FixedVariable | LocalVariable.Flags.CompilerGenerated | LocalVariable.Flags.Used,
5020                                         vi.Location);
5021                                 pinned_string.Type = rc.BuiltinTypes.String;
5022
5023                                 eclass = ExprClass.Variable;
5024                                 type = rc.BuiltinTypes.Int;
5025                                 return this;
5026                         }
5027
5028                         public override void Emit (EmitContext ec)
5029                         {
5030                                 pinned_string.CreateBuilder (ec);
5031
5032                                 expr.Emit (ec);
5033                                 pinned_string.EmitAssign (ec);
5034
5035                                 // TODO: Should use Binary::Add
5036                                 pinned_string.Emit (ec);
5037                                 ec.Emit (OpCodes.Conv_I);
5038
5039                                 var m = ec.Module.PredefinedMembers.RuntimeHelpersOffsetToStringData.Resolve (loc);
5040                                 if (m == null)
5041                                         return;
5042
5043                                 PropertyExpr pe = new PropertyExpr (m, pinned_string.Location);
5044                                 //pe.InstanceExpression = pinned_string;
5045                                 pe.Resolve (new ResolveContext (ec.MemberContext)).Emit (ec);
5046
5047                                 ec.Emit (OpCodes.Add);
5048                                 vi.EmitAssign (ec);
5049                         }
5050
5051                         public override void EmitExit (EmitContext ec)
5052                         {
5053                                 ec.EmitNull ();
5054                                 pinned_string.EmitAssign (ec);
5055                         }
5056                 }
5057
5058                 public class VariableDeclaration : BlockVariableDeclaration
5059                 {
5060                         public VariableDeclaration (FullNamedExpression type, LocalVariable li)
5061                                 : base (type, li)
5062                         {
5063                         }
5064
5065                         protected override Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
5066                         {
5067                                 if (!Variable.Type.IsPointer && li == Variable) {
5068                                         bc.Report.Error (209, TypeExpression.Location,
5069                                                 "The type of locals declared in a fixed statement must be a pointer type");
5070                                         return null;
5071                                 }
5072
5073                                 //
5074                                 // The rules for the possible declarators are pretty wise,
5075                                 // but the production on the grammar is more concise.
5076                                 //
5077                                 // So we have to enforce these rules here.
5078                                 //
5079                                 // We do not resolve before doing the case 1 test,
5080                                 // because the grammar is explicit in that the token &
5081                                 // is present, so we need to test for this particular case.
5082                                 //
5083
5084                                 if (initializer is Cast) {
5085                                         bc.Report.Error (254, initializer.Location, "The right hand side of a fixed statement assignment may not be a cast expression");
5086                                         return null;
5087                                 }
5088
5089                                 initializer = initializer.Resolve (bc);
5090
5091                                 if (initializer == null)
5092                                         return null;
5093
5094                                 //
5095                                 // Case 1: Array
5096                                 //
5097                                 if (initializer.Type.IsArray) {
5098                                         TypeSpec array_type = TypeManager.GetElementType (initializer.Type);
5099
5100                                         //
5101                                         // Provided that array_type is unmanaged,
5102                                         //
5103                                         if (!TypeManager.VerifyUnmanaged (bc.Module, array_type, loc))
5104                                                 return null;
5105
5106                                         //
5107                                         // and T* is implicitly convertible to the
5108                                         // pointer type given in the fixed statement.
5109                                         //
5110                                         ArrayPtr array_ptr = new ArrayPtr (initializer, array_type, loc);
5111
5112                                         Expression converted = Convert.ImplicitConversionRequired (bc, array_ptr.Resolve (bc), li.Type, loc);
5113                                         if (converted == null)
5114                                                 return null;
5115
5116                                         //
5117                                         // fixed (T* e_ptr = (e == null || e.Length == 0) ? null : converted [0])
5118                                         //
5119                                         converted = new Conditional (new BooleanExpression (new Binary (Binary.Operator.LogicalOr,
5120                                                 new Binary (Binary.Operator.Equality, initializer, new NullLiteral (loc)),
5121                                                 new Binary (Binary.Operator.Equality, new MemberAccess (initializer, "Length"), new IntConstant (bc.BuiltinTypes, 0, loc)))),
5122                                                         new NullLiteral (loc),
5123                                                         converted, loc);
5124
5125                                         converted = converted.Resolve (bc);
5126
5127                                         return new ExpressionEmitter (converted, li);
5128                                 }
5129
5130                                 //
5131                                 // Case 2: string
5132                                 //
5133                                 if (initializer.Type.BuiltinType == BuiltinTypeSpec.Type.String) {
5134                                         return new StringEmitter (initializer, li, loc).Resolve (bc);
5135                                 }
5136
5137                                 // Case 3: fixed buffer
5138                                 if (initializer is FixedBufferPtr) {
5139                                         return new ExpressionEmitter (initializer, li);
5140                                 }
5141
5142                                 //
5143                                 // Case 4: & object.
5144                                 //
5145                                 bool already_fixed = true;
5146                                 Unary u = initializer as Unary;
5147                                 if (u != null && u.Oper == Unary.Operator.AddressOf) {
5148                                         IVariableReference vr = u.Expr as IVariableReference;
5149                                         if (vr == null || !vr.IsFixed) {
5150                                                 already_fixed = false;
5151                                         }
5152                                 }
5153
5154                                 if (already_fixed) {
5155                                         bc.Report.Error (213, loc, "You cannot use the fixed statement to take the address of an already fixed expression");
5156                                 }
5157
5158                                 initializer = Convert.ImplicitConversionRequired (bc, initializer, li.Type, loc);
5159                                 return new ExpressionEmitter (initializer, li);
5160                         }
5161                 }
5162
5163
5164                 VariableDeclaration decl;
5165                 Statement statement;
5166                 bool has_ret;
5167
5168                 public Fixed (VariableDeclaration decl, Statement stmt, Location l)
5169                 {
5170                         this.decl = decl;
5171                         statement = stmt;
5172                         loc = l;
5173                 }
5174
5175                 #region Properties
5176
5177                 public Statement Statement {
5178                         get {
5179                                 return statement;
5180                         }
5181                 }
5182
5183                 public BlockVariableDeclaration Variables {
5184                         get {
5185                                 return decl;
5186                         }
5187                 }
5188
5189                 #endregion
5190
5191                 public override bool Resolve (BlockContext ec)
5192                 {
5193                         using (ec.Set (ResolveContext.Options.FixedInitializerScope)) {
5194                                 if (!decl.Resolve (ec))
5195                                         return false;
5196                         }
5197
5198                         ec.StartFlowBranching (FlowBranching.BranchingType.Conditional, loc);
5199                         bool ok = statement.Resolve (ec);
5200                         bool flow_unreachable = ec.EndFlowBranching ();
5201                         has_ret = flow_unreachable;
5202
5203                         return ok;
5204                 }
5205                 
5206                 protected override void DoEmit (EmitContext ec)
5207                 {
5208                         decl.Variable.CreateBuilder (ec);
5209                         decl.Initializer.Emit (ec);
5210                         if (decl.Declarators != null) {
5211                                 foreach (var d in decl.Declarators) {
5212                                         d.Variable.CreateBuilder (ec);
5213                                         d.Initializer.Emit (ec);
5214                                 }
5215                         }
5216
5217                         statement.Emit (ec);
5218
5219                         if (has_ret)
5220                                 return;
5221
5222                         //
5223                         // Clear the pinned variable
5224                         //
5225                         ((Emitter) decl.Initializer).EmitExit (ec);
5226                         if (decl.Declarators != null) {
5227                                 foreach (var d in decl.Declarators) {
5228                                         ((Emitter)d.Initializer).EmitExit (ec);
5229                                 }
5230                         }
5231                 }
5232
5233                 protected override void CloneTo (CloneContext clonectx, Statement t)
5234                 {
5235                         Fixed target = (Fixed) t;
5236
5237                         target.decl = (VariableDeclaration) decl.Clone (clonectx);
5238                         target.statement = statement.Clone (clonectx);
5239                 }
5240                 
5241                 public override object Accept (StructuralVisitor visitor)
5242                 {
5243                         return visitor.Visit (this);
5244                 }
5245         }
5246
5247         public class Catch : Statement
5248         {
5249                 Block block;
5250                 LocalVariable li;
5251                 FullNamedExpression type_expr;
5252                 CompilerAssign assign;
5253                 TypeSpec type;
5254                 
5255                 public Catch (Block block, Location loc)
5256                 {
5257                         this.block = block;
5258                         this.loc = loc;
5259                 }
5260
5261                 #region Properties
5262
5263                 public Block Block {
5264                         get {
5265                                 return block;
5266                         }
5267                 }
5268
5269                 public TypeSpec CatchType {
5270                         get {
5271                                 return type;
5272                         }
5273                 }
5274
5275                 public bool IsGeneral {
5276                         get {
5277                                 return type_expr == null;
5278                         }
5279                 }
5280
5281                 public FullNamedExpression TypeExpression {
5282                         get {
5283                                 return type_expr;
5284                         }
5285                         set {
5286                                 type_expr = value;
5287                         }
5288                 }
5289
5290                 public LocalVariable Variable {
5291                         get {
5292                                 return li;
5293                         }
5294                         set {
5295                                 li = value;
5296                         }
5297                 }
5298
5299                 #endregion
5300
5301                 protected override void DoEmit (EmitContext ec)
5302                 {
5303                         if (IsGeneral)
5304                                 ec.BeginCatchBlock (ec.BuiltinTypes.Object);
5305                         else
5306                                 ec.BeginCatchBlock (CatchType);
5307
5308                         if (li != null) {
5309                                 li.CreateBuilder (ec);
5310
5311                                 //
5312                                 // Special case hoisted catch variable, we have to use a temporary variable
5313                                 // to pass via anonymous storey initialization with the value still on top
5314                                 // of the stack
5315                                 //
5316                                 if (li.HoistedVariant != null) {
5317                                         LocalTemporary lt = new LocalTemporary (li.Type);
5318                                         lt.Store (ec);
5319
5320                                         // switch to assigning from the temporary variable and not from top of the stack
5321                                         assign.UpdateSource (lt);
5322                                 }
5323                         } else {
5324                                 ec.Emit (OpCodes.Pop);
5325                         }
5326
5327                         Block.Emit (ec);
5328                 }
5329
5330                 public override bool Resolve (BlockContext ec)
5331                 {
5332                         using (ec.With (ResolveContext.Options.CatchScope, true)) {
5333                                 if (type_expr != null) {
5334                                         type = type_expr.ResolveAsType (ec);
5335                                         if (type == null)
5336                                                 return false;
5337
5338                                         if (type.BuiltinType != BuiltinTypeSpec.Type.Exception && !TypeSpec.IsBaseClass (type, ec.BuiltinTypes.Exception, false)) {
5339                                                 ec.Report.Error (155, loc, "The type caught or thrown must be derived from System.Exception");
5340                                         } else if (li != null) {
5341                                                 li.Type = type;
5342                                                 li.PrepareForFlowAnalysis (ec);
5343
5344                                                 // source variable is at the top of the stack
5345                                                 Expression source = new EmptyExpression (li.Type);
5346                                                 if (li.Type.IsGenericParameter)
5347                                                         source = new UnboxCast (source, li.Type);
5348
5349                                                 //
5350                                                 // Uses Location.Null to hide from symbol file
5351                                                 //
5352                                                 assign = new CompilerAssign (new LocalVariableReference (li, Location.Null), source, Location.Null);
5353                                                 Block.AddScopeStatement (new StatementExpression (assign, Location.Null));
5354                                         }
5355                                 }
5356
5357                                 return Block.Resolve (ec);
5358                         }
5359                 }
5360
5361                 protected override void CloneTo (CloneContext clonectx, Statement t)
5362                 {
5363                         Catch target = (Catch) t;
5364
5365                         if (type_expr != null)
5366                                 target.type_expr = (FullNamedExpression) type_expr.Clone (clonectx);
5367
5368                         target.block = clonectx.LookupBlock (block);
5369                 }
5370         }
5371
5372         public class TryFinally : TryFinallyBlock
5373         {
5374                 Block fini;
5375
5376                 public TryFinally (Statement stmt, Block fini, Location loc)
5377                          : base (stmt, loc)
5378                 {
5379                         this.fini = fini;
5380                 }
5381
5382                 public Block Finallyblock {
5383                         get {
5384                                 return fini;
5385                         }
5386                 }
5387
5388                 public override bool Resolve (BlockContext ec)
5389                 {
5390                         bool ok = true;
5391
5392                         ec.StartFlowBranching (this);
5393
5394                         if (!stmt.Resolve (ec))
5395                                 ok = false;
5396
5397                         if (ok)
5398                                 ec.CurrentBranching.CreateSibling (fini, FlowBranching.SiblingType.Finally);
5399
5400                         using (ec.With (ResolveContext.Options.FinallyScope, true)) {
5401                                 if (!fini.Resolve (ec))
5402                                         ok = false;
5403                         }
5404
5405                         ec.EndFlowBranching ();
5406
5407                         ok &= base.Resolve (ec);
5408
5409                         return ok;
5410                 }
5411
5412                 protected override void EmitTryBody (EmitContext ec)
5413                 {
5414                         stmt.Emit (ec);
5415                 }
5416
5417                 public override void EmitFinallyBody (EmitContext ec)
5418                 {
5419                         fini.Emit (ec);
5420                 }
5421
5422                 protected override void CloneTo (CloneContext clonectx, Statement t)
5423                 {
5424                         TryFinally target = (TryFinally) t;
5425
5426                         target.stmt = (Statement) stmt.Clone (clonectx);
5427                         if (fini != null)
5428                                 target.fini = clonectx.LookupBlock (fini);
5429                 }
5430                 
5431                 public override object Accept (StructuralVisitor visitor)
5432                 {
5433                         return visitor.Visit (this);
5434                 }
5435         }
5436
5437         public class TryCatch : ExceptionStatement
5438         {
5439                 public Block Block;
5440                 List<Catch> clauses;
5441                 readonly bool inside_try_finally;
5442
5443                 public TryCatch (Block block, List<Catch> catch_clauses, Location l, bool inside_try_finally)
5444                         : base (l)
5445                 {
5446                         this.Block = block;
5447                         this.clauses = catch_clauses;
5448                         this.inside_try_finally = inside_try_finally;
5449                 }
5450
5451                 public List<Catch> Clauses {
5452                         get {
5453                                 return clauses;
5454                         }
5455                 }
5456
5457                 public bool IsTryCatchFinally {
5458                         get {
5459                                 return inside_try_finally;
5460                         }
5461                 }
5462
5463                 public override bool Resolve (BlockContext ec)
5464                 {
5465                         bool ok = true;
5466
5467                         ec.StartFlowBranching (this);
5468
5469                         if (!Block.Resolve (ec))
5470                                 ok = false;
5471
5472                         for (int i = 0; i < clauses.Count; ++i) {
5473                                 var c = clauses[i];
5474                                 ec.CurrentBranching.CreateSibling (c.Block, FlowBranching.SiblingType.Catch);
5475
5476                                 if (!c.Resolve (ec)) {
5477                                         ok = false;
5478                                         continue;
5479                                 }
5480
5481                                 TypeSpec resolved_type = c.CatchType;
5482                                 for (int ii = 0; ii < clauses.Count; ++ii) {
5483                                         if (ii == i)
5484                                                 continue;
5485
5486                                         if (clauses[ii].IsGeneral) {
5487                                                 if (resolved_type.BuiltinType != BuiltinTypeSpec.Type.Exception)
5488                                                         continue;
5489
5490                                                 if (!ec.Module.DeclaringAssembly.WrapNonExceptionThrows)
5491                                                         continue;
5492
5493                                                 if (!ec.Module.PredefinedAttributes.RuntimeCompatibility.IsDefined)
5494                                                         continue;
5495
5496                                                 ec.Report.Warning (1058, 1, c.loc,
5497                                                         "A previous catch clause already catches all exceptions. All non-exceptions thrown will be wrapped in a `System.Runtime.CompilerServices.RuntimeWrappedException'");
5498
5499                                                 continue;
5500                                         }
5501
5502                                         if (ii >= i)
5503                                                 continue;
5504
5505                                         var ct = clauses[ii].CatchType;
5506                                         if (ct == null)
5507                                                 continue;
5508
5509                                         if (resolved_type == ct || TypeSpec.IsBaseClass (resolved_type, ct, true)) {
5510                                                 ec.Report.Error (160, c.loc,
5511                                                         "A previous catch clause already catches all exceptions of this or a super type `{0}'",
5512                                                         ct.GetSignatureForError ());
5513                                                 ok = false;
5514                                         }
5515                                 }
5516                         }
5517
5518                         ec.EndFlowBranching ();
5519
5520                         return base.Resolve (ec) && ok;
5521                 }
5522
5523                 protected sealed override void DoEmit (EmitContext ec)
5524                 {
5525                         if (!inside_try_finally)
5526                                 EmitTryBodyPrepare (ec);
5527
5528                         Block.Emit (ec);
5529
5530                         foreach (Catch c in clauses)
5531                                 c.Emit (ec);
5532
5533                         if (!inside_try_finally)
5534                                 ec.EndExceptionBlock ();
5535                 }
5536
5537                 protected override void CloneTo (CloneContext clonectx, Statement t)
5538                 {
5539                         TryCatch target = (TryCatch) t;
5540
5541                         target.Block = clonectx.LookupBlock (Block);
5542                         if (clauses != null){
5543                                 target.clauses = new List<Catch> ();
5544                                 foreach (Catch c in clauses)
5545                                         target.clauses.Add ((Catch) c.Clone (clonectx));
5546                         }
5547                 }
5548
5549                 public override object Accept (StructuralVisitor visitor)
5550                 {
5551                         return visitor.Visit (this);
5552                 }
5553         }
5554
5555         public class Using : TryFinallyBlock
5556         {
5557                 public class VariableDeclaration : BlockVariableDeclaration
5558                 {
5559                         Statement dispose_call;
5560
5561                         public VariableDeclaration (FullNamedExpression type, LocalVariable li)
5562                                 : base (type, li)
5563                         {
5564                         }
5565
5566                         public VariableDeclaration (LocalVariable li, Location loc)
5567                                 : base (li)
5568                         {
5569                                 this.loc = loc;
5570                         }
5571
5572                         public VariableDeclaration (Expression expr)
5573                                 : base (null)
5574                         {
5575                                 loc = expr.Location;
5576                                 Initializer = expr;
5577                         }
5578
5579                         #region Properties
5580
5581                         public bool IsNested { get; private set; }
5582
5583                         #endregion
5584
5585                         public void EmitDispose (EmitContext ec)
5586                         {
5587                                 dispose_call.Emit (ec);
5588                         }
5589
5590                         public override bool Resolve (BlockContext bc)
5591                         {
5592                                 if (IsNested)
5593                                         return true;
5594
5595                                 return base.Resolve (bc, false);
5596                         }
5597
5598                         public Expression ResolveExpression (BlockContext bc)
5599                         {
5600                                 var e = Initializer.Resolve (bc);
5601                                 if (e == null)
5602                                         return null;
5603
5604                                 li = LocalVariable.CreateCompilerGenerated (e.Type, bc.CurrentBlock, loc);
5605                                 Initializer = ResolveInitializer (bc, Variable, e);
5606                                 return e;
5607                         }
5608
5609                         protected override Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
5610                         {
5611                                 if (li.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
5612                                         initializer = initializer.Resolve (bc);
5613                                         if (initializer == null)
5614                                                 return null;
5615
5616                                         // Once there is dynamic used defer conversion to runtime even if we know it will never succeed
5617                                         Arguments args = new Arguments (1);
5618                                         args.Add (new Argument (initializer));
5619                                         initializer = new DynamicConversion (bc.BuiltinTypes.IDisposable, 0, args, initializer.Location).Resolve (bc);
5620                                         if (initializer == null)
5621                                                 return null;
5622
5623                                         var var = LocalVariable.CreateCompilerGenerated (initializer.Type, bc.CurrentBlock, loc);
5624                                         dispose_call = CreateDisposeCall (bc, var);
5625                                         dispose_call.Resolve (bc);
5626
5627                                         return base.ResolveInitializer (bc, li, new SimpleAssign (var.CreateReferenceExpression (bc, loc), initializer, loc));
5628                                 }
5629
5630                                 if (li == Variable) {
5631                                         CheckIDiposableConversion (bc, li, initializer);
5632                                         dispose_call = CreateDisposeCall (bc, li);
5633                                         dispose_call.Resolve (bc);
5634                                 }
5635
5636                                 return base.ResolveInitializer (bc, li, initializer);
5637                         }
5638
5639                         protected virtual void CheckIDiposableConversion (BlockContext bc, LocalVariable li, Expression initializer)
5640                         {
5641                                 var type = li.Type;
5642
5643                                 if (type.BuiltinType != BuiltinTypeSpec.Type.IDisposable && !type.ImplementsInterface (bc.BuiltinTypes.IDisposable, false)) {
5644                                         if (type.IsNullableType) {
5645                                                 // it's handled in CreateDisposeCall
5646                                                 return;
5647                                         }
5648
5649                                         bc.Report.SymbolRelatedToPreviousError (type);
5650                                         var loc = type_expr == null ? initializer.Location : type_expr.Location;
5651                                         bc.Report.Error (1674, loc, "`{0}': type used in a using statement must be implicitly convertible to `System.IDisposable'",
5652                                                 type.GetSignatureForError ());
5653
5654                                         return;
5655                                 }
5656                         }
5657
5658                         protected virtual Statement CreateDisposeCall (BlockContext bc, LocalVariable lv)
5659                         {
5660                                 var lvr = lv.CreateReferenceExpression (bc, lv.Location);
5661                                 var type = lv.Type;
5662                                 var loc = lv.Location;
5663
5664                                 var idt = bc.BuiltinTypes.IDisposable;
5665                                 var m = bc.Module.PredefinedMembers.IDisposableDispose.Resolve (loc);
5666
5667                                 var dispose_mg = MethodGroupExpr.CreatePredefined (m, idt, loc);
5668                                 dispose_mg.InstanceExpression = type.IsNullableType ?
5669                                         new Cast (new TypeExpression (idt, loc), lvr, loc).Resolve (bc) :
5670                                         lvr;
5671
5672                                 //
5673                                 // Hide it from symbol file via null location
5674                                 //
5675                                 Statement dispose = new StatementExpression (new Invocation (dispose_mg, null), Location.Null);
5676
5677                                 // Add conditional call when disposing possible null variable
5678                                 if (!type.IsStruct || type.IsNullableType)
5679                                         dispose = new If (new Binary (Binary.Operator.Inequality, lvr, new NullLiteral (loc)), dispose, dispose.loc);
5680
5681                                 return dispose;
5682                         }
5683
5684                         public void ResolveDeclaratorInitializer (BlockContext bc)
5685                         {
5686                                 Initializer = base.ResolveInitializer (bc, Variable, Initializer);
5687                         }
5688
5689                         public Statement RewriteUsingDeclarators (BlockContext bc, Statement stmt)
5690                         {
5691                                 for (int i = declarators.Count - 1; i >= 0; --i) {
5692                                         var d = declarators [i];
5693                                         var vd = new VariableDeclaration (d.Variable, d.Variable.Location);
5694                                         vd.Initializer = d.Initializer;
5695                                         vd.IsNested = true;
5696                                         vd.dispose_call = CreateDisposeCall (bc, d.Variable);
5697                                         vd.dispose_call.Resolve (bc);
5698
5699                                         stmt = new Using (vd, stmt, d.Variable.Location);
5700                                 }
5701
5702                                 declarators = null;
5703                                 return stmt;
5704                         }       
5705
5706                         public override object Accept (StructuralVisitor visitor)
5707                         {
5708                                 return visitor.Visit (this);
5709                         }       
5710                 }
5711
5712                 VariableDeclaration decl;
5713
5714                 public Using (VariableDeclaration decl, Statement stmt, Location loc)
5715                         : base (stmt, loc)
5716                 {
5717                         this.decl = decl;
5718                 }
5719
5720                 public Using (Expression expr, Statement stmt, Location loc)
5721                         : base (stmt, loc)
5722                 {
5723                         this.decl = new VariableDeclaration (expr);
5724                 }
5725
5726                 #region Properties
5727
5728                 public Expression Expr {
5729                         get {
5730                                 return decl.Variable == null ? decl.Initializer : null;
5731                         }
5732                 }
5733
5734                 public BlockVariableDeclaration Variables {
5735                         get {
5736                                 return decl;
5737                         }
5738                 }
5739
5740                 #endregion
5741
5742                 public override void Emit (EmitContext ec)
5743                 {
5744                         //
5745                         // Don't emit sequence point it will be set on variable declaration
5746                         //
5747                         DoEmit (ec);
5748                 }
5749
5750                 protected override void EmitTryBodyPrepare (EmitContext ec)
5751                 {
5752                         decl.Emit (ec);
5753                         base.EmitTryBodyPrepare (ec);
5754                 }
5755
5756                 protected override void EmitTryBody (EmitContext ec)
5757                 {
5758                         stmt.Emit (ec);
5759                 }
5760
5761                 public override void EmitFinallyBody (EmitContext ec)
5762                 {
5763                         decl.EmitDispose (ec);
5764                 }
5765
5766                 public override bool Resolve (BlockContext ec)
5767                 {
5768                         VariableReference vr;
5769                         bool vr_locked = false;
5770
5771                         using (ec.Set (ResolveContext.Options.UsingInitializerScope)) {
5772                                 if (decl.Variable == null) {
5773                                         vr = decl.ResolveExpression (ec) as VariableReference;
5774                                         if (vr != null) {
5775                                                 vr_locked = vr.IsLockedByStatement;
5776                                                 vr.IsLockedByStatement = true;
5777                                         }
5778                                 } else {
5779                                         if (decl.IsNested) {
5780                                                 decl.ResolveDeclaratorInitializer (ec);
5781                                         } else {
5782                                                 if (!decl.Resolve (ec))
5783                                                         return false;
5784
5785                                                 if (decl.Declarators != null) {
5786                                                         stmt = decl.RewriteUsingDeclarators (ec, stmt);
5787                                                 }
5788                                         }
5789
5790                                         vr = null;
5791                                 }
5792                         }
5793
5794                         ec.StartFlowBranching (this);
5795
5796                         stmt.Resolve (ec);
5797
5798                         ec.EndFlowBranching ();
5799
5800                         if (vr != null)
5801                                 vr.IsLockedByStatement = vr_locked;
5802
5803                         base.Resolve (ec);
5804
5805                         return true;
5806                 }
5807
5808                 protected override void CloneTo (CloneContext clonectx, Statement t)
5809                 {
5810                         Using target = (Using) t;
5811
5812                         target.decl = (VariableDeclaration) decl.Clone (clonectx);
5813                         target.stmt = stmt.Clone (clonectx);
5814                 }
5815
5816                 public override object Accept (StructuralVisitor visitor)
5817                 {
5818                         return visitor.Visit (this);
5819                 }
5820         }
5821
5822         /// <summary>
5823         ///   Implementation of the foreach C# statement
5824         /// </summary>
5825         public class Foreach : Statement
5826         {
5827                 abstract class IteratorStatement : Statement
5828                 {
5829                         protected readonly Foreach for_each;
5830
5831                         protected IteratorStatement (Foreach @foreach)
5832                         {
5833                                 this.for_each = @foreach;
5834                                 this.loc = @foreach.expr.Location;
5835                         }
5836
5837                         protected override void CloneTo (CloneContext clonectx, Statement target)
5838                         {
5839                                 throw new NotImplementedException ();
5840                         }
5841
5842                         public override void Emit (EmitContext ec)
5843                         {
5844                                 if (ec.EmitAccurateDebugInfo) {
5845                                         ec.Emit (OpCodes.Nop);
5846                                 }
5847
5848                                 base.Emit (ec);
5849                         }
5850                 }
5851
5852                 sealed class ArrayForeach : IteratorStatement
5853                 {
5854                         TemporaryVariableReference[] lengths;
5855                         Expression [] length_exprs;
5856                         StatementExpression[] counter;
5857                         TemporaryVariableReference[] variables;
5858
5859                         TemporaryVariableReference copy;
5860
5861                         public ArrayForeach (Foreach @foreach, int rank)
5862                                 : base (@foreach)
5863                         {
5864                                 counter = new StatementExpression[rank];
5865                                 variables = new TemporaryVariableReference[rank];
5866                                 length_exprs = new Expression [rank];
5867
5868                                 //
5869                                 // Only use temporary length variables when dealing with
5870                                 // multi-dimensional arrays
5871                                 //
5872                                 if (rank > 1)
5873                                         lengths = new TemporaryVariableReference [rank];
5874                         }
5875
5876                         public override bool Resolve (BlockContext ec)
5877                         {
5878                                 Block variables_block = for_each.variable.Block;
5879                                 copy = TemporaryVariableReference.Create (for_each.expr.Type, variables_block, loc);
5880                                 copy.Resolve (ec);
5881
5882                                 int rank = length_exprs.Length;
5883                                 Arguments list = new Arguments (rank);
5884                                 for (int i = 0; i < rank; i++) {
5885                                         var v = TemporaryVariableReference.Create (ec.BuiltinTypes.Int, variables_block, loc);
5886                                         variables[i] = v;
5887                                         counter[i] = new StatementExpression (new UnaryMutator (UnaryMutator.Mode.PostIncrement, v, Location.Null));
5888                                         counter[i].Resolve (ec);
5889
5890                                         if (rank == 1) {
5891                                                 length_exprs [i] = new MemberAccess (copy, "Length").Resolve (ec);
5892                                         } else {
5893                                                 lengths[i] = TemporaryVariableReference.Create (ec.BuiltinTypes.Int, variables_block, loc);
5894                                                 lengths[i].Resolve (ec);
5895
5896                                                 Arguments args = new Arguments (1);
5897                                                 args.Add (new Argument (new IntConstant (ec.BuiltinTypes, i, loc)));
5898                                                 length_exprs [i] = new Invocation (new MemberAccess (copy, "GetLength"), args).Resolve (ec);
5899                                         }
5900
5901                                         list.Add (new Argument (v));
5902                                 }
5903
5904                                 var access = new ElementAccess (copy, list, loc).Resolve (ec);
5905                                 if (access == null)
5906                                         return false;
5907
5908                                 TypeSpec var_type;
5909                                 if (for_each.type is VarExpr) {
5910                                         // Infer implicitly typed local variable from foreach array type
5911                                         var_type = access.Type;
5912                                 } else {
5913                                         var_type = for_each.type.ResolveAsType (ec);
5914
5915                                         if (var_type == null)
5916                                                 return false;
5917
5918                                         access = Convert.ExplicitConversion (ec, access, var_type, loc);
5919                                         if (access == null)
5920                                                 return false;
5921                                 }
5922
5923                                 for_each.variable.Type = var_type;
5924
5925                                 var variable_ref = new LocalVariableReference (for_each.variable, loc).Resolve (ec);
5926                                 if (variable_ref == null)
5927                                         return false;
5928
5929                                 for_each.body.AddScopeStatement (new StatementExpression (new CompilerAssign (variable_ref, access, Location.Null), for_each.type.Location));
5930
5931                                 bool ok = true;
5932
5933                                 ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
5934                                 ec.CurrentBranching.CreateSibling ();
5935
5936                                 ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc);
5937                                 if (!for_each.body.Resolve (ec))
5938                                         ok = false;
5939                                 ec.EndFlowBranching ();
5940
5941                                 // There's no direct control flow from the end of the embedded statement to the end of the loop
5942                                 ec.CurrentBranching.CurrentUsageVector.Goto ();
5943
5944                                 ec.EndFlowBranching ();
5945
5946                                 return ok;
5947                         }
5948
5949                         protected override void DoEmit (EmitContext ec)
5950                         {
5951                                 copy.EmitAssign (ec, for_each.expr);
5952
5953                                 int rank = length_exprs.Length;
5954                                 Label[] test = new Label [rank];
5955                                 Label[] loop = new Label [rank];
5956
5957                                 for (int i = 0; i < rank; i++) {
5958                                         test [i] = ec.DefineLabel ();
5959                                         loop [i] = ec.DefineLabel ();
5960
5961                                         if (lengths != null)
5962                                                 lengths [i].EmitAssign (ec, length_exprs [i]);
5963                                 }
5964
5965                                 IntConstant zero = new IntConstant (ec.BuiltinTypes, 0, loc);
5966                                 for (int i = 0; i < rank; i++) {
5967                                         variables [i].EmitAssign (ec, zero);
5968
5969                                         ec.Emit (OpCodes.Br, test [i]);
5970                                         ec.MarkLabel (loop [i]);
5971                                 }
5972
5973                                 for_each.body.Emit (ec);
5974
5975                                 ec.MarkLabel (ec.LoopBegin);
5976                                 ec.Mark (for_each.expr.Location);
5977
5978                                 for (int i = rank - 1; i >= 0; i--){
5979                                         counter [i].Emit (ec);
5980
5981                                         ec.MarkLabel (test [i]);
5982                                         variables [i].Emit (ec);
5983
5984                                         if (lengths != null)
5985                                                 lengths [i].Emit (ec);
5986                                         else
5987                                                 length_exprs [i].Emit (ec);
5988
5989                                         ec.Emit (OpCodes.Blt, loop [i]);
5990                                 }
5991
5992                                 ec.MarkLabel (ec.LoopEnd);
5993                         }
5994                 }
5995
5996                 sealed class CollectionForeach : IteratorStatement, OverloadResolver.IErrorHandler
5997                 {
5998                         class RuntimeDispose : Using.VariableDeclaration
5999                         {
6000                                 public RuntimeDispose (LocalVariable lv, Location loc)
6001                                         : base (lv, loc)
6002                                 {
6003                                 }
6004
6005                                 protected override void CheckIDiposableConversion (BlockContext bc, LocalVariable li, Expression initializer)
6006                                 {
6007                                         // Defered to runtime check
6008                                 }
6009
6010                                 protected override Statement CreateDisposeCall (BlockContext bc, LocalVariable lv)
6011                                 {
6012                                         var idt = bc.BuiltinTypes.IDisposable;
6013
6014                                         //
6015                                         // Fabricates code like
6016                                         //
6017                                         // if ((temp = vr as IDisposable) != null) temp.Dispose ();
6018                                         //
6019
6020                                         var dispose_variable = LocalVariable.CreateCompilerGenerated (idt, bc.CurrentBlock, loc);
6021
6022                                         var idisaposable_test = new Binary (Binary.Operator.Inequality, new CompilerAssign (
6023                                                 dispose_variable.CreateReferenceExpression (bc, loc),
6024                                                 new As (lv.CreateReferenceExpression (bc, loc), new TypeExpression (dispose_variable.Type, loc), loc),
6025                                                 loc), new NullLiteral (loc));
6026
6027                                         var m = bc.Module.PredefinedMembers.IDisposableDispose.Resolve (loc);
6028
6029                                         var dispose_mg = MethodGroupExpr.CreatePredefined (m, idt, loc);
6030                                         dispose_mg.InstanceExpression = dispose_variable.CreateReferenceExpression (bc, loc);
6031
6032                                         Statement dispose = new StatementExpression (new Invocation (dispose_mg, null));
6033                                         return new If (idisaposable_test, dispose, loc);
6034                                 }
6035                         }
6036
6037                         LocalVariable variable;
6038                         Expression expr;
6039                         Statement statement;
6040                         ExpressionStatement init;
6041                         TemporaryVariableReference enumerator_variable;
6042                         bool ambiguous_getenumerator_name;
6043
6044                         public CollectionForeach (Foreach @foreach, LocalVariable var, Expression expr)
6045                                 : base (@foreach)
6046                         {
6047                                 this.variable = var;
6048                                 this.expr = expr;
6049                         }
6050
6051                         void Error_WrongEnumerator (ResolveContext rc, MethodSpec enumerator)
6052                         {
6053                                 rc.Report.SymbolRelatedToPreviousError (enumerator);
6054                                 rc.Report.Error (202, loc,
6055                                         "foreach statement requires that the return type `{0}' of `{1}' must have a suitable public MoveNext method and public Current property",
6056                                                 enumerator.ReturnType.GetSignatureForError (), enumerator.GetSignatureForError ());
6057                         }
6058
6059                         MethodGroupExpr ResolveGetEnumerator (ResolveContext rc)
6060                         {
6061                                 //
6062                                 // Option 1: Try to match by name GetEnumerator first
6063                                 //
6064                                 var mexpr = Expression.MemberLookup (rc, false, expr.Type,
6065                                         "GetEnumerator", 0, Expression.MemberLookupRestrictions.ExactArity, loc);               // TODO: What if CS0229 ?
6066
6067                                 var mg = mexpr as MethodGroupExpr;
6068                                 if (mg != null) {
6069                                         mg.InstanceExpression = expr;
6070                                         Arguments args = new Arguments (0);
6071                                         mg = mg.OverloadResolve (rc, ref args, this, OverloadResolver.Restrictions.ProbingOnly);
6072
6073                                         // For ambiguous GetEnumerator name warning CS0278 was reported, but Option 2 could still apply
6074                                         if (ambiguous_getenumerator_name)
6075                                                 mg = null;
6076
6077                                         if (mg != null && args.Count == 0 && !mg.BestCandidate.IsStatic && mg.BestCandidate.IsPublic) {
6078                                                 return mg;
6079                                         }
6080                                 }
6081
6082                                 //
6083                                 // Option 2: Try to match using IEnumerable interfaces with preference of generic version
6084                                 //
6085                                 var t = expr.Type;
6086                                 PredefinedMember<MethodSpec> iface_candidate = null;
6087                                 var ptypes = rc.Module.PredefinedTypes;
6088                                 var gen_ienumerable = ptypes.IEnumerableGeneric;
6089                                 if (!gen_ienumerable.Define ())
6090                                         gen_ienumerable = null;
6091
6092                                 var ifaces = t.Interfaces;
6093                                 if (ifaces != null) {
6094                                         foreach (var iface in ifaces) {
6095                                                 if (gen_ienumerable != null && iface.MemberDefinition == gen_ienumerable.TypeSpec.MemberDefinition) {
6096                                                         if (iface_candidate != null && iface_candidate != rc.Module.PredefinedMembers.IEnumerableGetEnumerator) {
6097                                                                 rc.Report.SymbolRelatedToPreviousError (expr.Type);
6098                                                                 rc.Report.Error (1640, loc,
6099                                                                         "foreach statement cannot operate on variables of type `{0}' because it contains multiple implementation of `{1}'. Try casting to a specific implementation",
6100                                                                         expr.Type.GetSignatureForError (), gen_ienumerable.TypeSpec.GetSignatureForError ());
6101
6102                                                                 return null;
6103                                                         }
6104
6105                                                         // TODO: Cache this somehow
6106                                                         iface_candidate = new PredefinedMember<MethodSpec> (rc.Module, iface,
6107                                                                 MemberFilter.Method ("GetEnumerator", 0, ParametersCompiled.EmptyReadOnlyParameters, null));
6108
6109                                                         continue;
6110                                                 }
6111
6112                                                 if (iface.BuiltinType == BuiltinTypeSpec.Type.IEnumerable && iface_candidate == null) {
6113                                                         iface_candidate = rc.Module.PredefinedMembers.IEnumerableGetEnumerator;
6114                                                 }
6115                                         }
6116                                 }
6117
6118                                 if (iface_candidate == null) {
6119                                         if (expr.Type != InternalType.ErrorType) {
6120                                                 rc.Report.Error (1579, loc,
6121                                                         "foreach statement cannot operate on variables of type `{0}' because it does not contain a definition for `{1}' or is inaccessible",
6122                                                         expr.Type.GetSignatureForError (), "GetEnumerator");
6123                                         }
6124
6125                                         return null;
6126                                 }
6127
6128                                 var method = iface_candidate.Resolve (loc);
6129                                 if (method == null)
6130                                         return null;
6131
6132                                 mg = MethodGroupExpr.CreatePredefined (method, expr.Type, loc);
6133                                 mg.InstanceExpression = expr;
6134                                 return mg;
6135                         }
6136
6137                         MethodGroupExpr ResolveMoveNext (ResolveContext rc, MethodSpec enumerator)
6138                         {
6139                                 var ms = MemberCache.FindMember (enumerator.ReturnType,
6140                                         MemberFilter.Method ("MoveNext", 0, ParametersCompiled.EmptyReadOnlyParameters, rc.BuiltinTypes.Bool),
6141                                         BindingRestriction.InstanceOnly) as MethodSpec;
6142
6143                                 if (ms == null || !ms.IsPublic) {
6144                                         Error_WrongEnumerator (rc, enumerator);
6145                                         return null;
6146                                 }
6147
6148                                 return MethodGroupExpr.CreatePredefined (ms, enumerator.ReturnType, expr.Location);
6149                         }
6150
6151                         PropertySpec ResolveCurrent (ResolveContext rc, MethodSpec enumerator)
6152                         {
6153                                 var ps = MemberCache.FindMember (enumerator.ReturnType,
6154                                         MemberFilter.Property ("Current", null),
6155                                         BindingRestriction.InstanceOnly) as PropertySpec;
6156
6157                                 if (ps == null || !ps.IsPublic) {
6158                                         Error_WrongEnumerator (rc, enumerator);
6159                                         return null;
6160                                 }
6161
6162                                 return ps;
6163                         }
6164
6165                         public override bool Resolve (BlockContext ec)
6166                         {
6167                                 bool is_dynamic = expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
6168
6169                                 if (is_dynamic) {
6170                                         expr = Convert.ImplicitConversionRequired (ec, expr, ec.BuiltinTypes.IEnumerable, loc);
6171                                 } else if (expr.Type.IsNullableType) {
6172                                         expr = new Nullable.UnwrapCall (expr).Resolve (ec);
6173                                 }
6174
6175                                 var get_enumerator_mg = ResolveGetEnumerator (ec);
6176                                 if (get_enumerator_mg == null) {
6177                                         return false;
6178                                 }
6179
6180                                 var get_enumerator = get_enumerator_mg.BestCandidate;
6181                                 enumerator_variable = TemporaryVariableReference.Create (get_enumerator.ReturnType, variable.Block, loc);
6182                                 enumerator_variable.Resolve (ec);
6183
6184                                 // Prepare bool MoveNext ()
6185                                 var move_next_mg = ResolveMoveNext (ec, get_enumerator);
6186                                 if (move_next_mg == null) {
6187                                         return false;
6188                                 }
6189
6190                                 move_next_mg.InstanceExpression = enumerator_variable;
6191
6192                                 // Prepare ~T~ Current { get; }
6193                                 var current_prop = ResolveCurrent (ec, get_enumerator);
6194                                 if (current_prop == null) {
6195                                         return false;
6196                                 }
6197
6198                                 var current_pe = new PropertyExpr (current_prop, loc) { InstanceExpression = enumerator_variable }.Resolve (ec);
6199                                 if (current_pe == null)
6200                                         return false;
6201
6202                                 VarExpr ve = for_each.type as VarExpr;
6203
6204                                 if (ve != null) {
6205                                         if (is_dynamic) {
6206                                                 // Source type is dynamic, set element type to dynamic too
6207                                                 variable.Type = ec.BuiltinTypes.Dynamic;
6208                                         } else {
6209                                                 // Infer implicitly typed local variable from foreach enumerable type
6210                                                 variable.Type = current_pe.Type;
6211                                         }
6212                                 } else {
6213                                         if (is_dynamic) {
6214                                                 // Explicit cast of dynamic collection elements has to be done at runtime
6215                                                 current_pe = EmptyCast.Create (current_pe, ec.BuiltinTypes.Dynamic);
6216                                         }
6217
6218                                         variable.Type = for_each.type.ResolveAsType (ec);
6219
6220                                         if (variable.Type == null)
6221                                                 return false;
6222
6223                                         current_pe = Convert.ExplicitConversion (ec, current_pe, variable.Type, loc);
6224                                         if (current_pe == null)
6225                                                 return false;
6226                                 }
6227
6228                                 var variable_ref = new LocalVariableReference (variable, loc).Resolve (ec);
6229                                 if (variable_ref == null)
6230                                         return false;
6231
6232                                 for_each.body.AddScopeStatement (new StatementExpression (new CompilerAssign (variable_ref, current_pe, Location.Null), for_each.type.Location));
6233
6234                                 var init = new Invocation (get_enumerator_mg, null);
6235
6236                                 statement = new While (new BooleanExpression (new Invocation (move_next_mg, null)),
6237                                          for_each.body, Location.Null);
6238
6239                                 var enum_type = enumerator_variable.Type;
6240
6241                                 //
6242                                 // Add Dispose method call when enumerator can be IDisposable
6243                                 //
6244                                 if (!enum_type.ImplementsInterface (ec.BuiltinTypes.IDisposable, false)) {
6245                                         if (!enum_type.IsSealed && !TypeSpec.IsValueType (enum_type)) {
6246                                                 //
6247                                                 // Runtime Dispose check
6248                                                 //
6249                                                 var vd = new RuntimeDispose (enumerator_variable.LocalInfo, Location.Null);
6250                                                 vd.Initializer = init;
6251                                                 statement = new Using (vd, statement, Location.Null);
6252                                         } else {
6253                                                 //
6254                                                 // No Dispose call needed
6255                                                 //
6256                                                 this.init = new SimpleAssign (enumerator_variable, init, Location.Null);
6257                                                 this.init.Resolve (ec);
6258                                         }
6259                                 } else {
6260                                         //
6261                                         // Static Dispose check
6262                                         //
6263                                         var vd = new Using.VariableDeclaration (enumerator_variable.LocalInfo, Location.Null);
6264                                         vd.Initializer = init;
6265                                         statement = new Using (vd, statement, Location.Null);
6266                                 }
6267
6268                                 return statement.Resolve (ec);
6269                         }
6270
6271                         protected override void DoEmit (EmitContext ec)
6272                         {
6273                                 enumerator_variable.LocalInfo.CreateBuilder (ec);
6274
6275                                 if (init != null)
6276                                         init.EmitStatement (ec);
6277
6278                                 statement.Emit (ec);
6279                         }
6280
6281                         #region IErrorHandler Members
6282
6283                         bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext ec, MemberSpec best, MemberSpec ambiguous)
6284                         {
6285                                 ec.Report.SymbolRelatedToPreviousError (best);
6286                                 ec.Report.Warning (278, 2, expr.Location,
6287                                         "`{0}' contains ambiguous implementation of `{1}' pattern. Method `{2}' is ambiguous with method `{3}'",
6288                                         expr.Type.GetSignatureForError (), "enumerable",
6289                                         best.GetSignatureForError (), ambiguous.GetSignatureForError ());
6290
6291                                 ambiguous_getenumerator_name = true;
6292                                 return true;
6293                         }
6294
6295                         bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
6296                         {
6297                                 return false;
6298                         }
6299
6300                         bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
6301                         {
6302                                 return false;
6303                         }
6304
6305                         bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
6306                         {
6307                                 return false;
6308                         }
6309
6310                         #endregion
6311                 }
6312
6313                 Expression type;
6314                 LocalVariable variable;
6315                 Expression expr;
6316                 Statement statement;
6317                 Block body;
6318
6319                 public Foreach (Expression type, LocalVariable var, Expression expr, Statement stmt, Block body, Location l)
6320                 {
6321                         this.type = type;
6322                         this.variable = var;
6323                         this.expr = expr;
6324                         this.statement = stmt;
6325                         this.body = body;
6326                         loc = l;
6327                 }
6328
6329                 public Expression Expr {
6330                         get { return expr; }
6331                 }
6332
6333                 public Statement Statement {
6334                         get { return statement; }
6335                 }
6336
6337                 public Expression TypeExpression {
6338                         get { return type; }
6339                 }
6340
6341                 public LocalVariable Variable {
6342                         get { return variable; }
6343                 }
6344
6345                 public override bool Resolve (BlockContext ec)
6346                 {
6347                         expr = expr.Resolve (ec);
6348                         if (expr == null)
6349                                 return false;
6350
6351                         if (expr.IsNull) {
6352                                 ec.Report.Error (186, loc, "Use of null is not valid in this context");
6353                                 return false;
6354                         }
6355
6356                         body.AddStatement (statement);
6357
6358                         if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.String) {
6359                                 statement = new ArrayForeach (this, 1);
6360                         } else if (expr.Type is ArrayContainer) {
6361                                 statement = new ArrayForeach (this, ((ArrayContainer) expr.Type).Rank);
6362                         } else {
6363                                 if (expr.eclass == ExprClass.MethodGroup || expr is AnonymousMethodExpression) {
6364                                         ec.Report.Error (446, expr.Location, "Foreach statement cannot operate on a `{0}'",
6365                                                 expr.ExprClassName);
6366                                         return false;
6367                                 }
6368
6369                                 statement = new CollectionForeach (this, variable, expr);
6370                         }
6371
6372                         return statement.Resolve (ec);
6373                 }
6374
6375                 protected override void DoEmit (EmitContext ec)
6376                 {
6377                         variable.CreateBuilder (ec);
6378
6379                         Label old_begin = ec.LoopBegin, old_end = ec.LoopEnd;
6380                         ec.LoopBegin = ec.DefineLabel ();
6381                         ec.LoopEnd = ec.DefineLabel ();
6382
6383                         statement.Emit (ec);
6384
6385                         ec.LoopBegin = old_begin;
6386                         ec.LoopEnd = old_end;
6387                 }
6388
6389                 protected override void CloneTo (CloneContext clonectx, Statement t)
6390                 {
6391                         Foreach target = (Foreach) t;
6392
6393                         target.type = type.Clone (clonectx);
6394                         target.expr = expr.Clone (clonectx);
6395                         target.body = (Block) body.Clone (clonectx);
6396                         target.statement = statement.Clone (clonectx);
6397                 }
6398                 
6399                 public override object Accept (StructuralVisitor visitor)
6400                 {
6401                         return visitor.Visit (this);
6402                 }
6403         }
6404 }