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