[Mono.Debugger.Soft] Implement IsGenericType/Method for protocol < 2.12
[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.IsFullyInitialized (ec, 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 void AddLocalName (string name, INamedBlockVariable li)
2103                 {
2104                         ParametersBlock.TopBlock.AddLocalName (name, li, false);
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 void AddLocalName (string name, INamedBlockVariable li, bool ignoreChildrenBlocks)
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                                 if (!ignoreChildrenBlocks) {
3051                                         // Collision with children
3052                                         b = existing.Block;
3053                                         while ((b = b.Parent) != null) {
3054                                                 if (li.Block == b) {
3055                                                         li.Block.Error_AlreadyDeclared (name, li, "child");
3056                                                         i = existing_list.Count;
3057                                                         break;
3058                                                 }
3059                                         }
3060                                 }
3061                         }
3062
3063                         existing_list.Add (li);
3064                 }
3065
3066                 public void AddLabel (string name, LabeledStatement label)
3067                 {
3068                         if (labels == null)
3069                                 labels = new Dictionary<string, object> ();
3070
3071                         object value;
3072                         if (!labels.TryGetValue (name, out value)) {
3073                                 labels.Add (name, label);
3074                                 return;
3075                         }
3076
3077                         LabeledStatement existing = value as LabeledStatement;
3078                         List<LabeledStatement> existing_list;
3079                         if (existing != null) {
3080                                 existing_list = new List<LabeledStatement> ();
3081                                 existing_list.Add (existing);
3082                                 labels[name] = existing_list;
3083                         } else {
3084                                 existing_list = (List<LabeledStatement>) value;
3085                         }
3086
3087                         //
3088                         // A collision checking between labels
3089                         //
3090                         for (int i = 0; i < existing_list.Count; ++i) {
3091                                 existing = existing_list[i];
3092                                 Block b = existing.Block;
3093
3094                                 // Collision at same level
3095                                 if (label.Block == b) {
3096                                         Report.SymbolRelatedToPreviousError (existing.loc, name);
3097                                         Report.Error (140, label.loc, "The label `{0}' is a duplicate", name);
3098                                         break;
3099                                 }
3100
3101                                 // Collision with parent
3102                                 b = label.Block;
3103                                 while ((b = b.Parent) != null) {
3104                                         if (existing.Block == b) {
3105                                                 Report.Error (158, label.loc,
3106                                                         "The label `{0}' shadows another label by the same name in a contained scope", name);
3107                                                 i = existing_list.Count;
3108                                                 break;
3109                                         }
3110                                 }
3111
3112                                 // Collision with with children
3113                                 b = existing.Block;
3114                                 while ((b = b.Parent) != null) {
3115                                         if (label.Block == b) {
3116                                                 Report.Error (158, label.loc,
3117                                                         "The label `{0}' shadows another label by the same name in a contained scope", name);
3118                                                 i = existing_list.Count;
3119                                                 break;
3120                                         }
3121                                 }
3122                         }
3123
3124                         existing_list.Add (label);
3125                 }
3126
3127                 //
3128                 // Creates an arguments set from all parameters, useful for method proxy calls
3129                 //
3130                 public Arguments GetAllParametersArguments ()
3131                 {
3132                         int count = parameters.Count;
3133                         Arguments args = new Arguments (count);
3134                         for (int i = 0; i < count; ++i) {
3135                                 var arg_expr = GetParameterReference (i, parameter_info[i].Location);
3136                                 args.Add (new Argument (arg_expr));
3137                         }
3138
3139                         return args;
3140                 }
3141
3142                 //
3143                 // Lookup inside a block, the returned value can represent 3 states
3144                 //
3145                 // true+variable: A local name was found and it's valid
3146                 // false+variable: A local name was found in a child block only
3147                 // false+null: No local name was found
3148                 //
3149                 public bool GetLocalName (string name, Block block, ref INamedBlockVariable variable)
3150                 {
3151                         if (names == null)
3152                                 return false;
3153
3154                         object value;
3155                         if (!names.TryGetValue (name, out value))
3156                                 return false;
3157
3158                         variable = value as INamedBlockVariable;
3159                         Block b = block;
3160                         if (variable != null) {
3161                                 do {
3162                                         if (variable.Block == b.Original)
3163                                                 return true;
3164
3165                                         b = b.Parent;
3166                                 } while (b != null);
3167
3168                                 b = variable.Block;
3169                                 do {
3170                                         if (block == b)
3171                                                 return false;
3172
3173                                         b = b.Parent;
3174                                 } while (b != null);
3175                         } else {
3176                                 List<INamedBlockVariable> list = (List<INamedBlockVariable>) value;
3177                                 for (int i = 0; i < list.Count; ++i) {
3178                                         variable = list[i];
3179                                         do {
3180                                                 if (variable.Block == b.Original)
3181                                                         return true;
3182
3183                                                 b = b.Parent;
3184                                         } while (b != null);
3185
3186                                         b = variable.Block;
3187                                         do {
3188                                                 if (block == b)
3189                                                         return false;
3190
3191                                                 b = b.Parent;
3192                                         } while (b != null);
3193
3194                                         b = block;
3195                                 }
3196                         }
3197
3198                         variable = null;
3199                         return false;
3200                 }
3201
3202                 public LabeledStatement GetLabel (string name, Block block)
3203                 {
3204                         if (labels == null)
3205                                 return null;
3206
3207                         object value;
3208                         if (!labels.TryGetValue (name, out value)) {
3209                                 return null;
3210                         }
3211
3212                         var label = value as LabeledStatement;
3213                         Block b = block;
3214                         if (label != null) {
3215                                 if (label.Block == b.Original)
3216                                         return label;
3217
3218                                 // TODO: Temporary workaround for the switch block implicit label block
3219                                 if (label.Block.IsCompilerGenerated && label.Block.Parent == b.Original)
3220                                         return label;
3221                         } else {
3222                                 List<LabeledStatement> list = (List<LabeledStatement>) value;
3223                                 for (int i = 0; i < list.Count; ++i) {
3224                                         label = list[i];
3225                                         if (label.Block == b.Original)
3226                                                 return label;
3227
3228                                         // TODO: Temporary workaround for the switch block implicit label block
3229                                         if (label.Block.IsCompilerGenerated && label.Block.Parent == b.Original)
3230                                                 return label;
3231                                 }
3232                         }
3233                                 
3234                         return null;
3235                 }
3236
3237                 // <summary>
3238                 //   Returns the "this" instance variable of this block.
3239                 //   See AddThisVariable() for more information.
3240                 // </summary>
3241                 public LocalVariable ThisVariable {
3242                         get { return this_variable; }
3243                 }
3244
3245                 // <summary>
3246                 //   This is used by non-static `struct' constructors which do not have an
3247                 //   initializer - in this case, the constructor must initialize all of the
3248                 //   struct's fields.  To do this, we add a "this" variable and use the flow
3249                 //   analysis code to ensure that it's been fully initialized before control
3250                 //   leaves the constructor.
3251                 // </summary>
3252                 public void AddThisVariable (BlockContext bc)
3253                 {
3254                         if (this_variable != null)
3255                                 throw new InternalErrorException (StartLocation.ToString ());
3256
3257                         this_variable = new LocalVariable (this, "this", LocalVariable.Flags.IsThis | LocalVariable.Flags.Used, StartLocation);
3258                         this_variable.Type = bc.CurrentType;
3259                         this_variable.PrepareForFlowAnalysis (bc);
3260                 }
3261
3262                 public bool IsThisAssigned (BlockContext ec)
3263                 {
3264                         return this_variable == null || this_variable.IsThisAssigned (ec, this);
3265                 }
3266
3267                 public override void Emit (EmitContext ec)
3268                 {
3269                         if (Report.Errors > 0)
3270                                 return;
3271
3272 #if PRODUCTION
3273                         try {
3274 #endif
3275
3276                         base.Emit (ec);
3277
3278                         ec.Mark (EndLocation);
3279
3280                         if (ec.HasReturnLabel)
3281                                 ec.MarkLabel (ec.ReturnLabel);
3282
3283                         if (ec.return_value != null) {
3284                                 ec.Emit (OpCodes.Ldloc, ec.return_value);
3285                                 ec.Emit (OpCodes.Ret);
3286                         } else {
3287                                 //
3288                                 // If `HasReturnLabel' is set, then we already emitted a
3289                                 // jump to the end of the method, so we must emit a `ret'
3290                                 // there.
3291                                 //
3292                                 // Unfortunately, System.Reflection.Emit automatically emits
3293                                 // a leave to the end of a finally block.  This is a problem
3294                                 // if no code is following the try/finally block since we may
3295                                 // jump to a point after the end of the method.
3296                                 // As a workaround, we're always creating a return label in
3297                                 // this case.
3298                                 //
3299
3300                                 if (ec.HasReturnLabel || !unreachable) {
3301                                         if (ec.ReturnType.Kind != MemberKind.Void)
3302                                                 ec.Emit (OpCodes.Ldloc, ec.TemporaryReturn ());
3303                                         ec.Emit (OpCodes.Ret);
3304                                 }
3305                         }
3306
3307 #if PRODUCTION
3308                         } catch (Exception e){
3309                                 Console.WriteLine ("Exception caught by the compiler while emitting:");
3310                                 Console.WriteLine ("   Block that caused the problem begin at: " + block.loc);
3311                                         
3312                                 Console.WriteLine (e.GetType ().FullName + ": " + e.Message);
3313                                 throw;
3314                         }
3315 #endif
3316                 }
3317
3318                 protected override void EmitSymbolInfo (EmitContext ec)
3319                 {
3320                         AnonymousExpression ae = ec.CurrentAnonymousMethod;
3321                         if ((ae != null) && (ae.Storey != null))
3322                                 SymbolWriter.DefineScopeVariable (ae.Storey.ID);
3323
3324                         base.EmitSymbolInfo (ec);
3325                 }
3326         }
3327         
3328         public class SwitchLabel {
3329                 Expression label;
3330                 Constant converted;
3331                 readonly Location loc;
3332
3333                 Label? il_label;
3334
3335                 //
3336                 // if expr == null, then it is the default case.
3337                 //
3338                 public SwitchLabel (Expression expr, Location l)
3339                 {
3340                         label = expr;
3341                         loc = l;
3342                 }
3343
3344                 public bool IsDefault {
3345                         get {
3346                                 return label == null;
3347                         }
3348                 }
3349
3350                 public Expression Label {
3351                         get {
3352                                 return label;
3353                         }
3354                 }
3355
3356                 public Location Location {
3357                         get {
3358                                 return loc;
3359                         }
3360                 }
3361
3362                 public Constant Converted {
3363                         get {
3364                                 return converted;
3365                         }
3366                         set {
3367                                 converted = value;
3368                         }
3369                 }
3370
3371                 public Label GetILLabel (EmitContext ec)
3372                 {
3373                         if (il_label == null){
3374                                 il_label = ec.DefineLabel ();
3375                         }
3376
3377                         return il_label.Value;
3378                 }
3379
3380                 //
3381                 // Resolves the expression, reduces it to a literal if possible
3382                 // and then converts it to the requested type.
3383                 //
3384                 public bool ResolveAndReduce (ResolveContext ec, TypeSpec required_type, bool allow_nullable)
3385                 {       
3386                         Expression e = label.Resolve (ec);
3387
3388                         if (e == null)
3389                                 return false;
3390
3391                         Constant c = e as Constant;
3392                         if (c == null){
3393                                 ec.Report.Error (150, loc, "A constant value is expected");
3394                                 return false;
3395                         }
3396
3397                         if (allow_nullable && c is NullLiteral) {
3398                                 converted = c;
3399                                 return true;
3400                         }
3401
3402                         converted = c.ImplicitConversionRequired (ec, required_type, loc);
3403                         return converted != null;
3404                 }
3405
3406                 public void Error_AlreadyOccurs (ResolveContext ec, TypeSpec switch_type, SwitchLabel collision_with)
3407                 {
3408                         string label;
3409                         if (converted == null)
3410                                 label = "default";
3411                         else
3412                                 label = converted.GetValueAsLiteral ();
3413                         
3414                         ec.Report.SymbolRelatedToPreviousError (collision_with.loc, null);
3415                         ec.Report.Error (152, loc, "The label `case {0}:' already occurs in this switch statement", label);
3416                 }
3417
3418                 public SwitchLabel Clone (CloneContext clonectx)
3419                 {
3420                         if (label == null)
3421                                 return this;
3422
3423                         return new SwitchLabel (label.Clone (clonectx), loc);
3424                 }
3425         }
3426
3427         public class SwitchSection {
3428                 public readonly List<SwitchLabel> Labels;
3429                 public readonly Block Block;
3430                 
3431                 public SwitchSection (List<SwitchLabel> labels, Block block)
3432                 {
3433                         Labels = labels;
3434                         Block = block;
3435                 }
3436
3437                 public SwitchSection Clone (CloneContext clonectx)
3438                 {
3439                         var cloned_labels = new List<SwitchLabel> ();
3440
3441                         foreach (SwitchLabel sl in Labels)
3442                                 cloned_labels.Add (sl.Clone (clonectx));
3443                         
3444                         return new SwitchSection (cloned_labels, clonectx.LookupBlock (Block));
3445                 }
3446         }
3447         
3448         public class Switch : Statement
3449         {
3450                 // structure used to hold blocks of keys while calculating table switch
3451                 sealed class LabelsRange : IComparable<LabelsRange>
3452                 {
3453                         public readonly long min;
3454                         public long max;
3455                         public readonly List<long> label_values;
3456
3457                         public LabelsRange (long value)
3458                         {
3459                                 min = max = value;
3460                                 label_values = new List<long> ();
3461                                 label_values.Add (value);
3462                         }
3463
3464                         public LabelsRange (long min, long max, ICollection<long> values)
3465                         {
3466                                 this.min = min;
3467                                 this.max = max;
3468                                 this.label_values = new List<long> (values);
3469                         }
3470
3471                         public long Range {
3472                                 get {
3473                                         return max - min + 1;
3474                                 }
3475                         }
3476
3477                         public bool AddValue (long value)
3478                         {
3479                                 var gap = value - min + 1;
3480                                 // Ensure the range has > 50% occupancy
3481                                 if (gap > 2 * (label_values.Count + 1) || gap <= 0)
3482                                         return false;
3483
3484                                 max = value;
3485                                 label_values.Add (value);
3486                                 return true;
3487                         }
3488
3489                         public int CompareTo (LabelsRange other)
3490                         {
3491                                 int nLength = label_values.Count;
3492                                 int nLengthOther = other.label_values.Count;
3493                                 if (nLengthOther == nLength)
3494                                         return (int) (other.min - min);
3495
3496                                 return nLength - nLengthOther;
3497                         }
3498                 }
3499
3500                 sealed class LabelMarker : Statement
3501                 {
3502                         readonly Switch s;
3503                         readonly List<SwitchLabel> labels;
3504
3505                         public LabelMarker (Switch s, List<SwitchLabel> labels)
3506                         {
3507                                 this.s = s;
3508                                 this.labels = labels;
3509                         }
3510
3511                         protected override void CloneTo (CloneContext clonectx, Statement target)
3512                         {
3513                         }
3514
3515                         protected override void DoEmit (EmitContext ec)
3516                         {
3517                                 foreach (var l in labels) {
3518                                         if (l.IsDefault)
3519                                                 ec.MarkLabel (s.DefaultLabel);
3520                                         else
3521                                                 ec.MarkLabel (l.GetILLabel (ec));
3522                                 }
3523                         }
3524                 }
3525
3526                 public List<SwitchSection> Sections;
3527                 public Expression Expr;
3528
3529                 //
3530                 // Mapping of all labels to their SwitchLabels
3531                 //
3532                 Dictionary<long, SwitchLabel> labels;
3533                 Dictionary<string, SwitchLabel> string_labels;
3534
3535                 /// <summary>
3536                 ///   The governing switch type
3537                 /// </summary>
3538                 public TypeSpec SwitchType;
3539
3540                 //
3541                 // Computed
3542                 //
3543                 Label default_target;
3544                 Label null_target;
3545                 Expression new_expr;
3546                 bool is_constant;
3547
3548                 SwitchSection constant_section;
3549                 SwitchSection default_section;
3550                 SwitchLabel null_section;
3551
3552                 Statement simple_stmt;
3553                 VariableReference value;
3554                 ExpressionStatement string_dictionary;
3555                 FieldExpr switch_cache_field;
3556                 ExplicitBlock block;
3557
3558                 //
3559                 // Nullable Types support
3560                 //
3561                 Nullable.Unwrap unwrap;
3562
3563                 public Switch (Expression e, ExplicitBlock block, List<SwitchSection> sects, Location l)
3564                 {
3565                         Expr = e;
3566                         this.block = block;
3567                         Sections = sects;
3568                         loc = l;
3569                 }
3570
3571                 public ExplicitBlock Block {
3572                         get {
3573                                 return block;
3574                         }
3575                 }
3576
3577                 public Label DefaultLabel {
3578                         get {
3579                                 return default_target;
3580                         }
3581                 }
3582
3583                 public bool GotDefault {
3584                         get {
3585                                 return default_section != null;
3586                         }
3587                 }
3588
3589                 public bool IsNullable {
3590                         get {
3591                                 return unwrap != null;
3592                         }
3593                 }
3594
3595                 //
3596                 // Determines the governing type for a switch.  The returned
3597                 // expression might be the expression from the switch, or an
3598                 // expression that includes any potential conversions to
3599                 //
3600                 Expression SwitchGoverningType (ResolveContext ec, Expression expr)
3601                 {
3602                         switch (expr.Type.BuiltinType) {
3603                         case BuiltinTypeSpec.Type.Byte:
3604                         case BuiltinTypeSpec.Type.SByte:
3605                         case BuiltinTypeSpec.Type.UShort:
3606                         case BuiltinTypeSpec.Type.Short:
3607                         case BuiltinTypeSpec.Type.UInt:
3608                         case BuiltinTypeSpec.Type.Int:
3609                         case BuiltinTypeSpec.Type.ULong:
3610                         case BuiltinTypeSpec.Type.Long:
3611                         case BuiltinTypeSpec.Type.Char:
3612                         case BuiltinTypeSpec.Type.String:
3613                         case BuiltinTypeSpec.Type.Bool:
3614                                 return expr;
3615                         }
3616
3617                         if (expr.Type.IsEnum)
3618                                 return expr;
3619
3620                         //
3621                         // Try to find a *user* defined implicit conversion.
3622                         //
3623                         // If there is no implicit conversion, or if there are multiple
3624                         // conversions, we have to report an error
3625                         //
3626                         Expression converted = null;
3627                         foreach (TypeSpec tt in ec.BuiltinTypes.SwitchUserTypes) {
3628                                 Expression e;
3629                                 
3630                                 e = Convert.ImplicitUserConversion (ec, expr, tt, loc);
3631                                 if (e == null)
3632                                         continue;
3633
3634                                 //
3635                                 // Ignore over-worked ImplicitUserConversions that do
3636                                 // an implicit conversion in addition to the user conversion.
3637                                 // 
3638                                 if (!(e is UserCast))
3639                                         continue;
3640
3641                                 if (converted != null){
3642                                         ec.Report.ExtraInformation (loc, "(Ambiguous implicit user defined conversion in previous ");
3643                                         return null;
3644                                 }
3645
3646                                 converted = e;
3647                         }
3648                         return converted;
3649                 }
3650
3651                 public static TypeSpec[] CreateSwitchUserTypes (BuiltinTypes types)
3652                 {
3653                         // LAMESPEC: For some reason it does not contain bool which looks like csc bug
3654                         return new[] {
3655                                 types.SByte,
3656                                 types.Byte,
3657                                 types.Short,
3658                                 types.UShort,
3659                                 types.Int,
3660                                 types.UInt,
3661                                 types.Long,
3662                                 types.ULong,
3663                                 types.Char,
3664                                 types.String
3665                         };
3666                 }
3667
3668                 //
3669                 // Performs the basic sanity checks on the switch statement
3670                 // (looks for duplicate keys and non-constant expressions).
3671                 //
3672                 // It also returns a hashtable with the keys that we will later
3673                 // use to compute the switch tables
3674                 //
3675                 bool CheckSwitch (ResolveContext ec)
3676                 {
3677                         bool error = false;
3678                         if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String)
3679                                 string_labels = new Dictionary<string, SwitchLabel> (Sections.Count + 1);
3680                         else
3681                                 labels = new Dictionary<long, SwitchLabel> (Sections.Count + 1);
3682                                 
3683                         foreach (SwitchSection ss in Sections){
3684                                 foreach (SwitchLabel sl in ss.Labels){
3685                                         if (sl.IsDefault){
3686                                                 if (default_section != null){
3687                                                         sl.Error_AlreadyOccurs (ec, SwitchType, default_section.Labels [0]);
3688                                                         error = true;
3689                                                 }
3690                                                 default_section = ss;
3691                                                 continue;
3692                                         }
3693
3694                                         if (!sl.ResolveAndReduce (ec, SwitchType, IsNullable)) {
3695                                                 error = true;
3696                                                 continue;
3697                                         }
3698                                         
3699                                         try {
3700                                                 if (string_labels != null) {
3701                                                         string s = sl.Converted.GetValue () as string;
3702                                                         if (s == null)
3703                                                                 null_section = sl;
3704                                                         else
3705                                                                 string_labels.Add (s, sl);
3706                                                 } else {
3707                                                         if (sl.Converted is NullLiteral) {
3708                                                                 null_section = sl;
3709                                                         } else {
3710                                                                 labels.Add (sl.Converted.GetValueAsLong (), sl);
3711                                                         }
3712                                                 }
3713                                         } catch (ArgumentException) {
3714                                                 if (string_labels != null)
3715                                                         sl.Error_AlreadyOccurs (ec, SwitchType, string_labels[(string) sl.Converted.GetValue ()]);
3716                                                 else
3717                                                         sl.Error_AlreadyOccurs (ec, SwitchType, labels[sl.Converted.GetValueAsLong ()]);
3718
3719                                                 error = true;
3720                                         }
3721                                 }
3722                         }
3723                         return !error;
3724                 }
3725                 
3726                 //
3727                 // This method emits code for a lookup-based switch statement (non-string)
3728                 // Basically it groups the cases into blocks that are at least half full,
3729                 // and then spits out individual lookup opcodes for each block.
3730                 // It emits the longest blocks first, and short blocks are just
3731                 // handled with direct compares.
3732                 //
3733                 void EmitTableSwitch (EmitContext ec, Expression val)
3734                 {
3735                         Label lbl_default = default_target;
3736
3737                         if (labels != null && labels.Count > 0) {
3738                                 List<LabelsRange> ranges;
3739                                 if (string_labels != null) {
3740                                         // We have done all hard work for string already
3741                                         // setup single range only
3742                                         ranges = new List<LabelsRange> (1);
3743                                         ranges.Add (new LabelsRange (0, labels.Count - 1, labels.Keys));
3744                                 } else {
3745                                         var element_keys = new long[labels.Count];
3746                                         labels.Keys.CopyTo (element_keys, 0);
3747                                         Array.Sort (element_keys);
3748
3749                                         //
3750                                         // Build possible ranges of switch labes to reduce number
3751                                         // of comparisons
3752                                         //
3753                                         ranges = new List<LabelsRange> (element_keys.Length);
3754                                         var range = new LabelsRange (element_keys[0]);
3755                                         ranges.Add (range);
3756                                         for (int i = 1; i < element_keys.Length; ++i) {
3757                                                 var l = element_keys[i];
3758                                                 if (range.AddValue (l))
3759                                                         continue;
3760
3761                                                 range = new LabelsRange (l);
3762                                                 ranges.Add (range);
3763                                         }
3764
3765                                         // sort the blocks so we can tackle the largest ones first
3766                                         ranges.Sort ();
3767                                 }
3768
3769                                 TypeSpec compare_type = SwitchType.IsEnum ? EnumSpec.GetUnderlyingType (SwitchType) : SwitchType;
3770
3771                                 for (int range_index = ranges.Count - 1; range_index >= 0; --range_index) {
3772                                         LabelsRange kb = ranges[range_index];
3773                                         lbl_default = (range_index == 0) ? default_target : ec.DefineLabel ();
3774
3775                                         // Optimize small ranges using simple equality check
3776                                         if (kb.Range <= 2) {
3777                                                 foreach (var key in kb.label_values) {
3778                                                         SwitchLabel sl = labels[key];
3779                                                         if (sl.Converted.IsDefaultValue) {
3780                                                                 val.EmitBranchable (ec, sl.GetILLabel (ec), false);
3781                                                         } else {
3782                                                                 val.Emit (ec);
3783                                                                 sl.Converted.Emit (ec);
3784                                                                 ec.Emit (OpCodes.Beq, sl.GetILLabel (ec));
3785                                                         }
3786                                                 }
3787                                         } else {
3788                                                 // TODO: if all the keys in the block are the same and there are
3789                                                 //       no gaps/defaults then just use a range-check.
3790                                                 if (compare_type.BuiltinType == BuiltinTypeSpec.Type.Long || compare_type.BuiltinType == BuiltinTypeSpec.Type.ULong) {
3791                                                         // TODO: optimize constant/I4 cases
3792
3793                                                         // check block range (could be > 2^31)
3794                                                         val.Emit (ec);
3795                                                         ec.EmitLong (kb.min);
3796                                                         ec.Emit (OpCodes.Blt, lbl_default);
3797
3798                                                         val.Emit (ec);
3799                                                         ec.EmitLong (kb.max);
3800                                                         ec.Emit (OpCodes.Bgt, lbl_default);
3801
3802                                                         // normalize range
3803                                                         val.Emit (ec);
3804                                                         if (kb.min != 0) {
3805                                                                 ec.EmitLong (kb.min);
3806                                                                 ec.Emit (OpCodes.Sub);
3807                                                         }
3808
3809                                                         ec.Emit (OpCodes.Conv_I4);      // assumes < 2^31 labels!
3810                                                 } else {
3811                                                         // normalize range
3812                                                         val.Emit (ec);
3813                                                         int first = (int) kb.min;
3814                                                         if (first > 0) {
3815                                                                 ec.EmitInt (first);
3816                                                                 ec.Emit (OpCodes.Sub);
3817                                                         } else if (first < 0) {
3818                                                                 ec.EmitInt (-first);
3819                                                                 ec.Emit (OpCodes.Add);
3820                                                         }
3821                                                 }
3822
3823                                                 // first, build the list of labels for the switch
3824                                                 int iKey = 0;
3825                                                 long cJumps = kb.Range;
3826                                                 Label[] switch_labels = new Label[cJumps];
3827                                                 for (int iJump = 0; iJump < cJumps; iJump++) {
3828                                                         var key = kb.label_values[iKey];
3829                                                         if (key == kb.min + iJump) {
3830                                                                 switch_labels[iJump] = labels[key].GetILLabel (ec);
3831                                                                 iKey++;
3832                                                         } else {
3833                                                                 switch_labels[iJump] = lbl_default;
3834                                                         }
3835                                                 }
3836
3837                                                 // emit the switch opcode
3838                                                 ec.Emit (OpCodes.Switch, switch_labels);
3839                                         }
3840
3841                                         // mark the default for this block
3842                                         if (range_index != 0)
3843                                                 ec.MarkLabel (lbl_default);
3844                                 }
3845
3846                                 // the last default just goes to the end
3847                                 if (ranges.Count > 0)
3848                                         ec.Emit (OpCodes.Br, lbl_default);
3849                         }
3850
3851                         // now emit the code for the sections
3852                         bool found_default = false;
3853
3854                         foreach (SwitchSection ss in Sections) {
3855                                 foreach (SwitchLabel sl in ss.Labels) {
3856                                         if (sl.IsDefault) {
3857                                                 ec.MarkLabel (lbl_default);
3858                                                 found_default = true;
3859                                                 if (null_section == null)
3860                                                         ec.MarkLabel (null_target);
3861                                         } else if (sl.Converted.IsNull) {
3862                                                 ec.MarkLabel (null_target);
3863                                         }
3864
3865                                         ec.MarkLabel (sl.GetILLabel (ec));
3866                                 }
3867
3868                                 ss.Block.Emit (ec);
3869                         }
3870                         
3871                         if (!found_default) {
3872                                 ec.MarkLabel (lbl_default);
3873                                 if (null_section == null) {
3874                                         ec.MarkLabel (null_target);
3875                                 }
3876                         }
3877                 }
3878
3879                 SwitchLabel FindLabel (Constant value)
3880                 {
3881                         SwitchLabel sl = null;
3882
3883                         if (string_labels != null) {
3884                                 string s = value.GetValue () as string;
3885                                 if (s == null) {
3886                                         if (null_section != null)
3887                                                 sl = null_section;
3888                                         else if (default_section != null)
3889                                                 sl = default_section.Labels[0];
3890                                 } else {
3891                                         string_labels.TryGetValue (s, out sl);
3892                                 }
3893                         } else {
3894                                 if (value is NullLiteral) {
3895                                         sl = null_section;
3896                                 } else {
3897                                         labels.TryGetValue (value.GetValueAsLong (), out sl);
3898                                 }
3899                         }
3900
3901                         return sl;
3902                 }
3903
3904                 SwitchSection FindSection (SwitchLabel label)
3905                 {
3906                         foreach (SwitchSection ss in Sections){
3907                                 foreach (SwitchLabel sl in ss.Labels){
3908                                         if (label == sl)
3909                                                 return ss;
3910                                 }
3911                         }
3912
3913                         return null;
3914                 }
3915
3916                 public override bool Resolve (BlockContext ec)
3917                 {
3918                         Expr = Expr.Resolve (ec);
3919                         if (Expr == null)
3920                                 return false;
3921
3922                         new_expr = SwitchGoverningType (ec, Expr);
3923
3924                         if (new_expr == null && Expr.Type.IsNullableType) {
3925                                 unwrap = Nullable.Unwrap.Create (Expr, false);
3926                                 if (unwrap == null)
3927                                         return false;
3928
3929                                 new_expr = SwitchGoverningType (ec, unwrap);
3930                         }
3931
3932                         if (new_expr == null){
3933                                 ec.Report.Error (151, loc,
3934                                         "A switch expression of type `{0}' cannot be converted to an integral type, bool, char, string, enum or nullable type",
3935                                         TypeManager.CSharpName (Expr.Type));
3936                                 return false;
3937                         }
3938
3939                         // Validate switch.
3940                         SwitchType = new_expr.Type;
3941
3942                         if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.Bool && ec.Module.Compiler.Settings.Version == LanguageVersion.ISO_1) {
3943                                 ec.Report.FeatureIsNotAvailable (ec.Module.Compiler, loc, "switch expression of boolean type");
3944                                 return false;
3945                         }
3946
3947                         if (!CheckSwitch (ec))
3948                                 return false;
3949
3950                         Switch old_switch = ec.Switch;
3951                         ec.Switch = this;
3952                         ec.Switch.SwitchType = SwitchType;
3953
3954                         ec.StartFlowBranching (FlowBranching.BranchingType.Switch, loc);
3955
3956                         var constant = new_expr as Constant;
3957                         if (constant != null) {
3958                                 is_constant = true;
3959                                 SwitchLabel label = FindLabel (constant);
3960                                 if (label != null)
3961                                         constant_section = FindSection (label);
3962
3963                                 if (constant_section == null)
3964                                         constant_section = default_section;
3965                         } else {
3966                                 //
3967                                 // Store switch expression for comparission purposes
3968                                 //
3969                                 value = new_expr as VariableReference;
3970                                 if (value == null)
3971                                         value = TemporaryVariableReference.Create (SwitchType, ec.CurrentBlock, loc);
3972                         }
3973
3974                         bool first = true;
3975                         bool ok = true;
3976                         foreach (SwitchSection ss in Sections){
3977                                 if (!first)
3978                                         ec.CurrentBranching.CreateSibling (
3979                                                 null, FlowBranching.SiblingType.SwitchSection);
3980                                 else
3981                                         first = false;
3982
3983                                 if (is_constant && (ss != constant_section)) {
3984                                         // If we're a constant switch, we're only emitting
3985                                         // one single section - mark all the others as
3986                                         // unreachable.
3987                                         ec.CurrentBranching.CurrentUsageVector.Goto ();
3988                                         if (!ss.Block.ResolveUnreachable (ec, true)) {
3989                                                 ok = false;
3990                                         }
3991                                 } else {
3992                                         if (!ss.Block.Resolve (ec))
3993                                                 ok = false;
3994                                 }
3995                         }
3996
3997                         if (default_section == null)
3998                                 ec.CurrentBranching.CreateSibling (null, FlowBranching.SiblingType.SwitchSection);
3999
4000                         ec.EndFlowBranching ();
4001                         ec.Switch = old_switch;
4002
4003                         if (!ok)
4004                                 return false;
4005
4006                         if (!is_constant) {
4007                                 if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String) {
4008                                         if (string_labels.Count < 7)
4009                                                 ResolveSimpleSwitch (ec);
4010                                         else
4011                                                 ResolveStringSwitchMap (ec);
4012                                 } else if (labels.Count < 3 && !IsNullable) {
4013                                         ResolveSimpleSwitch (ec);
4014                                 }
4015                         }
4016
4017                         return true;
4018                 }
4019
4020                 public SwitchLabel ResolveGotoCase (ResolveContext rc, Constant value)
4021                 {
4022                         var sl = FindLabel (value);
4023
4024                         if (sl == null) {
4025                                 FlowBranchingBlock.Error_UnknownLabel (loc, "case " + value.GetValueAsLiteral (), rc.Report);
4026                         }
4027
4028                         return sl;
4029                 }
4030
4031                 //
4032                 // Prepares switch using simple if/else comparison for small label count (4 + optional default)
4033                 //
4034                 void ResolveSimpleSwitch (BlockContext bc)
4035                 {
4036                         simple_stmt = default_section != null ? default_section.Block : null;
4037
4038                         for (int i = Sections.Count - 1; i >= 0; --i) {
4039                                 var s = Sections[i];
4040
4041                                 if (s == default_section) {
4042                                         s.Block.AddScopeStatement (new LabelMarker (this, s.Labels));
4043                                         continue;
4044                                 }
4045
4046                                 s.Block.AddScopeStatement (new LabelMarker (this, s.Labels));
4047
4048                                 Expression cond = null;
4049                                 for (int ci = 0; ci < s.Labels.Count; ++ci) {
4050                                         var e = new Binary (Binary.Operator.Equality, value, s.Labels[ci].Converted, loc);
4051
4052                                         if (ci > 0) {
4053                                                 cond = new Binary (Binary.Operator.LogicalOr, cond, e, loc);
4054                                         } else {
4055                                                 cond = e;
4056                                         }
4057                                 }
4058
4059                                 simple_stmt = new If (cond, s.Block, simple_stmt, loc);
4060                         }
4061
4062                         // It's null for empty switch
4063                         if (simple_stmt != null)
4064                                 simple_stmt.Resolve (bc);
4065                 }
4066
4067                 //
4068                 // Converts string switch into string hashtable
4069                 //
4070                 void ResolveStringSwitchMap (ResolveContext ec)
4071                 {
4072                         FullNamedExpression string_dictionary_type;
4073                         if (ec.Module.PredefinedTypes.Dictionary.Define ()) {
4074                                 string_dictionary_type = new TypeExpression (
4075                                         ec.Module.PredefinedTypes.Dictionary.TypeSpec.MakeGenericType (ec,
4076                                                 new [] { ec.BuiltinTypes.String, ec.BuiltinTypes.Int }),
4077                                         loc);
4078                         } else if (ec.Module.PredefinedTypes.Hashtable.Define ()) {
4079                                 string_dictionary_type = new TypeExpression (ec.Module.PredefinedTypes.Hashtable.TypeSpec, loc);
4080                         } else {
4081                                 ec.Module.PredefinedTypes.Dictionary.Resolve ();
4082                                 return;
4083                         }
4084
4085                         var ctype = ec.CurrentMemberDefinition.Parent.PartialContainer;
4086                         Field field = new Field (ctype, string_dictionary_type,
4087                                 Modifiers.STATIC | Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED,
4088                                 new MemberName (CompilerGeneratedClass.MakeName (null, "f", "switch$map", ec.Module.CounterSwitchTypes++), loc), null);
4089                         if (!field.Define ())
4090                                 return;
4091                         ctype.AddField (field);
4092
4093                         var init = new List<Expression> ();
4094                         int counter = 0;
4095                         labels = new Dictionary<long, SwitchLabel> (string_labels.Count);
4096                         string value = null;
4097                         foreach (SwitchSection section in Sections) {
4098                                 bool contains_label = false;
4099                                 foreach (SwitchLabel sl in section.Labels) {
4100                                         if (sl.IsDefault || sl.Converted.IsNull)
4101                                                 continue;
4102
4103                                         if (!contains_label) {
4104                                                 labels.Add (counter, sl);
4105                                                 contains_label = true;
4106                                         }
4107
4108                                         value = (string) sl.Converted.GetValue ();
4109                                         var init_args = new List<Expression> (2);
4110                                         init_args.Add (new StringLiteral (ec.BuiltinTypes, value, sl.Location));
4111
4112                                         sl.Converted = new IntConstant (ec.BuiltinTypes, counter, loc);
4113                                         init_args.Add (sl.Converted);
4114
4115                                         init.Add (new CollectionElementInitializer (init_args, loc));
4116                                 }
4117
4118                                 //
4119                                 // Don't add empty sections
4120                                 //
4121                                 if (contains_label)
4122                                         ++counter;
4123                         }
4124
4125                         Arguments args = new Arguments (1);
4126                         args.Add (new Argument (new IntConstant (ec.BuiltinTypes, init.Count, loc)));
4127                         Expression initializer = new NewInitialize (string_dictionary_type, args,
4128                                 new CollectionOrObjectInitializers (init, loc), loc);
4129
4130                         switch_cache_field = new FieldExpr (field, loc);
4131                         string_dictionary = new SimpleAssign (switch_cache_field, initializer.Resolve (ec));
4132                 }
4133
4134                 void DoEmitStringSwitch (EmitContext ec)
4135                 {
4136                         Label l_initialized = ec.DefineLabel ();
4137
4138                         //
4139                         // Skip initialization when value is null
4140                         //
4141                         value.EmitBranchable (ec, null_target, false);
4142
4143                         //
4144                         // Check if string dictionary is initialized and initialize
4145                         //
4146                         switch_cache_field.EmitBranchable (ec, l_initialized, true);
4147                         string_dictionary.EmitStatement (ec);
4148                         ec.MarkLabel (l_initialized);
4149
4150                         LocalTemporary string_switch_variable = new LocalTemporary (ec.BuiltinTypes.Int);
4151
4152                         ResolveContext rc = new ResolveContext (ec.MemberContext);
4153
4154                         if (switch_cache_field.Type.IsGeneric) {
4155                                 Arguments get_value_args = new Arguments (2);
4156                                 get_value_args.Add (new Argument (value));
4157                                 get_value_args.Add (new Argument (string_switch_variable, Argument.AType.Out));
4158                                 Expression get_item = new Invocation (new MemberAccess (switch_cache_field, "TryGetValue", loc), get_value_args).Resolve (rc);
4159                                 if (get_item == null)
4160                                         return;
4161
4162                                 //
4163                                 // A value was not found, go to default case
4164                                 //
4165                                 get_item.EmitBranchable (ec, default_target, false);
4166                         } else {
4167                                 Arguments get_value_args = new Arguments (1);
4168                                 get_value_args.Add (new Argument (value));
4169
4170                                 Expression get_item = new ElementAccess (switch_cache_field, get_value_args, loc).Resolve (rc);
4171                                 if (get_item == null)
4172                                         return;
4173
4174                                 LocalTemporary get_item_object = new LocalTemporary (ec.BuiltinTypes.Object);
4175                                 get_item_object.EmitAssign (ec, get_item, true, false);
4176                                 ec.Emit (OpCodes.Brfalse, default_target);
4177
4178                                 ExpressionStatement get_item_int = (ExpressionStatement) new SimpleAssign (string_switch_variable,
4179                                         new Cast (new TypeExpression (ec.BuiltinTypes.Int, loc), get_item_object, loc)).Resolve (rc);
4180
4181                                 get_item_int.EmitStatement (ec);
4182                                 get_item_object.Release (ec);
4183                         }
4184
4185                         EmitTableSwitch (ec, string_switch_variable);
4186                         string_switch_variable.Release (ec);
4187                 }
4188
4189                 protected override void DoEmit (EmitContext ec)
4190                 {
4191                         //
4192                         // Needed to emit anonymous storey initialization
4193                         // Otherwise it does not contain any statements for now
4194                         //
4195                         block.Emit (ec);
4196
4197                         default_target = ec.DefineLabel ();
4198                         null_target = ec.DefineLabel ();
4199
4200                         if (IsNullable) {
4201                                 unwrap.EmitCheck (ec);
4202                                 ec.Emit (OpCodes.Brfalse, null_target);
4203                                 value.EmitAssign (ec, new_expr, false, false);
4204                         } else if (new_expr != value && !is_constant) {
4205                                 value.EmitAssign (ec, new_expr, false, false);
4206                         }
4207
4208                         //
4209                         // Setup the codegen context
4210                         //
4211                         Label old_end = ec.LoopEnd;
4212                         Switch old_switch = ec.Switch;
4213                         
4214                         ec.LoopEnd = ec.DefineLabel ();
4215                         ec.Switch = this;
4216
4217                         // Emit Code.
4218                         if (is_constant) {
4219                                 if (constant_section != null)
4220                                         constant_section.Block.Emit (ec);
4221                         } else if (string_dictionary != null) {
4222                                 DoEmitStringSwitch (ec);
4223                         } else if (simple_stmt != null) {
4224                                 simple_stmt.Emit (ec);
4225                         } else {
4226                                 EmitTableSwitch (ec, value);
4227                         }
4228
4229                         // Restore context state. 
4230                         ec.MarkLabel (ec.LoopEnd);
4231
4232                         //
4233                         // Restore the previous context
4234                         //
4235                         ec.LoopEnd = old_end;
4236                         ec.Switch = old_switch;
4237                 }
4238
4239                 protected override void CloneTo (CloneContext clonectx, Statement t)
4240                 {
4241                         Switch target = (Switch) t;
4242
4243                         target.Expr = Expr.Clone (clonectx);
4244                         target.Sections = new List<SwitchSection> ();
4245                         foreach (SwitchSection ss in Sections){
4246                                 target.Sections.Add (ss.Clone (clonectx));
4247                         }
4248                 }
4249                 
4250                 public override object Accept (StructuralVisitor visitor)
4251                 {
4252                         return visitor.Visit (this);
4253                 }
4254         }
4255
4256         // A place where execution can restart in an iterator
4257         public abstract class ResumableStatement : Statement
4258         {
4259                 bool prepared;
4260                 protected Label resume_point;
4261
4262                 public Label PrepareForEmit (EmitContext ec)
4263                 {
4264                         if (!prepared) {
4265                                 prepared = true;
4266                                 resume_point = ec.DefineLabel ();
4267                         }
4268                         return resume_point;
4269                 }
4270
4271                 public virtual Label PrepareForDispose (EmitContext ec, Label end)
4272                 {
4273                         return end;
4274                 }
4275
4276                 public virtual void EmitForDispose (EmitContext ec, LocalBuilder pc, Label end, bool have_dispatcher)
4277                 {
4278                 }
4279         }
4280
4281         public abstract class TryFinallyBlock : ExceptionStatement
4282         {
4283                 protected Statement stmt;
4284                 Label dispose_try_block;
4285                 bool prepared_for_dispose, emitted_dispose;
4286
4287                 protected TryFinallyBlock (Statement stmt, Location loc)
4288                         : base (loc)
4289                 {
4290                         this.stmt = stmt;
4291                 }
4292
4293                 #region Properties
4294
4295                 public Statement Statement {
4296                         get {
4297                                 return stmt;
4298                         }
4299                 }
4300
4301                 #endregion
4302
4303                 protected abstract void EmitTryBody (EmitContext ec);
4304                 protected abstract void EmitFinallyBody (EmitContext ec);
4305
4306                 public override Label PrepareForDispose (EmitContext ec, Label end)
4307                 {
4308                         if (!prepared_for_dispose) {
4309                                 prepared_for_dispose = true;
4310                                 dispose_try_block = ec.DefineLabel ();
4311                         }
4312                         return dispose_try_block;
4313                 }
4314
4315                 protected sealed override void DoEmit (EmitContext ec)
4316                 {
4317                         EmitTryBodyPrepare (ec);
4318                         EmitTryBody (ec);
4319
4320                         ec.BeginFinallyBlock ();
4321
4322                         Label start_finally = ec.DefineLabel ();
4323                         if (resume_points != null) {
4324                                 var state_machine = (StateMachineInitializer) ec.CurrentAnonymousMethod;
4325
4326                                 ec.Emit (OpCodes.Ldloc, state_machine.SkipFinally);
4327                                 ec.Emit (OpCodes.Brfalse_S, start_finally);
4328                                 ec.Emit (OpCodes.Endfinally);
4329                         }
4330
4331                         ec.MarkLabel (start_finally);
4332                         EmitFinallyBody (ec);
4333
4334                         ec.EndExceptionBlock ();
4335                 }
4336
4337                 public override void EmitForDispose (EmitContext ec, LocalBuilder pc, Label end, bool have_dispatcher)
4338                 {
4339                         if (emitted_dispose)
4340                                 return;
4341
4342                         emitted_dispose = true;
4343
4344                         Label end_of_try = ec.DefineLabel ();
4345
4346                         // Ensure that the only way we can get into this code is through a dispatcher
4347                         if (have_dispatcher)
4348                                 ec.Emit (OpCodes.Br, end);
4349
4350                         ec.BeginExceptionBlock ();
4351
4352                         ec.MarkLabel (dispose_try_block);
4353
4354                         Label[] labels = null;
4355                         for (int i = 0; i < resume_points.Count; ++i) {
4356                                 ResumableStatement s = resume_points[i];
4357                                 Label ret = s.PrepareForDispose (ec, end_of_try);
4358                                 if (ret.Equals (end_of_try) && labels == null)
4359                                         continue;
4360                                 if (labels == null) {
4361                                         labels = new Label[resume_points.Count];
4362                                         for (int j = 0; j < i; ++j)
4363                                                 labels[j] = end_of_try;
4364                                 }
4365                                 labels[i] = ret;
4366                         }
4367
4368                         if (labels != null) {
4369                                 int j;
4370                                 for (j = 1; j < labels.Length; ++j)
4371                                         if (!labels[0].Equals (labels[j]))
4372                                                 break;
4373                                 bool emit_dispatcher = j < labels.Length;
4374
4375                                 if (emit_dispatcher) {
4376                                         //SymbolWriter.StartIteratorDispatcher (ec.ig);
4377                                         ec.Emit (OpCodes.Ldloc, pc);
4378                                         ec.EmitInt (first_resume_pc);
4379                                         ec.Emit (OpCodes.Sub);
4380                                         ec.Emit (OpCodes.Switch, labels);
4381                                         //SymbolWriter.EndIteratorDispatcher (ec.ig);
4382                                 }
4383
4384                                 foreach (ResumableStatement s in resume_points)
4385                                         s.EmitForDispose (ec, pc, end_of_try, emit_dispatcher);
4386                         }
4387
4388                         ec.MarkLabel (end_of_try);
4389
4390                         ec.BeginFinallyBlock ();
4391
4392                         EmitFinallyBody (ec);
4393
4394                         ec.EndExceptionBlock ();
4395                 }
4396         }
4397
4398         //
4399         // Base class for blocks using exception handling
4400         //
4401         public abstract class ExceptionStatement : ResumableStatement
4402         {
4403 #if !STATIC
4404                 bool code_follows;
4405 #endif
4406                 protected List<ResumableStatement> resume_points;
4407                 protected int first_resume_pc;
4408
4409                 protected ExceptionStatement (Location loc)
4410                 {
4411                         this.loc = loc;
4412                 }
4413
4414                 protected virtual void EmitTryBodyPrepare (EmitContext ec)
4415                 {
4416                         StateMachineInitializer state_machine = null;
4417                         if (resume_points != null) {
4418                                 state_machine = (StateMachineInitializer) ec.CurrentAnonymousMethod;
4419
4420                                 ec.EmitInt ((int) IteratorStorey.State.Running);
4421                                 ec.Emit (OpCodes.Stloc, state_machine.CurrentPC);
4422                         }
4423
4424                         ec.BeginExceptionBlock ();
4425
4426                         if (resume_points != null) {
4427                                 ec.MarkLabel (resume_point);
4428
4429                                 // For normal control flow, we want to fall-through the Switch
4430                                 // So, we use CurrentPC rather than the $PC field, and initialize it to an outside value above
4431                                 ec.Emit (OpCodes.Ldloc, state_machine.CurrentPC);
4432                                 ec.EmitInt (first_resume_pc);
4433                                 ec.Emit (OpCodes.Sub);
4434
4435                                 Label[] labels = new Label[resume_points.Count];
4436                                 for (int i = 0; i < resume_points.Count; ++i)
4437                                         labels[i] = resume_points[i].PrepareForEmit (ec);
4438                                 ec.Emit (OpCodes.Switch, labels);
4439                         }
4440                 }
4441
4442                 public void SomeCodeFollows ()
4443                 {
4444 #if !STATIC
4445                         code_follows = true;
4446 #endif
4447                 }
4448
4449                 public override bool Resolve (BlockContext ec)
4450                 {
4451 #if !STATIC
4452                         // System.Reflection.Emit automatically emits a 'leave' at the end of a try clause
4453                         // So, ensure there's some IL code after this statement.
4454                         if (!code_follows && resume_points == null && ec.CurrentBranching.CurrentUsageVector.IsUnreachable)
4455                                 ec.NeedReturnLabel ();
4456 #endif
4457                         return true;
4458                 }
4459
4460                 public void AddResumePoint (ResumableStatement stmt, int pc)
4461                 {
4462                         if (resume_points == null) {
4463                                 resume_points = new List<ResumableStatement> ();
4464                                 first_resume_pc = pc;
4465                         }
4466
4467                         if (pc != first_resume_pc + resume_points.Count)
4468                                 throw new InternalErrorException ("missed an intervening AddResumePoint?");
4469
4470                         resume_points.Add (stmt);
4471                 }
4472
4473         }
4474
4475         public class Lock : TryFinallyBlock
4476         {
4477                 Expression expr;
4478                 TemporaryVariableReference expr_copy;
4479                 TemporaryVariableReference lock_taken;
4480                         
4481                 public Lock (Expression expr, Statement stmt, Location loc)
4482                         : base (stmt, loc)
4483                 {
4484                         this.expr = expr;
4485                 }
4486
4487                 public Expression Expr {
4488                         get {
4489                                 return this.expr;
4490                         }
4491                 }
4492
4493                 public override bool Resolve (BlockContext ec)
4494                 {
4495                         expr = expr.Resolve (ec);
4496                         if (expr == null)
4497                                 return false;
4498
4499                         if (!TypeSpec.IsReferenceType (expr.Type)) {
4500                                 ec.Report.Error (185, loc,
4501                                         "`{0}' is not a reference type as required by the lock statement",
4502                                         expr.Type.GetSignatureForError ());
4503                         }
4504
4505                         if (expr.Type.IsGenericParameter) {
4506                                 expr = Convert.ImplicitTypeParameterConversion (expr, (TypeParameterSpec)expr.Type, ec.BuiltinTypes.Object);
4507                         }
4508
4509                         VariableReference lv = expr as VariableReference;
4510                         bool locked;
4511                         if (lv != null) {
4512                                 locked = lv.IsLockedByStatement;
4513                                 lv.IsLockedByStatement = true;
4514                         } else {
4515                                 lv = null;
4516                                 locked = false;
4517                         }
4518
4519                         using (ec.Set (ResolveContext.Options.LockScope)) {
4520                                 ec.StartFlowBranching (this);
4521                                 Statement.Resolve (ec);
4522                                 ec.EndFlowBranching ();
4523                         }
4524
4525                         if (lv != null) {
4526                                 lv.IsLockedByStatement = locked;
4527                         }
4528
4529                         base.Resolve (ec);
4530
4531                         //
4532                         // Have to keep original lock value around to unlock same location
4533                         // in the case the original has changed or is null
4534                         //
4535                         expr_copy = TemporaryVariableReference.Create (ec.BuiltinTypes.Object, ec.CurrentBlock, loc);
4536                         expr_copy.Resolve (ec);
4537
4538                         //
4539                         // Ensure Monitor methods are available
4540                         //
4541                         if (ResolvePredefinedMethods (ec) > 1) {
4542                                 lock_taken = TemporaryVariableReference.Create (ec.BuiltinTypes.Bool, ec.CurrentBlock, loc);
4543                                 lock_taken.Resolve (ec);
4544                         }
4545
4546                         return true;
4547                 }
4548                 
4549                 protected override void EmitTryBodyPrepare (EmitContext ec)
4550                 {
4551                         expr_copy.EmitAssign (ec, expr);
4552
4553                         if (lock_taken != null) {
4554                                 //
4555                                 // Initialize ref variable
4556                                 //
4557                                 lock_taken.EmitAssign (ec, new BoolLiteral (ec.BuiltinTypes, false, loc));
4558                         } else {
4559                                 //
4560                                 // Monitor.Enter (expr_copy)
4561                                 //
4562                                 expr_copy.Emit (ec);
4563                                 ec.Emit (OpCodes.Call, ec.Module.PredefinedMembers.MonitorEnter.Get ());
4564                         }
4565
4566                         base.EmitTryBodyPrepare (ec);
4567                 }
4568
4569                 protected override void EmitTryBody (EmitContext ec)
4570                 {
4571                         //
4572                         // Monitor.Enter (expr_copy, ref lock_taken)
4573                         //
4574                         if (lock_taken != null) {
4575                                 expr_copy.Emit (ec);
4576                                 lock_taken.LocalInfo.CreateBuilder (ec);
4577                                 lock_taken.AddressOf (ec, AddressOp.Load);
4578                                 ec.Emit (OpCodes.Call, ec.Module.PredefinedMembers.MonitorEnter_v4.Get ());
4579                         }
4580
4581                         Statement.Emit (ec);
4582                 }
4583
4584                 protected override void EmitFinallyBody (EmitContext ec)
4585                 {
4586                         //
4587                         // if (lock_taken) Monitor.Exit (expr_copy)
4588                         //
4589                         Label skip = ec.DefineLabel ();
4590
4591                         if (lock_taken != null) {
4592                                 lock_taken.Emit (ec);
4593                                 ec.Emit (OpCodes.Brfalse_S, skip);
4594                         }
4595
4596                         expr_copy.Emit (ec);
4597                         var m = ec.Module.PredefinedMembers.MonitorExit.Resolve (loc);
4598                         if (m != null)
4599                                 ec.Emit (OpCodes.Call, m);
4600
4601                         ec.MarkLabel (skip);
4602                 }
4603
4604                 int ResolvePredefinedMethods (ResolveContext rc)
4605                 {
4606                         // Try 4.0 Monitor.Enter (object, ref bool) overload first
4607                         var m = rc.Module.PredefinedMembers.MonitorEnter_v4.Get ();
4608                         if (m != null)
4609                                 return 4;
4610
4611                         m = rc.Module.PredefinedMembers.MonitorEnter.Get ();
4612                         if (m != null)
4613                                 return 1;
4614
4615                         rc.Module.PredefinedMembers.MonitorEnter_v4.Resolve (loc);
4616                         return 0;
4617                 }
4618
4619                 protected override void CloneTo (CloneContext clonectx, Statement t)
4620                 {
4621                         Lock target = (Lock) t;
4622
4623                         target.expr = expr.Clone (clonectx);
4624                         target.stmt = Statement.Clone (clonectx);
4625                 }
4626                 
4627                 public override object Accept (StructuralVisitor visitor)
4628                 {
4629                         return visitor.Visit (this);
4630                 }
4631
4632         }
4633
4634         public class Unchecked : Statement {
4635                 public Block Block;
4636                 
4637                 public Unchecked (Block b, Location loc)
4638                 {
4639                         Block = b;
4640                         b.Unchecked = true;
4641                         this.loc = loc;
4642                 }
4643
4644                 public override bool Resolve (BlockContext ec)
4645                 {
4646                         using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
4647                                 return Block.Resolve (ec);
4648                 }
4649                 
4650                 protected override void DoEmit (EmitContext ec)
4651                 {
4652                         using (ec.With (EmitContext.Options.CheckedScope, false))
4653                                 Block.Emit (ec);
4654                 }
4655
4656                 protected override void CloneTo (CloneContext clonectx, Statement t)
4657                 {
4658                         Unchecked target = (Unchecked) t;
4659
4660                         target.Block = clonectx.LookupBlock (Block);
4661                 }
4662                 
4663                 public override object Accept (StructuralVisitor visitor)
4664                 {
4665                         return visitor.Visit (this);
4666                 }
4667         }
4668
4669         public class Checked : Statement {
4670                 public Block Block;
4671                 
4672                 public Checked (Block b, Location loc)
4673                 {
4674                         Block = b;
4675                         b.Unchecked = false;
4676                         this.loc = loc;
4677                 }
4678
4679                 public override bool Resolve (BlockContext ec)
4680                 {
4681                         using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
4682                                 return Block.Resolve (ec);
4683                 }
4684
4685                 protected override void DoEmit (EmitContext ec)
4686                 {
4687                         using (ec.With (EmitContext.Options.CheckedScope, true))
4688                                 Block.Emit (ec);
4689                 }
4690
4691                 protected override void CloneTo (CloneContext clonectx, Statement t)
4692                 {
4693                         Checked target = (Checked) t;
4694
4695                         target.Block = clonectx.LookupBlock (Block);
4696                 }
4697                 
4698                 public override object Accept (StructuralVisitor visitor)
4699                 {
4700                         return visitor.Visit (this);
4701                 }
4702         }
4703
4704         public class Unsafe : Statement {
4705                 public Block Block;
4706
4707                 public Unsafe (Block b, Location loc)
4708                 {
4709                         Block = b;
4710                         Block.Unsafe = true;
4711                         this.loc = loc;
4712                 }
4713
4714                 public override bool Resolve (BlockContext ec)
4715                 {
4716                         if (ec.CurrentIterator != null)
4717                                 ec.Report.Error (1629, loc, "Unsafe code may not appear in iterators");
4718
4719                         using (ec.Set (ResolveContext.Options.UnsafeScope))
4720                                 return Block.Resolve (ec);
4721                 }
4722                 
4723                 protected override void DoEmit (EmitContext ec)
4724                 {
4725                         Block.Emit (ec);
4726                 }
4727
4728                 protected override void CloneTo (CloneContext clonectx, Statement t)
4729                 {
4730                         Unsafe target = (Unsafe) t;
4731
4732                         target.Block = clonectx.LookupBlock (Block);
4733                 }
4734                 
4735                 public override object Accept (StructuralVisitor visitor)
4736                 {
4737                         return visitor.Visit (this);
4738                 }
4739         }
4740
4741         // 
4742         // Fixed statement
4743         //
4744         public class Fixed : Statement
4745         {
4746                 abstract class Emitter : ShimExpression
4747                 {
4748                         protected LocalVariable vi;
4749
4750                         protected Emitter (Expression expr, LocalVariable li)
4751                                 : base (expr)
4752                         {
4753                                 vi = li;
4754                         }
4755
4756                         public abstract void EmitExit (EmitContext ec);
4757                 }
4758
4759                 class ExpressionEmitter : Emitter {
4760                         public ExpressionEmitter (Expression converted, LocalVariable li) :
4761                                 base (converted, li)
4762                         {
4763                         }
4764
4765                         protected override Expression DoResolve (ResolveContext rc)
4766                         {
4767                                 throw new NotImplementedException ();
4768                         }
4769
4770                         public override void Emit (EmitContext ec) {
4771                                 //
4772                                 // Store pointer in pinned location
4773                                 //
4774                                 expr.Emit (ec);
4775                                 vi.EmitAssign (ec);
4776                         }
4777
4778                         public override void EmitExit (EmitContext ec)
4779                         {
4780                                 ec.EmitInt (0);
4781                                 ec.Emit (OpCodes.Conv_U);
4782                                 vi.EmitAssign (ec);
4783                         }
4784                 }
4785
4786                 class StringEmitter : Emitter
4787                 {
4788                         LocalVariable pinned_string;
4789
4790                         public StringEmitter (Expression expr, LocalVariable li, Location loc)
4791                                 : base (expr, li)
4792                         {
4793                         }
4794
4795                         protected override Expression DoResolve (ResolveContext rc)
4796                         {
4797                                 pinned_string = new LocalVariable (vi.Block, "$pinned",
4798                                         LocalVariable.Flags.FixedVariable | LocalVariable.Flags.CompilerGenerated | LocalVariable.Flags.Used,
4799                                         vi.Location);
4800                                 pinned_string.Type = rc.BuiltinTypes.String;
4801
4802                                 eclass = ExprClass.Variable;
4803                                 type = rc.BuiltinTypes.Int;
4804                                 return this;
4805                         }
4806
4807                         public override void Emit (EmitContext ec)
4808                         {
4809                                 pinned_string.CreateBuilder (ec);
4810
4811                                 expr.Emit (ec);
4812                                 pinned_string.EmitAssign (ec);
4813
4814                                 // TODO: Should use Binary::Add
4815                                 pinned_string.Emit (ec);
4816                                 ec.Emit (OpCodes.Conv_I);
4817
4818                                 var m = ec.Module.PredefinedMembers.RuntimeHelpersOffsetToStringData.Resolve (loc);
4819                                 if (m == null)
4820                                         return;
4821
4822                                 PropertyExpr pe = new PropertyExpr (m, pinned_string.Location);
4823                                 //pe.InstanceExpression = pinned_string;
4824                                 pe.Resolve (new ResolveContext (ec.MemberContext)).Emit (ec);
4825
4826                                 ec.Emit (OpCodes.Add);
4827                                 vi.EmitAssign (ec);
4828                         }
4829
4830                         public override void EmitExit (EmitContext ec)
4831                         {
4832                                 ec.EmitNull ();
4833                                 pinned_string.EmitAssign (ec);
4834                         }
4835                 }
4836
4837                 public class VariableDeclaration : BlockVariableDeclaration
4838                 {
4839                         public VariableDeclaration (FullNamedExpression type, LocalVariable li)
4840                                 : base (type, li)
4841                         {
4842                         }
4843
4844                         protected override Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
4845                         {
4846                                 if (!Variable.Type.IsPointer && li == Variable) {
4847                                         bc.Report.Error (209, TypeExpression.Location,
4848                                                 "The type of locals declared in a fixed statement must be a pointer type");
4849                                         return null;
4850                                 }
4851
4852                                 //
4853                                 // The rules for the possible declarators are pretty wise,
4854                                 // but the production on the grammar is more concise.
4855                                 //
4856                                 // So we have to enforce these rules here.
4857                                 //
4858                                 // We do not resolve before doing the case 1 test,
4859                                 // because the grammar is explicit in that the token &
4860                                 // is present, so we need to test for this particular case.
4861                                 //
4862
4863                                 if (initializer is Cast) {
4864                                         bc.Report.Error (254, initializer.Location, "The right hand side of a fixed statement assignment may not be a cast expression");
4865                                         return null;
4866                                 }
4867
4868                                 initializer = initializer.Resolve (bc);
4869
4870                                 if (initializer == null)
4871                                         return null;
4872
4873                                 //
4874                                 // Case 1: Array
4875                                 //
4876                                 if (initializer.Type.IsArray) {
4877                                         TypeSpec array_type = TypeManager.GetElementType (initializer.Type);
4878
4879                                         //
4880                                         // Provided that array_type is unmanaged,
4881                                         //
4882                                         if (!TypeManager.VerifyUnmanaged (bc.Module, array_type, loc))
4883                                                 return null;
4884
4885                                         //
4886                                         // and T* is implicitly convertible to the
4887                                         // pointer type given in the fixed statement.
4888                                         //
4889                                         ArrayPtr array_ptr = new ArrayPtr (initializer, array_type, loc);
4890
4891                                         Expression converted = Convert.ImplicitConversionRequired (bc, array_ptr.Resolve (bc), li.Type, loc);
4892                                         if (converted == null)
4893                                                 return null;
4894
4895                                         //
4896                                         // fixed (T* e_ptr = (e == null || e.Length == 0) ? null : converted [0])
4897                                         //
4898                                         converted = new Conditional (new BooleanExpression (new Binary (Binary.Operator.LogicalOr,
4899                                                 new Binary (Binary.Operator.Equality, initializer, new NullLiteral (loc), loc),
4900                                                 new Binary (Binary.Operator.Equality, new MemberAccess (initializer, "Length"), new IntConstant (bc.BuiltinTypes, 0, loc), loc), loc)),
4901                                                         new NullLiteral (loc),
4902                                                         converted, loc);
4903
4904                                         converted = converted.Resolve (bc);
4905
4906                                         return new ExpressionEmitter (converted, li);
4907                                 }
4908
4909                                 //
4910                                 // Case 2: string
4911                                 //
4912                                 if (initializer.Type.BuiltinType == BuiltinTypeSpec.Type.String) {
4913                                         return new StringEmitter (initializer, li, loc).Resolve (bc);
4914                                 }
4915
4916                                 // Case 3: fixed buffer
4917                                 if (initializer is FixedBufferPtr) {
4918                                         return new ExpressionEmitter (initializer, li);
4919                                 }
4920
4921                                 //
4922                                 // Case 4: & object.
4923                                 //
4924                                 bool already_fixed = true;
4925                                 Unary u = initializer as Unary;
4926                                 if (u != null && u.Oper == Unary.Operator.AddressOf) {
4927                                         IVariableReference vr = u.Expr as IVariableReference;
4928                                         if (vr == null || !vr.IsFixed) {
4929                                                 already_fixed = false;
4930                                         }
4931                                 }
4932
4933                                 if (already_fixed) {
4934                                         bc.Report.Error (213, loc, "You cannot use the fixed statement to take the address of an already fixed expression");
4935                                 }
4936
4937                                 initializer = Convert.ImplicitConversionRequired (bc, initializer, li.Type, loc);
4938                                 return new ExpressionEmitter (initializer, li);
4939                         }
4940                 }
4941
4942
4943                 VariableDeclaration decl;
4944                 Statement statement;
4945                 bool has_ret;
4946
4947                 public Fixed (VariableDeclaration decl, Statement stmt, Location l)
4948                 {
4949                         this.decl = decl;
4950                         statement = stmt;
4951                         loc = l;
4952                 }
4953
4954                 #region Properties
4955
4956                 public Statement Statement {
4957                         get {
4958                                 return statement;
4959                         }
4960                 }
4961
4962                 public BlockVariableDeclaration Variables {
4963                         get {
4964                                 return decl;
4965                         }
4966                 }
4967
4968                 #endregion
4969
4970                 public override bool Resolve (BlockContext ec)
4971                 {
4972                         using (ec.Set (ResolveContext.Options.FixedInitializerScope)) {
4973                                 if (!decl.Resolve (ec))
4974                                         return false;
4975                         }
4976
4977                         ec.StartFlowBranching (FlowBranching.BranchingType.Conditional, loc);
4978                         bool ok = statement.Resolve (ec);
4979                         bool flow_unreachable = ec.EndFlowBranching ();
4980                         has_ret = flow_unreachable;
4981
4982                         return ok;
4983                 }
4984                 
4985                 protected override void DoEmit (EmitContext ec)
4986                 {
4987                         decl.Variable.CreateBuilder (ec);
4988                         decl.Initializer.Emit (ec);
4989                         if (decl.Declarators != null) {
4990                                 foreach (var d in decl.Declarators) {
4991                                         d.Variable.CreateBuilder (ec);
4992                                         d.Initializer.Emit (ec);
4993                                 }
4994                         }
4995
4996                         statement.Emit (ec);
4997
4998                         if (has_ret)
4999                                 return;
5000
5001                         //
5002                         // Clear the pinned variable
5003                         //
5004                         ((Emitter) decl.Initializer).EmitExit (ec);
5005                         if (decl.Declarators != null) {
5006                                 foreach (var d in decl.Declarators) {
5007                                         ((Emitter)d.Initializer).EmitExit (ec);
5008                                 }
5009                         }
5010                 }
5011
5012                 protected override void CloneTo (CloneContext clonectx, Statement t)
5013                 {
5014                         Fixed target = (Fixed) t;
5015
5016                         target.decl = (VariableDeclaration) decl.Clone (clonectx);
5017                         target.statement = statement.Clone (clonectx);
5018                 }
5019                 
5020                 public override object Accept (StructuralVisitor visitor)
5021                 {
5022                         return visitor.Visit (this);
5023                 }
5024         }
5025
5026         public class Catch : Statement
5027         {
5028                 Block block;
5029                 LocalVariable li;
5030                 FullNamedExpression type_expr;
5031                 CompilerAssign assign;
5032                 TypeSpec type;
5033                 
5034                 public Catch (Block block, Location loc)
5035                 {
5036                         this.block = block;
5037                         this.loc = loc;
5038                 }
5039
5040                 #region Properties
5041
5042                 public Block Block {
5043                         get {
5044                                 return block;
5045                         }
5046                 }
5047
5048                 public TypeSpec CatchType {
5049                         get {
5050                                 return type;
5051                         }
5052                 }
5053
5054                 public bool IsGeneral {
5055                         get {
5056                                 return type_expr == null;
5057                         }
5058                 }
5059
5060                 public FullNamedExpression TypeExpression {
5061                         get {
5062                                 return type_expr;
5063                         }
5064                         set {
5065                                 type_expr = value;
5066                         }
5067                 }
5068
5069                 public LocalVariable Variable {
5070                         get {
5071                                 return li;
5072                         }
5073                         set {
5074                                 li = value;
5075                         }
5076                 }
5077
5078                 #endregion
5079
5080                 protected override void DoEmit (EmitContext ec)
5081                 {
5082                         if (IsGeneral)
5083                                 ec.BeginCatchBlock (ec.BuiltinTypes.Object);
5084                         else
5085                                 ec.BeginCatchBlock (CatchType);
5086
5087                         if (li != null) {
5088                                 li.CreateBuilder (ec);
5089
5090                                 //
5091                                 // Special case hoisted catch variable, we have to use a temporary variable
5092                                 // to pass via anonymous storey initialization with the value still on top
5093                                 // of the stack
5094                                 //
5095                                 if (li.HoistedVariant != null) {
5096                                         LocalTemporary lt = new LocalTemporary (li.Type);
5097                                         SymbolWriter.OpenCompilerGeneratedBlock (ec);
5098                                         lt.Store (ec);
5099                                         SymbolWriter.CloseCompilerGeneratedBlock (ec);
5100
5101                                         // switch to assigning from the temporary variable and not from top of the stack
5102                                         assign.UpdateSource (lt);
5103                                 }
5104                         } else {
5105                                 SymbolWriter.OpenCompilerGeneratedBlock (ec);
5106                                 ec.Emit (OpCodes.Pop);
5107                                 SymbolWriter.CloseCompilerGeneratedBlock (ec);
5108                         }
5109
5110                         Block.Emit (ec);
5111                 }
5112
5113                 public override bool Resolve (BlockContext ec)
5114                 {
5115                         using (ec.With (ResolveContext.Options.CatchScope, true)) {
5116                                 if (type_expr != null) {
5117                                         type = type_expr.ResolveAsType (ec);
5118                                         if (type == null)
5119                                                 return false;
5120
5121                                         if (type.BuiltinType != BuiltinTypeSpec.Type.Exception && !TypeSpec.IsBaseClass (type, ec.BuiltinTypes.Exception, false)) {
5122                                                 ec.Report.Error (155, loc, "The type caught or thrown must be derived from System.Exception");
5123                                         } else if (li != null) {
5124                                                 li.Type = type;
5125                                                 li.PrepareForFlowAnalysis (ec);
5126
5127                                                 // source variable is at the top of the stack
5128                                                 Expression source = new EmptyExpression (li.Type);
5129                                                 if (li.Type.IsGenericParameter)
5130                                                         source = new UnboxCast (source, li.Type);
5131
5132                                                 assign = new CompilerAssign (new LocalVariableReference (li, loc), source, loc);
5133                                                 Block.AddScopeStatement (new StatementExpression (assign));
5134                                         }
5135                                 }
5136
5137                                 return Block.Resolve (ec);
5138                         }
5139                 }
5140
5141                 protected override void CloneTo (CloneContext clonectx, Statement t)
5142                 {
5143                         Catch target = (Catch) t;
5144
5145                         if (type_expr != null)
5146                                 target.type_expr = (FullNamedExpression) type_expr.Clone (clonectx);
5147
5148                         target.block = clonectx.LookupBlock (block);
5149                 }
5150         }
5151
5152         public class TryFinally : TryFinallyBlock
5153         {
5154                 Block fini;
5155
5156                 public TryFinally (Statement stmt, Block fini, Location loc)
5157                          : base (stmt, loc)
5158                 {
5159                         this.fini = fini;
5160                 }
5161
5162                 public Block Finallyblock {
5163                         get {
5164                                 return fini;
5165                         }
5166                 }
5167
5168                 public override bool Resolve (BlockContext ec)
5169                 {
5170                         bool ok = true;
5171
5172                         ec.StartFlowBranching (this);
5173
5174                         if (!stmt.Resolve (ec))
5175                                 ok = false;
5176
5177                         if (ok)
5178                                 ec.CurrentBranching.CreateSibling (fini, FlowBranching.SiblingType.Finally);
5179                         using (ec.With (ResolveContext.Options.FinallyScope, true)) {
5180                                 if (!fini.Resolve (ec))
5181                                         ok = false;
5182                         }
5183
5184                         ec.EndFlowBranching ();
5185
5186                         ok &= base.Resolve (ec);
5187
5188                         return ok;
5189                 }
5190
5191                 protected override void EmitTryBody (EmitContext ec)
5192                 {
5193                         stmt.Emit (ec);
5194                 }
5195
5196                 protected override void EmitFinallyBody (EmitContext ec)
5197                 {
5198                         fini.Emit (ec);
5199                 }
5200
5201                 protected override void CloneTo (CloneContext clonectx, Statement t)
5202                 {
5203                         TryFinally target = (TryFinally) t;
5204
5205                         target.stmt = (Statement) stmt.Clone (clonectx);
5206                         if (fini != null)
5207                                 target.fini = clonectx.LookupBlock (fini);
5208                 }
5209                 
5210                 public override object Accept (StructuralVisitor visitor)
5211                 {
5212                         return visitor.Visit (this);
5213                 }
5214         }
5215
5216         public class TryCatch : ExceptionStatement
5217         {
5218                 public Block Block;
5219                 List<Catch> clauses;
5220                 readonly bool inside_try_finally;
5221
5222                 public TryCatch (Block block, List<Catch> catch_clauses, Location l, bool inside_try_finally)
5223                         : base (l)
5224                 {
5225                         this.Block = block;
5226                         this.clauses = catch_clauses;
5227                         this.inside_try_finally = inside_try_finally;
5228                 }
5229
5230                 public List<Catch> Clauses {
5231                         get {
5232                                 return clauses;
5233                         }
5234                 }
5235
5236                 public bool IsTryCatchFinally {
5237                         get {
5238                                 return inside_try_finally;
5239                         }
5240                 }
5241
5242                 public override bool Resolve (BlockContext ec)
5243                 {
5244                         bool ok = true;
5245
5246                         ec.StartFlowBranching (this);
5247
5248                         if (!Block.Resolve (ec))
5249                                 ok = false;
5250
5251                         for (int i = 0; i < clauses.Count; ++i) {
5252                                 var c = clauses[i];
5253                                 ec.CurrentBranching.CreateSibling (c.Block, FlowBranching.SiblingType.Catch);
5254
5255                                 if (!c.Resolve (ec)) {
5256                                         ok = false;
5257                                         continue;
5258                                 }
5259
5260                                 TypeSpec resolved_type = c.CatchType;
5261                                 for (int ii = 0; ii < clauses.Count; ++ii) {
5262                                         if (ii == i)
5263                                                 continue;
5264
5265                                         if (clauses[ii].IsGeneral) {
5266                                                 if (resolved_type.BuiltinType != BuiltinTypeSpec.Type.Exception)
5267                                                         continue;
5268
5269                                                 if (!ec.Module.DeclaringAssembly.WrapNonExceptionThrows)
5270                                                         continue;
5271
5272                                                 if (!ec.Module.PredefinedAttributes.RuntimeCompatibility.IsDefined)
5273                                                         continue;
5274
5275                                                 ec.Report.Warning (1058, 1, c.loc,
5276                                                         "A previous catch clause already catches all exceptions. All non-exceptions thrown will be wrapped in a `System.Runtime.CompilerServices.RuntimeWrappedException'");
5277
5278                                                 continue;
5279                                         }
5280
5281                                         if (ii >= i)
5282                                                 continue;
5283
5284                                         var ct = clauses[ii].CatchType;
5285                                         if (ct == null)
5286                                                 continue;
5287
5288                                         if (resolved_type == ct || TypeSpec.IsBaseClass (resolved_type, ct, true)) {
5289                                                 ec.Report.Error (160, c.loc,
5290                                                         "A previous catch clause already catches all exceptions of this or a super type `{0}'",
5291                                                         ct.GetSignatureForError ());
5292                                                 ok = false;
5293                                         }
5294                                 }
5295                         }
5296
5297                         ec.EndFlowBranching ();
5298
5299                         return base.Resolve (ec) && ok;
5300                 }
5301
5302                 protected sealed override void DoEmit (EmitContext ec)
5303                 {
5304                         if (!inside_try_finally)
5305                                 EmitTryBodyPrepare (ec);
5306
5307                         Block.Emit (ec);
5308
5309                         foreach (Catch c in clauses)
5310                                 c.Emit (ec);
5311
5312                         if (!inside_try_finally)
5313                                 ec.EndExceptionBlock ();
5314                 }
5315
5316                 protected override void CloneTo (CloneContext clonectx, Statement t)
5317                 {
5318                         TryCatch target = (TryCatch) t;
5319
5320                         target.Block = clonectx.LookupBlock (Block);
5321                         if (clauses != null){
5322                                 target.clauses = new List<Catch> ();
5323                                 foreach (Catch c in clauses)
5324                                         target.clauses.Add ((Catch) c.Clone (clonectx));
5325                         }
5326                 }
5327
5328                 public override object Accept (StructuralVisitor visitor)
5329                 {
5330                         return visitor.Visit (this);
5331                 }
5332         }
5333
5334         public class Using : TryFinallyBlock
5335         {
5336                 public class VariableDeclaration : BlockVariableDeclaration
5337                 {
5338                         Statement dispose_call;
5339
5340                         public VariableDeclaration (FullNamedExpression type, LocalVariable li)
5341                                 : base (type, li)
5342                         {
5343                         }
5344
5345                         public VariableDeclaration (LocalVariable li, Location loc)
5346                                 : base (li)
5347                         {
5348                                 this.loc = loc;
5349                         }
5350
5351                         public VariableDeclaration (Expression expr)
5352                                 : base (null)
5353                         {
5354                                 loc = expr.Location;
5355                                 Initializer = expr;
5356                         }
5357
5358                         #region Properties
5359
5360                         public bool IsNested { get; private set; }
5361
5362                         #endregion
5363
5364                         public void EmitDispose (EmitContext ec)
5365                         {
5366                                 dispose_call.Emit (ec);
5367                         }
5368
5369                         public override bool Resolve (BlockContext bc)
5370                         {
5371                                 if (IsNested)
5372                                         return true;
5373
5374                                 return base.Resolve (bc, false);
5375                         }
5376
5377                         public Expression ResolveExpression (BlockContext bc)
5378                         {
5379                                 var e = Initializer.Resolve (bc);
5380                                 if (e == null)
5381                                         return null;
5382
5383                                 li = LocalVariable.CreateCompilerGenerated (e.Type, bc.CurrentBlock, loc);
5384                                 Initializer = ResolveInitializer (bc, Variable, e);
5385                                 return e;
5386                         }
5387
5388                         protected override Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
5389                         {
5390                                 if (li.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
5391                                         initializer = initializer.Resolve (bc);
5392                                         if (initializer == null)
5393                                                 return null;
5394
5395                                         // Once there is dynamic used defer conversion to runtime even if we know it will never succeed
5396                                         Arguments args = new Arguments (1);
5397                                         args.Add (new Argument (initializer));
5398                                         initializer = new DynamicConversion (bc.BuiltinTypes.IDisposable, 0, args, initializer.Location).Resolve (bc);
5399                                         if (initializer == null)
5400                                                 return null;
5401
5402                                         var var = LocalVariable.CreateCompilerGenerated (initializer.Type, bc.CurrentBlock, loc);
5403                                         dispose_call = CreateDisposeCall (bc, var);
5404                                         dispose_call.Resolve (bc);
5405
5406                                         return base.ResolveInitializer (bc, li, new SimpleAssign (var.CreateReferenceExpression (bc, loc), initializer, loc));
5407                                 }
5408
5409                                 if (li == Variable) {
5410                                         CheckIDiposableConversion (bc, li, initializer);
5411                                         dispose_call = CreateDisposeCall (bc, li);
5412                                         dispose_call.Resolve (bc);
5413                                 }
5414
5415                                 return base.ResolveInitializer (bc, li, initializer);
5416                         }
5417
5418                         protected virtual void CheckIDiposableConversion (BlockContext bc, LocalVariable li, Expression initializer)
5419                         {
5420                                 var type = li.Type;
5421
5422                                 if (type.BuiltinType != BuiltinTypeSpec.Type.IDisposable && !type.ImplementsInterface (bc.BuiltinTypes.IDisposable, false)) {
5423                                         if (type.IsNullableType) {
5424                                                 // it's handled in CreateDisposeCall
5425                                                 return;
5426                                         }
5427
5428                                         bc.Report.SymbolRelatedToPreviousError (type);
5429                                         var loc = type_expr == null ? initializer.Location : type_expr.Location;
5430                                         bc.Report.Error (1674, loc, "`{0}': type used in a using statement must be implicitly convertible to `System.IDisposable'",
5431                                                 type.GetSignatureForError ());
5432
5433                                         return;
5434                                 }
5435                         }
5436
5437                         protected virtual Statement CreateDisposeCall (BlockContext bc, LocalVariable lv)
5438                         {
5439                                 var lvr = lv.CreateReferenceExpression (bc, lv.Location);
5440                                 var type = lv.Type;
5441                                 var loc = lv.Location;
5442
5443                                 var idt = bc.BuiltinTypes.IDisposable;
5444                                 var m = bc.Module.PredefinedMembers.IDisposableDispose.Resolve (loc);
5445
5446                                 var dispose_mg = MethodGroupExpr.CreatePredefined (m, idt, loc);
5447                                 dispose_mg.InstanceExpression = type.IsNullableType ?
5448                                         new Cast (new TypeExpression (idt, loc), lvr, loc).Resolve (bc) :
5449                                         lvr;
5450
5451                                 Statement dispose = new StatementExpression (new Invocation (dispose_mg, null));
5452
5453                                 // Add conditional call when disposing possible null variable
5454                                 if (!type.IsStruct || type.IsNullableType)
5455                                         dispose = new If (new Binary (Binary.Operator.Inequality, lvr, new NullLiteral (loc), loc), dispose, loc);
5456
5457                                 return dispose;
5458                         }
5459
5460                         public void ResolveDeclaratorInitializer (BlockContext bc)
5461                         {
5462                                 Initializer = base.ResolveInitializer (bc, Variable, Initializer);
5463                         }
5464
5465                         public Statement RewriteUsingDeclarators (BlockContext bc, Statement stmt)
5466                         {
5467                                 for (int i = declarators.Count - 1; i >= 0; --i) {
5468                                         var d = declarators [i];
5469                                         var vd = new VariableDeclaration (d.Variable, type_expr.Location);
5470                                         vd.Initializer = d.Initializer;
5471                                         vd.IsNested = true;
5472                                         vd.dispose_call = CreateDisposeCall (bc, d.Variable);
5473                                         vd.dispose_call.Resolve (bc);
5474
5475                                         stmt = new Using (vd, stmt, d.Variable.Location);
5476                                 }
5477
5478                                 declarators = null;
5479                                 return stmt;
5480                         }       
5481
5482                         public override object Accept (StructuralVisitor visitor)
5483                         {
5484                                 return visitor.Visit (this);
5485                         }       
5486                 }
5487
5488                 VariableDeclaration decl;
5489
5490                 public Using (VariableDeclaration decl, Statement stmt, Location loc)
5491                         : base (stmt, loc)
5492                 {
5493                         this.decl = decl;
5494                 }
5495
5496                 public Using (Expression expr, Statement stmt, Location loc)
5497                         : base (stmt, loc)
5498                 {
5499                         this.decl = new VariableDeclaration (expr);
5500                 }
5501
5502                 #region Properties
5503
5504                 public Expression Expr {
5505                         get {
5506                                 return decl.Variable == null ? decl.Initializer : null;
5507                         }
5508                 }
5509
5510                 public BlockVariableDeclaration Variables {
5511                         get {
5512                                 return decl;
5513                         }
5514                 }
5515
5516                 #endregion
5517
5518                 protected override void EmitTryBodyPrepare (EmitContext ec)
5519                 {
5520                         decl.Emit (ec);
5521                         base.EmitTryBodyPrepare (ec);
5522                 }
5523
5524                 protected override void EmitTryBody (EmitContext ec)
5525                 {
5526                         stmt.Emit (ec);
5527                 }
5528
5529                 protected override void EmitFinallyBody (EmitContext ec)
5530                 {
5531                         decl.EmitDispose (ec);
5532                 }
5533
5534                 public override bool Resolve (BlockContext ec)
5535                 {
5536                         VariableReference vr;
5537                         bool vr_locked = false;
5538
5539                         using (ec.Set (ResolveContext.Options.UsingInitializerScope)) {
5540                                 if (decl.Variable == null) {
5541                                         vr = decl.ResolveExpression (ec) as VariableReference;
5542                                         if (vr != null) {
5543                                                 vr_locked = vr.IsLockedByStatement;
5544                                                 vr.IsLockedByStatement = true;
5545                                         }
5546                                 } else {
5547                                         if (decl.IsNested) {
5548                                                 decl.ResolveDeclaratorInitializer (ec);
5549                                         } else {
5550                                                 if (!decl.Resolve (ec))
5551                                                         return false;
5552
5553                                                 if (decl.Declarators != null) {
5554                                                         stmt = decl.RewriteUsingDeclarators (ec, stmt);
5555                                                 }
5556                                         }
5557
5558                                         vr = null;
5559                                 }
5560                         }
5561
5562                         ec.StartFlowBranching (this);
5563
5564                         stmt.Resolve (ec);
5565
5566                         ec.EndFlowBranching ();
5567
5568                         if (vr != null)
5569                                 vr.IsLockedByStatement = vr_locked;
5570
5571                         base.Resolve (ec);
5572
5573                         return true;
5574                 }
5575
5576                 protected override void CloneTo (CloneContext clonectx, Statement t)
5577                 {
5578                         Using target = (Using) t;
5579
5580                         target.decl = (VariableDeclaration) decl.Clone (clonectx);
5581                         target.stmt = stmt.Clone (clonectx);
5582                 }
5583
5584                 public override object Accept (StructuralVisitor visitor)
5585                 {
5586                         return visitor.Visit (this);
5587                 }
5588         }
5589
5590         /// <summary>
5591         ///   Implementation of the foreach C# statement
5592         /// </summary>
5593         public class Foreach : Statement
5594         {
5595                 sealed class ArrayForeach : Statement
5596                 {
5597                         readonly Foreach for_each;
5598                         readonly Statement statement;
5599
5600                         Expression conv;
5601                         TemporaryVariableReference[] lengths;
5602                         Expression [] length_exprs;
5603                         StatementExpression[] counter;
5604                         TemporaryVariableReference[] variables;
5605
5606                         TemporaryVariableReference copy;
5607                         Expression access;
5608                         LocalVariableReference variable;
5609
5610                         public ArrayForeach (Foreach @foreach, int rank)
5611                         {
5612                                 for_each = @foreach;
5613                                 statement = for_each.statement;
5614                                 loc = @foreach.loc;
5615
5616                                 counter = new StatementExpression[rank];
5617                                 variables = new TemporaryVariableReference[rank];
5618                                 length_exprs = new Expression [rank];
5619
5620                                 //
5621                                 // Only use temporary length variables when dealing with
5622                                 // multi-dimensional arrays
5623                                 //
5624                                 if (rank > 1)
5625                                         lengths = new TemporaryVariableReference [rank];
5626                         }
5627
5628                         protected override void CloneTo (CloneContext clonectx, Statement target)
5629                         {
5630                                 throw new NotImplementedException ();
5631                         }
5632
5633                         public override bool Resolve (BlockContext ec)
5634                         {
5635                                 Block variables_block = for_each.variable.Block;
5636                                 copy = TemporaryVariableReference.Create (for_each.expr.Type, variables_block, loc);
5637                                 copy.Resolve (ec);
5638
5639                                 int rank = length_exprs.Length;
5640                                 Arguments list = new Arguments (rank);
5641                                 for (int i = 0; i < rank; i++) {
5642                                         var v = TemporaryVariableReference.Create (ec.BuiltinTypes.Int, variables_block, loc);
5643                                         variables[i] = v;
5644                                         counter[i] = new StatementExpression (new UnaryMutator (UnaryMutator.Mode.PostIncrement, v, loc));
5645                                         counter[i].Resolve (ec);
5646
5647                                         if (rank == 1) {
5648                                                 length_exprs [i] = new MemberAccess (copy, "Length").Resolve (ec);
5649                                         } else {
5650                                                 lengths[i] = TemporaryVariableReference.Create (ec.BuiltinTypes.Int, variables_block, loc);
5651                                                 lengths[i].Resolve (ec);
5652
5653                                                 Arguments args = new Arguments (1);
5654                                                 args.Add (new Argument (new IntConstant (ec.BuiltinTypes, i, loc)));
5655                                                 length_exprs [i] = new Invocation (new MemberAccess (copy, "GetLength"), args).Resolve (ec);
5656                                         }
5657
5658                                         list.Add (new Argument (v));
5659                                 }
5660
5661                                 access = new ElementAccess (copy, list, loc).Resolve (ec);
5662                                 if (access == null)
5663                                         return false;
5664
5665                                 TypeSpec var_type;
5666                                 if (for_each.type is VarExpr) {
5667                                         // Infer implicitly typed local variable from foreach array type
5668                                         var_type = access.Type;
5669                                 } else {
5670                                         var_type = for_each.type.ResolveAsType (ec);
5671                                 }
5672
5673                                 if (var_type == null)
5674                                         return false;
5675
5676                                 conv = Convert.ExplicitConversion (ec, access, var_type, loc);
5677                                 if (conv == null)
5678                                         return false;
5679
5680                                 bool ok = true;
5681
5682                                 ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
5683                                 ec.CurrentBranching.CreateSibling ();
5684
5685                                 for_each.variable.Type = conv.Type;
5686                                 variable = new LocalVariableReference (for_each.variable, loc);
5687                                 variable.Resolve (ec);
5688
5689                                 ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc);
5690                                 if (!statement.Resolve (ec))
5691                                         ok = false;
5692                                 ec.EndFlowBranching ();
5693
5694                                 // There's no direct control flow from the end of the embedded statement to the end of the loop
5695                                 ec.CurrentBranching.CurrentUsageVector.Goto ();
5696
5697                                 ec.EndFlowBranching ();
5698
5699                                 return ok;
5700                         }
5701
5702                         protected override void DoEmit (EmitContext ec)
5703                         {
5704                                 copy.EmitAssign (ec, for_each.expr);
5705
5706                                 int rank = length_exprs.Length;
5707                                 Label[] test = new Label [rank];
5708                                 Label[] loop = new Label [rank];
5709
5710                                 for (int i = 0; i < rank; i++) {
5711                                         test [i] = ec.DefineLabel ();
5712                                         loop [i] = ec.DefineLabel ();
5713
5714                                         if (lengths != null)
5715                                                 lengths [i].EmitAssign (ec, length_exprs [i]);
5716                                 }
5717
5718                                 IntConstant zero = new IntConstant (ec.BuiltinTypes, 0, loc);
5719                                 for (int i = 0; i < rank; i++) {
5720                                         variables [i].EmitAssign (ec, zero);
5721
5722                                         ec.Emit (OpCodes.Br, test [i]);
5723                                         ec.MarkLabel (loop [i]);
5724                                 }
5725
5726                                 variable.local_info.CreateBuilder (ec);
5727                                 variable.EmitAssign (ec, conv, false, false);
5728
5729                                 statement.Emit (ec);
5730
5731                                 ec.MarkLabel (ec.LoopBegin);
5732
5733                                 for (int i = rank - 1; i >= 0; i--){
5734                                         counter [i].Emit (ec);
5735
5736                                         ec.MarkLabel (test [i]);
5737                                         variables [i].Emit (ec);
5738
5739                                         if (lengths != null)
5740                                                 lengths [i].Emit (ec);
5741                                         else
5742                                                 length_exprs [i].Emit (ec);
5743
5744                                         ec.Emit (OpCodes.Blt, loop [i]);
5745                                 }
5746
5747                                 ec.MarkLabel (ec.LoopEnd);
5748                         }
5749                 }
5750
5751                 sealed class CollectionForeach : Statement, OverloadResolver.IErrorHandler
5752                 {
5753                         class Body : Statement
5754                         {
5755                                 TypeSpec type;
5756                                 LocalVariableReference variable;
5757                                 Expression current, conv;
5758                                 Statement statement;
5759
5760                                 public Body (TypeSpec type, LocalVariable variable,
5761                                                                    Expression current, Statement statement,
5762                                                                    Location loc)
5763                                 {
5764                                         this.type = type;
5765                                         this.variable = new LocalVariableReference (variable, loc);
5766                                         this.current = current;
5767                                         this.statement = statement;
5768                                         this.loc = loc;
5769                                 }
5770
5771                                 protected override void CloneTo (CloneContext clonectx, Statement target)
5772                                 {
5773                                         throw new NotImplementedException ();
5774                                 }
5775
5776                                 public override bool Resolve (BlockContext ec)
5777                                 {
5778                                         current = current.Resolve (ec);
5779                                         if (current == null)
5780                                                 return false;
5781
5782                                         conv = Convert.ExplicitConversion (ec, current, type, loc);
5783                                         if (conv == null)
5784                                                 return false;
5785
5786                                         variable.local_info.Type = conv.Type;
5787                                         variable.Resolve (ec);
5788
5789                                         if (!statement.Resolve (ec))
5790                                                 return false;
5791
5792                                         return true;
5793                                 }
5794
5795                                 protected override void DoEmit (EmitContext ec)
5796                                 {
5797                                         variable.local_info.CreateBuilder (ec);
5798                                         variable.EmitAssign (ec, conv, false, false);
5799
5800                                         statement.Emit (ec);
5801                                 }
5802                         }
5803
5804                         class RuntimeDispose : Using.VariableDeclaration
5805                         {
5806                                 public RuntimeDispose (LocalVariable lv, Location loc)
5807                                         : base (lv, loc)
5808                                 {
5809                                 }
5810
5811                                 protected override void CheckIDiposableConversion (BlockContext bc, LocalVariable li, Expression initializer)
5812                                 {
5813                                         // Defered to runtime check
5814                                 }
5815
5816                                 protected override Statement CreateDisposeCall (BlockContext bc, LocalVariable lv)
5817                                 {
5818                                         var idt = bc.BuiltinTypes.IDisposable;
5819
5820                                         //
5821                                         // Fabricates code like
5822                                         //
5823                                         // if ((temp = vr as IDisposable) != null) temp.Dispose ();
5824                                         //
5825
5826                                         var dispose_variable = LocalVariable.CreateCompilerGenerated (idt, bc.CurrentBlock, loc);
5827
5828                                         var idisaposable_test = new Binary (Binary.Operator.Inequality, new CompilerAssign (
5829                                                 dispose_variable.CreateReferenceExpression (bc, loc),
5830                                                 new As (lv.CreateReferenceExpression (bc, loc), new TypeExpression (dispose_variable.Type, loc), loc),
5831                                                 loc), new NullLiteral (loc), loc);
5832
5833                                         var m = bc.Module.PredefinedMembers.IDisposableDispose.Resolve (loc);
5834
5835                                         var dispose_mg = MethodGroupExpr.CreatePredefined (m, idt, loc);
5836                                         dispose_mg.InstanceExpression = dispose_variable.CreateReferenceExpression (bc, loc);
5837
5838                                         Statement dispose = new StatementExpression (new Invocation (dispose_mg, null));
5839                                         return new If (idisaposable_test, dispose, loc);
5840                                 }
5841                         }
5842
5843                         LocalVariable variable;
5844                         Expression expr;
5845                         Statement statement;
5846                         Expression var_type;
5847                         ExpressionStatement init;
5848                         TemporaryVariableReference enumerator_variable;
5849                         bool ambiguous_getenumerator_name;
5850
5851                         public CollectionForeach (Expression var_type, LocalVariable var, Expression expr, Statement stmt, Location l)
5852                         {
5853                                 this.var_type = var_type;
5854                                 this.variable = var;
5855                                 this.expr = expr;
5856                                 statement = stmt;
5857                                 loc = l;
5858                         }
5859
5860                         protected override void CloneTo (CloneContext clonectx, Statement target)
5861                         {
5862                                 throw new NotImplementedException ();
5863                         }
5864
5865                         void Error_WrongEnumerator (ResolveContext rc, MethodSpec enumerator)
5866                         {
5867                                 rc.Report.SymbolRelatedToPreviousError (enumerator);
5868                                 rc.Report.Error (202, loc,
5869                                         "foreach statement requires that the return type `{0}' of `{1}' must have a suitable public MoveNext method and public Current property",
5870                                                 enumerator.ReturnType.GetSignatureForError (), enumerator.GetSignatureForError ());
5871                         }
5872
5873                         MethodGroupExpr ResolveGetEnumerator (ResolveContext rc)
5874                         {
5875                                 //
5876                                 // Option 1: Try to match by name GetEnumerator first
5877                                 //
5878                                 var mexpr = Expression.MemberLookup (rc, false, expr.Type,
5879                                         "GetEnumerator", 0, Expression.MemberLookupRestrictions.ExactArity, loc);               // TODO: What if CS0229 ?
5880
5881                                 var mg = mexpr as MethodGroupExpr;
5882                                 if (mg != null) {
5883                                         mg.InstanceExpression = expr;
5884                                         Arguments args = new Arguments (0);
5885                                         mg = mg.OverloadResolve (rc, ref args, this, OverloadResolver.Restrictions.None);
5886
5887                                         // For ambiguous GetEnumerator name warning CS0278 was reported, but Option 2 could still apply
5888                                         if (ambiguous_getenumerator_name)
5889                                                 mg = null;
5890
5891                                         if (mg != null && args.Count == 0 && !mg.BestCandidate.IsStatic && mg.BestCandidate.IsPublic) {
5892                                                 return mg;
5893                                         }
5894                                 }
5895
5896                                 //
5897                                 // Option 2: Try to match using IEnumerable interfaces with preference of generic version
5898                                 //
5899                                 var t = expr.Type;
5900                                 PredefinedMember<MethodSpec> iface_candidate = null;
5901                                 var ptypes = rc.Module.PredefinedTypes;
5902                                 var gen_ienumerable = ptypes.IEnumerableGeneric;
5903                                 if (!gen_ienumerable.Define ())
5904                                         gen_ienumerable = null;
5905
5906                                 do {
5907                                         var ifaces = t.Interfaces;
5908                                         if (ifaces != null) {
5909                                                 foreach (var iface in ifaces) {
5910                                                         if (gen_ienumerable != null && iface.MemberDefinition == gen_ienumerable.TypeSpec.MemberDefinition) {
5911                                                                 if (iface_candidate != null && iface_candidate != rc.Module.PredefinedMembers.IEnumerableGetEnumerator) {
5912                                                                         rc.Report.SymbolRelatedToPreviousError (expr.Type);
5913                                                                         rc.Report.Error (1640, loc,
5914                                                                                 "foreach statement cannot operate on variables of type `{0}' because it contains multiple implementation of `{1}'. Try casting to a specific implementation",
5915                                                                                 expr.Type.GetSignatureForError (), gen_ienumerable.TypeSpec.GetSignatureForError ());
5916
5917                                                                         return null;
5918                                                                 }
5919
5920                                                                 // TODO: Cache this somehow
5921                                                                 iface_candidate = new PredefinedMember<MethodSpec> (rc.Module, iface,
5922                                                                         MemberFilter.Method ("GetEnumerator", 0, ParametersCompiled.EmptyReadOnlyParameters, null));
5923
5924                                                                 continue;
5925                                                         }
5926
5927                                                         if (iface.BuiltinType == BuiltinTypeSpec.Type.IEnumerable && iface_candidate == null) {
5928                                                                 iface_candidate = rc.Module.PredefinedMembers.IEnumerableGetEnumerator;
5929                                                         }
5930                                                 }
5931                                         }
5932
5933                                         if (t.IsGenericParameter)
5934                                                 t = t.BaseType;
5935                                         else
5936                                                 t = null;
5937
5938                                 } while (t != null);
5939
5940                                 if (iface_candidate == null) {
5941                                         if (expr.Type != InternalType.ErrorType) {
5942                                                 rc.Report.Error (1579, loc,
5943                                                         "foreach statement cannot operate on variables of type `{0}' because it does not contain a definition for `{1}' or is inaccessible",
5944                                                         expr.Type.GetSignatureForError (), "GetEnumerator");
5945                                         }
5946
5947                                         return null;
5948                                 }
5949
5950                                 var method = iface_candidate.Resolve (loc);
5951                                 if (method == null)
5952                                         return null;
5953
5954                                 mg = MethodGroupExpr.CreatePredefined (method, expr.Type, loc);
5955                                 mg.InstanceExpression = expr;
5956                                 return mg;
5957                         }
5958
5959                         MethodGroupExpr ResolveMoveNext (ResolveContext rc, MethodSpec enumerator)
5960                         {
5961                                 var ms = MemberCache.FindMember (enumerator.ReturnType,
5962                                         MemberFilter.Method ("MoveNext", 0, ParametersCompiled.EmptyReadOnlyParameters, rc.BuiltinTypes.Bool),
5963                                         BindingRestriction.InstanceOnly) as MethodSpec;
5964
5965                                 if (ms == null || !ms.IsPublic) {
5966                                         Error_WrongEnumerator (rc, enumerator);
5967                                         return null;
5968                                 }
5969
5970                                 return MethodGroupExpr.CreatePredefined (ms, enumerator.ReturnType, loc);
5971                         }
5972
5973                         PropertySpec ResolveCurrent (ResolveContext rc, MethodSpec enumerator)
5974                         {
5975                                 var ps = MemberCache.FindMember (enumerator.ReturnType,
5976                                         MemberFilter.Property ("Current", null),
5977                                         BindingRestriction.InstanceOnly) as PropertySpec;
5978
5979                                 if (ps == null || !ps.IsPublic) {
5980                                         Error_WrongEnumerator (rc, enumerator);
5981                                         return null;
5982                                 }
5983
5984                                 return ps;
5985                         }
5986
5987                         public override bool Resolve (BlockContext ec)
5988                         {
5989                                 bool is_dynamic = expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
5990
5991                                 if (is_dynamic) {
5992                                         expr = Convert.ImplicitConversionRequired (ec, expr, ec.BuiltinTypes.IEnumerable, loc);
5993                                 } else if (expr.Type.IsNullableType) {
5994                                         expr = new Nullable.UnwrapCall (expr).Resolve (ec);
5995                                 }
5996
5997                                 var get_enumerator_mg = ResolveGetEnumerator (ec);
5998                                 if (get_enumerator_mg == null) {
5999                                         return false;
6000                                 }
6001
6002                                 var get_enumerator = get_enumerator_mg.BestCandidate;
6003                                 enumerator_variable = TemporaryVariableReference.Create (get_enumerator.ReturnType, variable.Block, loc);
6004                                 enumerator_variable.Resolve (ec);
6005
6006                                 // Prepare bool MoveNext ()
6007                                 var move_next_mg = ResolveMoveNext (ec, get_enumerator);
6008                                 if (move_next_mg == null) {
6009                                         return false;
6010                                 }
6011
6012                                 move_next_mg.InstanceExpression = enumerator_variable;
6013
6014                                 // Prepare ~T~ Current { get; }
6015                                 var current_prop = ResolveCurrent (ec, get_enumerator);
6016                                 if (current_prop == null) {
6017                                         return false;
6018                                 }
6019
6020                                 var current_pe = new PropertyExpr (current_prop, loc) { InstanceExpression = enumerator_variable }.Resolve (ec);
6021                                 if (current_pe == null)
6022                                         return false;
6023
6024                                 VarExpr ve = var_type as VarExpr;
6025
6026                                 if (ve != null) {
6027                                         if (is_dynamic) {
6028                                                 // Source type is dynamic, set element type to dynamic too
6029                                                 variable.Type = ec.BuiltinTypes.Dynamic;
6030                                         } else {
6031                                                 // Infer implicitly typed local variable from foreach enumerable type
6032                                                 variable.Type = current_pe.Type;
6033                                         }
6034                                 } else {
6035                                         if (is_dynamic) {
6036                                                 // Explicit cast of dynamic collection elements has to be done at runtime
6037                                                 current_pe = EmptyCast.Create (current_pe, ec.BuiltinTypes.Dynamic);
6038                                         }
6039
6040                                         variable.Type = var_type.ResolveAsType (ec);
6041                                 }
6042
6043                                 if (variable.Type == null)
6044                                         return false;
6045
6046                                 var init = new Invocation (get_enumerator_mg, null);
6047
6048                                 statement = new While (new BooleanExpression (new Invocation (move_next_mg, null)),
6049                                         new Body (variable.Type, variable, current_pe, statement, loc), loc);
6050
6051                                 var enum_type = enumerator_variable.Type;
6052
6053                                 //
6054                                 // Add Dispose method call when enumerator can be IDisposable
6055                                 //
6056                                 if (!enum_type.ImplementsInterface (ec.BuiltinTypes.IDisposable, false)) {
6057                                         if (!enum_type.IsSealed && !TypeSpec.IsValueType (enum_type)) {
6058                                                 //
6059                                                 // Runtime Dispose check
6060                                                 //
6061                                                 var vd = new RuntimeDispose (enumerator_variable.LocalInfo, loc);
6062                                                 vd.Initializer = init;
6063                                                 statement = new Using (vd, statement, loc);
6064                                         } else {
6065                                                 //
6066                                                 // No Dispose call needed
6067                                                 //
6068                                                 this.init = new SimpleAssign (enumerator_variable, init);
6069                                                 this.init.Resolve (ec);
6070                                         }
6071                                 } else {
6072                                         //
6073                                         // Static Dispose check
6074                                         //
6075                                         var vd = new Using.VariableDeclaration (enumerator_variable.LocalInfo, loc);
6076                                         vd.Initializer = init;
6077                                         statement = new Using (vd, statement, loc);
6078                                 }
6079
6080                                 return statement.Resolve (ec);
6081                         }
6082
6083                         protected override void DoEmit (EmitContext ec)
6084                         {
6085                                 enumerator_variable.LocalInfo.CreateBuilder (ec);
6086
6087                                 if (init != null)
6088                                         init.EmitStatement (ec);
6089
6090                                 statement.Emit (ec);
6091                         }
6092
6093                         #region IErrorHandler Members
6094
6095                         bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext ec, MemberSpec best, MemberSpec ambiguous)
6096                         {
6097                                 ec.Report.SymbolRelatedToPreviousError (best);
6098                                 ec.Report.Warning (278, 2, loc,
6099                                         "`{0}' contains ambiguous implementation of `{1}' pattern. Method `{2}' is ambiguous with method `{3}'",
6100                                         expr.Type.GetSignatureForError (), "enumerable",
6101                                         best.GetSignatureForError (), ambiguous.GetSignatureForError ());
6102
6103                                 ambiguous_getenumerator_name = true;
6104                                 return true;
6105                         }
6106
6107                         bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
6108                         {
6109                                 return false;
6110                         }
6111
6112                         bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
6113                         {
6114                                 return false;
6115                         }
6116
6117                         bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
6118                         {
6119                                 return false;
6120                         }
6121
6122                         #endregion
6123                 }
6124
6125                 Expression type;
6126                 LocalVariable variable;
6127                 Expression expr;
6128                 Statement statement;
6129
6130                 public Foreach (Expression type, LocalVariable var, Expression expr, Statement stmt, Location l)
6131                 {
6132                         this.type = type;
6133                         this.variable = var;
6134                         this.expr = expr;
6135                         statement = stmt;
6136                         loc = l;
6137                 }
6138
6139                 public Expression Expr {
6140                         get { return expr; }
6141                 }
6142
6143                 public Statement Statement {
6144                         get { return statement; }
6145                 }
6146
6147                 public Expression TypeExpression {
6148                         get { return type; }
6149                 }
6150
6151                 public LocalVariable Variable {
6152                         get { return variable; }
6153                 }
6154
6155
6156                 public override bool Resolve (BlockContext ec)
6157                 {
6158                         expr = expr.Resolve (ec);
6159                         if (expr == null)
6160                                 return false;
6161
6162                         if (expr.IsNull) {
6163                                 ec.Report.Error (186, loc, "Use of null is not valid in this context");
6164                                 return false;
6165                         }
6166
6167                         if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.String) {
6168                                 statement = new ArrayForeach (this, 1);
6169                         } else if (expr.Type is ArrayContainer) {
6170                                 statement = new ArrayForeach (this, ((ArrayContainer) expr.Type).Rank);
6171                         } else {
6172                                 if (expr.eclass == ExprClass.MethodGroup || expr is AnonymousMethodExpression) {
6173                                         ec.Report.Error (446, expr.Location, "Foreach statement cannot operate on a `{0}'",
6174                                                 expr.ExprClassName);
6175                                         return false;
6176                                 }
6177
6178                                 statement = new CollectionForeach (type, variable, expr, statement, loc);
6179                         }
6180
6181                         return statement.Resolve (ec);
6182                 }
6183
6184                 protected override void DoEmit (EmitContext ec)
6185                 {
6186                         Label old_begin = ec.LoopBegin, old_end = ec.LoopEnd;
6187                         ec.LoopBegin = ec.DefineLabel ();
6188                         ec.LoopEnd = ec.DefineLabel ();
6189
6190                         statement.Emit (ec);
6191
6192                         ec.LoopBegin = old_begin;
6193                         ec.LoopEnd = old_end;
6194                 }
6195
6196                 protected override void CloneTo (CloneContext clonectx, Statement t)
6197                 {
6198                         Foreach target = (Foreach) t;
6199
6200                         target.type = type.Clone (clonectx);
6201                         target.expr = expr.Clone (clonectx);
6202                         target.statement = statement.Clone (clonectx);
6203                 }
6204                 
6205                 public override object Accept (StructuralVisitor visitor)
6206                 {
6207                         return visitor.Visit (this);
6208                 }
6209         }
6210 }