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