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