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