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