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