2009-08-25 Marek Safar <marek.safar@gmail.com>
[mono.git] / mcs / mcs / statement.cs
1 //
2 // statement.cs: Statement representation for the IL tree.
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //   Martin Baulig (martin@ximian.com)
7 //   Marek Safar (marek.safar@seznam.cz)
8 //
9 // Copyright 2001, 2002, 2003 Ximian, Inc.
10 // Copyright 2003, 2004 Novell, Inc.
11 //
12
13 using System;
14 using System.Text;
15 using System.Reflection;
16 using System.Reflection.Emit;
17 using System.Diagnostics;
18 using System.Collections;
19 using System.Collections.Specialized;
20
21 namespace Mono.CSharp {
22         
23         public abstract class Statement {
24                 public Location loc;
25                 
26                 /// <summary>
27                 ///   Resolves the statement, true means that all sub-statements
28                 ///   did resolve ok.
29                 //  </summary>
30                 public virtual bool Resolve (BlockContext ec)
31                 {
32                         return true;
33                 }
34
35                 /// <summary>
36                 ///   We already know that the statement is unreachable, but we still
37                 ///   need to resolve it to catch errors.
38                 /// </summary>
39                 public virtual bool ResolveUnreachable (BlockContext ec, bool warn)
40                 {
41                         //
42                         // This conflicts with csc's way of doing this, but IMHO it's
43                         // the right thing to do.
44                         //
45                         // If something is unreachable, we still check whether it's
46                         // correct.  This means that you cannot use unassigned variables
47                         // in unreachable code, for instance.
48                         //
49
50                         if (warn)
51                                 Report.Warning (162, 2, loc, "Unreachable code detected");
52
53                         ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc);
54                         bool ok = Resolve (ec);
55                         ec.KillFlowBranching ();
56
57                         return ok;
58                 }
59                                 
60                 /// <summary>
61                 ///   Return value indicates whether all code paths emitted return.
62                 /// </summary>
63                 protected abstract void DoEmit (EmitContext ec);
64
65                 /// <summary>
66                 ///   Utility wrapper routine for Error, just to beautify the code
67                 /// </summary>
68                 public void Error (int error, string format, params object[] args)
69                 {
70                         Error (error, String.Format (format, args));
71                 }
72
73                 public void Error (int error, string s)
74                 {
75                         if (!loc.IsNull)
76                                 Report.Error (error, loc, s);
77                         else
78                                 Report.Error (error, s);
79                 }
80
81                 public virtual void Emit (EmitContext ec)
82                 {
83                         ec.Mark (loc);
84                         DoEmit (ec);
85                 }
86
87                 //
88                 // This routine must be overrided in derived classes and make copies
89                 // of all the data that might be modified if resolved
90                 // 
91                 protected abstract void CloneTo (CloneContext clonectx, Statement target);
92
93                 public Statement Clone (CloneContext clonectx)
94                 {
95                         Statement s = (Statement) this.MemberwiseClone ();
96                         CloneTo (clonectx, s);
97                         return s;
98                 }
99
100                 public virtual Expression CreateExpressionTree (ResolveContext ec)
101                 {
102                         Report.Error (834, loc, "A lambda expression with statement body cannot be converted to an expresion tree");
103                         return null;
104                 }
105
106                 public Statement PerformClone ()
107                 {
108                         CloneContext clonectx = new CloneContext ();
109
110                         return Clone (clonectx);
111                 }
112
113                 public abstract void MutateHoistedGenericType (AnonymousMethodStorey storey);
114         }
115
116         //
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 (BlockContext ec)
187                 {
188                         return true;
189                 }
190
191                 public override bool ResolveUnreachable (BlockContext 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 (BlockContext 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 (BlockContext 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 (BlockContext 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 (BlockContext 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 (BlockContext 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 (BlockContext 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 (BlockContext 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 (BlockContext 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                                 Report.Error (127, loc, "`{0}': A return keyword must not be followed by any expression when method returns void",
822                                         ec.GetSignatureForError ());
823                         }
824
825                         Expr = Expr.Resolve (ec);
826                         if (Expr == null)
827                                 return false;
828
829                         if (ec.HasSet (ResolveContext.Options.InferReturnType)) {
830                                 ec.ReturnTypeInference.AddCommonTypeBound (Expr.Type);
831                                 return true;
832                         }
833
834                         if (Expr.Type != ec.ReturnType) {
835                                 Expr = Convert.ImplicitConversionRequired (ec, Expr, ec.ReturnType, loc);
836
837                                 if (Expr == null) {
838                                         if (am != null) {
839                                                 Report.Error (1662, loc,
840                                                         "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",
841                                                         am.ContainerType, am.GetSignatureForError ());
842                                         }
843                                         return false;
844                                 }
845                         }
846
847                         return true;                    
848                 }
849                 
850                 protected override void DoEmit (EmitContext ec)
851                 {
852                         if (Expr != null) {
853                                 Expr.Emit (ec);
854
855                                 if (unwind_protect)
856                                         ec.ig.Emit (OpCodes.Stloc, ec.TemporaryReturn ());
857                         }
858
859                         if (unwind_protect)
860                                 ec.ig.Emit (OpCodes.Leave, ec.ReturnLabel);
861                         else
862                                 ec.ig.Emit (OpCodes.Ret);
863                 }
864
865                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
866                 {
867                         if (Expr != null)
868                                 Expr.MutateHoistedGenericType (storey);
869                 }
870
871                 protected override void CloneTo (CloneContext clonectx, Statement t)
872                 {
873                         Return target = (Return) t;
874                         // It's null for simple return;
875                         if (Expr != null)
876                                 target.Expr = Expr.Clone (clonectx);
877                 }
878         }
879
880         public class Goto : Statement {
881                 string target;
882                 LabeledStatement label;
883                 bool unwind_protect;
884
885                 public override bool Resolve (BlockContext ec)
886                 {
887                         int errors = Report.Errors;
888                         unwind_protect = ec.CurrentBranching.AddGotoOrigin (ec.CurrentBranching.CurrentUsageVector, this);
889                         ec.CurrentBranching.CurrentUsageVector.Goto ();
890                         return errors == Report.Errors;
891                 }
892                 
893                 public Goto (string label, Location l)
894                 {
895                         loc = l;
896                         target = label;
897                 }
898
899                 public string Target {
900                         get { return target; }
901                 }
902
903                 public void SetResolvedTarget (LabeledStatement label)
904                 {
905                         this.label = label;
906                         label.AddReference ();
907                 }
908
909                 protected override void CloneTo (CloneContext clonectx, Statement target)
910                 {
911                         // Nothing to clone
912                 }
913
914                 protected override void DoEmit (EmitContext ec)
915                 {
916                         if (label == null)
917                                 throw new InternalErrorException ("goto emitted before target resolved");
918                         Label l = label.LabelTarget (ec);
919                         ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, l);
920                 }
921
922                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
923                 {
924                 }
925         }
926
927         public class LabeledStatement : Statement {
928                 string name;
929                 bool defined;
930                 bool referenced;
931                 Label label;
932                 ILGenerator ig;
933
934                 FlowBranching.UsageVector vectors;
935                 
936                 public LabeledStatement (string name, Location l)
937                 {
938                         this.name = name;
939                         this.loc = l;
940                 }
941
942                 public Label LabelTarget (EmitContext ec)
943                 {
944                         if (defined)
945                                 return label;
946                         ig = ec.ig;
947                         label = ec.ig.DefineLabel ();
948                         defined = true;
949
950                         return label;
951                 }
952
953                 public string Name {
954                         get { return name; }
955                 }
956
957                 public bool IsDefined {
958                         get { return defined; }
959                 }
960
961                 public bool HasBeenReferenced {
962                         get { return referenced; }
963                 }
964
965                 public FlowBranching.UsageVector JumpOrigins {
966                         get { return vectors; }
967                 }
968
969                 public void AddUsageVector (FlowBranching.UsageVector vector)
970                 {
971                         vector = vector.Clone ();
972                         vector.Next = vectors;
973                         vectors = vector;
974                 }
975
976                 protected override void CloneTo (CloneContext clonectx, Statement target)
977                 {
978                         // nothing to clone
979                 }
980
981                 public override bool Resolve (BlockContext ec)
982                 {
983                         // this flow-branching will be terminated when the surrounding block ends
984                         ec.StartFlowBranching (this);
985                         return true;
986                 }
987
988                 protected override void DoEmit (EmitContext ec)
989                 {
990                         if (ig != null && ig != ec.ig)
991                                 throw new InternalErrorException ("cannot happen");
992                         LabelTarget (ec);
993                         ec.ig.MarkLabel (label);
994                 }
995
996                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
997                 {
998                 }
999
1000                 public void AddReference ()
1001                 {
1002                         referenced = true;
1003                 }
1004         }
1005         
1006
1007         /// <summary>
1008         ///   `goto default' statement
1009         /// </summary>
1010         public class GotoDefault : Statement {
1011                 
1012                 public GotoDefault (Location l)
1013                 {
1014                         loc = l;
1015                 }
1016
1017                 protected override void CloneTo (CloneContext clonectx, Statement target)
1018                 {
1019                         // nothing to clone
1020                 }
1021
1022                 public override bool Resolve (BlockContext ec)
1023                 {
1024                         ec.CurrentBranching.CurrentUsageVector.Goto ();
1025                         return true;
1026                 }
1027
1028                 protected override void DoEmit (EmitContext ec)
1029                 {
1030                         if (ec.Switch == null){
1031                                 Report.Error (153, loc, "A goto case is only valid inside a switch statement");
1032                                 return;
1033                         }
1034
1035                         if (!ec.Switch.GotDefault){
1036                                 FlowBranchingBlock.Error_UnknownLabel (loc, "default");
1037                                 return;
1038                         }
1039                         ec.ig.Emit (OpCodes.Br, ec.Switch.DefaultTarget);
1040                 }
1041
1042                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1043                 {
1044                 }
1045         }
1046
1047         /// <summary>
1048         ///   `goto case' statement
1049         /// </summary>
1050         public class GotoCase : Statement {
1051                 Expression expr;
1052                 SwitchLabel sl;
1053                 
1054                 public GotoCase (Expression e, Location l)
1055                 {
1056                         expr = e;
1057                         loc = l;
1058                 }
1059
1060                 public override bool Resolve (BlockContext ec)
1061                 {
1062                         if (ec.Switch == null){
1063                                 Report.Error (153, loc, "A goto case is only valid inside a switch statement");
1064                                 return false;
1065                         }
1066
1067                         ec.CurrentBranching.CurrentUsageVector.Goto ();
1068
1069                         expr = expr.Resolve (ec);
1070                         if (expr == null)
1071                                 return false;
1072
1073                         Constant c = expr as Constant;
1074                         if (c == null) {
1075                                 Error (150, "A constant value is expected");
1076                                 return false;
1077                         }
1078
1079                         Type type = ec.Switch.SwitchType;
1080                         Constant res = c.TryReduce (ec, type, c.Location);
1081                         if (res == null) {
1082                                 c.Error_ValueCannotBeConverted (ec, loc, type, true);
1083                                 return false;
1084                         }
1085
1086                         if (!Convert.ImplicitStandardConversionExists (c, type))
1087                                 Report.Warning (469, 2, loc,
1088                                         "The `goto case' value is not implicitly convertible to type `{0}'",
1089                                         TypeManager.CSharpName (type));
1090
1091                         object val = res.GetValue ();
1092                         if (val == null)
1093                                 val = SwitchLabel.NullStringCase;
1094                                         
1095                         sl = (SwitchLabel) ec.Switch.Elements [val];
1096
1097                         if (sl == null){
1098                                 FlowBranchingBlock.Error_UnknownLabel (loc, "case " + 
1099                                         (c.GetValue () == null ? "null" : val.ToString ()));
1100                                 return false;
1101                         }
1102
1103                         return true;
1104                 }
1105
1106                 protected override void DoEmit (EmitContext ec)
1107                 {
1108                         ec.ig.Emit (OpCodes.Br, sl.GetILLabelCode (ec));
1109                 }
1110
1111                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1112                 {
1113                         expr.MutateHoistedGenericType (storey);
1114                 }
1115
1116                 protected override void CloneTo (CloneContext clonectx, Statement t)
1117                 {
1118                         GotoCase target = (GotoCase) t;
1119
1120                         target.expr = expr.Clone (clonectx);
1121                 }
1122         }
1123         
1124         public class Throw : Statement {
1125                 Expression expr;
1126                 
1127                 public Throw (Expression expr, Location l)
1128                 {
1129                         this.expr = expr;
1130                         loc = l;
1131                 }
1132
1133                 public override bool Resolve (BlockContext ec)
1134                 {
1135                         if (expr == null) {
1136                                 ec.CurrentBranching.CurrentUsageVector.Goto ();
1137                                 return ec.CurrentBranching.CheckRethrow (loc);
1138                         }
1139
1140                         expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
1141                         ec.CurrentBranching.CurrentUsageVector.Goto ();
1142
1143                         if (expr == null)
1144                                 return false;
1145
1146                         if (Convert.ImplicitConversionExists (ec, expr, TypeManager.exception_type))
1147                                 expr = Convert.ImplicitConversion (ec, expr, TypeManager.exception_type, loc);
1148                         else
1149                                 Report.Error (155, expr.Location, "The type caught or thrown must be derived from System.Exception");
1150
1151                         return true;
1152                 }
1153                         
1154                 protected override void DoEmit (EmitContext ec)
1155                 {
1156                         if (expr == null)
1157                                 ec.ig.Emit (OpCodes.Rethrow);
1158                         else {
1159                                 expr.Emit (ec);
1160
1161                                 ec.ig.Emit (OpCodes.Throw);
1162                         }
1163                 }
1164
1165                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1166                 {
1167                         if (expr != null)
1168                                 expr.MutateHoistedGenericType (storey);
1169                 }
1170
1171                 protected override void CloneTo (CloneContext clonectx, Statement t)
1172                 {
1173                         Throw target = (Throw) t;
1174
1175                         if (expr != null)
1176                                 target.expr = expr.Clone (clonectx);
1177                 }
1178         }
1179
1180         public class Break : Statement {
1181                 
1182                 public Break (Location l)
1183                 {
1184                         loc = l;
1185                 }
1186
1187                 bool unwind_protect;
1188
1189                 public override bool Resolve (BlockContext ec)
1190                 {
1191                         int errors = Report.Errors;
1192                         unwind_protect = ec.CurrentBranching.AddBreakOrigin (ec.CurrentBranching.CurrentUsageVector, loc);
1193                         ec.CurrentBranching.CurrentUsageVector.Goto ();
1194                         return errors == Report.Errors;
1195                 }
1196
1197                 protected override void DoEmit (EmitContext ec)
1198                 {
1199                         ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopEnd);
1200                 }
1201
1202                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1203                 {
1204                 }
1205                 
1206                 protected override void CloneTo (CloneContext clonectx, Statement t)
1207                 {
1208                         // nothing needed
1209                 }
1210         }
1211
1212         public class Continue : Statement {
1213                 
1214                 public Continue (Location l)
1215                 {
1216                         loc = l;
1217                 }
1218
1219                 bool unwind_protect;
1220
1221                 public override bool Resolve (BlockContext ec)
1222                 {
1223                         int errors = Report.Errors;
1224                         unwind_protect = ec.CurrentBranching.AddContinueOrigin (ec.CurrentBranching.CurrentUsageVector, loc);
1225                         ec.CurrentBranching.CurrentUsageVector.Goto ();
1226                         return errors == Report.Errors;
1227                 }
1228
1229                 protected override void DoEmit (EmitContext ec)
1230                 {
1231                         ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopBegin);
1232                 }
1233
1234                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1235                 {
1236                 }
1237
1238                 protected override void CloneTo (CloneContext clonectx, Statement t)
1239                 {
1240                         // nothing needed.
1241                 }
1242         }
1243
1244         public interface ILocalVariable
1245         {
1246                 void Emit (EmitContext ec);
1247                 void EmitAssign (EmitContext ec);
1248                 void EmitAddressOf (EmitContext ec);
1249         }
1250
1251         public interface IKnownVariable {
1252                 Block Block { get; }
1253                 Location Location { get; }
1254         }
1255
1256         //
1257         // The information about a user-perceived local variable
1258         //
1259         public class LocalInfo : IKnownVariable, ILocalVariable {
1260                 public readonly FullNamedExpression Type;
1261
1262                 public Type VariableType;
1263                 public readonly string Name;
1264                 public readonly Location Location;
1265                 public readonly Block Block;
1266
1267                 public VariableInfo VariableInfo;
1268                 public HoistedVariable HoistedVariableReference;
1269
1270                 [Flags]
1271                 enum Flags : byte {
1272                         Used = 1,
1273                         ReadOnly = 2,
1274                         Pinned = 4,
1275                         IsThis = 8,
1276                         AddressTaken = 32,
1277                         CompilerGenerated = 64,
1278                         IsConstant = 128
1279                 }
1280
1281                 public enum ReadOnlyContext: byte {
1282                         Using,
1283                         Foreach,
1284                         Fixed
1285                 }
1286
1287                 Flags flags;
1288                 ReadOnlyContext ro_context;
1289                 LocalBuilder builder;
1290
1291                 public LocalInfo (FullNamedExpression type, string name, Block block, Location l)
1292                 {
1293                         Type = type;
1294                         Name = name;
1295                         Block = block;
1296                         Location = l;
1297                 }
1298
1299                 public LocalInfo (DeclSpace ds, Block block, Location l)
1300                 {
1301                         VariableType = ds.IsGeneric ? ds.CurrentType : ds.TypeBuilder;
1302                         Block = block;
1303                         Location = l;
1304                 }
1305
1306                 public void ResolveVariable (EmitContext ec)
1307                 {
1308                         if (HoistedVariableReference != null)
1309                                 return;
1310
1311                         if (builder == null) {
1312                                 if (Pinned)
1313                                         //
1314                                         // This is needed to compile on both .NET 1.x and .NET 2.x
1315                                         // the later introduced `DeclareLocal (Type t, bool pinned)'
1316                                         //
1317                                         builder = TypeManager.DeclareLocalPinned (ec.ig, VariableType);
1318                                 else
1319                                         builder = ec.ig.DeclareLocal (TypeManager.TypeToReflectionType (VariableType));
1320                         }
1321                 }
1322
1323                 public void Emit (EmitContext ec)
1324                 {
1325                         ec.ig.Emit (OpCodes.Ldloc, builder);
1326                 }
1327
1328                 public void EmitAssign (EmitContext ec)
1329                 {
1330                         ec.ig.Emit (OpCodes.Stloc, builder);
1331                 }
1332
1333                 public void EmitAddressOf (EmitContext ec)
1334                 {
1335                         ec.ig.Emit (OpCodes.Ldloca, builder);
1336                 }
1337
1338                 public void EmitSymbolInfo (EmitContext ec)
1339                 {
1340                         if (builder != null)
1341                                 ec.DefineLocalVariable (Name, builder);
1342                 }
1343
1344                 public bool IsThisAssigned (BlockContext ec, Block block)
1345                 {
1346                         if (VariableInfo == null)
1347                                 throw new Exception ();
1348
1349                         if (!ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (VariableInfo))
1350                                 return true;
1351
1352                         return VariableInfo.TypeInfo.IsFullyInitialized (ec.CurrentBranching, VariableInfo, block.StartLocation);
1353                 }
1354
1355                 public bool IsAssigned (BlockContext ec)
1356                 {
1357                         if (VariableInfo == null)
1358                                 throw new Exception ();
1359
1360                         return !ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (VariableInfo);
1361                 }
1362
1363                 public bool Resolve (ResolveContext ec)
1364                 {
1365                         if (VariableType != null)
1366                                 return true;
1367
1368                         TypeExpr texpr = Type.ResolveAsContextualType (ec, false);
1369                         if (texpr == null)
1370                                 return false;
1371                                 
1372                         VariableType = texpr.Type;
1373
1374                         if (TypeManager.IsGenericParameter (VariableType))
1375                                 return true;
1376
1377                         if (VariableType.IsAbstract && VariableType.IsSealed) {
1378                                 FieldBase.Error_VariableOfStaticClass (Location, Name, VariableType);
1379                                 return false;
1380                         }
1381
1382                         if (VariableType.IsPointer && !ec.IsUnsafe)
1383                                 Expression.UnsafeError (Location);
1384
1385                         return true;
1386                 }
1387
1388                 public bool IsConstant {
1389                         get { return (flags & Flags.IsConstant) != 0; }
1390                         set { flags |= Flags.IsConstant; }
1391                 }
1392
1393                 public bool AddressTaken {
1394                         get { return (flags & Flags.AddressTaken) != 0; }
1395                         set { flags |= Flags.AddressTaken; }
1396                 }
1397
1398                 public bool CompilerGenerated {
1399                         get { return (flags & Flags.CompilerGenerated) != 0; }
1400                         set { flags |= Flags.CompilerGenerated; }
1401                 }
1402
1403                 public override string ToString ()
1404                 {
1405                         return String.Format ("LocalInfo ({0},{1},{2},{3})",
1406                                               Name, Type, VariableInfo, Location);
1407                 }
1408
1409                 public bool Used {
1410                         get { return (flags & Flags.Used) != 0; }
1411                         set { flags = value ? (flags | Flags.Used) : (unchecked (flags & ~Flags.Used)); }
1412                 }
1413
1414                 public bool ReadOnly {
1415                         get { return (flags & Flags.ReadOnly) != 0; }
1416                 }
1417
1418                 public void SetReadOnlyContext (ReadOnlyContext context)
1419                 {
1420                         flags |= Flags.ReadOnly;
1421                         ro_context = context;
1422                 }
1423
1424                 public string GetReadOnlyContext ()
1425                 {
1426                         if (!ReadOnly)
1427                                 throw new InternalErrorException ("Variable is not readonly");
1428
1429                         switch (ro_context) {
1430                         case ReadOnlyContext.Fixed:
1431                                 return "fixed variable";
1432                         case ReadOnlyContext.Foreach:
1433                                 return "foreach iteration variable";
1434                         case ReadOnlyContext.Using:
1435                                 return "using variable";
1436                         }
1437                         throw new NotImplementedException ();
1438                 }
1439
1440                 //
1441                 // Whether the variable is pinned, if Pinned the variable has been 
1442                 // allocated in a pinned slot with DeclareLocal.
1443                 //
1444                 public bool Pinned {
1445                         get { return (flags & Flags.Pinned) != 0; }
1446                         set { flags = value ? (flags | Flags.Pinned) : (flags & ~Flags.Pinned); }
1447                 }
1448
1449                 public bool IsThis {
1450                         get { return (flags & Flags.IsThis) != 0; }
1451                         set { flags = value ? (flags | Flags.IsThis) : (flags & ~Flags.IsThis); }
1452                 }
1453
1454                 Block IKnownVariable.Block {
1455                         get { return Block; }
1456                 }
1457
1458                 Location IKnownVariable.Location {
1459                         get { return Location; }
1460                 }
1461
1462                 public LocalInfo Clone (CloneContext clonectx)
1463                 {
1464                         //
1465                         // Variables in anonymous block are not resolved yet
1466                         //
1467                         if (VariableType == null)
1468                                 return new LocalInfo ((FullNamedExpression) Type.Clone (clonectx), Name, clonectx.LookupBlock (Block), Location);
1469
1470                         //
1471                         // Variables in method block are resolved
1472                         //
1473                         LocalInfo li = new LocalInfo (null, Name, clonectx.LookupBlock (Block), Location);
1474                         li.VariableType = VariableType;
1475                         return li;                      
1476                 }
1477         }
1478
1479         /// <summary>
1480         ///   Block represents a C# block.
1481         /// </summary>
1482         ///
1483         /// <remarks>
1484         ///   This class is used in a number of places: either to represent
1485         ///   explicit blocks that the programmer places or implicit blocks.
1486         ///
1487         ///   Implicit blocks are used as labels or to introduce variable
1488         ///   declarations.
1489         ///
1490         ///   Top-level blocks derive from Block, and they are called ToplevelBlock
1491         ///   they contain extra information that is not necessary on normal blocks.
1492         /// </remarks>
1493         public class Block : Statement {
1494                 public Block    Parent;
1495                 public Location StartLocation;
1496                 public Location EndLocation = Location.Null;
1497
1498                 public ExplicitBlock Explicit;
1499                 public ToplevelBlock Toplevel; // TODO: Use Explicit
1500
1501                 [Flags]
1502                 public enum Flags : byte {
1503                         Unchecked = 1,
1504                         BlockUsed = 2,
1505                         VariablesInitialized = 4,
1506                         HasRet = 8,
1507                         Unsafe = 16,
1508                         IsIterator = 32,
1509                         HasCapturedVariable = 64,
1510                         HasCapturedThis = 128
1511                 }
1512                 protected Flags flags;
1513
1514                 public bool Unchecked {
1515                         get { return (flags & Flags.Unchecked) != 0; }
1516                         set { flags = value ? flags | Flags.Unchecked : flags & ~Flags.Unchecked; }
1517                 }
1518
1519                 public bool Unsafe {
1520                         get { return (flags & Flags.Unsafe) != 0; }
1521                         set { flags |= Flags.Unsafe; }
1522                 }
1523
1524                 //
1525                 // The statements in this block
1526                 //
1527                 protected ArrayList statements;
1528
1529                 //
1530                 // An array of Blocks.  We keep track of children just
1531                 // to generate the local variable declarations.
1532                 //
1533                 // Statements and child statements are handled through the
1534                 // statements.
1535                 //
1536                 ArrayList children;
1537
1538                 //
1539                 // Labels.  (label, block) pairs.
1540                 //
1541                 protected HybridDictionary labels;
1542
1543                 //
1544                 // Keeps track of (name, type) pairs
1545                 //
1546                 IDictionary variables;
1547
1548                 //
1549                 // Keeps track of constants
1550                 HybridDictionary constants;
1551
1552                 //
1553                 // Temporary variables.
1554                 //
1555                 ArrayList temporary_variables;
1556                 
1557                 //
1558                 // If this is a switch section, the enclosing switch block.
1559                 //
1560                 Block switch_block;
1561
1562                 protected ArrayList scope_initializers;
1563
1564                 ArrayList anonymous_children;
1565
1566                 protected static int id;
1567
1568                 int this_id;
1569
1570                 int assignable_slots;
1571                 bool unreachable_shown;
1572                 bool unreachable;
1573                 
1574                 public Block (Block parent)
1575                         : this (parent, (Flags) 0, Location.Null, Location.Null)
1576                 { }
1577
1578                 public Block (Block parent, Flags flags)
1579                         : this (parent, flags, Location.Null, Location.Null)
1580                 { }
1581
1582                 public Block (Block parent, Location start, Location end)
1583                         : this (parent, (Flags) 0, start, end)
1584                 { }
1585
1586                 //
1587                 // Useful when TopLevel block is downgraded to normal block
1588                 //
1589                 public Block (ToplevelBlock parent, ToplevelBlock source)
1590                         : this (parent, source.flags, source.StartLocation, source.EndLocation)
1591                 {
1592                         statements = source.statements;
1593                         children = source.children;
1594                         labels = source.labels;
1595                         variables = source.variables;
1596                         constants = source.constants;
1597                         switch_block = source.switch_block;
1598                 }
1599
1600                 public Block (Block parent, Flags flags, Location start, Location end)
1601                 {
1602                         if (parent != null) {
1603                                 parent.AddChild (this);
1604
1605                                 // the appropriate constructors will fixup these fields
1606                                 Toplevel = parent.Toplevel;
1607                                 Explicit = parent.Explicit;
1608                         }
1609                         
1610                         this.Parent = parent;
1611                         this.flags = flags;
1612                         this.StartLocation = start;
1613                         this.EndLocation = end;
1614                         this.loc = start;
1615                         this_id = id++;
1616                         statements = new ArrayList (4);
1617                 }
1618
1619                 public Block CreateSwitchBlock (Location start)
1620                 {
1621                         // FIXME: should this be implicit?
1622                         Block new_block = new ExplicitBlock (this, start, start);
1623                         new_block.switch_block = this;
1624                         return new_block;
1625                 }
1626
1627                 public int ID {
1628                         get { return this_id; }
1629                 }
1630
1631                 public IDictionary Variables {
1632                         get {
1633                                 if (variables == null)
1634                                         variables = new ListDictionary ();
1635                                 return variables;
1636                         }
1637                 }
1638
1639                 void AddChild (Block b)
1640                 {
1641                         if (children == null)
1642                                 children = new ArrayList (1);
1643                         
1644                         children.Add (b);
1645                 }
1646
1647                 public void SetEndLocation (Location loc)
1648                 {
1649                         EndLocation = loc;
1650                 }
1651
1652                 protected static void Error_158 (string name, Location loc)
1653                 {
1654                         Report.Error (158, loc, "The label `{0}' shadows another label " +
1655                                       "by the same name in a contained scope", name);
1656                 }
1657
1658                 /// <summary>
1659                 ///   Adds a label to the current block. 
1660                 /// </summary>
1661                 ///
1662                 /// <returns>
1663                 ///   false if the name already exists in this block. true
1664                 ///   otherwise.
1665                 /// </returns>
1666                 ///
1667                 public bool AddLabel (LabeledStatement target)
1668                 {
1669                         if (switch_block != null)
1670                                 return switch_block.AddLabel (target);
1671
1672                         string name = target.Name;
1673
1674                         Block cur = this;
1675                         while (cur != null) {
1676                                 LabeledStatement s = cur.DoLookupLabel (name);
1677                                 if (s != null) {
1678                                         Report.SymbolRelatedToPreviousError (s.loc, s.Name);
1679                                         Report.Error (140, target.loc, "The label `{0}' is a duplicate", name);
1680                                         return false;
1681                                 }
1682
1683                                 if (this == Explicit)
1684                                         break;
1685
1686                                 cur = cur.Parent;
1687                         }
1688
1689                         while (cur != null) {
1690                                 if (cur.DoLookupLabel (name) != null) {
1691                                         Error_158 (name, target.loc);
1692                                         return false;
1693                                 }
1694
1695                                 if (children != null) {
1696                                         foreach (Block b in children) {
1697                                                 LabeledStatement s = b.DoLookupLabel (name);
1698                                                 if (s == null)
1699                                                         continue;
1700
1701                                                 Report.SymbolRelatedToPreviousError (s.loc, s.Name);
1702                                                 Error_158 (name, target.loc);
1703                                                 return false;
1704                                         }
1705                                 }
1706
1707                                 cur = cur.Parent;
1708                         }
1709
1710                         Toplevel.CheckError158 (name, target.loc);
1711
1712                         if (labels == null)
1713                                 labels = new HybridDictionary();
1714
1715                         labels.Add (name, target);
1716                         return true;
1717                 }
1718
1719                 public LabeledStatement LookupLabel (string name)
1720                 {
1721                         LabeledStatement s = DoLookupLabel (name);
1722                         if (s != null)
1723                                 return s;
1724
1725                         if (children == null)
1726                                 return null;
1727
1728                         foreach (Block child in children) {
1729                                 if (Explicit != child.Explicit)
1730                                         continue;
1731
1732                                 s = child.LookupLabel (name);
1733                                 if (s != null)
1734                                         return s;
1735                         }
1736
1737                         return null;
1738                 }
1739
1740                 LabeledStatement DoLookupLabel (string name)
1741                 {
1742                         if (switch_block != null)
1743                                 return switch_block.LookupLabel (name);
1744
1745                         if (labels != null)
1746                                 if (labels.Contains (name))
1747                                         return ((LabeledStatement) labels [name]);
1748
1749                         return null;
1750                 }
1751
1752                 public bool CheckInvariantMeaningInBlock (string name, Expression e, Location loc)
1753                 {
1754                         Block b = this;
1755                         IKnownVariable kvi = b.Explicit.GetKnownVariable (name);
1756                         while (kvi == null) {
1757                                 b = b.Explicit.Parent;
1758                                 if (b == null)
1759                                         return true;
1760                                 kvi = b.Explicit.GetKnownVariable (name);
1761                         }
1762
1763                         if (kvi.Block == b)
1764                                 return true;
1765
1766                         // Is kvi.Block nested inside 'b'
1767                         if (b.Explicit != kvi.Block.Explicit) {
1768                                 //
1769                                 // If a variable by the same name it defined in a nested block of this
1770                                 // block, we violate the invariant meaning in a block.
1771                                 //
1772                                 if (b == this) {
1773                                         Report.SymbolRelatedToPreviousError (kvi.Location, name);
1774                                         Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", name);
1775                                         return false;
1776                                 }
1777
1778                                 //
1779                                 // It's ok if the definition is in a nested subblock of b, but not
1780                                 // nested inside this block -- a definition in a sibling block
1781                                 // should not affect us.
1782                                 //
1783                                 return true;
1784                         }
1785
1786                         //
1787                         // Block 'b' and kvi.Block are the same textual block.
1788                         // However, different variables are extant.
1789                         //
1790                         // Check if the variable is in scope in both blocks.  We use
1791                         // an indirect check that depends on AddVariable doing its
1792                         // part in maintaining the invariant-meaning-in-block property.
1793                         //
1794                         if (e is VariableReference || (e is Constant && b.GetLocalInfo (name) != null))
1795                                 return true;
1796
1797                         if (this is ToplevelBlock) {
1798                                 Report.SymbolRelatedToPreviousError (kvi.Location, name);
1799                                 e.Error_VariableIsUsedBeforeItIsDeclared (name);
1800                                 return false;
1801                         }
1802
1803                         //
1804                         // Even though we detected the error when the name is used, we
1805                         // treat it as if the variable declaration was in error.
1806                         //
1807                         Report.SymbolRelatedToPreviousError (loc, name);
1808                         Error_AlreadyDeclared (kvi.Location, name, "parent or current");
1809                         return false;
1810                 }
1811
1812                 protected virtual bool CheckParentConflictName (ToplevelBlock block, string name, Location l)
1813                 {
1814                         LocalInfo vi = GetLocalInfo (name);
1815                         if (vi != null) {
1816                                 Report.SymbolRelatedToPreviousError (vi.Location, name);
1817                                 if (Explicit == vi.Block.Explicit) {
1818                                         Error_AlreadyDeclared (l, name, null);
1819                                 } else {
1820                                         Error_AlreadyDeclared (l, name, this is ToplevelBlock ?
1821                                                 "parent or current" : "parent");
1822                                 }
1823                                 return false;
1824                         }
1825
1826                         if (block != null) {
1827                                 Expression e = block.GetParameterReference (name, Location.Null);
1828                                 if (e != null) {
1829                                         ParameterReference pr = e as ParameterReference;
1830                                         if (this is Linq.QueryBlock && (pr != null && pr.Parameter is Linq.QueryBlock.ImplicitQueryParameter || e is MemberAccess))
1831                                                 Error_AlreadyDeclared (loc, name);
1832                                         else
1833                                                 Error_AlreadyDeclared (loc, name, "parent or current");
1834                                         return false;
1835                                 }
1836                         }
1837
1838                         return true;
1839                 }
1840
1841                 public LocalInfo AddVariable (Expression type, string name, Location l)
1842                 {
1843                         if (!CheckParentConflictName (Toplevel, name, l))
1844                                 return null;
1845
1846                         if (Toplevel.GenericMethod != null) {
1847                                 foreach (TypeParameter tp in Toplevel.GenericMethod.CurrentTypeParameters) {
1848                                         if (tp.Name == name) {
1849                                                 Report.SymbolRelatedToPreviousError (tp);
1850                                                 Error_AlreadyDeclaredTypeParameter (loc, name, "local variable");
1851                                                 return null;
1852                                         }
1853                                 }
1854                         }                       
1855
1856                         IKnownVariable kvi = Explicit.GetKnownVariable (name);
1857                         if (kvi != null) {
1858                                 Report.SymbolRelatedToPreviousError (kvi.Location, name);
1859                                 Error_AlreadyDeclared (l, name, "child");
1860                                 return null;
1861                         }
1862
1863                         LocalInfo vi = new LocalInfo ((FullNamedExpression) type, name, this, l);
1864                         AddVariable (vi);
1865
1866                         if ((flags & Flags.VariablesInitialized) != 0)
1867                                 throw new InternalErrorException ("block has already been resolved");
1868
1869                         return vi;
1870                 }
1871                 
1872                 protected virtual void AddVariable (LocalInfo li)
1873                 {
1874                         Variables.Add (li.Name, li);
1875                         Explicit.AddKnownVariable (li.Name, li);
1876                 }
1877
1878                 protected virtual void Error_AlreadyDeclared (Location loc, string var, string reason)
1879                 {
1880                         if (reason == null) {
1881                                 Error_AlreadyDeclared (loc, var);
1882                                 return;
1883                         }
1884                         
1885                         Report.Error (136, loc, "A local variable named `{0}' cannot be declared " +
1886                                       "in this scope because it would give a different meaning " +
1887                                       "to `{0}', which is already used in a `{1}' scope " +
1888                                       "to denote something else", var, reason);
1889                 }
1890
1891                 protected virtual void Error_AlreadyDeclared (Location loc, string name)
1892                 {
1893                         Report.Error (128, loc,
1894                                 "A local variable named `{0}' is already defined in this scope", name);
1895                 }
1896                                         
1897                 public virtual void Error_AlreadyDeclaredTypeParameter (Location loc, string name, string conflict)
1898                 {
1899                         Report.Error (412, loc, "The type parameter name `{0}' is the same as `{1}'",
1900                                 name, conflict);
1901                 }
1902
1903                 public bool AddConstant (Expression type, string name, Expression value, Location l)
1904                 {
1905                         if (AddVariable (type, name, l) == null)
1906                                 return false;
1907                         
1908                         if (constants == null)
1909                                 constants = new HybridDictionary();
1910
1911                         constants.Add (name, value);
1912
1913                         // A block is considered used if we perform an initialization in a local declaration, even if it is constant.
1914                         Use ();
1915                         return true;
1916                 }
1917
1918                 static int next_temp_id = 0;
1919
1920                 public LocalInfo AddTemporaryVariable (TypeExpr te, Location loc)
1921                 {
1922                         Report.Debug (64, "ADD TEMPORARY", this, Toplevel, loc);
1923
1924                         if (temporary_variables == null)
1925                                 temporary_variables = new ArrayList ();
1926
1927                         int id = ++next_temp_id;
1928                         string name = "$s_" + id.ToString ();
1929
1930                         LocalInfo li = new LocalInfo (te, name, this, loc);
1931                         li.CompilerGenerated = true;
1932                         temporary_variables.Add (li);
1933                         return li;
1934                 }
1935
1936                 public LocalInfo GetLocalInfo (string name)
1937                 {
1938                         LocalInfo ret;
1939                         for (Block b = this; b != null; b = b.Parent) {
1940                                 if (b.variables != null) {
1941                                         ret = (LocalInfo) b.variables [name];
1942                                         if (ret != null)
1943                                                 return ret;
1944                                 }
1945                         }
1946
1947                         return null;
1948                 }
1949
1950                 public Expression GetVariableType (string name)
1951                 {
1952                         LocalInfo vi = GetLocalInfo (name);
1953                         return vi == null ? null : vi.Type;
1954                 }
1955
1956                 public Expression GetConstantExpression (string name)
1957                 {
1958                         for (Block b = this; b != null; b = b.Parent) {
1959                                 if (b.constants != null) {
1960                                         Expression ret = b.constants [name] as Expression;
1961                                         if (ret != null)
1962                                                 return ret;
1963                                 }
1964                         }
1965                         return null;
1966                 }
1967
1968                 //
1969                 // It should be used by expressions which require to
1970                 // register a statement during resolve process.
1971                 //
1972                 public void AddScopeStatement (Statement s)
1973                 {
1974                         if (scope_initializers == null)
1975                                 scope_initializers = new ArrayList ();
1976
1977                         scope_initializers.Add (s);
1978                 }
1979                 
1980                 public void AddStatement (Statement s)
1981                 {
1982                         statements.Add (s);
1983                         flags |= Flags.BlockUsed;
1984                 }
1985
1986                 public bool Used {
1987                         get { return (flags & Flags.BlockUsed) != 0; }
1988                 }
1989
1990                 public void Use ()
1991                 {
1992                         flags |= Flags.BlockUsed;
1993                 }
1994
1995                 public bool HasRet {
1996                         get { return (flags & Flags.HasRet) != 0; }
1997                 }
1998
1999                 public int AssignableSlots {
2000                         get {
2001 // TODO: Re-enable                      
2002 //                              if ((flags & Flags.VariablesInitialized) == 0)
2003 //                                      throw new Exception ("Variables have not been initialized yet");
2004                                 return assignable_slots;
2005                         }
2006                 }
2007
2008                 public ArrayList AnonymousChildren {
2009                         get { return anonymous_children; }
2010                 }
2011
2012                 public void AddAnonymousChild (ToplevelBlock b)
2013                 {
2014                         if (anonymous_children == null)
2015                                 anonymous_children = new ArrayList ();
2016
2017                         anonymous_children.Add (b);
2018                 }
2019
2020                 void DoResolveConstants (BlockContext ec)
2021                 {
2022                         if (constants == null)
2023                                 return;
2024
2025                         if (variables == null)
2026                                 throw new InternalErrorException ("cannot happen");
2027
2028                         foreach (DictionaryEntry de in variables) {
2029                                 string name = (string) de.Key;
2030                                 LocalInfo vi = (LocalInfo) de.Value;
2031                                 Type variable_type = vi.VariableType;
2032
2033                                 if (variable_type == null) {
2034                                         if (vi.Type is VarExpr)
2035                                                 Report.Error (822, vi.Type.Location, "An implicitly typed local variable cannot be a constant");
2036
2037                                         continue;
2038                                 }
2039
2040                                 Expression cv = (Expression) constants [name];
2041                                 if (cv == null)
2042                                         continue;
2043
2044                                 // Don't let 'const int Foo = Foo;' succeed.
2045                                 // Removing the name from 'constants' ensures that we get a LocalVariableReference below,
2046                                 // which in turn causes the 'must be constant' error to be triggered.
2047                                 constants.Remove (name);
2048
2049                                 if (!Const.IsConstantTypeValid (variable_type)) {
2050                                         Const.Error_InvalidConstantType (variable_type, loc);
2051                                         continue;
2052                                 }
2053
2054                                 ec.CurrentBlock = this;
2055                                 Expression e;
2056                                 using (ec.With (ResolveContext.Options.ConstantCheckState, (flags & Flags.Unchecked) == 0)) {
2057                                         e = cv.Resolve (ec);
2058                                 }
2059                                 if (e == null)
2060                                         continue;
2061
2062                                 Constant ce = e as Constant;
2063                                 if (ce == null) {
2064                                         Const.Error_ExpressionMustBeConstant (vi.Location, name);
2065                                         continue;
2066                                 }
2067
2068                                 e = ce.ConvertImplicitly (variable_type);
2069                                 if (e == null) {
2070                                         if (TypeManager.IsReferenceType (variable_type))
2071                                                 Const.Error_ConstantCanBeInitializedWithNullOnly (variable_type, vi.Location, vi.Name);
2072                                         else
2073                                                 ce.Error_ValueCannotBeConverted (ec, vi.Location, variable_type, false);
2074                                         continue;
2075                                 }
2076
2077                                 constants.Add (name, e);
2078                                 vi.IsConstant = true;
2079                         }
2080                 }
2081
2082                 protected void ResolveMeta (BlockContext ec, int offset)
2083                 {
2084                         Report.Debug (64, "BLOCK RESOLVE META", this, Parent);
2085
2086                         // If some parent block was unsafe, we remain unsafe even if this block
2087                         // isn't explicitly marked as such.
2088                         using (ec.With (ResolveContext.Options.UnsafeScope, ec.IsUnsafe | Unsafe)) {
2089                                 flags |= Flags.VariablesInitialized;
2090
2091                                 if (variables != null) {
2092                                         foreach (LocalInfo li in variables.Values) {
2093                                                 if (!li.Resolve (ec))
2094                                                         continue;
2095                                                 li.VariableInfo = new VariableInfo (li, offset);
2096                                                 offset += li.VariableInfo.Length;
2097                                         }
2098                                 }
2099                                 assignable_slots = offset;
2100
2101                                 DoResolveConstants (ec);
2102
2103                                 if (children == null)
2104                                         return;
2105                                 foreach (Block b in children)
2106                                         b.ResolveMeta (ec, offset);
2107                         }
2108                 }
2109
2110                 //
2111                 // Emits the local variable declarations for a block
2112                 //
2113                 public virtual void EmitMeta (EmitContext ec)
2114                 {
2115                         if (variables != null){
2116                                 foreach (LocalInfo vi in variables.Values)
2117                                         vi.ResolveVariable (ec);
2118                         }
2119
2120                         if (temporary_variables != null) {
2121                                 for (int i = 0; i < temporary_variables.Count; i++)
2122                                         ((LocalInfo)temporary_variables[i]).ResolveVariable(ec);
2123                         }
2124
2125                         if (children != null) {
2126                                 for (int i = 0; i < children.Count; i++)
2127                                         ((Block)children[i]).EmitMeta(ec);
2128                         }
2129                 }
2130
2131                 void UsageWarning ()
2132                 {
2133                         if (variables == null || Report.WarningLevel < 3)
2134                                 return;
2135
2136                         foreach (DictionaryEntry de in variables) {
2137                                 LocalInfo vi = (LocalInfo) de.Value;
2138
2139                                 if (!vi.Used) {
2140                                         string name = (string) de.Key;
2141
2142                                         // vi.VariableInfo can be null for 'catch' variables
2143                                         if (vi.VariableInfo != null && vi.VariableInfo.IsEverAssigned)
2144                                                 Report.Warning (219, 3, vi.Location, "The variable `{0}' is assigned but its value is never used", name);
2145                                         else
2146                                                 Report.Warning (168, 3, vi.Location, "The variable `{0}' is declared but never used", name);
2147                                 }
2148                         }
2149                 }
2150
2151                 static void CheckPossibleMistakenEmptyStatement (Statement s)
2152                 {
2153                         Statement body;
2154
2155                         // Some statements are wrapped by a Block. Since
2156                         // others' internal could be changed, here I treat
2157                         // them as possibly wrapped by Block equally.
2158                         Block b = s as Block;
2159                         if (b != null && b.statements.Count == 1)
2160                                 s = (Statement) b.statements [0];
2161
2162                         if (s is Lock)
2163                                 body = ((Lock) s).Statement;
2164                         else if (s is For)
2165                                 body = ((For) s).Statement;
2166                         else if (s is Foreach)
2167                                 body = ((Foreach) s).Statement;
2168                         else if (s is While)
2169                                 body = ((While) s).Statement;
2170                         else if (s is Fixed)
2171                                 body = ((Fixed) s).Statement;
2172                         else if (s is Using)
2173                                 body = ((Using) s).EmbeddedStatement;
2174                         else if (s is UsingTemporary)
2175                                 body = ((UsingTemporary) s).Statement;
2176                         else
2177                                 return;
2178
2179                         if (body == null || body is EmptyStatement)
2180                                 Report.Warning (642, 3, s.loc, "Possible mistaken empty statement");
2181                 }
2182
2183                 public override bool Resolve (BlockContext ec)
2184                 {
2185                         Block prev_block = ec.CurrentBlock;
2186                         bool ok = true;
2187
2188                         int errors = Report.Errors;
2189
2190                         ec.CurrentBlock = this;
2191                         ec.StartFlowBranching (this);
2192
2193                         Report.Debug (4, "RESOLVE BLOCK", StartLocation, ec.CurrentBranching);
2194
2195                         //
2196                         // Compiler generated scope statements
2197                         //
2198                         if (scope_initializers != null) {
2199                                 foreach (Statement s in scope_initializers)
2200                                         s.Resolve (ec);
2201                         }
2202
2203                         //
2204                         // This flag is used to notate nested statements as unreachable from the beginning of this block.
2205                         // For the purposes of this resolution, it doesn't matter that the whole block is unreachable 
2206                         // from the beginning of the function.  The outer Resolve() that detected the unreachability is
2207                         // responsible for handling the situation.
2208                         //
2209                         int statement_count = statements.Count;
2210                         for (int ix = 0; ix < statement_count; ix++){
2211                                 Statement s = (Statement) statements [ix];
2212                                 // Check possible empty statement (CS0642)
2213                                 if (Report.WarningLevel >= 3 &&
2214                                         ix + 1 < statement_count &&
2215                                                 statements [ix + 1] is ExplicitBlock)
2216                                         CheckPossibleMistakenEmptyStatement (s);
2217
2218                                 //
2219                                 // Warn if we detect unreachable code.
2220                                 //
2221                                 if (unreachable) {
2222                                         if (s is EmptyStatement)
2223                                                 continue;
2224
2225                                         if (!unreachable_shown && !(s is LabeledStatement)) {
2226                                                 Report.Warning (162, 2, s.loc, "Unreachable code detected");
2227                                                 unreachable_shown = true;
2228                                         }
2229
2230                                         Block c_block = s as Block;
2231                                         if (c_block != null)
2232                                                 c_block.unreachable = c_block.unreachable_shown = true;
2233                                 }
2234
2235                                 //
2236                                 // Note that we're not using ResolveUnreachable() for unreachable
2237                                 // statements here.  ResolveUnreachable() creates a temporary
2238                                 // flow branching and kills it afterwards.  This leads to problems
2239                                 // if you have two unreachable statements where the first one
2240                                 // assigns a variable and the second one tries to access it.
2241                                 //
2242
2243                                 if (!s.Resolve (ec)) {
2244                                         ok = false;
2245                                         if (ec.IsInProbingMode)
2246                                                 break;
2247
2248                                         statements [ix] = EmptyStatement.Value;
2249                                         continue;
2250                                 }
2251
2252                                 if (unreachable && !(s is LabeledStatement) && !(s is Block))
2253                                         statements [ix] = EmptyStatement.Value;
2254
2255                                 unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
2256                                 if (unreachable && s is LabeledStatement)
2257                                         throw new InternalErrorException ("should not happen");
2258                         }
2259
2260                         Report.Debug (4, "RESOLVE BLOCK DONE", StartLocation,
2261                                       ec.CurrentBranching, statement_count);
2262
2263                         while (ec.CurrentBranching is FlowBranchingLabeled)
2264                                 ec.EndFlowBranching ();
2265
2266                         bool flow_unreachable = ec.EndFlowBranching ();
2267
2268                         ec.CurrentBlock = prev_block;
2269
2270                         if (flow_unreachable)
2271                                 flags |= Flags.HasRet;
2272
2273                         // If we're a non-static `struct' constructor which doesn't have an
2274                         // initializer, then we must initialize all of the struct's fields.
2275                         if (this == Toplevel && !Toplevel.IsThisAssigned (ec) && !flow_unreachable)
2276                                 ok = false;
2277
2278                         if ((labels != null) && (Report.WarningLevel >= 2)) {
2279                                 foreach (LabeledStatement label in labels.Values)
2280                                         if (!label.HasBeenReferenced)
2281                                                 Report.Warning (164, 2, label.loc, "This label has not been referenced");
2282                         }
2283
2284                         if (ok && errors == Report.Errors)
2285                                 UsageWarning ();
2286
2287                         return ok;
2288                 }
2289
2290                 public override bool ResolveUnreachable (BlockContext ec, bool warn)
2291                 {
2292                         unreachable_shown = true;
2293                         unreachable = true;
2294
2295                         if (warn)
2296                                 Report.Warning (162, 2, loc, "Unreachable code detected");
2297
2298                         ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc);
2299                         bool ok = Resolve (ec);
2300                         ec.KillFlowBranching ();
2301
2302                         return ok;
2303                 }
2304                 
2305                 protected override void DoEmit (EmitContext ec)
2306                 {
2307                         for (int ix = 0; ix < statements.Count; ix++){
2308                                 Statement s = (Statement) statements [ix];
2309                                 s.Emit (ec);
2310                         }
2311                 }
2312
2313                 public override void Emit (EmitContext ec)
2314                 {
2315                         if (scope_initializers != null)
2316                                 EmitScopeInitializers (ec);
2317
2318                         ec.Mark (StartLocation);
2319                         DoEmit (ec);
2320
2321                         if (SymbolWriter.HasSymbolWriter)
2322                                 EmitSymbolInfo (ec);
2323                 }
2324
2325                 protected void EmitScopeInitializers (EmitContext ec)
2326                 {
2327                         SymbolWriter.OpenCompilerGeneratedBlock (ec.ig);
2328
2329                         using (ec.With (EmitContext.Options.OmitDebugInfo, true)) {
2330                                 foreach (Statement s in scope_initializers)
2331                                         s.Emit (ec);
2332                         }
2333
2334                         SymbolWriter.CloseCompilerGeneratedBlock (ec.ig);
2335                 }
2336
2337                 protected virtual void EmitSymbolInfo (EmitContext ec)
2338                 {
2339                         if (variables != null) {
2340                                 foreach (LocalInfo vi in variables.Values) {
2341                                         vi.EmitSymbolInfo (ec);
2342                                 }
2343                         }
2344                 }
2345
2346                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2347                 {
2348                         MutateVariables (storey);
2349
2350                         if (scope_initializers != null) {
2351                                 foreach (Statement s in scope_initializers)
2352                                         s.MutateHoistedGenericType (storey);
2353                         }
2354
2355                         foreach (Statement s in statements)
2356                                 s.MutateHoistedGenericType (storey);
2357                 }
2358
2359                 void MutateVariables (AnonymousMethodStorey storey)
2360                 {
2361                         if (variables != null) {
2362                                 foreach (LocalInfo vi in variables.Values) {
2363                                         vi.VariableType = storey.MutateType (vi.VariableType);
2364                                 }
2365                         }
2366
2367                         if (temporary_variables != null) {
2368                                 foreach (LocalInfo vi in temporary_variables)
2369                                         vi.VariableType = storey.MutateType (vi.VariableType);
2370                         }
2371                 }
2372
2373                 public override string ToString ()
2374                 {
2375                         return String.Format ("{0} ({1}:{2})", GetType (),ID, StartLocation);
2376                 }
2377
2378                 protected override void CloneTo (CloneContext clonectx, Statement t)
2379                 {
2380                         Block target = (Block) t;
2381
2382                         clonectx.AddBlockMap (this, target);
2383
2384                         //target.Toplevel = (ToplevelBlock) clonectx.LookupBlock (Toplevel);
2385                         target.Explicit = (ExplicitBlock) clonectx.LookupBlock (Explicit);
2386                         if (Parent != null)
2387                                 target.Parent = clonectx.RemapBlockCopy (Parent);
2388
2389                         if (variables != null){
2390                                 target.variables = new Hashtable ();
2391
2392                                 foreach (DictionaryEntry de in variables){
2393                                         LocalInfo newlocal = ((LocalInfo) de.Value).Clone (clonectx);
2394                                         target.variables [de.Key] = newlocal;
2395                                         clonectx.AddVariableMap ((LocalInfo) de.Value, newlocal);
2396                                 }
2397                         }
2398
2399                         target.statements = new ArrayList (statements.Count);
2400                         foreach (Statement s in statements)
2401                                 target.statements.Add (s.Clone (clonectx));
2402
2403                         if (target.children != null){
2404                                 target.children = new ArrayList (children.Count);
2405                                 foreach (Block b in children){
2406                                         target.children.Add (clonectx.LookupBlock (b));
2407                                 }
2408                         }
2409
2410                         //
2411                         // TODO: labels, switch_block, constants (?), anonymous_children
2412                         //
2413                 }
2414         }
2415
2416         public class ExplicitBlock : Block {
2417                 HybridDictionary known_variables;
2418                 protected AnonymousMethodStorey am_storey;
2419
2420                 public ExplicitBlock (Block parent, Location start, Location end)
2421                         : this (parent, (Flags) 0, start, end)
2422                 {
2423                 }
2424
2425                 public ExplicitBlock (Block parent, Flags flags, Location start, Location end)
2426                         : base (parent, flags, start, end)
2427                 {
2428                         this.Explicit = this;
2429                 }
2430
2431                 // <summary>
2432                 //   Marks a variable with name @name as being used in this or a child block.
2433                 //   If a variable name has been used in a child block, it's illegal to
2434                 //   declare a variable with the same name in the current block.
2435                 // </summary>
2436                 internal void AddKnownVariable (string name, IKnownVariable info)
2437                 {
2438                         if (known_variables == null)
2439                                 known_variables = new HybridDictionary();
2440
2441                         known_variables [name] = info;
2442
2443                         if (Parent != null)
2444                                 Parent.Explicit.AddKnownVariable (name, info);
2445                 }
2446
2447                 public AnonymousMethodStorey AnonymousMethodStorey {
2448                         get { return am_storey; }
2449                 }
2450
2451                 //
2452                 // Creates anonymous method storey in current block
2453                 //
2454                 public AnonymousMethodStorey CreateAnonymousMethodStorey (ResolveContext ec)
2455                 {
2456                         //
2457                         // When referencing a variable in iterator storey from children anonymous method
2458                         //
2459                         if (Toplevel.am_storey is IteratorStorey) {
2460                                 return Toplevel.am_storey;
2461                         }
2462
2463                         //
2464                         // An iterator has only 1 storey block
2465                         //
2466                         if (ec.CurrentIterator != null)
2467                             return ec.CurrentIterator.Storey;
2468
2469                         if (am_storey == null) {
2470                                 MemberBase mc = ec.MemberContext as MemberBase;
2471                                 GenericMethod gm = mc == null ? null : mc.GenericMethod;
2472
2473                                 //
2474                                 // Creates anonymous method storey for this block
2475                                 //
2476                                 am_storey = new AnonymousMethodStorey (this, ec.CurrentTypeDefinition, mc, gm, "AnonStorey");
2477                         }
2478
2479                         return am_storey;
2480                 }
2481
2482                 public override void Emit (EmitContext ec)
2483                 {
2484                         if (am_storey != null)
2485                                 am_storey.EmitStoreyInstantiation (ec);
2486
2487                         bool emit_debug_info = SymbolWriter.HasSymbolWriter && Parent != null && !(am_storey is IteratorStorey);
2488                         if (emit_debug_info)
2489                                 ec.BeginScope ();
2490
2491                         base.Emit (ec);
2492
2493                         if (emit_debug_info)
2494                                 ec.EndScope ();
2495                 }
2496
2497                 public override void EmitMeta (EmitContext ec)
2498                 {
2499                         //
2500                         // Creates anonymous method storey
2501                         //
2502                         if (am_storey != null) {
2503                                 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.Storey != null) {
2504                                         //
2505                                         // Creates parent storey reference when hoisted this is accessible
2506                                         //
2507                                         if (am_storey.OriginalSourceBlock.Explicit.HasCapturedThis) {
2508                                                 ExplicitBlock parent = Toplevel.Parent.Explicit;
2509
2510                                                 //
2511                                                 // Hoisted this exists in top-level parent storey only
2512                                                 //
2513                                                 while (parent.am_storey == null || parent.am_storey.Parent is AnonymousMethodStorey)
2514                                                         parent = parent.Parent.Explicit;
2515
2516                                                 am_storey.AddParentStoreyReference (parent.am_storey);
2517                                         }
2518
2519                                         am_storey.ChangeParentStorey (ec.CurrentAnonymousMethod.Storey);
2520                                 }
2521
2522                                 am_storey.DefineType ();
2523                                 am_storey.ResolveType ();
2524                                 am_storey.Define ();
2525                                 am_storey.Parent.PartialContainer.AddCompilerGeneratedClass (am_storey);
2526
2527                                 ArrayList ref_blocks = am_storey.ReferencesFromChildrenBlock;
2528                                 if (ref_blocks != null) {
2529                                         foreach (ExplicitBlock ref_block in ref_blocks) {
2530                                                 for (ExplicitBlock b = ref_block.Explicit; b != this; b = b.Parent.Explicit) {
2531                                                         if (b.am_storey != null) {
2532                                                                 b.am_storey.AddParentStoreyReference (am_storey);
2533
2534                                                                 // Stop propagation inside same top block
2535                                                                 if (b.Toplevel == Toplevel)
2536                                                                         break;
2537
2538                                                                 b = b.Toplevel;
2539                                                     }
2540                                                         b.HasCapturedVariable = true;
2541                                                 }
2542                                         }
2543                                 }
2544                         }
2545
2546                         base.EmitMeta (ec);
2547                 }
2548
2549                 internal IKnownVariable GetKnownVariable (string name)
2550                 {
2551                         return known_variables == null ? null : (IKnownVariable) known_variables [name];
2552                 }
2553
2554                 public bool HasCapturedThis
2555                 {
2556                         set { flags = value ? flags | Flags.HasCapturedThis : flags & ~Flags.HasCapturedThis; }
2557                         get { return (flags & Flags.HasCapturedThis) != 0; }
2558                 }
2559
2560                 public bool HasCapturedVariable
2561                 {
2562                         set { flags = value ? flags | Flags.HasCapturedVariable : flags & ~Flags.HasCapturedVariable; }
2563                         get { return (flags & Flags.HasCapturedVariable) != 0; }
2564                 }
2565
2566                 protected override void CloneTo (CloneContext clonectx, Statement t)
2567                 {
2568                         ExplicitBlock target = (ExplicitBlock) t;
2569                         target.known_variables = null;
2570                         base.CloneTo (clonectx, t);
2571                 }
2572         }
2573
2574         public class ToplevelParameterInfo : IKnownVariable {
2575                 public readonly ToplevelBlock Block;
2576                 public readonly int Index;
2577                 public VariableInfo VariableInfo;
2578
2579                 Block IKnownVariable.Block {
2580                         get { return Block; }
2581                 }
2582                 public Parameter Parameter {
2583                         get { return Block.Parameters [Index]; }
2584                 }
2585
2586                 public Type ParameterType {
2587                         get { return Block.Parameters.Types [Index]; }
2588                 }
2589
2590                 public Location Location {
2591                         get { return Parameter.Location; }
2592                 }
2593
2594                 public ToplevelParameterInfo (ToplevelBlock block, int idx)
2595                 {
2596                         this.Block = block;
2597                         this.Index = idx;
2598                 }
2599         }
2600
2601         //
2602         // A toplevel block contains extra information, the split is done
2603         // only to separate information that would otherwise bloat the more
2604         // lightweight Block.
2605         //
2606         // In particular, this was introduced when the support for Anonymous
2607         // Methods was implemented. 
2608         // 
2609         public class ToplevelBlock : ExplicitBlock
2610         {
2611                 // 
2612                 // Block is converted to an expression
2613                 //
2614                 sealed class BlockScopeExpression : Expression
2615                 {
2616                         Expression child;
2617                         readonly ToplevelBlock block;
2618
2619                         public BlockScopeExpression (Expression child, ToplevelBlock block)
2620                         {
2621                                 this.child = child;
2622                                 this.block = block;
2623                         }
2624
2625                         public override Expression CreateExpressionTree (ResolveContext ec)
2626                         {
2627                                 throw new NotSupportedException ();
2628                         }
2629
2630                         public override Expression DoResolve (ResolveContext ec)
2631                         {
2632                                 if (child == null)
2633                                         return null;
2634                                 
2635                                 child = child.Resolve (ec);
2636                                 if (child == null)
2637                                         return null;
2638
2639                                 eclass = child.eclass;
2640                                 type = child.Type;
2641                                 return this;
2642                         }
2643
2644                         public override void Emit (EmitContext ec)
2645                         {
2646                                 block.EmitMeta (ec);
2647                                 block.EmitScopeInitializers (ec);
2648                                 child.Emit (ec);
2649                         }
2650
2651                         public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2652                         {
2653                                 type = storey.MutateType (type);
2654                                 child.MutateHoistedGenericType (storey);
2655                                 block.MutateHoistedGenericType (storey);
2656                         }
2657                 }
2658
2659                 GenericMethod generic;
2660                 protected ParametersCompiled parameters;
2661                 ToplevelParameterInfo[] parameter_info;
2662                 LocalInfo this_variable;
2663                 bool resolved;
2664                 bool unreachable;
2665
2666                 public HoistedVariable HoistedThisVariable;
2667
2668                 public bool Resolved {
2669                         get {
2670                                 return resolved;
2671                         }
2672                 }
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 (ResolveContext 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 (BlockContext ec)
2881                 {
2882                         return this_variable == null || this_variable.IsThisAssigned (ec, this);
2883                 }
2884
2885                 public bool Resolve (FlowBranching parent, BlockContext 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 (ResolveContext.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 (BlockContext 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 (ResolveContext 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 (ResolveContext 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 (ResolveContext 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 (BlockContext 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 (ResolveContext 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                         ResolveContext rc = new ResolveContext (ec.MemberContext);
3860
3861                         if (TypeManager.generic_ienumerable_type != null) {
3862                                 Arguments get_value_args = new Arguments (2);
3863                                 get_value_args.Add (new Argument (value));
3864                                 get_value_args.Add (new Argument (string_switch_variable, Argument.AType.Out));
3865                                 Expression get_item = new Invocation (new MemberAccess (switch_cache_field, "TryGetValue", loc), get_value_args).Resolve (rc);
3866                                 if (get_item == null)
3867                                         return;
3868
3869                                 //
3870                                 // A value was not found, go to default case
3871                                 //
3872                                 get_item.EmitBranchable (ec, default_target, false);
3873                         } else {
3874                                 Arguments get_value_args = new Arguments (1);
3875                                 get_value_args.Add (new Argument (value));
3876
3877                                 Expression get_item = new IndexerAccess (new ElementAccess (switch_cache_field, get_value_args), loc).Resolve (rc);
3878                                 if (get_item == null)
3879                                         return;
3880
3881                                 LocalTemporary get_item_object = new LocalTemporary (TypeManager.object_type);
3882                                 get_item_object.EmitAssign (ec, get_item, true, false);
3883                                 ec.ig.Emit (OpCodes.Brfalse, default_target);
3884
3885                                 ExpressionStatement get_item_int = (ExpressionStatement) new SimpleAssign (string_switch_variable,
3886                                         new Cast (new TypeExpression (TypeManager.int32_type, loc), get_item_object, loc)).Resolve (rc);
3887
3888                                 get_item_int.EmitStatement (ec);
3889                                 get_item_object.Release (ec);
3890                         }
3891
3892                         TableSwitchEmit (ec, string_switch_variable);
3893                         string_switch_variable.Release (ec);
3894                 }
3895                 
3896                 protected override void DoEmit (EmitContext ec)
3897                 {
3898                         ILGenerator ig = ec.ig;
3899
3900                         default_target = ig.DefineLabel ();
3901                         null_target = ig.DefineLabel ();
3902
3903                         // Store variable for comparission purposes
3904                         // TODO: Don't duplicate non-captured VariableReference
3905                         LocalTemporary value;
3906                         if (HaveUnwrap) {
3907                                 value = new LocalTemporary (SwitchType);
3908                                 unwrap.EmitCheck (ec);
3909                                 ig.Emit (OpCodes.Brfalse, null_target);
3910                                 new_expr.Emit (ec);
3911                                 value.Store (ec);
3912                         } else if (!is_constant) {
3913                                 value = new LocalTemporary (SwitchType);
3914                                 new_expr.Emit (ec);
3915                                 value.Store (ec);
3916                         } else
3917                                 value = null;
3918
3919                         //
3920                         // Setup the codegen context
3921                         //
3922                         Label old_end = ec.LoopEnd;
3923                         Switch old_switch = ec.Switch;
3924                         
3925                         ec.LoopEnd = ig.DefineLabel ();
3926                         ec.Switch = this;
3927
3928                         // Emit Code.
3929                         if (is_constant) {
3930                                 if (constant_section != null)
3931                                         constant_section.Block.Emit (ec);
3932                         } else if (string_dictionary != null) {
3933                                 DoEmitStringSwitch (value, ec);
3934                         } else {
3935                                 TableSwitchEmit (ec, value);
3936                         }
3937
3938                         if (value != null)
3939                                 value.Release (ec);
3940
3941                         // Restore context state. 
3942                         ig.MarkLabel (ec.LoopEnd);
3943
3944                         //
3945                         // Restore the previous context
3946                         //
3947                         ec.LoopEnd = old_end;
3948                         ec.Switch = old_switch;
3949                 }
3950
3951                 protected override void CloneTo (CloneContext clonectx, Statement t)
3952                 {
3953                         Switch target = (Switch) t;
3954
3955                         target.Expr = Expr.Clone (clonectx);
3956                         target.Sections = new ArrayList ();
3957                         foreach (SwitchSection ss in Sections){
3958                                 target.Sections.Add (ss.Clone (clonectx));
3959                         }
3960                 }
3961         }
3962
3963         // A place where execution can restart in an iterator
3964         public abstract class ResumableStatement : Statement
3965         {
3966                 bool prepared;
3967                 protected Label resume_point;
3968
3969                 public Label PrepareForEmit (EmitContext ec)
3970                 {
3971                         if (!prepared) {
3972                                 prepared = true;
3973                                 resume_point = ec.ig.DefineLabel ();
3974                         }
3975                         return resume_point;
3976                 }
3977
3978                 public virtual Label PrepareForDispose (EmitContext ec, Label end)
3979                 {
3980                         return end;
3981                 }
3982                 public virtual void EmitForDispose (EmitContext ec, Iterator iterator, Label end, bool have_dispatcher)
3983                 {
3984                 }
3985         }
3986
3987         // Base class for statements that are implemented in terms of try...finally
3988         public abstract class ExceptionStatement : ResumableStatement
3989         {
3990                 bool code_follows;
3991                 Iterator iter;
3992
3993                 protected abstract void EmitPreTryBody (EmitContext ec);
3994                 protected abstract void EmitTryBody (EmitContext ec);
3995                 protected abstract void EmitFinallyBody (EmitContext ec);
3996
3997                 protected sealed override void DoEmit (EmitContext ec)
3998                 {
3999                         ILGenerator ig = ec.ig;
4000
4001                         EmitPreTryBody (ec);
4002
4003                         if (resume_points != null) {
4004                                 IntConstant.EmitInt (ig, (int) Iterator.State.Running);
4005                                 ig.Emit (OpCodes.Stloc, iter.CurrentPC);
4006                         }
4007
4008                         ig.BeginExceptionBlock ();
4009
4010                         if (resume_points != null) {
4011                                 ig.MarkLabel (resume_point);
4012
4013                                 // For normal control flow, we want to fall-through the Switch
4014                                 // So, we use CurrentPC rather than the $PC field, and initialize it to an outside value above
4015                                 ig.Emit (OpCodes.Ldloc, iter.CurrentPC);
4016                                 IntConstant.EmitInt (ig, first_resume_pc);
4017                                 ig.Emit (OpCodes.Sub);
4018
4019                                 Label [] labels = new Label [resume_points.Count];
4020                                 for (int i = 0; i < resume_points.Count; ++i)
4021                                         labels [i] = ((ResumableStatement) resume_points [i]).PrepareForEmit (ec);
4022                                 ig.Emit (OpCodes.Switch, labels);
4023                         }
4024
4025                         EmitTryBody (ec);
4026
4027                         ig.BeginFinallyBlock ();
4028
4029                         Label start_finally = ec.ig.DefineLabel ();
4030                         if (resume_points != null) {
4031                                 ig.Emit (OpCodes.Ldloc, iter.SkipFinally);
4032                                 ig.Emit (OpCodes.Brfalse_S, start_finally);
4033                                 ig.Emit (OpCodes.Endfinally);
4034                         }
4035
4036                         ig.MarkLabel (start_finally);
4037                         EmitFinallyBody (ec);
4038
4039                         ig.EndExceptionBlock ();
4040                 }
4041
4042                 public void SomeCodeFollows ()
4043                 {
4044                         code_follows = true;
4045                 }
4046
4047                 public override bool Resolve (BlockContext ec)
4048                 {
4049                         // System.Reflection.Emit automatically emits a 'leave' at the end of a try clause
4050                         // So, ensure there's some IL code after this statement.
4051                         if (!code_follows && resume_points == null && ec.CurrentBranching.CurrentUsageVector.IsUnreachable)
4052                                 ec.NeedReturnLabel ();
4053
4054                         iter = ec.CurrentIterator;
4055                         return true;
4056                 }
4057
4058                 ArrayList resume_points;
4059                 int first_resume_pc;
4060                 public void AddResumePoint (ResumableStatement stmt, int pc)
4061                 {
4062                         if (resume_points == null) {
4063                                 resume_points = new ArrayList ();
4064                                 first_resume_pc = pc;
4065                         }
4066
4067                         if (pc != first_resume_pc + resume_points.Count)
4068                                 throw new InternalErrorException ("missed an intervening AddResumePoint?");
4069
4070                         resume_points.Add (stmt);
4071                 }
4072
4073                 Label dispose_try_block;
4074                 bool prepared_for_dispose, emitted_dispose;
4075                 public override Label PrepareForDispose (EmitContext ec, Label end)
4076                 {
4077                         if (!prepared_for_dispose) {
4078                                 prepared_for_dispose = true;
4079                                 dispose_try_block = ec.ig.DefineLabel ();
4080                         }
4081                         return dispose_try_block;
4082                 }
4083
4084                 public override void EmitForDispose (EmitContext ec, Iterator iterator, Label end, bool have_dispatcher)
4085                 {
4086                         if (emitted_dispose)
4087                                 return;
4088
4089                         emitted_dispose = true;
4090
4091                         ILGenerator ig = ec.ig;
4092
4093                         Label end_of_try = ig.DefineLabel ();
4094
4095                         // Ensure that the only way we can get into this code is through a dispatcher
4096                         if (have_dispatcher)
4097                                 ig.Emit (OpCodes.Br, end);
4098
4099                         ig.BeginExceptionBlock ();
4100
4101                         ig.MarkLabel (dispose_try_block);
4102
4103                         Label [] labels = null;
4104                         for (int i = 0; i < resume_points.Count; ++i) {
4105                                 ResumableStatement s = (ResumableStatement) resume_points [i];
4106                                 Label ret = s.PrepareForDispose (ec, end_of_try);
4107                                 if (ret.Equals (end_of_try) && labels == null)
4108                                         continue;
4109                                 if (labels == null) {
4110                                         labels = new Label [resume_points.Count];
4111                                         for (int j = 0; j < i; ++j)
4112                                                 labels [j] = end_of_try;
4113                                 }
4114                                 labels [i] = ret;
4115                         }
4116
4117                         if (labels != null) {
4118                                 int j;
4119                                 for (j = 1; j < labels.Length; ++j)
4120                                         if (!labels [0].Equals (labels [j]))
4121                                                 break;
4122                                 bool emit_dispatcher = j < labels.Length;
4123
4124                                 if (emit_dispatcher) {
4125                                         //SymbolWriter.StartIteratorDispatcher (ec.ig);
4126                                         ig.Emit (OpCodes.Ldloc, iterator.CurrentPC);
4127                                         IntConstant.EmitInt (ig, first_resume_pc);
4128                                         ig.Emit (OpCodes.Sub);
4129                                         ig.Emit (OpCodes.Switch, labels);
4130                                         //SymbolWriter.EndIteratorDispatcher (ec.ig);
4131                                 }
4132
4133                                 foreach (ResumableStatement s in resume_points)
4134                                         s.EmitForDispose (ec, iterator, end_of_try, emit_dispatcher);
4135                         }
4136
4137                         ig.MarkLabel (end_of_try);
4138
4139                         ig.BeginFinallyBlock ();
4140
4141                         EmitFinallyBody (ec);
4142
4143                         ig.EndExceptionBlock ();
4144                 }
4145         }
4146
4147         public class Lock : ExceptionStatement {
4148                 Expression expr;
4149                 public Statement Statement;
4150                 TemporaryVariable temp;
4151                         
4152                 public Lock (Expression expr, Statement stmt, Location l)
4153                 {
4154                         this.expr = expr;
4155                         Statement = stmt;
4156                         loc = l;
4157                 }
4158
4159                 public override bool Resolve (BlockContext ec)
4160                 {
4161                         expr = expr.Resolve (ec);
4162                         if (expr == null)
4163                                 return false;
4164
4165                         if (!TypeManager.IsReferenceType (expr.Type)){
4166                                 Report.Error (185, loc,
4167                                               "`{0}' is not a reference type as required by the lock statement",
4168                                               TypeManager.CSharpName (expr.Type));
4169                                 return false;
4170                         }
4171
4172                         ec.StartFlowBranching (this);
4173                         bool ok = Statement.Resolve (ec);
4174                         ec.EndFlowBranching ();
4175
4176                         ok &= base.Resolve (ec);
4177
4178                         // Avoid creating libraries that reference the internal
4179                         // mcs NullType:
4180                         Type t = expr.Type;
4181                         if (t == TypeManager.null_type)
4182                                 t = TypeManager.object_type;
4183                         
4184                         temp = new TemporaryVariable (t, loc);
4185                         temp.Resolve (ec);
4186
4187                         if (TypeManager.void_monitor_enter_object == null || TypeManager.void_monitor_exit_object == null) {
4188                                 Type monitor_type = TypeManager.CoreLookupType ("System.Threading", "Monitor", Kind.Class, true);
4189                                 TypeManager.void_monitor_enter_object = TypeManager.GetPredefinedMethod (
4190                                         monitor_type, "Enter", loc, TypeManager.object_type);
4191                                 TypeManager.void_monitor_exit_object = TypeManager.GetPredefinedMethod (
4192                                         monitor_type, "Exit", loc, TypeManager.object_type);
4193                         }
4194                         
4195                         return ok;
4196                 }
4197                 
4198                 protected override void EmitPreTryBody (EmitContext ec)
4199                 {
4200                         ILGenerator ig = ec.ig;
4201
4202                         temp.EmitAssign (ec, expr);
4203                         temp.Emit (ec);
4204                         ig.Emit (OpCodes.Call, TypeManager.void_monitor_enter_object);
4205                 }
4206
4207                 protected override void EmitTryBody (EmitContext ec)
4208                 {
4209                         Statement.Emit (ec);
4210                 }
4211
4212                 protected override void EmitFinallyBody (EmitContext ec)
4213                 {
4214                         temp.Emit (ec);
4215                         ec.ig.Emit (OpCodes.Call, TypeManager.void_monitor_exit_object);
4216                 }
4217
4218                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4219                 {
4220                         expr.MutateHoistedGenericType (storey);
4221                         temp.MutateHoistedGenericType (storey);
4222                         Statement.MutateHoistedGenericType (storey);
4223                 }
4224                 
4225                 protected override void CloneTo (CloneContext clonectx, Statement t)
4226                 {
4227                         Lock target = (Lock) t;
4228
4229                         target.expr = expr.Clone (clonectx);
4230                         target.Statement = Statement.Clone (clonectx);
4231                 }
4232         }
4233
4234         public class Unchecked : Statement {
4235                 public Block Block;
4236                 
4237                 public Unchecked (Block b)
4238                 {
4239                         Block = b;
4240                         b.Unchecked = true;
4241                 }
4242
4243                 public override bool Resolve (BlockContext ec)
4244                 {
4245                         using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
4246                                 return Block.Resolve (ec);
4247                 }
4248                 
4249                 protected override void DoEmit (EmitContext ec)
4250                 {
4251                         using (ec.With (EmitContext.Options.AllCheckStateFlags, false))
4252                                 Block.Emit (ec);
4253                 }
4254
4255                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4256                 {
4257                         Block.MutateHoistedGenericType (storey);
4258                 }
4259
4260                 protected override void CloneTo (CloneContext clonectx, Statement t)
4261                 {
4262                         Unchecked target = (Unchecked) t;
4263
4264                         target.Block = clonectx.LookupBlock (Block);
4265                 }
4266         }
4267
4268         public class Checked : Statement {
4269                 public Block Block;
4270                 
4271                 public Checked (Block b)
4272                 {
4273                         Block = b;
4274                         b.Unchecked = false;
4275                 }
4276
4277                 public override bool Resolve (BlockContext ec)
4278                 {
4279                         using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
4280                                 return Block.Resolve (ec);
4281                 }
4282
4283                 protected override void DoEmit (EmitContext ec)
4284                 {
4285                         using (ec.With (EmitContext.Options.AllCheckStateFlags, true))
4286                                 Block.Emit (ec);
4287                 }
4288
4289                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4290                 {
4291                         Block.MutateHoistedGenericType (storey);
4292                 }
4293
4294                 protected override void CloneTo (CloneContext clonectx, Statement t)
4295                 {
4296                         Checked target = (Checked) t;
4297
4298                         target.Block = clonectx.LookupBlock (Block);
4299                 }
4300         }
4301
4302         public class Unsafe : Statement {
4303                 public Block Block;
4304
4305                 public Unsafe (Block b)
4306                 {
4307                         Block = b;
4308                         Block.Unsafe = true;
4309                         loc = b.StartLocation;
4310                 }
4311
4312                 public override bool Resolve (BlockContext ec)
4313                 {
4314                         if (ec.CurrentIterator != null)
4315                                 Report.Error (1629, loc, "Unsafe code may not appear in iterators");
4316
4317                         using (ec.Set (ResolveContext.Options.UnsafeScope))
4318                                 return Block.Resolve (ec);
4319                 }
4320                 
4321                 protected override void DoEmit (EmitContext ec)
4322                 {
4323                         Block.Emit (ec);
4324                 }
4325
4326                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4327                 {
4328                         Block.MutateHoistedGenericType (storey);
4329                 }
4330
4331                 protected override void CloneTo (CloneContext clonectx, Statement t)
4332                 {
4333                         Unsafe target = (Unsafe) t;
4334
4335                         target.Block = clonectx.LookupBlock (Block);
4336                 }
4337         }
4338
4339         // 
4340         // Fixed statement
4341         //
4342         public class Fixed : Statement {
4343                 Expression type;
4344                 ArrayList declarators;
4345                 Statement statement;
4346                 Type expr_type;
4347                 Emitter[] data;
4348                 bool has_ret;
4349
4350                 abstract class Emitter
4351                 {
4352                         protected LocalInfo vi;
4353                         protected Expression converted;
4354
4355                         protected Emitter (Expression expr, LocalInfo li)
4356                         {
4357                                 converted = expr;
4358                                 vi = li;
4359                         }
4360
4361                         public abstract void Emit (EmitContext ec);
4362                         public abstract void EmitExit (EmitContext ec);
4363                 }
4364
4365                 class ExpressionEmitter : Emitter {
4366                         public ExpressionEmitter (Expression converted, LocalInfo li) :
4367                                 base (converted, li)
4368                         {
4369                         }
4370
4371                         public override void Emit (EmitContext ec) {
4372                                 //
4373                                 // Store pointer in pinned location
4374                                 //
4375                                 converted.Emit (ec);
4376                                 vi.EmitAssign (ec);
4377                         }
4378
4379                         public override void EmitExit (EmitContext ec)
4380                         {
4381                                 ec.ig.Emit (OpCodes.Ldc_I4_0);
4382                                 ec.ig.Emit (OpCodes.Conv_U);
4383                                 vi.EmitAssign (ec);
4384                         }
4385                 }
4386
4387                 class StringEmitter : Emitter
4388                 {
4389                         LocalInfo pinned_string;
4390
4391                         public StringEmitter (Expression expr, LocalInfo li, Location loc):
4392                                 base (expr, li)
4393                         {
4394                                 pinned_string = new LocalInfo (new TypeExpression (TypeManager.string_type, loc), null, null, loc);
4395                                 pinned_string.Pinned = true;
4396                         }
4397
4398                         public StringEmitter Resolve (ResolveContext rc)
4399                         {
4400                                 pinned_string.Resolve (rc);
4401
4402                                 if (TypeManager.int_get_offset_to_string_data == null) {
4403                                         TypeManager.int_get_offset_to_string_data = TypeManager.GetPredefinedProperty (
4404                                                 TypeManager.runtime_helpers_type, "OffsetToStringData", pinned_string.Location, TypeManager.int32_type);
4405                                 }
4406
4407                                 return this;
4408                         }
4409
4410                         public override void Emit (EmitContext ec)
4411                         {
4412                                 pinned_string.ResolveVariable (ec);
4413
4414                                 converted.Emit (ec);
4415                                 pinned_string.EmitAssign (ec);
4416
4417                                 // TODO: Should use Binary::Add
4418                                 pinned_string.Emit (ec);
4419                                 ec.ig.Emit (OpCodes.Conv_I);
4420
4421                                 PropertyExpr pe = new PropertyExpr (pinned_string.VariableType, TypeManager.int_get_offset_to_string_data, pinned_string.Location);
4422                                 //pe.InstanceExpression = pinned_string;
4423                                 pe.Resolve (new ResolveContext (ec.MemberContext)).Emit (ec);
4424
4425                                 ec.ig.Emit (OpCodes.Add);
4426                                 vi.EmitAssign (ec);
4427                         }
4428
4429                         public override void EmitExit (EmitContext ec)
4430                         {
4431                                 ec.ig.Emit (OpCodes.Ldnull);
4432                                 pinned_string.EmitAssign (ec);
4433                         }
4434                 }
4435
4436                 public Fixed (Expression type, ArrayList decls, Statement stmt, Location l)
4437                 {
4438                         this.type = type;
4439                         declarators = decls;
4440                         statement = stmt;
4441                         loc = l;
4442                 }
4443
4444                 public Statement Statement {
4445                         get { return statement; }
4446                 }
4447
4448                 public override bool Resolve (BlockContext ec)
4449                 {
4450                         if (!ec.IsUnsafe){
4451                                 Expression.UnsafeError (loc);
4452                                 return false;
4453                         }
4454                         
4455                         TypeExpr texpr = type.ResolveAsContextualType (ec, false);
4456                         if (texpr == null) {
4457                                 if (type is VarExpr)
4458                                         Report.Error (821, type.Location, "A fixed statement cannot use an implicitly typed local variable");
4459
4460                                 return false;
4461                         }
4462
4463                         expr_type = texpr.Type;
4464
4465                         data = new Emitter [declarators.Count];
4466
4467                         if (!expr_type.IsPointer){
4468                                 Report.Error (209, loc, "The type of locals declared in a fixed statement must be a pointer type");
4469                                 return false;
4470                         }
4471                         
4472                         int i = 0;
4473                         foreach (Pair p in declarators){
4474                                 LocalInfo vi = (LocalInfo) p.First;
4475                                 Expression e = (Expression) p.Second;
4476                                 
4477                                 vi.VariableInfo.SetAssigned (ec);
4478                                 vi.SetReadOnlyContext (LocalInfo.ReadOnlyContext.Fixed);
4479
4480                                 //
4481                                 // The rules for the possible declarators are pretty wise,
4482                                 // but the production on the grammar is more concise.
4483                                 //
4484                                 // So we have to enforce these rules here.
4485                                 //
4486                                 // We do not resolve before doing the case 1 test,
4487                                 // because the grammar is explicit in that the token &
4488                                 // is present, so we need to test for this particular case.
4489                                 //
4490
4491                                 if (e is Cast){
4492                                         Report.Error (254, loc, "The right hand side of a fixed statement assignment may not be a cast expression");
4493                                         return false;
4494                                 }
4495
4496                                 using (ec.Set (ResolveContext.Options.FixedInitializerScope)) {
4497                                         e = e.Resolve (ec);
4498                                 }
4499
4500                                 if (e == null)
4501                                         return false;
4502
4503                                 //
4504                                 // Case 2: Array
4505                                 //
4506                                 if (e.Type.IsArray){
4507                                         Type array_type = TypeManager.GetElementType (e.Type);
4508                                         
4509                                         //
4510                                         // Provided that array_type is unmanaged,
4511                                         //
4512                                         if (!TypeManager.VerifyUnManaged (array_type, loc))
4513                                                 return false;
4514
4515                                         //
4516                                         // and T* is implicitly convertible to the
4517                                         // pointer type given in the fixed statement.
4518                                         //
4519                                         ArrayPtr array_ptr = new ArrayPtr (e, array_type, loc);
4520                                         
4521                                         Expression converted = Convert.ImplicitConversionRequired (
4522                                                 ec, array_ptr, vi.VariableType, loc);
4523                                         if (converted == null)
4524                                                 return false;
4525                                         
4526                                         //
4527                                         // fixed (T* e_ptr = (e == null || e.Length == 0) ? null : converted [0])
4528                                         //
4529                                         converted = new Conditional (new Binary (Binary.Operator.LogicalOr,
4530                                                 new Binary (Binary.Operator.Equality, e, new NullLiteral (loc)),
4531                                                 new Binary (Binary.Operator.Equality, new MemberAccess (e, "Length"), new IntConstant (0, loc))),
4532                                                         new NullPointer (loc),
4533                                                         converted);
4534
4535                                         converted = converted.Resolve (ec);                                     
4536
4537                                         data [i] = new ExpressionEmitter (converted, vi);
4538                                         i++;
4539
4540                                         continue;
4541                                 }
4542
4543                                 //
4544                                 // Case 3: string
4545                                 //
4546                                 if (e.Type == TypeManager.string_type){
4547                                         data [i] = new StringEmitter (e, vi, loc).Resolve (ec);
4548                                         i++;
4549                                         continue;
4550                                 }
4551
4552                                 // Case 4: fixed buffer
4553                                 if (e is FixedBufferPtr) {
4554                                         data [i++] = new ExpressionEmitter (e, vi);
4555                                         continue;
4556                                 }
4557
4558                                 //
4559                                 // Case 1: & object.
4560                                 //
4561                                 Unary u = e as Unary;
4562                                 if (u != null && u.Oper == Unary.Operator.AddressOf) {
4563                                         IVariableReference vr = u.Expr as IVariableReference;
4564                                         if (vr == null || !vr.IsFixed) {
4565                                                 data [i] = new ExpressionEmitter (e, vi);
4566                                         }
4567                                 }
4568
4569                                 if (data [i++] == null)
4570                                         Report.Error (213, vi.Location, "You cannot use the fixed statement to take the address of an already fixed expression");
4571
4572                                 e = Convert.ImplicitConversionRequired (ec, e, expr_type, loc);
4573                         }
4574
4575                         ec.StartFlowBranching (FlowBranching.BranchingType.Conditional, loc);
4576                         bool ok = statement.Resolve (ec);
4577                         bool flow_unreachable = ec.EndFlowBranching ();
4578                         has_ret = flow_unreachable;
4579
4580                         return ok;
4581                 }
4582                 
4583                 protected override void DoEmit (EmitContext ec)
4584                 {
4585                         for (int i = 0; i < data.Length; i++) {
4586                                 data [i].Emit (ec);
4587                         }
4588
4589                         statement.Emit (ec);
4590
4591                         if (has_ret)
4592                                 return;
4593
4594                         //
4595                         // Clear the pinned variable
4596                         //
4597                         for (int i = 0; i < data.Length; i++) {
4598                                 data [i].EmitExit (ec);
4599                         }
4600                 }
4601
4602                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4603                 {
4604                         // Fixed statement cannot be used inside anonymous methods or lambdas
4605                         throw new NotSupportedException ();
4606                 }
4607
4608                 protected override void CloneTo (CloneContext clonectx, Statement t)
4609                 {
4610                         Fixed target = (Fixed) t;
4611
4612                         target.type = type.Clone (clonectx);
4613                         target.declarators = new ArrayList (declarators.Count);
4614                         foreach (Pair p in declarators) {
4615                                 LocalInfo vi = (LocalInfo) p.First;
4616                                 Expression e = (Expression) p.Second;
4617
4618                                 target.declarators.Add (
4619                                         new Pair (clonectx.LookupVariable (vi), e.Clone (clonectx)));                           
4620                         }
4621                         
4622                         target.statement = statement.Clone (clonectx);
4623                 }
4624         }
4625         
4626         public class Catch : Statement {
4627                 public readonly string Name;
4628                 public Block  Block;
4629                 public Block  VarBlock;
4630
4631                 Expression type_expr;
4632                 Type type;
4633                 
4634                 public Catch (Expression type, string name, Block block, Block var_block, Location l)
4635                 {
4636                         type_expr = type;
4637                         Name = name;
4638                         Block = block;
4639                         VarBlock = var_block;
4640                         loc = l;
4641                 }
4642
4643                 public Type CatchType {
4644                         get {
4645                                 return type;
4646                         }
4647                 }
4648
4649                 public bool IsGeneral {
4650                         get {
4651                                 return type_expr == null;
4652                         }
4653                 }
4654
4655                 protected override void DoEmit (EmitContext ec)
4656                 {
4657                         ILGenerator ig = ec.ig;
4658
4659                         if (CatchType != null)
4660                                 ig.BeginCatchBlock (CatchType);
4661                         else
4662                                 ig.BeginCatchBlock (TypeManager.object_type);
4663
4664                         if (VarBlock != null)
4665                                 VarBlock.Emit (ec);
4666
4667                         if (Name != null) {
4668                                 // TODO: Move to resolve
4669                                 LocalVariableReference lvr = new LocalVariableReference (Block, Name, loc);
4670                                 lvr.Resolve (new ResolveContext (ec.MemberContext));
4671                                 
4672 #if GMCS_SOURCE
4673                                 // Only to make verifier happy
4674                                 if (TypeManager.IsGenericParameter (lvr.Type))
4675                                         ig.Emit (OpCodes.Unbox_Any, lvr.Type);
4676 #endif
4677
4678                                 Expression source;
4679                                 if (lvr.IsHoisted) {
4680                                         LocalTemporary lt = new LocalTemporary (lvr.Type);
4681                                         lt.Store (ec);
4682                                         source = lt;
4683                                 } else {
4684                                         // Variable is at the top of the stack
4685                                         source = EmptyExpression.Null;
4686                                 }
4687
4688                                 lvr.EmitAssign (ec, source, false, false);
4689                         } else
4690                                 ig.Emit (OpCodes.Pop);
4691
4692                         Block.Emit (ec);
4693                 }
4694
4695                 public override bool Resolve (BlockContext ec)
4696                 {
4697                         using (ec.With (ResolveContext.Options.CatchScope, true)) {
4698                                 if (type_expr != null) {
4699                                         TypeExpr te = type_expr.ResolveAsTypeTerminal (ec, false);
4700                                         if (te == null)
4701                                                 return false;
4702
4703                                         type = te.Type;
4704
4705                                         if (type != TypeManager.exception_type && !TypeManager.IsSubclassOf (type, TypeManager.exception_type)){
4706                                                 Error (155, "The type caught or thrown must be derived from System.Exception");
4707                                                 return false;
4708                                         }
4709                                 } else
4710                                         type = null;
4711
4712                                 if (!Block.Resolve (ec))
4713                                         return false;
4714
4715                                 // Even though VarBlock surrounds 'Block' we resolve it later, so that we can correctly
4716                                 // emit the "unused variable" warnings.
4717                                 if (VarBlock != null)
4718                                         return VarBlock.Resolve (ec);
4719
4720                                 return true;
4721                         }
4722                 }
4723
4724                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4725                 {
4726                         if (type != null)
4727                                 type = storey.MutateType (type);
4728                         if (VarBlock != null)
4729                                 VarBlock.MutateHoistedGenericType (storey);
4730                         Block.MutateHoistedGenericType (storey);
4731                 }
4732
4733                 protected override void CloneTo (CloneContext clonectx, Statement t)
4734                 {
4735                         Catch target = (Catch) t;
4736
4737                         if (type_expr != null)
4738                                 target.type_expr = type_expr.Clone (clonectx);
4739                         if (VarBlock != null)
4740                                 target.VarBlock = clonectx.LookupBlock (VarBlock);                      
4741                         target.Block = clonectx.LookupBlock (Block);
4742                 }
4743         }
4744
4745         public class TryFinally : ExceptionStatement {
4746                 Statement stmt;
4747                 Block fini;
4748
4749                 public TryFinally (Statement stmt, Block fini, Location l)
4750                 {
4751                         this.stmt = stmt;
4752                         this.fini = fini;
4753                         loc = l;
4754                 }
4755
4756                 public override bool Resolve (BlockContext ec)
4757                 {
4758                         bool ok = true;
4759
4760                         ec.StartFlowBranching (this);
4761
4762                         if (!stmt.Resolve (ec))
4763                                 ok = false;
4764
4765                         if (ok)
4766                                 ec.CurrentBranching.CreateSibling (fini, FlowBranching.SiblingType.Finally);
4767                         using (ec.With (ResolveContext.Options.FinallyScope, true)) {
4768                                 if (!fini.Resolve (ec))
4769                                         ok = false;
4770                         }
4771
4772                         ec.EndFlowBranching ();
4773
4774                         ok &= base.Resolve (ec);
4775
4776                         return ok;
4777                 }
4778
4779                 protected override void EmitPreTryBody (EmitContext ec)
4780                 {
4781                 }
4782
4783                 protected override void EmitTryBody (EmitContext ec)
4784                 {
4785                         stmt.Emit (ec);
4786                 }
4787
4788                 protected override void EmitFinallyBody (EmitContext ec)
4789                 {
4790                         fini.Emit (ec);
4791                 }
4792
4793                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4794                 {
4795                         stmt.MutateHoistedGenericType (storey);
4796                         fini.MutateHoistedGenericType (storey);
4797                 }
4798
4799                 protected override void CloneTo (CloneContext clonectx, Statement t)
4800                 {
4801                         TryFinally target = (TryFinally) t;
4802
4803                         target.stmt = (Statement) stmt.Clone (clonectx);
4804                         if (fini != null)
4805                                 target.fini = clonectx.LookupBlock (fini);
4806                 }
4807         }
4808
4809         public class TryCatch : Statement {
4810                 public Block Block;
4811                 public ArrayList Specific;
4812                 public Catch General;
4813                 bool inside_try_finally, code_follows;
4814
4815                 public TryCatch (Block block, ArrayList catch_clauses, Location l, bool inside_try_finally)
4816                 {
4817                         this.Block = block;
4818                         this.Specific = catch_clauses;
4819                         this.General = null;
4820                         this.inside_try_finally = inside_try_finally;
4821
4822                         for (int i = 0; i < catch_clauses.Count; ++i) {
4823                                 Catch c = (Catch) catch_clauses [i];
4824                                 if (c.IsGeneral) {
4825                                         if (i != catch_clauses.Count - 1)
4826                                                 Report.Error (1017, c.loc, "Try statement already has an empty catch block");
4827                                         this.General = c;
4828                                         catch_clauses.RemoveAt (i);
4829                                         i--;
4830                                 }
4831                         }
4832
4833                         loc = l;
4834                 }
4835
4836                 public override bool Resolve (BlockContext ec)
4837                 {
4838                         bool ok = true;
4839
4840                         ec.StartFlowBranching (this);
4841
4842                         if (!Block.Resolve (ec))
4843                                 ok = false;
4844
4845                         Type[] prev_catches = new Type [Specific.Count];
4846                         int last_index = 0;
4847                         foreach (Catch c in Specific){
4848                                 ec.CurrentBranching.CreateSibling (c.Block, FlowBranching.SiblingType.Catch);
4849
4850                                 if (c.Name != null) {
4851                                         LocalInfo vi = c.Block.GetLocalInfo (c.Name);
4852                                         if (vi == null)
4853                                                 throw new Exception ();
4854
4855                                         vi.VariableInfo = null;
4856                                 }
4857
4858                                 if (!c.Resolve (ec)) {
4859                                         ok = false;
4860                                         continue;
4861                                 }
4862
4863                                 Type resolved_type = c.CatchType;
4864                                 for (int ii = 0; ii < last_index; ++ii) {
4865                                         if (resolved_type == prev_catches [ii] || TypeManager.IsSubclassOf (resolved_type, prev_catches [ii])) {
4866                                                 Report.Error (160, c.loc,
4867                                                         "A previous catch clause already catches all exceptions of this or a super type `{0}'",
4868                                                         TypeManager.CSharpName (prev_catches [ii]));
4869                                                 ok = false;
4870                                         }
4871                                 }
4872
4873                                 prev_catches [last_index++] = resolved_type;
4874                         }
4875
4876                         if (General != null) {
4877                                 if (CodeGen.Assembly.WrapNonExceptionThrows) {
4878                                         foreach (Catch c in Specific){
4879                                                 if (c.CatchType == TypeManager.exception_type && PredefinedAttributes.Get.RuntimeCompatibility.IsDefined) {
4880                                                         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'");
4881                                                 }
4882                                         }
4883                                 }
4884
4885                                 ec.CurrentBranching.CreateSibling (General.Block, FlowBranching.SiblingType.Catch);
4886
4887                                 if (!General.Resolve (ec))
4888                                         ok = false;
4889                         }
4890
4891                         ec.EndFlowBranching ();
4892
4893                         // System.Reflection.Emit automatically emits a 'leave' at the end of a try/catch clause
4894                         // So, ensure there's some IL code after this statement
4895                         if (!inside_try_finally && !code_follows && ec.CurrentBranching.CurrentUsageVector.IsUnreachable)
4896                                 ec.NeedReturnLabel ();
4897
4898                         return ok;
4899                 }
4900
4901                 public void SomeCodeFollows ()
4902                 {
4903                         code_follows = true;
4904                 }
4905                 
4906                 protected override void DoEmit (EmitContext ec)
4907                 {
4908                         ILGenerator ig = ec.ig;
4909
4910                         if (!inside_try_finally)
4911                                 ig.BeginExceptionBlock ();
4912
4913                         Block.Emit (ec);
4914
4915                         foreach (Catch c in Specific)
4916                                 c.Emit (ec);
4917
4918                         if (General != null)
4919                                 General.Emit (ec);
4920
4921                         if (!inside_try_finally)
4922                                 ig.EndExceptionBlock ();
4923                 }
4924
4925                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4926                 {
4927                         Block.MutateHoistedGenericType (storey);
4928
4929                         if (General != null)
4930                                 General.MutateHoistedGenericType (storey);
4931                         if (Specific != null) {
4932                                 foreach (Catch c in Specific)
4933                                         c.MutateHoistedGenericType (storey);
4934                         }
4935                 }
4936
4937                 protected override void CloneTo (CloneContext clonectx, Statement t)
4938                 {
4939                         TryCatch target = (TryCatch) t;
4940
4941                         target.Block = clonectx.LookupBlock (Block);
4942                         if (General != null)
4943                                 target.General = (Catch) General.Clone (clonectx);
4944                         if (Specific != null){
4945                                 target.Specific = new ArrayList ();
4946                                 foreach (Catch c in Specific)
4947                                         target.Specific.Add (c.Clone (clonectx));
4948                         }
4949                 }
4950         }
4951
4952         // FIXME: Why is it almost exact copy of Using ??
4953         public class UsingTemporary : ExceptionStatement {
4954                 TemporaryVariable local_copy;
4955                 public Statement Statement;
4956                 Expression expr;
4957                 Type expr_type;
4958
4959                 public UsingTemporary (Expression expr, Statement stmt, Location l)
4960                 {
4961                         this.expr = expr;
4962                         Statement = stmt;
4963                         loc = l;
4964                 }
4965
4966                 public override bool Resolve (BlockContext ec)
4967                 {
4968                         expr = expr.Resolve (ec);
4969                         if (expr == null)
4970                                 return false;
4971
4972                         expr_type = expr.Type;
4973
4974                         if (!TypeManager.ImplementsInterface (expr_type, TypeManager.idisposable_type)) {
4975                                 if (Convert.ImplicitConversion (ec, expr, TypeManager.idisposable_type, loc) == null) {
4976                                         Using.Error_IsNotConvertibleToIDisposable (expr);
4977                                         return false;
4978                                 }
4979                         }
4980
4981                         local_copy = new TemporaryVariable (expr_type, loc);
4982                         local_copy.Resolve (ec);
4983
4984                         ec.StartFlowBranching (this);
4985
4986                         bool ok = Statement.Resolve (ec);
4987
4988                         ec.EndFlowBranching ();
4989
4990                         ok &= base.Resolve (ec);
4991
4992                         if (TypeManager.void_dispose_void == null) {
4993                                 TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
4994                                         TypeManager.idisposable_type, "Dispose", loc, Type.EmptyTypes);
4995                         }
4996
4997                         return ok;
4998                 }
4999
5000                 protected override void EmitPreTryBody (EmitContext ec)
5001                 {
5002                         local_copy.EmitAssign (ec, expr);
5003                 }
5004
5005                 protected override void EmitTryBody (EmitContext ec)
5006                 {
5007                         Statement.Emit (ec);
5008                 }
5009
5010                 protected override void EmitFinallyBody (EmitContext ec)
5011                 {
5012                         ILGenerator ig = ec.ig;
5013                         if (!TypeManager.IsStruct (expr_type)) {
5014                                 Label skip = ig.DefineLabel ();
5015                                 local_copy.Emit (ec);
5016                                 ig.Emit (OpCodes.Brfalse, skip);
5017                                 local_copy.Emit (ec);
5018                                 ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
5019                                 ig.MarkLabel (skip);
5020                                 return;
5021                         }
5022
5023                         Expression ml = Expression.MemberLookup (
5024                                 ec.CurrentType, TypeManager.idisposable_type, expr_type,
5025                                 "Dispose", Location.Null);
5026
5027                         if (!(ml is MethodGroupExpr)) {
5028                                 local_copy.Emit (ec);
5029                                 ig.Emit (OpCodes.Box, expr_type);
5030                                 ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
5031                                 return;
5032                         }
5033
5034                         MethodInfo mi = null;
5035
5036                         foreach (MethodInfo mk in ((MethodGroupExpr) ml).Methods) {
5037                                 if (TypeManager.GetParameterData (mk).Count == 0) {
5038                                         mi = mk;
5039                                         break;
5040                                 }
5041                         }
5042
5043                         if (mi == null) {
5044                                 Report.Error(-100, Mono.CSharp.Location.Null, "Internal error: No Dispose method which takes 0 parameters.");
5045                                 return;
5046                         }
5047
5048                         local_copy.AddressOf (ec, AddressOp.Load);
5049                         ig.Emit (OpCodes.Call, mi);
5050                 }
5051
5052                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5053                 {
5054                         expr_type = storey.MutateType (expr_type);
5055                         local_copy.MutateHoistedGenericType (storey);
5056                         Statement.MutateHoistedGenericType (storey);
5057                 }
5058
5059                 protected override void CloneTo (CloneContext clonectx, Statement t)
5060                 {
5061                         UsingTemporary target = (UsingTemporary) t;
5062
5063                         target.expr = expr.Clone (clonectx);
5064                         target.Statement = Statement.Clone (clonectx);
5065                 }
5066         }
5067
5068         public class Using : ExceptionStatement {
5069                 Statement stmt;
5070                 public Statement EmbeddedStatement {
5071                         get { return stmt is Using ? ((Using) stmt).EmbeddedStatement : stmt; }
5072                 }
5073
5074                 Expression var;
5075                 Expression init;
5076
5077                 ExpressionStatement assign;
5078
5079                 public Using (Expression var, Expression init, Statement stmt, Location l)
5080                 {
5081                         this.var = var;
5082                         this.init = init;
5083                         this.stmt = stmt;
5084                         loc = l;
5085                 }
5086
5087                 static public void Error_IsNotConvertibleToIDisposable (Expression expr)
5088                 {
5089                         Report.SymbolRelatedToPreviousError (expr.Type);
5090                         Report.Error (1674, expr.Location, "`{0}': type used in a using statement must be implicitly convertible to `System.IDisposable'",
5091                                 expr.GetSignatureForError ());
5092                 }
5093
5094                 protected override void EmitPreTryBody (EmitContext ec)
5095                 {
5096                         assign.EmitStatement (ec);
5097                 }
5098
5099                 protected override void EmitTryBody (EmitContext ec)
5100                 {
5101                         stmt.Emit (ec);
5102                 }
5103
5104                 protected override void EmitFinallyBody (EmitContext ec)
5105                 {
5106                         ILGenerator ig = ec.ig;
5107                         Label skip = ig.DefineLabel ();
5108
5109                         bool emit_null_check = !TypeManager.IsValueType (var.Type);
5110                         if (emit_null_check) {
5111                                 var.Emit (ec);
5112                                 ig.Emit (OpCodes.Brfalse, skip);
5113                         }
5114
5115                         Invocation.EmitCall (ec, false, var, TypeManager.void_dispose_void, null, loc);
5116
5117                         if (emit_null_check)
5118                                 ig.MarkLabel (skip);
5119                 }
5120
5121                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5122                 {
5123                         assign.MutateHoistedGenericType (storey);
5124                         var.MutateHoistedGenericType (storey);
5125                         stmt.MutateHoistedGenericType (storey);
5126                 }
5127
5128                 public override bool Resolve (BlockContext ec)
5129                 {
5130                         if (!ResolveVariable (ec))
5131                                 return false;
5132
5133                         ec.StartFlowBranching (this);
5134
5135                         bool ok = stmt.Resolve (ec);
5136
5137                         ec.EndFlowBranching ();
5138
5139                         ok &= base.Resolve (ec);
5140
5141                         if (TypeManager.void_dispose_void == null) {
5142                                 TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
5143                                         TypeManager.idisposable_type, "Dispose", loc, Type.EmptyTypes);
5144                         }
5145
5146                         return ok;
5147                 }
5148
5149                 bool ResolveVariable (BlockContext ec)
5150                 {
5151                         assign = new SimpleAssign (var, init, loc);
5152                         assign = assign.ResolveStatement (ec);
5153                         if (assign == null)
5154                                 return false;
5155
5156                         if (assign.Type == TypeManager.idisposable_type ||
5157                                 TypeManager.ImplementsInterface (assign.Type, TypeManager.idisposable_type)) {
5158                                 return true;
5159                         }
5160
5161                         Expression e = Convert.ImplicitConversionStandard (ec, assign, TypeManager.idisposable_type, var.Location);
5162                         if (e == null) {
5163                                 Error_IsNotConvertibleToIDisposable (var);
5164                                 return false;
5165                         }
5166
5167                         throw new NotImplementedException ("covariance?");
5168                 }
5169
5170                 protected override void CloneTo (CloneContext clonectx, Statement t)
5171                 {
5172                         Using target = (Using) t;
5173
5174                         target.var = var.Clone (clonectx);
5175                         target.init = init.Clone (clonectx);
5176                         target.stmt = stmt.Clone (clonectx);
5177                 }
5178         }
5179
5180         /// <summary>
5181         ///   Implementation of the foreach C# statement
5182         /// </summary>
5183         public class Foreach : Statement {
5184
5185                 sealed class ArrayForeach : Statement
5186                 {
5187                         class ArrayCounter : TemporaryVariable
5188                         {
5189                                 StatementExpression increment;
5190
5191                                 public ArrayCounter (Location loc)
5192                                         : base (TypeManager.int32_type, loc)
5193                                 {
5194                                 }
5195
5196                                 public void ResolveIncrement (BlockContext ec)
5197                                 {
5198                                         increment = new StatementExpression (new UnaryMutator (UnaryMutator.Mode.PostIncrement, this));
5199                                         increment.Resolve (ec);
5200                                 }
5201
5202                                 public void EmitIncrement (EmitContext ec)
5203                                 {
5204                                         increment.Emit (ec);
5205                                 }
5206                         }
5207
5208                         readonly Foreach for_each;
5209                         readonly Statement statement;
5210
5211                         Expression conv;
5212                         TemporaryVariable[] lengths;
5213                         Expression [] length_exprs;
5214                         ArrayCounter[] counter;
5215
5216                         TemporaryVariable copy;
5217                         Expression access;
5218
5219                         public ArrayForeach (Foreach @foreach, int rank)
5220                         {
5221                                 for_each = @foreach;
5222                                 statement = for_each.statement;
5223                                 loc = @foreach.loc;
5224
5225                                 counter = new ArrayCounter [rank];
5226                                 length_exprs = new Expression [rank];
5227
5228                                 //
5229                                 // Only use temporary length variables when dealing with
5230                                 // multi-dimensional arrays
5231                                 //
5232                                 if (rank > 1)
5233                                         lengths = new TemporaryVariable [rank];
5234                         }
5235
5236                         protected override void CloneTo (CloneContext clonectx, Statement target)
5237                         {
5238                                 throw new NotImplementedException ();
5239                         }
5240
5241                         public override bool Resolve (BlockContext ec)
5242                         {
5243                                 copy = new TemporaryVariable (for_each.expr.Type, loc);
5244                                 copy.Resolve (ec);
5245
5246                                 int rank = length_exprs.Length;
5247                                 Arguments list = new Arguments (rank);
5248                                 for (int i = 0; i < rank; i++) {
5249                                         counter [i] = new ArrayCounter (loc);
5250                                         counter [i].ResolveIncrement (ec);                                      
5251
5252                                         if (rank == 1) {
5253                                                 length_exprs [i] = new MemberAccess (copy, "Length").Resolve (ec);
5254                                         } else {
5255                                                 lengths [i] = new TemporaryVariable (TypeManager.int32_type, loc);
5256                                                 lengths [i].Resolve (ec);
5257
5258                                                 Arguments args = new Arguments (1);
5259                                                 args.Add (new Argument (new IntConstant (i, loc)));
5260                                                 length_exprs [i] = new Invocation (new MemberAccess (copy, "GetLength"), args).Resolve (ec);
5261                                         }
5262
5263                                         list.Add (new Argument (counter [i]));
5264                                 }
5265
5266                                 access = new ElementAccess (copy, list).Resolve (ec);
5267                                 if (access == null)
5268                                         return false;
5269
5270                                 Expression var_type = for_each.type;
5271                                 VarExpr ve = var_type as VarExpr;
5272                                 if (ve != null) {
5273                                         // Infer implicitly typed local variable from foreach array type
5274                                         var_type = new TypeExpression (access.Type, ve.Location);
5275                                 }
5276
5277                                 var_type = var_type.ResolveAsTypeTerminal (ec, false);
5278                                 if (var_type == null)
5279                                         return false;
5280
5281                                 conv = Convert.ExplicitConversion (ec, access, var_type.Type, loc);
5282                                 if (conv == null)
5283                                         return false;
5284
5285                                 bool ok = true;
5286
5287                                 ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
5288                                 ec.CurrentBranching.CreateSibling ();
5289
5290                                 for_each.variable = for_each.variable.ResolveLValue (ec, conv);
5291                                 if (for_each.variable == null)
5292                                         ok = false;
5293
5294                                 ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc);
5295                                 if (!statement.Resolve (ec))
5296                                         ok = false;
5297                                 ec.EndFlowBranching ();
5298
5299                                 // There's no direct control flow from the end of the embedded statement to the end of the loop
5300                                 ec.CurrentBranching.CurrentUsageVector.Goto ();
5301
5302                                 ec.EndFlowBranching ();
5303
5304                                 return ok;
5305                         }
5306
5307                         protected override void DoEmit (EmitContext ec)
5308                         {
5309                                 ILGenerator ig = ec.ig;
5310
5311                                 copy.EmitAssign (ec, for_each.expr);
5312
5313                                 int rank = length_exprs.Length;
5314                                 Label[] test = new Label [rank];
5315                                 Label[] loop = new Label [rank];
5316
5317                                 for (int i = 0; i < rank; i++) {
5318                                         test [i] = ig.DefineLabel ();
5319                                         loop [i] = ig.DefineLabel ();
5320
5321                                         if (lengths != null)
5322                                                 lengths [i].EmitAssign (ec, length_exprs [i]);
5323                                 }
5324
5325                                 IntConstant zero = new IntConstant (0, loc);
5326                                 for (int i = 0; i < rank; i++) {
5327                                         counter [i].EmitAssign (ec, zero);
5328
5329                                         ig.Emit (OpCodes.Br, test [i]);
5330                                         ig.MarkLabel (loop [i]);
5331                                 }
5332
5333                                 ((IAssignMethod) for_each.variable).EmitAssign (ec, conv, false, false);
5334
5335                                 statement.Emit (ec);
5336
5337                                 ig.MarkLabel (ec.LoopBegin);
5338
5339                                 for (int i = rank - 1; i >= 0; i--){
5340                                         counter [i].EmitIncrement (ec);
5341
5342                                         ig.MarkLabel (test [i]);
5343                                         counter [i].Emit (ec);
5344
5345                                         if (lengths != null)
5346                                                 lengths [i].Emit (ec);
5347                                         else
5348                                                 length_exprs [i].Emit (ec);
5349
5350                                         ig.Emit (OpCodes.Blt, loop [i]);
5351                                 }
5352
5353                                 ig.MarkLabel (ec.LoopEnd);
5354                         }
5355
5356                         public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5357                         {
5358                                 for_each.expr.MutateHoistedGenericType (storey);
5359
5360                                 copy.MutateHoistedGenericType (storey);
5361                                 conv.MutateHoistedGenericType (storey);
5362                                 statement.MutateHoistedGenericType (storey);
5363
5364                                 for (int i = 0; i < counter.Length; i++) {
5365                                         counter [i].MutateHoistedGenericType (storey);
5366                                         if (lengths != null)
5367                                                 lengths [i].MutateHoistedGenericType (storey);
5368                                 }
5369                         }
5370                 }
5371
5372                 sealed class CollectionForeach : Statement
5373                 {
5374                         class CollectionForeachStatement : Statement
5375                         {
5376                                 Type type;
5377                                 Expression variable, current, conv;
5378                                 Statement statement;
5379                                 Assign assign;
5380
5381                                 public CollectionForeachStatement (Type type, Expression variable,
5382                                                                    Expression current, Statement statement,
5383                                                                    Location loc)
5384                                 {
5385                                         this.type = type;
5386                                         this.variable = variable;
5387                                         this.current = current;
5388                                         this.statement = statement;
5389                                         this.loc = loc;
5390                                 }
5391
5392                                 protected override void CloneTo (CloneContext clonectx, Statement target)
5393                                 {
5394                                         throw new NotImplementedException ();
5395                                 }
5396
5397                                 public override bool Resolve (BlockContext ec)
5398                                 {
5399                                         current = current.Resolve (ec);
5400                                         if (current == null)
5401                                                 return false;
5402
5403                                         conv = Convert.ExplicitConversion (ec, current, type, loc);
5404                                         if (conv == null)
5405                                                 return false;
5406
5407                                         assign = new SimpleAssign (variable, conv, loc);
5408                                         if (assign.Resolve (ec) == null)
5409                                                 return false;
5410
5411                                         if (!statement.Resolve (ec))
5412                                                 return false;
5413
5414                                         return true;
5415                                 }
5416
5417                                 protected override void DoEmit (EmitContext ec)
5418                                 {
5419                                         assign.EmitStatement (ec);
5420                                         statement.Emit (ec);
5421                                 }
5422
5423                                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5424                                 {
5425                                         assign.MutateHoistedGenericType (storey);
5426                                         statement.MutateHoistedGenericType (storey);
5427                                 }
5428                         }
5429
5430                         Expression variable, expr;
5431                         Statement statement;
5432
5433                         TemporaryVariable enumerator;
5434                         Expression init;
5435                         Statement loop;
5436                         Statement wrapper;
5437
5438                         MethodGroupExpr get_enumerator;
5439                         PropertyExpr get_current;
5440                         MethodInfo move_next;
5441                         Expression var_type;
5442                         Type enumerator_type;
5443                         bool enumerator_found;
5444
5445                         public CollectionForeach (Expression var_type, Expression var,
5446                                                   Expression expr, Statement stmt, Location l)
5447                         {
5448                                 this.var_type = var_type;
5449                                 this.variable = var;
5450                                 this.expr = expr;
5451                                 statement = stmt;
5452                                 loc = l;
5453                         }
5454
5455                         protected override void CloneTo (CloneContext clonectx, Statement target)
5456                         {
5457                                 throw new NotImplementedException ();
5458                         }
5459
5460                         bool GetEnumeratorFilter (ResolveContext ec, MethodInfo mi)
5461                         {
5462                                 Type return_type = mi.ReturnType;
5463
5464                                 //
5465                                 // Ok, we can access it, now make sure that we can do something
5466                                 // with this `GetEnumerator'
5467                                 //
5468
5469                                 if (return_type == TypeManager.ienumerator_type ||
5470                                         TypeManager.ImplementsInterface (return_type, TypeManager.ienumerator_type)) {
5471                                         //
5472                                         // If it is not an interface, lets try to find the methods ourselves.
5473                                         // For example, if we have:
5474                                         // public class Foo : IEnumerator { public bool MoveNext () {} public int Current { get {}}}
5475                                         // We can avoid the iface call. This is a runtime perf boost.
5476                                         // even bigger if we have a ValueType, because we avoid the cost
5477                                         // of boxing.
5478                                         //
5479                                         // We have to make sure that both methods exist for us to take
5480                                         // this path. If one of the methods does not exist, we will just
5481                                         // use the interface. Sadly, this complex if statement is the only
5482                                         // way I could do this without a goto
5483                                         //
5484
5485                                         if (TypeManager.bool_movenext_void == null) {
5486                                                 TypeManager.bool_movenext_void = TypeManager.GetPredefinedMethod (
5487                                                         TypeManager.ienumerator_type, "MoveNext", loc, Type.EmptyTypes);
5488                                         }
5489
5490                                         if (TypeManager.ienumerator_getcurrent == null) {
5491                                                 TypeManager.ienumerator_getcurrent = TypeManager.GetPredefinedProperty (
5492                                                         TypeManager.ienumerator_type, "Current", loc, TypeManager.object_type);
5493                                         }
5494
5495                                         //
5496                                         // Prefer a generic enumerator over a non-generic one.
5497                                         //
5498                                         if (return_type.IsInterface && TypeManager.IsGenericType (return_type)) {
5499                                                 enumerator_type = return_type;
5500                                                 if (!FetchGetCurrent (ec, return_type))
5501                                                         get_current = new PropertyExpr (
5502                                                                 ec.CurrentType, TypeManager.ienumerator_getcurrent, loc);
5503                                                 if (!FetchMoveNext (return_type))
5504                                                         move_next = TypeManager.bool_movenext_void;
5505                                                 return true;
5506                                         }
5507
5508                                         if (return_type.IsInterface ||
5509                                             !FetchMoveNext (return_type) ||
5510                                             !FetchGetCurrent (ec, return_type)) {
5511                                                 enumerator_type = return_type;
5512                                                 move_next = TypeManager.bool_movenext_void;
5513                                                 get_current = new PropertyExpr (
5514                                                         ec.CurrentType, TypeManager.ienumerator_getcurrent, loc);
5515                                                 return true;
5516                                         }
5517                                 } else {
5518                                         //
5519                                         // Ok, so they dont return an IEnumerable, we will have to
5520                                         // find if they support the GetEnumerator pattern.
5521                                         //
5522
5523                                         if (TypeManager.HasElementType (return_type) || !FetchMoveNext (return_type) || !FetchGetCurrent (ec, return_type)) {
5524                                                 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",
5525                                                         TypeManager.CSharpName (return_type), TypeManager.CSharpSignature (mi));
5526                                                 return false;
5527                                         }
5528                                 }
5529
5530                                 enumerator_type = return_type;
5531
5532                                 return true;
5533                         }
5534
5535                         //
5536                         // Retrieves a `public bool MoveNext ()' method from the Type `t'
5537                         //
5538                         bool FetchMoveNext (Type t)
5539                         {
5540                                 MemberInfo[] move_next_list = TypeManager.MemberLookup (null, null, t,
5541                                         MemberTypes.Method,
5542                                         BindingFlags.Public | BindingFlags.Instance,
5543                                         "MoveNext", null);
5544
5545                                 if (move_next_list == null)
5546                                         return false;
5547
5548                                 foreach (MemberInfo m in move_next_list){
5549                                         MethodInfo mi = (MethodInfo) m;
5550                                 
5551                                         if ((TypeManager.GetParameterData (mi).Count == 0) &&
5552                                             TypeManager.TypeToCoreType (mi.ReturnType) == TypeManager.bool_type) {
5553                                                 move_next = mi;
5554                                                 return true;
5555                                         }
5556                                 }
5557
5558                                 return false;
5559                         }
5560                 
5561                         //
5562                         // Retrieves a `public T get_Current ()' method from the Type `t'
5563                         //
5564                         bool FetchGetCurrent (ResolveContext ec, Type t)
5565                         {
5566                                 PropertyExpr pe = Expression.MemberLookup (
5567                                         ec.CurrentType, t, "Current", MemberTypes.Property,
5568                                         Expression.AllBindingFlags, loc) as PropertyExpr;
5569                                 if (pe == null)
5570                                         return false;
5571
5572                                 get_current = pe;
5573                                 return true;
5574                         }
5575
5576                         void Error_Enumerator ()
5577                         {
5578                                 if (enumerator_found) {
5579                                         return;
5580                                 }
5581
5582                             Report.Error (1579, loc,
5583                                         "foreach statement cannot operate on variables of type `{0}' because it does not contain a definition for `GetEnumerator' or is not accessible",
5584                                         TypeManager.CSharpName (expr.Type));
5585                         }
5586
5587                         bool IsOverride (MethodInfo m)
5588                         {
5589                                 m = (MethodInfo) TypeManager.DropGenericMethodArguments (m);
5590
5591                                 if (!m.IsVirtual || ((m.Attributes & MethodAttributes.NewSlot) != 0))
5592                                         return false;
5593                                 if (m is MethodBuilder)
5594                                         return true;
5595
5596                                 MethodInfo base_method = m.GetBaseDefinition ();
5597                                 return base_method != m;
5598                         }
5599
5600                         bool TryType (ResolveContext ec, Type t)
5601                         {
5602                                 MethodGroupExpr mg = Expression.MemberLookup (
5603                                         ec.CurrentType, t, "GetEnumerator", MemberTypes.Method,
5604                                         Expression.AllBindingFlags, loc) as MethodGroupExpr;
5605                                 if (mg == null)
5606                                         return false;
5607
5608                                 MethodInfo result = null;
5609                                 MethodInfo tmp_move_next = null;
5610                                 PropertyExpr tmp_get_cur = null;
5611                                 Type tmp_enumerator_type = enumerator_type;
5612                                 foreach (MethodInfo mi in mg.Methods) {
5613                                         if (TypeManager.GetParameterData (mi).Count != 0)
5614                                                 continue;
5615                         
5616                                         // Check whether GetEnumerator is public
5617                                         if ((mi.Attributes & MethodAttributes.Public) != MethodAttributes.Public)
5618                                                 continue;
5619
5620                                         if (IsOverride (mi))
5621                                                 continue;
5622
5623                                         enumerator_found = true;
5624
5625                                         if (!GetEnumeratorFilter (ec, mi))
5626                                                 continue;
5627
5628                                         if (result != null) {
5629                                                 if (TypeManager.IsGenericType (result.ReturnType)) {
5630                                                         if (!TypeManager.IsGenericType (mi.ReturnType))
5631                                                                 continue;
5632
5633                                                         MethodBase mb = TypeManager.DropGenericMethodArguments (mi);
5634                                                         Report.SymbolRelatedToPreviousError (t);
5635                                                         Report.Error(1640, loc, "foreach statement cannot operate on variables of type `{0}' " +
5636                                                                      "because it contains multiple implementation of `{1}'. Try casting to a specific implementation",
5637                                                                      TypeManager.CSharpName (t), TypeManager.CSharpSignature (mb));
5638                                                         return false;
5639                                                 }
5640
5641                                                 // Always prefer generics enumerators
5642                                                 if (!TypeManager.IsGenericType (mi.ReturnType)) {
5643                                                         if (TypeManager.ImplementsInterface (mi.DeclaringType, result.DeclaringType) ||
5644                                                             TypeManager.ImplementsInterface (result.DeclaringType, mi.DeclaringType))
5645                                                                 continue;
5646
5647                                                         Report.SymbolRelatedToPreviousError (result);
5648                                                         Report.SymbolRelatedToPreviousError (mi);
5649                                                         Report.Warning (278, 2, loc, "`{0}' contains ambiguous implementation of `{1}' pattern. Method `{2}' is ambiguous with method `{3}'",
5650                                                                         TypeManager.CSharpName (t), "enumerable", TypeManager.CSharpSignature (result), TypeManager.CSharpSignature (mi));
5651                                                         return false;
5652                                                 }
5653                                         }
5654                                         result = mi;
5655                                         tmp_move_next = move_next;
5656                                         tmp_get_cur = get_current;
5657                                         tmp_enumerator_type = enumerator_type;
5658                                         if (mi.DeclaringType == t)
5659                                                 break;
5660                                 }
5661
5662                                 if (result != null) {
5663                                         move_next = tmp_move_next;
5664                                         get_current = tmp_get_cur;
5665                                         enumerator_type = tmp_enumerator_type;
5666                                         MethodInfo[] mi = new MethodInfo[] { (MethodInfo) result };
5667                                         get_enumerator = new MethodGroupExpr (mi, enumerator_type, loc);
5668
5669                                         if (t != expr.Type) {
5670                                                 expr = Convert.ExplicitConversion (
5671                                                         ec, expr, t, loc);
5672                                                 if (expr == null)
5673                                                         throw new InternalErrorException ();
5674                                         }
5675
5676                                         get_enumerator.InstanceExpression = expr;
5677                                         get_enumerator.IsBase = t != expr.Type;
5678
5679                                         return true;
5680                                 }
5681
5682                                 return false;
5683                         }
5684
5685                         bool ProbeCollectionType (ResolveContext ec, Type t)
5686                         {
5687                                 int errors = Report.Errors;
5688                                 for (Type tt = t; tt != null && tt != TypeManager.object_type;){
5689                                         if (TryType (ec, tt))
5690                                                 return true;
5691                                         tt = tt.BaseType;
5692                                 }
5693
5694                                 if (Report.Errors > errors)
5695                                         return false;
5696
5697                                 //
5698                                 // Now try to find the method in the interfaces
5699                                 //
5700                                 Type [] ifaces = TypeManager.GetInterfaces (t);
5701                                 foreach (Type i in ifaces){
5702                                         if (TryType (ec, i))
5703                                                 return true;
5704                                 }
5705
5706                                 return false;
5707                         }
5708
5709                         public override bool Resolve (BlockContext ec)
5710                         {
5711                                 enumerator_type = TypeManager.ienumerator_type;
5712
5713                                 if (!ProbeCollectionType (ec, expr.Type)) {
5714                                         Error_Enumerator ();
5715                                         return false;
5716                                 }
5717
5718                                 VarExpr ve = var_type as VarExpr;
5719                                 if (ve != null) {
5720                                         // Infer implicitly typed local variable from foreach enumerable type
5721                                         var_type = new TypeExpression (get_current.PropertyInfo.PropertyType, var_type.Location);
5722                                 }
5723
5724                                 var_type = var_type.ResolveAsTypeTerminal (ec, false);
5725                                 if (var_type == null)
5726                                         return false;
5727                                                                 
5728                                 enumerator = new TemporaryVariable (enumerator_type, loc);
5729                                 enumerator.Resolve (ec);
5730
5731                                 init = new Invocation (get_enumerator, null);
5732                                 init = init.Resolve (ec);
5733                                 if (init == null)
5734                                         return false;
5735
5736                                 Expression move_next_expr;
5737                                 {
5738                                         MemberInfo[] mi = new MemberInfo[] { move_next };
5739                                         MethodGroupExpr mg = new MethodGroupExpr (mi, var_type.Type, loc);
5740                                         mg.InstanceExpression = enumerator;
5741
5742                                         move_next_expr = new Invocation (mg, null);
5743                                 }
5744
5745                                 get_current.InstanceExpression = enumerator;
5746
5747                                 Statement block = new CollectionForeachStatement (
5748                                         var_type.Type, variable, get_current, statement, loc);
5749
5750                                 loop = new While (move_next_expr, block, loc);
5751
5752
5753                                 bool implements_idisposable = TypeManager.ImplementsInterface (enumerator_type, TypeManager.idisposable_type);
5754                                 if (implements_idisposable || !enumerator_type.IsSealed) {
5755                                         wrapper = new DisposableWrapper (this, implements_idisposable);
5756                                 } else {
5757                                         wrapper = new NonDisposableWrapper (this);
5758                                 }
5759
5760                                 return wrapper.Resolve (ec);
5761                         }
5762
5763                         protected override void DoEmit (EmitContext ec)
5764                         {
5765                                 wrapper.Emit (ec);
5766                         }
5767
5768                         class NonDisposableWrapper : Statement {
5769                                 CollectionForeach parent;
5770
5771                                 internal NonDisposableWrapper (CollectionForeach parent)
5772                                 {
5773                                         this.parent = parent;
5774                                 }
5775
5776                                 protected override void CloneTo (CloneContext clonectx, Statement target)
5777                                 {
5778                                         throw new NotSupportedException ();
5779                                 }
5780
5781                                 public override bool Resolve (BlockContext ec)
5782                                 {
5783                                         return parent.ResolveLoop (ec);
5784                                 }
5785
5786                                 protected override void DoEmit (EmitContext ec)
5787                                 {
5788                                         parent.EmitLoopInit (ec);
5789                                         parent.EmitLoopBody (ec);
5790                                 }
5791
5792                                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5793                                 {
5794                                         throw new NotSupportedException ();
5795                                 }
5796                         }
5797
5798                         sealed class DisposableWrapper : ExceptionStatement
5799                         {
5800                                 CollectionForeach parent;
5801                                 bool implements_idisposable;
5802
5803                                 internal DisposableWrapper (CollectionForeach parent, bool implements)
5804                                 {
5805                                         this.parent = parent;
5806                                         this.implements_idisposable = implements;
5807                                 }
5808
5809                                 protected override void CloneTo (CloneContext clonectx, Statement target)
5810                                 {
5811                                         throw new NotSupportedException ();
5812                                 }
5813
5814                                 public override bool Resolve (BlockContext ec)
5815                                 {
5816                                         bool ok = true;
5817
5818                                         ec.StartFlowBranching (this);
5819
5820                                         if (!parent.ResolveLoop (ec))
5821                                                 ok = false;
5822
5823                                         ec.EndFlowBranching ();
5824
5825                                         ok &= base.Resolve (ec);
5826
5827                                         if (TypeManager.void_dispose_void == null) {
5828                                                 TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
5829                                                         TypeManager.idisposable_type, "Dispose", loc, Type.EmptyTypes);
5830                                         }
5831                                         return ok;
5832                                 }
5833
5834                                 protected override void EmitPreTryBody (EmitContext ec)
5835                                 {
5836                                         parent.EmitLoopInit (ec);
5837                                 }
5838
5839                                 protected override void EmitTryBody (EmitContext ec)
5840                                 {
5841                                         parent.EmitLoopBody (ec);
5842                                 }
5843
5844                                 protected override void EmitFinallyBody (EmitContext ec)
5845                                 {
5846                                         Expression instance = parent.enumerator;
5847                                         if (!TypeManager.IsValueType (parent.enumerator_type)) {
5848                                                 ILGenerator ig = ec.ig;
5849
5850                                                 parent.enumerator.Emit (ec);
5851
5852                                                 Label call_dispose = ig.DefineLabel ();
5853
5854                                                 if (!implements_idisposable) {
5855                                                         ec.ig.Emit (OpCodes.Isinst, TypeManager.idisposable_type);
5856                                                         LocalTemporary temp = new LocalTemporary (TypeManager.idisposable_type);
5857                                                         temp.Store (ec);
5858                                                         temp.Emit (ec);
5859                                                         instance = temp;
5860                                                 }
5861                                                 
5862                                                 ig.Emit (OpCodes.Brtrue_S, call_dispose);
5863
5864                                                 // using 'endfinally' to empty the evaluation stack
5865                                                 ig.Emit (OpCodes.Endfinally);
5866                                                 ig.MarkLabel (call_dispose);
5867                                         }
5868
5869                                         Invocation.EmitCall (ec, false, instance, TypeManager.void_dispose_void, null, loc);
5870                                 }
5871
5872                                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5873                                 {
5874                                         throw new NotSupportedException ();
5875                                 }
5876                         }
5877
5878                         bool ResolveLoop (BlockContext ec)
5879                         {
5880                                 return loop.Resolve (ec);
5881                         }
5882
5883                         void EmitLoopInit (EmitContext ec)
5884                         {
5885                                 enumerator.EmitAssign (ec, init);
5886                         }
5887
5888                         void EmitLoopBody (EmitContext ec)
5889                         {
5890                                 loop.Emit (ec);
5891                         }
5892
5893                         public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5894                         {
5895                                 enumerator_type = storey.MutateType (enumerator_type);
5896                                 init.MutateHoistedGenericType (storey);
5897                                 loop.MutateHoistedGenericType (storey);
5898                         }
5899                 }
5900
5901                 Expression type;
5902                 Expression variable;
5903                 Expression expr;
5904                 Statement statement;
5905
5906                 public Foreach (Expression type, LocalVariableReference var, Expression expr,
5907                                 Statement stmt, Location l)
5908                 {
5909                         this.type = type;
5910                         this.variable = var;
5911                         this.expr = expr;
5912                         statement = stmt;
5913                         loc = l;
5914                 }
5915
5916                 public Statement Statement {
5917                         get { return statement; }
5918                 }
5919
5920                 public override bool Resolve (BlockContext ec)
5921                 {
5922                         expr = expr.Resolve (ec);
5923                         if (expr == null)
5924                                 return false;
5925
5926                         if (expr.IsNull) {
5927                                 Report.Error (186, loc, "Use of null is not valid in this context");
5928                                 return false;
5929                         }
5930
5931                         if (expr.Type == TypeManager.string_type) {
5932                                 statement = new ArrayForeach (this, 1);
5933                         } else if (expr.Type.IsArray) {
5934                                 statement = new ArrayForeach (this, expr.Type.GetArrayRank ());
5935                         } else {
5936                                 if (expr.eclass == ExprClass.MethodGroup || expr is AnonymousMethodExpression) {
5937                                         Report.Error (446, expr.Location, "Foreach statement cannot operate on a `{0}'",
5938                                                 expr.ExprClassName);
5939                                         return false;
5940                                 }
5941
5942                                 statement = new CollectionForeach (type, variable, expr, statement, loc);
5943                         }
5944
5945                         return statement.Resolve (ec);
5946                 }
5947
5948                 protected override void DoEmit (EmitContext ec)
5949                 {
5950                         ILGenerator ig = ec.ig;
5951
5952                         Label old_begin = ec.LoopBegin, old_end = ec.LoopEnd;
5953                         ec.LoopBegin = ig.DefineLabel ();
5954                         ec.LoopEnd = ig.DefineLabel ();
5955
5956                         statement.Emit (ec);
5957
5958                         ec.LoopBegin = old_begin;
5959                         ec.LoopEnd = old_end;
5960                 }
5961
5962                 protected override void CloneTo (CloneContext clonectx, Statement t)
5963                 {
5964                         Foreach target = (Foreach) t;
5965
5966                         target.type = type.Clone (clonectx);
5967                         target.variable = variable.Clone (clonectx);
5968                         target.expr = expr.Clone (clonectx);
5969                         target.statement = statement.Clone (clonectx);
5970                 }
5971
5972                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5973                 {
5974                         statement.MutateHoistedGenericType (storey);
5975                 }
5976         }
5977 }