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