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