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