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