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