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