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