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