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