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