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