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