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