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