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