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