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