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