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