Added the DEVEL compile define, used for conditional compilation of some development...
[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                         Unsafe = 16,
1523                         IsIterator = 32,
1524                         HasCapturedVariable = 64,
1525                         HasCapturedThis = 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
1563                 //
1564                 // Keeps track of constants
1565                 HybridDictionary constants;
1566
1567                 //
1568                 // Temporary variables.
1569                 //
1570                 ArrayList temporary_variables;
1571                 
1572                 //
1573                 // If this is a switch section, the enclosing switch block.
1574                 //
1575                 Block switch_block;
1576
1577                 ArrayList scope_initializers;
1578
1579                 ArrayList anonymous_children;
1580
1581                 protected static int id;
1582
1583                 int this_id;
1584
1585                 int assignable_slots;
1586                 bool unreachable_shown;
1587                 bool unreachable;
1588                 
1589                 public Block (Block parent)
1590                         : this (parent, (Flags) 0, Location.Null, Location.Null)
1591                 { }
1592
1593                 public Block (Block parent, Flags flags)
1594                         : this (parent, flags, Location.Null, Location.Null)
1595                 { }
1596
1597                 public Block (Block parent, Location start, Location end)
1598                         : this (parent, (Flags) 0, start, end)
1599                 { }
1600
1601                 //
1602                 // Useful when TopLevel block is downgraded to normal block
1603                 //
1604                 public Block (ToplevelBlock parent, ToplevelBlock source)
1605                         : this (parent, source.flags, source.StartLocation, source.EndLocation)
1606                 {
1607                         statements = source.statements;
1608                         children = source.children;
1609                         labels = source.labels;
1610                         variables = source.variables;
1611                         constants = source.constants;
1612                         switch_block = source.switch_block;
1613                 }
1614
1615                 public Block (Block parent, Flags flags, Location start, Location end)
1616                 {
1617                         if (parent != null) {
1618                                 parent.AddChild (this);
1619
1620                                 // the appropriate constructors will fixup these fields
1621                                 Toplevel = parent.Toplevel;
1622                                 Explicit = parent.Explicit;
1623                         }
1624                         
1625                         this.Parent = parent;
1626                         this.flags = flags;
1627                         this.StartLocation = start;
1628                         this.EndLocation = end;
1629                         this.loc = start;
1630                         this_id = id++;
1631                         statements = new ArrayList (4);
1632                 }
1633
1634                 public Block CreateSwitchBlock (Location start)
1635                 {
1636                         // FIXME: should this be implicit?
1637                         Block new_block = new ExplicitBlock (this, start, start);
1638                         new_block.switch_block = this;
1639                         return new_block;
1640                 }
1641
1642                 public int ID {
1643                         get { return this_id; }
1644                 }
1645
1646                 public IDictionary Variables {
1647                         get {
1648                                 if (variables == null)
1649                                         variables = new ListDictionary ();
1650                                 return variables;
1651                         }
1652                 }
1653
1654                 void AddChild (Block b)
1655                 {
1656                         if (children == null)
1657                                 children = new ArrayList (1);
1658                         
1659                         children.Add (b);
1660                 }
1661
1662                 public void SetEndLocation (Location loc)
1663                 {
1664                         EndLocation = loc;
1665                 }
1666
1667                 protected static void Error_158 (string name, Location loc)
1668                 {
1669                         Report.Error (158, loc, "The label `{0}' shadows another label " +
1670                                       "by the same name in a contained scope", name);
1671                 }
1672
1673                 /// <summary>
1674                 ///   Adds a label to the current block. 
1675                 /// </summary>
1676                 ///
1677                 /// <returns>
1678                 ///   false if the name already exists in this block. true
1679                 ///   otherwise.
1680                 /// </returns>
1681                 ///
1682                 public bool AddLabel (LabeledStatement target)
1683                 {
1684                         if (switch_block != null)
1685                                 return switch_block.AddLabel (target);
1686
1687                         string name = target.Name;
1688
1689                         Block cur = this;
1690                         while (cur != null) {
1691                                 LabeledStatement s = cur.DoLookupLabel (name);
1692                                 if (s != null) {
1693                                         Report.SymbolRelatedToPreviousError (s.loc, s.Name);
1694                                         Report.Error (140, target.loc, "The label `{0}' is a duplicate", name);
1695                                         return false;
1696                                 }
1697
1698                                 if (this == Explicit)
1699                                         break;
1700
1701                                 cur = cur.Parent;
1702                         }
1703
1704                         while (cur != null) {
1705                                 if (cur.DoLookupLabel (name) != null) {
1706                                         Error_158 (name, target.loc);
1707                                         return false;
1708                                 }
1709
1710                                 if (children != null) {
1711                                         foreach (Block b in children) {
1712                                                 LabeledStatement s = b.DoLookupLabel (name);
1713                                                 if (s == null)
1714                                                         continue;
1715
1716                                                 Report.SymbolRelatedToPreviousError (s.loc, s.Name);
1717                                                 Error_158 (name, target.loc);
1718                                                 return false;
1719                                         }
1720                                 }
1721
1722                                 cur = cur.Parent;
1723                         }
1724
1725                         Toplevel.CheckError158 (name, target.loc);
1726
1727                         if (labels == null)
1728                                 labels = new HybridDictionary();
1729
1730                         labels.Add (name, target);
1731                         return true;
1732                 }
1733
1734                 public LabeledStatement LookupLabel (string name)
1735                 {
1736                         LabeledStatement s = DoLookupLabel (name);
1737                         if (s != null)
1738                                 return s;
1739
1740                         if (children == null)
1741                                 return null;
1742
1743                         foreach (Block child in children) {
1744                                 if (Explicit != child.Explicit)
1745                                         continue;
1746
1747                                 s = child.LookupLabel (name);
1748                                 if (s != null)
1749                                         return s;
1750                         }
1751
1752                         return null;
1753                 }
1754
1755                 LabeledStatement DoLookupLabel (string name)
1756                 {
1757                         if (switch_block != null)
1758                                 return switch_block.LookupLabel (name);
1759
1760                         if (labels != null)
1761                                 if (labels.Contains (name))
1762                                         return ((LabeledStatement) labels [name]);
1763
1764                         return null;
1765                 }
1766
1767                 public bool CheckInvariantMeaningInBlock (string name, Expression e, Location loc)
1768                 {
1769                         Block b = this;
1770                         IKnownVariable kvi = b.Explicit.GetKnownVariable (name);
1771                         while (kvi == null) {
1772                                 b = b.Explicit.Parent;
1773                                 if (b == null)
1774                                         return true;
1775                                 kvi = b.Explicit.GetKnownVariable (name);
1776                         }
1777
1778                         if (kvi.Block == b)
1779                                 return true;
1780
1781                         // Is kvi.Block nested inside 'b'
1782                         if (b.Explicit != kvi.Block.Explicit) {
1783                                 //
1784                                 // If a variable by the same name it defined in a nested block of this
1785                                 // block, we violate the invariant meaning in a block.
1786                                 //
1787                                 if (b == this) {
1788                                         Report.SymbolRelatedToPreviousError (kvi.Location, name);
1789                                         Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", name);
1790                                         return false;
1791                                 }
1792
1793                                 //
1794                                 // It's ok if the definition is in a nested subblock of b, but not
1795                                 // nested inside this block -- a definition in a sibling block
1796                                 // should not affect us.
1797                                 //
1798                                 return true;
1799                         }
1800
1801                         //
1802                         // Block 'b' and kvi.Block are the same textual block.
1803                         // However, different variables are extant.
1804                         //
1805                         // Check if the variable is in scope in both blocks.  We use
1806                         // an indirect check that depends on AddVariable doing its
1807                         // part in maintaining the invariant-meaning-in-block property.
1808                         //
1809                         if (e is VariableReference || (e is Constant && b.GetLocalInfo (name) != null))
1810                                 return true;
1811
1812                         if (this is ToplevelBlock) {
1813                                 Report.SymbolRelatedToPreviousError (kvi.Location, name);
1814                                 e.Error_VariableIsUsedBeforeItIsDeclared (name);
1815                                 return false;
1816                         }
1817
1818                         //
1819                         // Even though we detected the error when the name is used, we
1820                         // treat it as if the variable declaration was in error.
1821                         //
1822                         Report.SymbolRelatedToPreviousError (loc, name);
1823                         Error_AlreadyDeclared (kvi.Location, name, "parent or current");
1824                         return false;
1825                 }
1826
1827                 protected virtual bool CheckParentConflictName (ToplevelBlock block, string name, Location l)
1828                 {
1829                         LocalInfo vi = GetLocalInfo (name);
1830                         if (vi != null) {
1831                                 Report.SymbolRelatedToPreviousError (vi.Location, name);
1832                                 if (Explicit == vi.Block.Explicit) {
1833                                         Error_AlreadyDeclared (l, name, null);
1834                                 } else {
1835                                         Error_AlreadyDeclared (l, name, this is ToplevelBlock ?
1836                                                 "parent or current" : "parent");
1837                                 }
1838                                 return false;
1839                         }
1840
1841                         if (block != null) {
1842                                 Expression e = block.GetParameterReference (name, Location.Null);
1843                                 if (e != null) {
1844                                         ParameterReference pr = e as ParameterReference;
1845                                         if (this is Linq.QueryBlock && (pr != null && pr.Parameter is Linq.QueryBlock.ImplicitQueryParameter || e is MemberAccess))
1846                                                 Error_AlreadyDeclared (loc, name);
1847                                         else
1848                                                 Error_AlreadyDeclared (loc, name, "parent or current");
1849                                         return false;
1850                                 }
1851                         }
1852
1853                         return true;
1854                 }
1855
1856                 public LocalInfo AddVariable (Expression type, string name, Location l)
1857                 {
1858                         if (!CheckParentConflictName (Toplevel, name, l))
1859                                 return null;
1860
1861                         if (Toplevel.GenericMethod != null) {
1862                                 foreach (TypeParameter tp in Toplevel.GenericMethod.CurrentTypeParameters) {
1863                                         if (tp.Name == name) {
1864                                                 Report.SymbolRelatedToPreviousError (tp);
1865                                                 Error_AlreadyDeclaredTypeParameter (loc, name, "local variable");
1866                                                 return null;
1867                                         }
1868                                 }
1869                         }                       
1870
1871                         IKnownVariable kvi = Explicit.GetKnownVariable (name);
1872                         if (kvi != null) {
1873                                 Report.SymbolRelatedToPreviousError (kvi.Location, name);
1874                                 Error_AlreadyDeclared (l, name, "child");
1875                                 return null;
1876                         }
1877
1878                         LocalInfo vi = new LocalInfo (type, name, this, l);
1879                         AddVariable (vi);
1880
1881                         if ((flags & Flags.VariablesInitialized) != 0)
1882                                 throw new InternalErrorException ("block has already been resolved");
1883
1884                         return vi;
1885                 }
1886                 
1887                 protected virtual void AddVariable (LocalInfo li)
1888                 {
1889                         Variables.Add (li.Name, li);
1890                         Explicit.AddKnownVariable (li.Name, li);
1891                 }
1892
1893                 protected virtual void Error_AlreadyDeclared (Location loc, string var, string reason)
1894                 {
1895                         if (reason == null) {
1896                                 Error_AlreadyDeclared (loc, var);
1897                                 return;
1898                         }
1899                         
1900                         Report.Error (136, loc, "A local variable named `{0}' cannot be declared " +
1901                                       "in this scope because it would give a different meaning " +
1902                                       "to `{0}', which is already used in a `{1}' scope " +
1903                                       "to denote something else", var, reason);
1904                 }
1905
1906                 protected virtual void Error_AlreadyDeclared (Location loc, string name)
1907                 {
1908                         Report.Error (128, loc,
1909                                 "A local variable named `{0}' is already defined in this scope", name);
1910                 }
1911                                         
1912                 public virtual void Error_AlreadyDeclaredTypeParameter (Location loc, string name, string conflict)
1913                 {
1914                         Report.Error (412, loc, "The type parameter name `{0}' is the same as `{1}'",
1915                                 name, conflict);
1916                 }                                       
1917
1918                 public bool AddConstant (Expression type, string name, Expression value, Location l)
1919                 {
1920                         if (AddVariable (type, name, l) == null)
1921                                 return false;
1922                         
1923                         if (constants == null)
1924                                 constants = new HybridDictionary();
1925
1926                         constants.Add (name, value);
1927
1928                         // A block is considered used if we perform an initialization in a local declaration, even if it is constant.
1929                         Use ();
1930                         return true;
1931                 }
1932
1933                 static int next_temp_id = 0;
1934
1935                 public LocalInfo AddTemporaryVariable (TypeExpr te, Location loc)
1936                 {
1937                         Report.Debug (64, "ADD TEMPORARY", this, Toplevel, loc);
1938
1939                         if (temporary_variables == null)
1940                                 temporary_variables = new ArrayList ();
1941
1942                         int id = ++next_temp_id;
1943                         string name = "$s_" + id.ToString ();
1944
1945                         LocalInfo li = new LocalInfo (te, name, this, loc);
1946                         li.CompilerGenerated = true;
1947                         temporary_variables.Add (li);
1948                         return li;
1949                 }
1950
1951                 public LocalInfo GetLocalInfo (string name)
1952                 {
1953                         LocalInfo ret;
1954                         for (Block b = this; b != null; b = b.Parent) {
1955                                 if (b.variables != null) {
1956                                         ret = (LocalInfo) b.variables [name];
1957                                         if (ret != null)
1958                                                 return ret;
1959                                 }
1960                         }
1961
1962                         return null;
1963                 }
1964
1965                 public Expression GetVariableType (string name)
1966                 {
1967                         LocalInfo vi = GetLocalInfo (name);
1968                         return vi == null ? null : vi.Type;
1969                 }
1970
1971                 public Expression GetConstantExpression (string name)
1972                 {
1973                         for (Block b = this; b != null; b = b.Parent) {
1974                                 if (b.constants != null) {
1975                                         Expression ret = b.constants [name] as Expression;
1976                                         if (ret != null)
1977                                                 return ret;
1978                                 }
1979                         }
1980                         return null;
1981                 }
1982
1983                 //
1984                 // It should be used by expressions which require to
1985                 // register a statement during resolve process.
1986                 //
1987                 public void AddScopeStatement (Statement s)
1988                 {
1989                         if (scope_initializers == null)
1990                                 scope_initializers = new ArrayList ();
1991
1992                         scope_initializers.Add (s);
1993                 }
1994                 
1995                 public void AddStatement (Statement s)
1996                 {
1997                         statements.Add (s);
1998                         flags |= Flags.BlockUsed;
1999                 }
2000
2001                 public bool Used {
2002                         get { return (flags & Flags.BlockUsed) != 0; }
2003                 }
2004
2005                 public void Use ()
2006                 {
2007                         flags |= Flags.BlockUsed;
2008                 }
2009
2010                 public bool HasRet {
2011                         get { return (flags & Flags.HasRet) != 0; }
2012                 }
2013
2014                 public int AssignableSlots {
2015                         get {
2016 // TODO: Re-enable                      
2017 //                              if ((flags & Flags.VariablesInitialized) == 0)
2018 //                                      throw new Exception ("Variables have not been initialized yet");
2019                                 return assignable_slots;
2020                         }
2021                 }
2022
2023                 public ArrayList AnonymousChildren {
2024                         get { return anonymous_children; }
2025                 }
2026
2027                 public void AddAnonymousChild (ToplevelBlock b)
2028                 {
2029                         if (anonymous_children == null)
2030                                 anonymous_children = new ArrayList ();
2031
2032                         anonymous_children.Add (b);
2033                 }
2034
2035                 void DoResolveConstants (EmitContext ec)
2036                 {
2037                         if (constants == null)
2038                                 return;
2039
2040                         if (variables == null)
2041                                 throw new InternalErrorException ("cannot happen");
2042
2043                         foreach (DictionaryEntry de in variables) {
2044                                 string name = (string) de.Key;
2045                                 LocalInfo vi = (LocalInfo) de.Value;
2046                                 Type variable_type = vi.VariableType;
2047
2048                                 if (variable_type == null) {
2049                                         if (vi.Type is VarExpr)
2050                                                 Report.Error (822, vi.Type.Location, "An implicitly typed local variable cannot be a constant");
2051
2052                                         continue;
2053                                 }
2054
2055                                 Expression cv = (Expression) constants [name];
2056                                 if (cv == null)
2057                                         continue;
2058
2059                                 // Don't let 'const int Foo = Foo;' succeed.
2060                                 // Removing the name from 'constants' ensures that we get a LocalVariableReference below,
2061                                 // which in turn causes the 'must be constant' error to be triggered.
2062                                 constants.Remove (name);
2063
2064                                 if (!Const.IsConstantTypeValid (variable_type)) {
2065                                         Const.Error_InvalidConstantType (variable_type, loc);
2066                                         continue;
2067                                 }
2068
2069                                 ec.CurrentBlock = this;
2070                                 Expression e;
2071                                 using (ec.With (EmitContext.Flags.ConstantCheckState, (flags & Flags.Unchecked) == 0)) {
2072                                         e = cv.Resolve (ec);
2073                                 }
2074                                 if (e == null)
2075                                         continue;
2076
2077                                 Constant ce = e as Constant;
2078                                 if (ce == null) {
2079                                         Const.Error_ExpressionMustBeConstant (vi.Location, name);
2080                                         continue;
2081                                 }
2082
2083                                 e = ce.ConvertImplicitly (variable_type);
2084                                 if (e == null) {
2085                                         if (TypeManager.IsReferenceType (variable_type))
2086                                                 Const.Error_ConstantCanBeInitializedWithNullOnly (variable_type, vi.Location, vi.Name);
2087                                         else
2088                                                 ce.Error_ValueCannotBeConverted (ec, vi.Location, variable_type, false);
2089                                         continue;
2090                                 }
2091
2092                                 constants.Add (name, e);
2093                                 vi.IsConstant = true;
2094                         }
2095                 }
2096
2097                 protected void ResolveMeta (EmitContext ec, int offset)
2098                 {
2099                         Report.Debug (64, "BLOCK RESOLVE META", this, Parent);
2100
2101                         // If some parent block was unsafe, we remain unsafe even if this block
2102                         // isn't explicitly marked as such.
2103                         using (ec.With (EmitContext.Flags.InUnsafe, ec.InUnsafe | Unsafe)) {
2104                                 flags |= Flags.VariablesInitialized;
2105
2106                                 if (variables != null) {
2107                                         foreach (LocalInfo li in variables.Values) {
2108                                                 if (!li.Resolve (ec))
2109                                                         continue;
2110                                                 li.VariableInfo = new VariableInfo (li, offset);
2111                                                 offset += li.VariableInfo.Length;
2112                                         }
2113                                 }
2114                                 assignable_slots = offset;
2115
2116                                 DoResolveConstants (ec);
2117
2118                                 if (children == null)
2119                                         return;
2120                                 foreach (Block b in children)
2121                                         b.ResolveMeta (ec, offset);
2122                         }
2123                 }
2124
2125                 //
2126                 // Emits the local variable declarations for a block
2127                 //
2128                 public virtual void EmitMeta (EmitContext ec)
2129                 {
2130                         if (variables != null){
2131                                 foreach (LocalInfo vi in variables.Values)
2132                                         vi.ResolveVariable (ec);
2133                         }
2134
2135                         if (temporary_variables != null) {
2136                                 for (int i = 0; i < temporary_variables.Count; i++)
2137                                         ((LocalInfo)temporary_variables[i]).ResolveVariable(ec);
2138                         }
2139
2140                         if (children != null) {
2141                                 for (int i = 0; i < children.Count; i++)
2142                                         ((Block)children[i]).EmitMeta(ec);
2143                         }
2144                 }
2145
2146                 void UsageWarning ()
2147                 {
2148                         if (variables == null || Report.WarningLevel < 3)
2149                                 return;
2150
2151                         foreach (DictionaryEntry de in variables) {
2152                                 LocalInfo vi = (LocalInfo) de.Value;
2153
2154                                 if (!vi.Used) {
2155                                         string name = (string) de.Key;
2156
2157                                         // vi.VariableInfo can be null for 'catch' variables
2158                                         if (vi.VariableInfo != null && vi.VariableInfo.IsEverAssigned)
2159                                                 Report.Warning (219, 3, vi.Location, "The variable `{0}' is assigned but its value is never used", name);
2160                                         else
2161                                                 Report.Warning (168, 3, vi.Location, "The variable `{0}' is declared but never used", name);
2162                                 }
2163                         }
2164                 }
2165
2166                 static void CheckPossibleMistakenEmptyStatement (Statement s)
2167                 {
2168                         Statement body;
2169
2170                         // Some statements are wrapped by a Block. Since
2171                         // others' internal could be changed, here I treat
2172                         // them as possibly wrapped by Block equally.
2173                         Block b = s as Block;
2174                         if (b != null && b.statements.Count == 1)
2175                                 s = (Statement) b.statements [0];
2176
2177                         if (s is Lock)
2178                                 body = ((Lock) s).Statement;
2179                         else if (s is For)
2180                                 body = ((For) s).Statement;
2181                         else if (s is Foreach)
2182                                 body = ((Foreach) s).Statement;
2183                         else if (s is While)
2184                                 body = ((While) s).Statement;
2185                         else if (s is Fixed)
2186                                 body = ((Fixed) s).Statement;
2187                         else if (s is Using)
2188                                 body = ((Using) s).EmbeddedStatement;
2189                         else if (s is UsingTemporary)
2190                                 body = ((UsingTemporary) s).Statement;
2191                         else
2192                                 return;
2193
2194                         if (body == null || body is EmptyStatement)
2195                                 Report.Warning (642, 3, s.loc, "Possible mistaken empty statement");
2196                 }
2197
2198                 public override bool Resolve (EmitContext ec)
2199                 {
2200                         Block prev_block = ec.CurrentBlock;
2201                         bool ok = true;
2202
2203                         int errors = Report.Errors;
2204
2205                         ec.CurrentBlock = this;
2206                         ec.StartFlowBranching (this);
2207
2208                         Report.Debug (4, "RESOLVE BLOCK", StartLocation, ec.CurrentBranching);
2209
2210                         //
2211                         // This flag is used to notate nested statements as unreachable from the beginning of this block.
2212                         // For the purposes of this resolution, it doesn't matter that the whole block is unreachable 
2213                         // from the beginning of the function.  The outer Resolve() that detected the unreachability is
2214                         // responsible for handling the situation.
2215                         //
2216                         int statement_count = statements.Count;
2217                         for (int ix = 0; ix < statement_count; ix++){
2218                                 Statement s = (Statement) statements [ix];
2219                                 // Check possible empty statement (CS0642)
2220                                 if (Report.WarningLevel >= 3 &&
2221                                         ix + 1 < statement_count &&
2222                                                 statements [ix + 1] is ExplicitBlock)
2223                                         CheckPossibleMistakenEmptyStatement (s);
2224
2225                                 //
2226                                 // Warn if we detect unreachable code.
2227                                 //
2228                                 if (unreachable) {
2229                                         if (s is EmptyStatement)
2230                                                 continue;
2231
2232                                         if (!unreachable_shown && !(s is LabeledStatement)) {
2233                                                 Report.Warning (162, 2, s.loc, "Unreachable code detected");
2234                                                 unreachable_shown = true;
2235                                         }
2236
2237                                         Block c_block = s as Block;
2238                                         if (c_block != null)
2239                                                 c_block.unreachable = c_block.unreachable_shown = true;
2240                                 }
2241
2242                                 //
2243                                 // Note that we're not using ResolveUnreachable() for unreachable
2244                                 // statements here.  ResolveUnreachable() creates a temporary
2245                                 // flow branching and kills it afterwards.  This leads to problems
2246                                 // if you have two unreachable statements where the first one
2247                                 // assigns a variable and the second one tries to access it.
2248                                 //
2249
2250                                 if (!s.Resolve (ec)) {
2251                                         ok = false;
2252                                         if (ec.IsInProbingMode)
2253                                                 break;
2254
2255                                         statements [ix] = EmptyStatement.Value;
2256                                         continue;
2257                                 }
2258
2259                                 if (unreachable && !(s is LabeledStatement) && !(s is Block))
2260                                         statements [ix] = EmptyStatement.Value;
2261
2262                                 unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
2263                                 if (unreachable && s is LabeledStatement)
2264                                         throw new InternalErrorException ("should not happen");
2265                         }
2266
2267                         Report.Debug (4, "RESOLVE BLOCK DONE", StartLocation,
2268                                       ec.CurrentBranching, statement_count);
2269
2270                         while (ec.CurrentBranching is FlowBranchingLabeled)
2271                                 ec.EndFlowBranching ();
2272
2273                         bool flow_unreachable = ec.EndFlowBranching ();
2274
2275                         ec.CurrentBlock = prev_block;
2276
2277                         if (flow_unreachable)
2278                                 flags |= Flags.HasRet;
2279
2280                         // If we're a non-static `struct' constructor which doesn't have an
2281                         // initializer, then we must initialize all of the struct's fields.
2282                         if (this == Toplevel && !Toplevel.IsThisAssigned (ec) && !flow_unreachable)
2283                                 ok = false;
2284
2285                         if ((labels != null) && (Report.WarningLevel >= 2)) {
2286                                 foreach (LabeledStatement label in labels.Values)
2287                                         if (!label.HasBeenReferenced)
2288                                                 Report.Warning (164, 2, label.loc, "This label has not been referenced");
2289                         }
2290
2291                         if (ok && errors == Report.Errors)
2292                                 UsageWarning ();
2293
2294                         return ok;
2295                 }
2296
2297                 public override bool ResolveUnreachable (EmitContext ec, bool warn)
2298                 {
2299                         unreachable_shown = true;
2300                         unreachable = true;
2301
2302                         if (warn)
2303                                 Report.Warning (162, 2, loc, "Unreachable code detected");
2304
2305                         ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc);
2306                         bool ok = Resolve (ec);
2307                         ec.KillFlowBranching ();
2308
2309                         return ok;
2310                 }
2311                 
2312                 protected override void DoEmit (EmitContext ec)
2313                 {
2314                         for (int ix = 0; ix < statements.Count; ix++){
2315                                 Statement s = (Statement) statements [ix];
2316                                 s.Emit (ec);
2317                         }
2318                 }
2319
2320                 public override void Emit (EmitContext ec)
2321                 {
2322                         Block prev_block = ec.CurrentBlock;
2323                         ec.CurrentBlock = this;
2324
2325                         if (scope_initializers != null) {
2326                                 SymbolWriter.OpenCompilerGeneratedBlock (ec.ig);
2327
2328                                 using (ec.Set (EmitContext.Flags.OmitDebuggingInfo)) {
2329                                         foreach (Statement s in scope_initializers)
2330                                                 s.Emit (ec);
2331                                 }
2332
2333                                 SymbolWriter.CloseCompilerGeneratedBlock (ec.ig);
2334                         }
2335
2336                         ec.Mark (StartLocation);
2337                         DoEmit (ec);
2338
2339                         if (SymbolWriter.HasSymbolWriter)
2340                                 EmitSymbolInfo (ec);
2341
2342                         ec.CurrentBlock = prev_block;
2343                 }
2344
2345                 protected virtual void EmitSymbolInfo (EmitContext ec)
2346                 {
2347                         if (variables != null) {
2348                                 foreach (LocalInfo vi in variables.Values) {
2349                                         vi.EmitSymbolInfo (ec);
2350                                 }
2351                         }
2352                 }
2353
2354                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2355                 {
2356                         MutateVariables (storey);
2357
2358                         if (scope_initializers != null) {
2359                                 foreach (Statement s in scope_initializers)
2360                                         s.MutateHoistedGenericType (storey);
2361                         }
2362
2363                         foreach (Statement s in statements)
2364                                 s.MutateHoistedGenericType (storey);
2365                 }
2366
2367                 void MutateVariables (AnonymousMethodStorey storey)
2368                 {
2369                         if (variables != null) {
2370                                 foreach (LocalInfo vi in variables.Values) {
2371                                         vi.VariableType = storey.MutateType (vi.VariableType);
2372                                 }
2373                         }
2374
2375                         if (temporary_variables != null) {
2376                                 foreach (LocalInfo vi in temporary_variables)
2377                                         vi.VariableType = storey.MutateType (vi.VariableType);
2378                         }
2379                 }
2380
2381                 public override string ToString ()
2382                 {
2383                         return String.Format ("{0} ({1}:{2})", GetType (),ID, StartLocation);
2384                 }
2385
2386                 protected override void CloneTo (CloneContext clonectx, Statement t)
2387                 {
2388                         Block target = (Block) t;
2389
2390                         clonectx.AddBlockMap (this, target);
2391
2392                         //target.Toplevel = (ToplevelBlock) clonectx.LookupBlock (Toplevel);
2393                         target.Explicit = (ExplicitBlock) clonectx.LookupBlock (Explicit);
2394                         if (Parent != null)
2395                                 target.Parent = clonectx.RemapBlockCopy (Parent);
2396
2397                         if (variables != null){
2398                                 target.variables = new Hashtable ();
2399
2400                                 foreach (DictionaryEntry de in variables){
2401                                         LocalInfo newlocal = ((LocalInfo) de.Value).Clone (clonectx);
2402                                         target.variables [de.Key] = newlocal;
2403                                         clonectx.AddVariableMap ((LocalInfo) de.Value, newlocal);
2404                                 }
2405                         }
2406
2407                         target.statements = new ArrayList (statements.Count);
2408                         foreach (Statement s in statements)
2409                                 target.statements.Add (s.Clone (clonectx));
2410
2411                         if (target.children != null){
2412                                 target.children = new ArrayList (children.Count);
2413                                 foreach (Block b in children){
2414                                         target.children.Add (clonectx.LookupBlock (b));
2415                                 }
2416                         }
2417
2418                         //
2419                         // TODO: labels, switch_block, constants (?), anonymous_children
2420                         //
2421                 }
2422         }
2423
2424         public class ExplicitBlock : Block {
2425                 HybridDictionary known_variables;
2426                 protected AnonymousMethodStorey am_storey;
2427
2428                 public ExplicitBlock (Block parent, Location start, Location end)
2429                         : this (parent, (Flags) 0, start, end)
2430                 {
2431                 }
2432
2433                 public ExplicitBlock (Block parent, Flags flags, Location start, Location end)
2434                         : base (parent, flags, start, end)
2435                 {
2436                         this.Explicit = this;
2437                 }
2438
2439                 // <summary>
2440                 //   Marks a variable with name @name as being used in this or a child block.
2441                 //   If a variable name has been used in a child block, it's illegal to
2442                 //   declare a variable with the same name in the current block.
2443                 // </summary>
2444                 internal void AddKnownVariable (string name, IKnownVariable info)
2445                 {
2446                         if (known_variables == null)
2447                                 known_variables = new HybridDictionary();
2448
2449                         known_variables [name] = info;
2450
2451                         if (Parent != null)
2452                                 Parent.Explicit.AddKnownVariable (name, info);
2453                 }
2454
2455                 public AnonymousMethodStorey AnonymousMethodStorey {
2456                         get { return am_storey; }
2457                 }
2458
2459                 //
2460                 // Creates anonymous method storey in current block
2461                 //
2462                 public AnonymousMethodStorey CreateAnonymousMethodStorey (EmitContext ec)
2463                 {
2464                         //
2465                         // When referencing a variable in iterator storey from children anonymous method
2466                         //
2467                         if (Toplevel.am_storey is IteratorStorey) {
2468                                 return Toplevel.am_storey;
2469                         }
2470
2471                         //
2472                         // An iterator has only 1 storey block
2473                         //
2474                         if (ec.CurrentIterator != null)
2475                             return ec.CurrentIterator.Storey;
2476
2477                         if (am_storey == null) {
2478                                 MemberBase mc = ec.ResolveContext as MemberBase;
2479                                 GenericMethod gm = mc == null ? null : mc.GenericMethod;
2480
2481                                 //
2482                                 // Creates anonymous method storey for this block
2483                                 //
2484                                 am_storey = new AnonymousMethodStorey (this, ec.TypeContainer, mc, gm, "AnonStorey");
2485                         }
2486
2487                         return am_storey;
2488                 }
2489
2490                 public override void Emit (EmitContext ec)
2491                 {
2492                         if (am_storey != null)
2493                                 am_storey.EmitStoreyInstantiation (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                                         if (am_storey.OriginalSourceBlock.Explicit.HasCapturedThis) {
2513                                                 ExplicitBlock parent = Toplevel.Parent.Explicit;
2514                                                 while (parent.am_storey == null)
2515                                                         parent = parent.Parent.Explicit;
2516
2517                                                 am_storey.AddParentStoreyReference (parent.am_storey);
2518                                         }
2519
2520                                         am_storey.ChangeParentStorey (ec.CurrentAnonymousMethod.Storey);
2521                                 }
2522
2523                                 am_storey.DefineType ();
2524                                 am_storey.ResolveType ();
2525                                 am_storey.Define ();
2526                                 am_storey.Parent.PartialContainer.AddCompilerGeneratedClass (am_storey);
2527
2528                                 ArrayList ref_blocks = am_storey.ReferencesFromChildrenBlock;
2529                                 if (ref_blocks != null) {
2530                                         foreach (ExplicitBlock ref_block in ref_blocks) {
2531                                                 for (ExplicitBlock b = ref_block.Explicit; b != this; b = b.Parent.Explicit) {
2532                                                         if (b.am_storey != null) {
2533                                                                 b.am_storey.AddParentStoreyReference (am_storey);
2534
2535                                                                 // Stop propagation inside same top block
2536                                                                 if (b.Toplevel == Toplevel)
2537                                                                         break;
2538
2539                                                                 b = b.Toplevel;
2540                                                     }
2541                                                         b.HasCapturedVariable = true;
2542                                                 }
2543                                         }
2544                                 }
2545                         }
2546
2547                         base.EmitMeta (ec);
2548                 }
2549
2550                 internal IKnownVariable GetKnownVariable (string name)
2551                 {
2552                         return known_variables == null ? null : (IKnownVariable) known_variables [name];
2553                 }
2554
2555                 public bool HasCapturedThis
2556                 {
2557                         set { flags = value ? flags | Flags.HasCapturedThis : flags & ~Flags.HasCapturedThis; }
2558                         get { return (flags & Flags.HasCapturedThis) != 0; }
2559                 }
2560
2561                 public bool HasCapturedVariable
2562                 {
2563                         set { flags = value ? flags | Flags.HasCapturedVariable : flags & ~Flags.HasCapturedVariable; }
2564                         get { return (flags & Flags.HasCapturedVariable) != 0; }
2565                 }
2566
2567                 protected override void CloneTo (CloneContext clonectx, Statement t)
2568                 {
2569                         ExplicitBlock target = (ExplicitBlock) t;
2570                         target.known_variables = null;
2571                         base.CloneTo (clonectx, t);
2572                 }
2573         }
2574
2575         public class ToplevelParameterInfo : IKnownVariable {
2576                 public readonly ToplevelBlock Block;
2577                 public readonly int Index;
2578                 public VariableInfo VariableInfo;
2579
2580                 Block IKnownVariable.Block {
2581                         get { return Block; }
2582                 }
2583                 public Parameter Parameter {
2584                         get { return Block.Parameters [Index]; }
2585                 }
2586
2587                 public Type ParameterType {
2588                         get { return Block.Parameters.Types [Index]; }
2589                 }
2590
2591                 public Location Location {
2592                         get { return Parameter.Location; }
2593                 }
2594
2595                 public ToplevelParameterInfo (ToplevelBlock block, int idx)
2596                 {
2597                         this.Block = block;
2598                         this.Index = idx;
2599                 }
2600         }
2601
2602         //
2603         // A toplevel block contains extra information, the split is done
2604         // only to separate information that would otherwise bloat the more
2605         // lightweight Block.
2606         //
2607         // In particular, this was introduced when the support for Anonymous
2608         // Methods was implemented. 
2609         // 
2610         public class ToplevelBlock : ExplicitBlock {
2611                 GenericMethod generic;
2612                 FlowBranchingToplevel top_level_branching;
2613                 protected Parameters parameters;
2614                 ToplevelParameterInfo[] parameter_info;
2615                 LocalInfo this_variable;
2616
2617                 public HoistedVariable HoistedThisVariable;
2618
2619                 //
2620                 // The parameters for the block.
2621                 //
2622                 public Parameters Parameters {
2623                         get { return parameters; }
2624                 }
2625
2626                 public GenericMethod GenericMethod {
2627                         get { return generic; }
2628                 }
2629
2630                 public ToplevelBlock Container {
2631                         get { return Parent == null ? null : Parent.Toplevel; }
2632                 }
2633
2634                 public ToplevelBlock (Block parent, Parameters parameters, Location start) :
2635                         this (parent, (Flags) 0, parameters, start)
2636                 {
2637                 }
2638
2639                 public ToplevelBlock (Block parent, Parameters parameters, GenericMethod generic, Location start) :
2640                         this (parent, parameters, start)
2641                 {
2642                         this.generic = generic;
2643                 }
2644                 
2645                 public ToplevelBlock (Parameters parameters, Location start) :
2646                         this (null, (Flags) 0, parameters, start)
2647                 {
2648                 }
2649
2650                 ToplevelBlock (Flags flags, Parameters parameters, Location start) :
2651                         this (null, flags, parameters, start)
2652                 {
2653                 }
2654
2655                 // We use 'Parent' to hook up to the containing block, but don't want to register the current block as a child.
2656                 // So, we use a two-stage setup -- first pass a null parent to the base constructor, and then override 'Parent'.
2657                 public ToplevelBlock (Block parent, Flags flags, Parameters parameters, Location start) :
2658                         base (null, flags, start, Location.Null)
2659                 {
2660                         this.Toplevel = this;
2661
2662                         this.parameters = parameters;
2663                         this.Parent = parent;
2664                         if (parent != null)
2665                                 parent.AddAnonymousChild (this);
2666
2667                         if (!this.parameters.IsEmpty)
2668                                 ProcessParameters ();
2669                 }
2670
2671                 public ToplevelBlock (Location loc)
2672                         : this (null, (Flags) 0, Parameters.EmptyReadOnlyParameters, loc)
2673                 {
2674                 }
2675
2676                 protected override void CloneTo (CloneContext clonectx, Statement t)
2677                 {
2678                         ToplevelBlock target = (ToplevelBlock) t;
2679                         base.CloneTo (clonectx, t);
2680
2681                         if (parameters.Count != 0)
2682                                 target.parameter_info = new ToplevelParameterInfo [parameters.Count];
2683                         for (int i = 0; i < parameters.Count; ++i)
2684                                 target.parameter_info [i] = new ToplevelParameterInfo (target, i);
2685                 }
2686
2687                 public bool CheckError158 (string name, Location loc)
2688                 {
2689                         if (AnonymousChildren != null) {
2690                                 foreach (ToplevelBlock child in AnonymousChildren) {
2691                                         if (!child.CheckError158 (name, loc))
2692                                                 return false;
2693                                 }
2694                         }
2695
2696                         for (ToplevelBlock c = Container; c != null; c = c.Container) {
2697                                 if (!c.DoCheckError158 (name, loc))
2698                                         return false;
2699                         }
2700
2701                         return true;
2702                 }
2703
2704                 void ProcessParameters ()
2705                 {
2706                         int n = parameters.Count;
2707                         parameter_info = new ToplevelParameterInfo [n];
2708                         ToplevelBlock top_parent = Parent == null ? null : Parent.Toplevel;
2709                         for (int i = 0; i < n; ++i) {
2710                                 parameter_info [i] = new ToplevelParameterInfo (this, i);
2711
2712                                 Parameter p = parameters [i];
2713                                 if (p == null)
2714                                         continue;
2715
2716                                 string name = p.Name;
2717                                 if (CheckParentConflictName (top_parent, name, loc))
2718                                         AddKnownVariable (name, parameter_info [i]);
2719                         }
2720
2721                         // mark this block as "used" so that we create local declarations in a sub-block
2722                         // FIXME: This appears to uncover a lot of bugs
2723                         //this.Use ();
2724                 }
2725
2726                 bool DoCheckError158 (string name, Location loc)
2727                 {
2728                         LabeledStatement s = LookupLabel (name);
2729                         if (s != null) {
2730                                 Report.SymbolRelatedToPreviousError (s.loc, s.Name);
2731                                 Error_158 (name, loc);
2732                                 return false;
2733                         }
2734
2735                         return true;
2736                 }
2737
2738                 public override Expression CreateExpressionTree (EmitContext ec)
2739                 {
2740                         if (statements.Count == 1)
2741                                 return ((Statement) statements [0]).CreateExpressionTree (ec);
2742
2743                         return base.CreateExpressionTree (ec);
2744                 }
2745
2746                 //
2747                 // Reformats this block to be top-level iterator block
2748                 //
2749                 public IteratorStorey ChangeToIterator (Iterator iterator, ToplevelBlock source)
2750                 {
2751                         IsIterator = true;
2752
2753                         // Creates block with original statements
2754                         AddStatement (new IteratorStatement (iterator, new Block (this, source)));
2755
2756                         source.statements = new ArrayList (1);
2757                         source.AddStatement (new Return (iterator, iterator.Location));
2758                         source.IsIterator = false;
2759
2760                         IteratorStorey iterator_storey = new IteratorStorey (iterator);
2761                         source.am_storey = iterator_storey;
2762                         return iterator_storey;
2763                 }
2764
2765                 public FlowBranchingToplevel TopLevelBranching {
2766                         get { return top_level_branching; }
2767                 }
2768
2769                 //
2770                 // Returns a parameter reference expression for the given name,
2771                 // or null if there is no such parameter
2772                 //
2773                 public Expression GetParameterReference (string name, Location loc)
2774                 {
2775                         for (ToplevelBlock t = this; t != null; t = t.Container) {
2776                                 Expression expr = t.GetParameterReferenceExpression (name, loc);
2777                                 if (expr != null)
2778                                         return expr;
2779                         }
2780
2781                         return null;
2782                 }
2783
2784                 protected virtual Expression GetParameterReferenceExpression (string name, Location loc)
2785                 {
2786                         int idx = parameters.GetParameterIndexByName (name);
2787                         return idx < 0 ?
2788                                 null : new ParameterReference (parameter_info [idx], loc);
2789                 }
2790
2791                 // <summary>
2792                 //   Returns the "this" instance variable of this block.
2793                 //   See AddThisVariable() for more information.
2794                 // </summary>
2795                 public LocalInfo ThisVariable {
2796                         get { return this_variable; }
2797                 }
2798
2799                 // <summary>
2800                 //   This is used by non-static `struct' constructors which do not have an
2801                 //   initializer - in this case, the constructor must initialize all of the
2802                 //   struct's fields.  To do this, we add a "this" variable and use the flow
2803                 //   analysis code to ensure that it's been fully initialized before control
2804                 //   leaves the constructor.
2805                 // </summary>
2806                 public LocalInfo AddThisVariable (DeclSpace ds, Location l)
2807                 {
2808                         if (this_variable == null) {
2809                                 this_variable = new LocalInfo (ds, this, l);
2810                                 this_variable.Used = true;
2811                                 this_variable.IsThis = true;
2812
2813                                 Variables.Add ("this", this_variable);
2814                         }
2815
2816                         return this_variable;
2817                 }
2818
2819                 public bool IsIterator {
2820                         get { return (flags & Flags.IsIterator) != 0; }
2821                         set { flags = value ? flags | Flags.IsIterator : flags & ~Flags.IsIterator; }
2822                 }
2823
2824                 public bool IsThisAssigned (EmitContext ec)
2825                 {
2826                         return this_variable == null || this_variable.IsThisAssigned (ec);
2827                 }
2828
2829                 public bool ResolveMeta (EmitContext ec, Parameters ip)
2830                 {
2831                         int errors = Report.Errors;
2832                         int orig_count = parameters.Count;
2833
2834                         if (top_level_branching != null)
2835                                 return true;
2836
2837                         if (ip != null)
2838                                 parameters = ip;
2839
2840                         // Assert: orig_count != parameter.Count => orig_count == 0
2841                         if (orig_count != 0 && orig_count != parameters.Count)
2842                                 throw new InternalErrorException ("parameter information mismatch");
2843
2844                         int offset = Parent == null ? 0 : Parent.AssignableSlots;
2845
2846                         for (int i = 0; i < orig_count; ++i) {
2847                                 Parameter.Modifier mod = parameters.FixedParameters [i].ModFlags;
2848
2849                                 if ((mod & Parameter.Modifier.OUT) != Parameter.Modifier.OUT)
2850                                         continue;
2851
2852                                 VariableInfo vi = new VariableInfo (ip, i, offset);
2853                                 parameter_info [i].VariableInfo = vi;
2854                                 offset += vi.Length;
2855                         }
2856
2857                         ResolveMeta (ec, offset);
2858
2859                         top_level_branching = ec.StartFlowBranching (this);
2860
2861                         return Report.Errors == errors;
2862                 }
2863
2864                 // <summary>
2865                 //   Check whether all `out' parameters have been assigned.
2866                 // </summary>
2867                 public void CheckOutParameters (FlowBranching.UsageVector vector, Location loc)
2868                 {
2869                         if (vector.IsUnreachable)
2870                                 return;
2871
2872                         int n = parameter_info == null ? 0 : parameter_info.Length;
2873
2874                         for (int i = 0; i < n; i++) {
2875                                 VariableInfo var = parameter_info [i].VariableInfo;
2876
2877                                 if (var == null)
2878                                         continue;
2879
2880                                 if (vector.IsAssigned (var, false))
2881                                         continue;
2882
2883                                 Report.Error (177, loc, "The out parameter `{0}' must be assigned to before control leaves the current method",
2884                                         var.Name);
2885                         }
2886                 }
2887
2888                 public override void EmitMeta (EmitContext ec)
2889                 {
2890                         parameters.ResolveVariable ();
2891
2892                         // Avoid declaring an IL variable for this_variable since it is not accessed
2893                         // from the generated IL
2894                         if (this_variable != null)
2895                                 Variables.Remove ("this");
2896                         base.EmitMeta (ec);
2897                 }
2898
2899                 protected override void EmitSymbolInfo (EmitContext ec)
2900                 {
2901                         AnonymousExpression ae = ec.CurrentAnonymousMethod;
2902                         if ((ae != null) && (ae.Storey != null))
2903                                 SymbolWriter.DefineScopeVariable (ae.Storey.ID);
2904
2905                         base.EmitSymbolInfo (ec);
2906                 }
2907
2908                 public override void Emit (EmitContext ec)
2909                 {
2910                         base.Emit (ec);
2911                         ec.Mark (EndLocation);
2912                 }
2913         }
2914         
2915         public class SwitchLabel {
2916                 Expression label;
2917                 object converted;
2918                 Location loc;
2919
2920                 Label il_label;
2921                 bool  il_label_set;
2922                 Label il_label_code;
2923                 bool  il_label_code_set;
2924
2925                 public static readonly object NullStringCase = new object ();
2926
2927                 //
2928                 // if expr == null, then it is the default case.
2929                 //
2930                 public SwitchLabel (Expression expr, Location l)
2931                 {
2932                         label = expr;
2933                         loc = l;
2934                 }
2935
2936                 public Expression Label {
2937                         get {
2938                                 return label;
2939                         }
2940                 }
2941
2942                 public Location Location {
2943                         get { return loc; }
2944                 }
2945
2946                 public object Converted {
2947                         get {
2948                                 return converted;
2949                         }
2950                 }
2951
2952                 public Label GetILLabel (EmitContext ec)
2953                 {
2954                         if (!il_label_set){
2955                                 il_label = ec.ig.DefineLabel ();
2956                                 il_label_set = true;
2957                         }
2958                         return il_label;
2959                 }
2960
2961                 public Label GetILLabelCode (EmitContext ec)
2962                 {
2963                         if (!il_label_code_set){
2964                                 il_label_code = ec.ig.DefineLabel ();
2965                                 il_label_code_set = true;
2966                         }
2967                         return il_label_code;
2968                 }                               
2969                 
2970                 //
2971                 // Resolves the expression, reduces it to a literal if possible
2972                 // and then converts it to the requested type.
2973                 //
2974                 public bool ResolveAndReduce (EmitContext ec, Type required_type, bool allow_nullable)
2975                 {       
2976                         Expression e = label.Resolve (ec);
2977
2978                         if (e == null)
2979                                 return false;
2980
2981                         Constant c = e as Constant;
2982                         if (c == null){
2983                                 Report.Error (150, loc, "A constant value is expected");
2984                                 return false;
2985                         }
2986
2987                         if (required_type == TypeManager.string_type && c.GetValue () == null) {
2988                                 converted = NullStringCase;
2989                                 return true;
2990                         }
2991
2992                         if (allow_nullable && c.GetValue () == null) {
2993                                 converted = NullStringCase;
2994                                 return true;
2995                         }
2996                         
2997                         c = c.ImplicitConversionRequired (ec, required_type, loc);
2998                         if (c == null)
2999                                 return false;
3000
3001                         converted = c.GetValue ();
3002                         return true;
3003                 }
3004
3005                 public void Error_AlreadyOccurs (Type switch_type, SwitchLabel collision_with)
3006                 {
3007                         string label;
3008                         if (converted == null)
3009                                 label = "default";
3010                         else if (converted == NullStringCase)
3011                                 label = "null";
3012                         else
3013                                 label = converted.ToString ();
3014                         
3015                         Report.SymbolRelatedToPreviousError (collision_with.loc, null);
3016                         Report.Error (152, loc, "The label `case {0}:' already occurs in this switch statement", label);
3017                 }
3018
3019                 public SwitchLabel Clone (CloneContext clonectx)
3020                 {
3021                         return new SwitchLabel (label.Clone (clonectx), loc);
3022                 }
3023         }
3024
3025         public class SwitchSection {
3026                 // An array of SwitchLabels.
3027                 public readonly ArrayList Labels;
3028                 public readonly Block Block;
3029                 
3030                 public SwitchSection (ArrayList labels, Block block)
3031                 {
3032                         Labels = labels;
3033                         Block = block;
3034                 }
3035
3036                 public SwitchSection Clone (CloneContext clonectx)
3037                 {
3038                         ArrayList cloned_labels = new ArrayList ();
3039
3040                         foreach (SwitchLabel sl in cloned_labels)
3041                                 cloned_labels.Add (sl.Clone (clonectx));
3042                         
3043                         return new SwitchSection (cloned_labels, clonectx.LookupBlock (Block));
3044                 }
3045         }
3046         
3047         public class Switch : Statement {
3048                 public ArrayList Sections;
3049                 public Expression Expr;
3050
3051                 /// <summary>
3052                 ///   Maps constants whose type type SwitchType to their  SwitchLabels.
3053                 /// </summary>
3054                 public IDictionary Elements;
3055
3056                 /// <summary>
3057                 ///   The governing switch type
3058                 /// </summary>
3059                 public Type SwitchType;
3060
3061                 //
3062                 // Computed
3063                 //
3064                 Label default_target;
3065                 Label null_target;
3066                 Expression new_expr;
3067                 bool is_constant;
3068                 bool has_null_case;
3069                 SwitchSection constant_section;
3070                 SwitchSection default_section;
3071
3072                 ExpressionStatement string_dictionary;
3073                 FieldExpr switch_cache_field;
3074                 static int unique_counter;
3075
3076 #if GMCS_SOURCE
3077                 //
3078                 // Nullable Types support for GMCS.
3079                 //
3080                 Nullable.Unwrap unwrap;
3081
3082                 protected bool HaveUnwrap {
3083                         get { return unwrap != null; }
3084                 }
3085 #else
3086                 protected bool HaveUnwrap {
3087                         get { return false; }
3088                 }
3089 #endif
3090
3091                 //
3092                 // The types allowed to be implicitly cast from
3093                 // on the governing type
3094                 //
3095                 static Type [] allowed_types;
3096                 
3097                 public Switch (Expression e, ArrayList sects, Location l)
3098                 {
3099                         Expr = e;
3100                         Sections = sects;
3101                         loc = l;
3102                 }
3103
3104                 public bool GotDefault {
3105                         get {
3106                                 return default_section != null;
3107                         }
3108                 }
3109
3110                 public Label DefaultTarget {
3111                         get {
3112                                 return default_target;
3113                         }
3114                 }
3115
3116                 //
3117                 // Determines the governing type for a switch.  The returned
3118                 // expression might be the expression from the switch, or an
3119                 // expression that includes any potential conversions to the
3120                 // integral types or to string.
3121                 //
3122                 Expression SwitchGoverningType (EmitContext ec, Expression expr)
3123                 {
3124                         Type t = expr.Type;
3125
3126                         if (t == TypeManager.byte_type ||
3127                             t == TypeManager.sbyte_type ||
3128                             t == TypeManager.ushort_type ||
3129                             t == TypeManager.short_type ||
3130                             t == TypeManager.uint32_type ||
3131                             t == TypeManager.int32_type ||
3132                             t == TypeManager.uint64_type ||
3133                             t == TypeManager.int64_type ||
3134                             t == TypeManager.char_type ||
3135                             t == TypeManager.string_type ||
3136                             t == TypeManager.bool_type ||
3137                             TypeManager.IsEnumType (t))
3138                                 return expr;
3139
3140                         if (allowed_types == null){
3141                                 allowed_types = new Type [] {
3142                                         TypeManager.sbyte_type,
3143                                         TypeManager.byte_type,
3144                                         TypeManager.short_type,
3145                                         TypeManager.ushort_type,
3146                                         TypeManager.int32_type,
3147                                         TypeManager.uint32_type,
3148                                         TypeManager.int64_type,
3149                                         TypeManager.uint64_type,
3150                                         TypeManager.char_type,
3151                                         TypeManager.string_type
3152                                 };
3153                         }
3154
3155                         //
3156                         // Try to find a *user* defined implicit conversion.
3157                         //
3158                         // If there is no implicit conversion, or if there are multiple
3159                         // conversions, we have to report an error
3160                         //
3161                         Expression converted = null;
3162                         foreach (Type tt in allowed_types){
3163                                 Expression e;
3164                                 
3165                                 e = Convert.ImplicitUserConversion (ec, expr, tt, loc);
3166                                 if (e == null)
3167                                         continue;
3168
3169                                 //
3170                                 // Ignore over-worked ImplicitUserConversions that do
3171                                 // an implicit conversion in addition to the user conversion.
3172                                 // 
3173                                 if (!(e is UserCast))
3174                                         continue;
3175
3176                                 if (converted != null){
3177                                         Report.ExtraInformation (loc, "(Ambiguous implicit user defined conversion in previous ");
3178                                         return null;
3179                                 }
3180
3181                                 converted = e;
3182                         }
3183                         return converted;
3184                 }
3185
3186                 //
3187                 // Performs the basic sanity checks on the switch statement
3188                 // (looks for duplicate keys and non-constant expressions).
3189                 //
3190                 // It also returns a hashtable with the keys that we will later
3191                 // use to compute the switch tables
3192                 //
3193                 bool CheckSwitch (EmitContext ec)
3194                 {
3195                         bool error = false;
3196                         Elements = Sections.Count > 10 ? 
3197                                 (IDictionary)new Hashtable () : 
3198                                 (IDictionary)new ListDictionary ();
3199                                 
3200                         foreach (SwitchSection ss in Sections){
3201                                 foreach (SwitchLabel sl in ss.Labels){
3202                                         if (sl.Label == null){
3203                                                 if (default_section != null){
3204                                                         sl.Error_AlreadyOccurs (SwitchType, (SwitchLabel)default_section.Labels [0]);
3205                                                         error = true;
3206                                                 }
3207                                                 default_section = ss;
3208                                                 continue;
3209                                         }
3210
3211                                         if (!sl.ResolveAndReduce (ec, SwitchType, HaveUnwrap)) {
3212                                                 error = true;
3213                                                 continue;
3214                                         }
3215                                         
3216                                         object key = sl.Converted;
3217                                         if (key == SwitchLabel.NullStringCase)
3218                                                 has_null_case = true;
3219
3220                                         try {
3221                                                 Elements.Add (key, sl);
3222                                         } catch (ArgumentException) {
3223                                                 sl.Error_AlreadyOccurs (SwitchType, (SwitchLabel)Elements [key]);
3224                                                 error = true;
3225                                         }
3226                                 }
3227                         }
3228                         return !error;
3229                 }
3230
3231                 void EmitObjectInteger (ILGenerator ig, object k)
3232                 {
3233                         if (k is int)
3234                                 IntConstant.EmitInt (ig, (int) k);
3235                         else if (k is Constant) {
3236                                 EmitObjectInteger (ig, ((Constant) k).GetValue ());
3237                         } 
3238                         else if (k is uint)
3239                                 IntConstant.EmitInt (ig, unchecked ((int) (uint) k));
3240                         else if (k is long)
3241                         {
3242                                 if ((long) k >= int.MinValue && (long) k <= int.MaxValue)
3243                                 {
3244                                         IntConstant.EmitInt (ig, (int) (long) k);
3245                                         ig.Emit (OpCodes.Conv_I8);
3246                                 }
3247                                 else
3248                                         LongConstant.EmitLong (ig, (long) k);
3249                         }
3250                         else if (k is ulong)
3251                         {
3252                                 ulong ul = (ulong) k;
3253                                 if (ul < (1L<<32))
3254                                 {
3255                                         IntConstant.EmitInt (ig, unchecked ((int) ul));
3256                                         ig.Emit (OpCodes.Conv_U8);
3257                                 }
3258                                 else
3259                                 {
3260                                         LongConstant.EmitLong (ig, unchecked ((long) ul));
3261                                 }
3262                         }
3263                         else if (k is char)
3264                                 IntConstant.EmitInt (ig, (int) ((char) k));
3265                         else if (k is sbyte)
3266                                 IntConstant.EmitInt (ig, (int) ((sbyte) k));
3267                         else if (k is byte)
3268                                 IntConstant.EmitInt (ig, (int) ((byte) k));
3269                         else if (k is short)
3270                                 IntConstant.EmitInt (ig, (int) ((short) k));
3271                         else if (k is ushort)
3272                                 IntConstant.EmitInt (ig, (int) ((ushort) k));
3273                         else if (k is bool)
3274                                 IntConstant.EmitInt (ig, ((bool) k) ? 1 : 0);
3275                         else
3276                                 throw new Exception ("Unhandled case");
3277                 }
3278                 
3279                 // structure used to hold blocks of keys while calculating table switch
3280                 class KeyBlock : IComparable
3281                 {
3282                         public KeyBlock (long _first)
3283                         {
3284                                 first = last = _first;
3285                         }
3286                         public long first;
3287                         public long last;
3288                         public ArrayList element_keys = null;
3289                         // how many items are in the bucket
3290                         public int Size = 1;
3291                         public int Length
3292                         {
3293                                 get { return (int) (last - first + 1); }
3294                         }
3295                         public static long TotalLength (KeyBlock kb_first, KeyBlock kb_last)
3296                         {
3297                                 return kb_last.last - kb_first.first + 1;
3298                         }
3299                         public int CompareTo (object obj)
3300                         {
3301                                 KeyBlock kb = (KeyBlock) obj;
3302                                 int nLength = Length;
3303                                 int nLengthOther = kb.Length;
3304                                 if (nLengthOther == nLength)
3305                                         return (int) (kb.first - first);
3306                                 return nLength - nLengthOther;
3307                         }
3308                 }
3309
3310                 /// <summary>
3311                 /// This method emits code for a lookup-based switch statement (non-string)
3312                 /// Basically it groups the cases into blocks that are at least half full,
3313                 /// and then spits out individual lookup opcodes for each block.
3314                 /// It emits the longest blocks first, and short blocks are just
3315                 /// handled with direct compares.
3316                 /// </summary>
3317                 /// <param name="ec"></param>
3318                 /// <param name="val"></param>
3319                 /// <returns></returns>
3320                 void TableSwitchEmit (EmitContext ec, Expression val)
3321                 {
3322                         int element_count = Elements.Count;
3323                         object [] element_keys = new object [element_count];
3324                         Elements.Keys.CopyTo (element_keys, 0);
3325                         Array.Sort (element_keys);
3326
3327                         // initialize the block list with one element per key
3328                         ArrayList key_blocks = new ArrayList (element_count);
3329                         foreach (object key in element_keys)
3330                                 key_blocks.Add (new KeyBlock (System.Convert.ToInt64 (key)));
3331
3332                         KeyBlock current_kb;
3333                         // iteratively merge the blocks while they are at least half full
3334                         // there's probably a really cool way to do this with a tree...
3335                         while (key_blocks.Count > 1)
3336                         {
3337                                 ArrayList key_blocks_new = new ArrayList ();
3338                                 current_kb = (KeyBlock) key_blocks [0];
3339                                 for (int ikb = 1; ikb < key_blocks.Count; ikb++)
3340                                 {
3341                                         KeyBlock kb = (KeyBlock) key_blocks [ikb];
3342                                         if ((current_kb.Size + kb.Size) * 2 >=  KeyBlock.TotalLength (current_kb, kb))
3343                                         {
3344                                                 // merge blocks
3345                                                 current_kb.last = kb.last;
3346                                                 current_kb.Size += kb.Size;
3347                                         }
3348                                         else
3349                                         {
3350                                                 // start a new block
3351                                                 key_blocks_new.Add (current_kb);
3352                                                 current_kb = kb;
3353                                         }
3354                                 }
3355                                 key_blocks_new.Add (current_kb);
3356                                 if (key_blocks.Count == key_blocks_new.Count)
3357                                         break;
3358                                 key_blocks = key_blocks_new;
3359                         }
3360
3361                         // initialize the key lists
3362                         foreach (KeyBlock kb in key_blocks)
3363                                 kb.element_keys = new ArrayList ();
3364
3365                         // fill the key lists
3366                         int iBlockCurr = 0;
3367                         if (key_blocks.Count > 0) {
3368                                 current_kb = (KeyBlock) key_blocks [0];
3369                                 foreach (object key in element_keys)
3370                                 {
3371                                         bool next_block = (key is UInt64) ? (ulong) key > (ulong) current_kb.last :
3372                                                 System.Convert.ToInt64 (key) > current_kb.last;
3373                                         if (next_block)
3374                                                 current_kb = (KeyBlock) key_blocks [++iBlockCurr];
3375                                         current_kb.element_keys.Add (key);
3376                                 }
3377                         }
3378
3379                         // sort the blocks so we can tackle the largest ones first
3380                         key_blocks.Sort ();
3381
3382                         // okay now we can start...
3383                         ILGenerator ig = ec.ig;
3384                         Label lbl_end = ig.DefineLabel ();      // at the end ;-)
3385                         Label lbl_default = default_target;
3386
3387                         Type type_keys = null;
3388                         if (element_keys.Length > 0)
3389                                 type_keys = element_keys [0].GetType ();        // used for conversions
3390
3391                         Type compare_type;
3392                         
3393                         if (TypeManager.IsEnumType (SwitchType))
3394                                 compare_type = TypeManager.GetEnumUnderlyingType (SwitchType);
3395                         else
3396                                 compare_type = SwitchType;
3397                         
3398                         for (int iBlock = key_blocks.Count - 1; iBlock >= 0; --iBlock)
3399                         {
3400                                 KeyBlock kb = ((KeyBlock) key_blocks [iBlock]);
3401                                 lbl_default = (iBlock == 0) ? default_target : ig.DefineLabel ();
3402                                 if (kb.Length <= 2)
3403                                 {
3404                                         foreach (object key in kb.element_keys) {
3405                                                 SwitchLabel sl = (SwitchLabel) Elements [key];
3406                                                 if (key is int && (int) key == 0) {
3407                                                         val.EmitBranchable (ec, sl.GetILLabel (ec), false);
3408                                                 } else {
3409                                                         val.Emit (ec);
3410                                                         EmitObjectInteger (ig, key);
3411                                                         ig.Emit (OpCodes.Beq, sl.GetILLabel (ec));
3412                                                 }
3413                                         }
3414                                 }
3415                                 else
3416                                 {
3417                                         // TODO: if all the keys in the block are the same and there are
3418                                         //       no gaps/defaults then just use a range-check.
3419                                         if (compare_type == TypeManager.int64_type ||
3420                                                 compare_type == TypeManager.uint64_type)
3421                                         {
3422                                                 // TODO: optimize constant/I4 cases
3423
3424                                                 // check block range (could be > 2^31)
3425                                                 val.Emit (ec);
3426                                                 EmitObjectInteger (ig, System.Convert.ChangeType (kb.first, type_keys));
3427                                                 ig.Emit (OpCodes.Blt, lbl_default);
3428                                                 val.Emit (ec);
3429                                                 EmitObjectInteger (ig, System.Convert.ChangeType (kb.last, type_keys));
3430                                                 ig.Emit (OpCodes.Bgt, lbl_default);
3431
3432                                                 // normalize range
3433                                                 val.Emit (ec);
3434                                                 if (kb.first != 0)
3435                                                 {
3436                                                         EmitObjectInteger (ig, System.Convert.ChangeType (kb.first, type_keys));
3437                                                         ig.Emit (OpCodes.Sub);
3438                                                 }
3439                                                 ig.Emit (OpCodes.Conv_I4);      // assumes < 2^31 labels!
3440                                         }
3441                                         else
3442                                         {
3443                                                 // normalize range
3444                                                 val.Emit (ec);
3445                                                 int first = (int) kb.first;
3446                                                 if (first > 0)
3447                                                 {
3448                                                         IntConstant.EmitInt (ig, first);
3449                                                         ig.Emit (OpCodes.Sub);
3450                                                 }
3451                                                 else if (first < 0)
3452                                                 {
3453                                                         IntConstant.EmitInt (ig, -first);
3454                                                         ig.Emit (OpCodes.Add);
3455                                                 }
3456                                         }
3457
3458                                         // first, build the list of labels for the switch
3459                                         int iKey = 0;
3460                                         int cJumps = kb.Length;
3461                                         Label [] switch_labels = new Label [cJumps];
3462                                         for (int iJump = 0; iJump < cJumps; iJump++)
3463                                         {
3464                                                 object key = kb.element_keys [iKey];
3465                                                 if (System.Convert.ToInt64 (key) == kb.first + iJump)
3466                                                 {
3467                                                         SwitchLabel sl = (SwitchLabel) Elements [key];
3468                                                         switch_labels [iJump] = sl.GetILLabel (ec);
3469                                                         iKey++;
3470                                                 }
3471                                                 else
3472                                                         switch_labels [iJump] = lbl_default;
3473                                         }
3474                                         // emit the switch opcode
3475                                         ig.Emit (OpCodes.Switch, switch_labels);
3476                                 }
3477
3478                                 // mark the default for this block
3479                                 if (iBlock != 0)
3480                                         ig.MarkLabel (lbl_default);
3481                         }
3482
3483                         // TODO: find the default case and emit it here,
3484                         //       to prevent having to do the following jump.
3485                         //       make sure to mark other labels in the default section
3486
3487                         // the last default just goes to the end
3488                         if (element_keys.Length > 0)
3489                                 ig.Emit (OpCodes.Br, lbl_default);
3490
3491                         // now emit the code for the sections
3492                         bool found_default = false;
3493
3494                         foreach (SwitchSection ss in Sections) {
3495                                 foreach (SwitchLabel sl in ss.Labels) {
3496                                         if (sl.Converted == SwitchLabel.NullStringCase) {
3497                                                 ig.MarkLabel (null_target);
3498                                         } else if (sl.Label == null) {
3499                                                 ig.MarkLabel (lbl_default);
3500                                                 found_default = true;
3501                                                 if (!has_null_case)
3502                                                         ig.MarkLabel (null_target);
3503                                         }
3504                                         ig.MarkLabel (sl.GetILLabel (ec));
3505                                         ig.MarkLabel (sl.GetILLabelCode (ec));
3506                                 }
3507                                 ss.Block.Emit (ec);
3508                         }
3509                         
3510                         if (!found_default) {
3511                                 ig.MarkLabel (lbl_default);
3512                                 if (!has_null_case) {
3513                                         ig.MarkLabel (null_target);
3514                                 }
3515                         }
3516                         
3517                         ig.MarkLabel (lbl_end);
3518                 }
3519
3520                 SwitchSection FindSection (SwitchLabel label)
3521                 {
3522                         foreach (SwitchSection ss in Sections){
3523                                 foreach (SwitchLabel sl in ss.Labels){
3524                                         if (label == sl)
3525                                                 return ss;
3526                                 }
3527                         }
3528
3529                         return null;
3530                 }
3531
3532                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3533                 {
3534                         foreach (SwitchSection ss in Sections)
3535                                 ss.Block.MutateHoistedGenericType (storey);
3536                 }
3537
3538                 public static void Reset ()
3539                 {
3540                         unique_counter = 0;
3541                 }
3542
3543                 public override bool Resolve (EmitContext ec)
3544                 {
3545                         Expr = Expr.Resolve (ec);
3546                         if (Expr == null)
3547                                 return false;
3548
3549                         new_expr = SwitchGoverningType (ec, Expr);
3550
3551 #if GMCS_SOURCE
3552                         if ((new_expr == null) && TypeManager.IsNullableType (Expr.Type)) {
3553                                 unwrap = Nullable.Unwrap.Create (Expr, ec);
3554                                 if (unwrap == null)
3555                                         return false;
3556
3557                                 new_expr = SwitchGoverningType (ec, unwrap);
3558                         }
3559 #endif
3560
3561                         if (new_expr == null){
3562                                 Report.Error (151, loc, "A value of an integral type or string expected for switch");
3563                                 return false;
3564                         }
3565
3566                         // Validate switch.
3567                         SwitchType = new_expr.Type;
3568
3569                         if (RootContext.Version == LanguageVersion.ISO_1 && SwitchType == TypeManager.bool_type) {
3570                                 Report.FeatureIsNotAvailable (loc, "switch expression of boolean type");
3571                                 return false;
3572                         }
3573
3574                         if (!CheckSwitch (ec))
3575                                 return false;
3576
3577                         if (HaveUnwrap)
3578                                 Elements.Remove (SwitchLabel.NullStringCase);
3579
3580                         Switch old_switch = ec.Switch;
3581                         ec.Switch = this;
3582                         ec.Switch.SwitchType = SwitchType;
3583
3584                         Report.Debug (1, "START OF SWITCH BLOCK", loc, ec.CurrentBranching);
3585                         ec.StartFlowBranching (FlowBranching.BranchingType.Switch, loc);
3586
3587                         is_constant = new_expr is Constant;
3588                         if (is_constant) {
3589                                 object key = ((Constant) new_expr).GetValue ();
3590                                 SwitchLabel label = (SwitchLabel) Elements [key];
3591
3592                                 constant_section = FindSection (label);
3593                                 if (constant_section == null)
3594                                         constant_section = default_section;
3595                         }
3596
3597                         bool first = true;
3598                         bool ok = true;
3599                         foreach (SwitchSection ss in Sections){
3600                                 if (!first)
3601                                         ec.CurrentBranching.CreateSibling (
3602                                                 null, FlowBranching.SiblingType.SwitchSection);
3603                                 else
3604                                         first = false;
3605
3606                                 if (is_constant && (ss != constant_section)) {
3607                                         // If we're a constant switch, we're only emitting
3608                                         // one single section - mark all the others as
3609                                         // unreachable.
3610                                         ec.CurrentBranching.CurrentUsageVector.Goto ();
3611                                         if (!ss.Block.ResolveUnreachable (ec, true)) {
3612                                                 ok = false;
3613                                         }
3614                                 } else {
3615                                         if (!ss.Block.Resolve (ec))
3616                                                 ok = false;
3617                                 }
3618                         }
3619
3620                         if (default_section == null)
3621                                 ec.CurrentBranching.CreateSibling (
3622                                         null, FlowBranching.SiblingType.SwitchSection);
3623
3624                         ec.EndFlowBranching ();
3625                         ec.Switch = old_switch;
3626
3627                         Report.Debug (1, "END OF SWITCH BLOCK", loc, ec.CurrentBranching);
3628
3629                         if (!ok)
3630                                 return false;
3631
3632                         if (SwitchType == TypeManager.string_type && !is_constant) {
3633                                 // TODO: Optimize single case, and single+default case
3634                                 ResolveStringSwitchMap (ec);
3635                         }
3636
3637                         return true;
3638                 }
3639
3640                 void ResolveStringSwitchMap (EmitContext ec)
3641                 {
3642                         FullNamedExpression string_dictionary_type;
3643 #if GMCS_SOURCE
3644                         MemberAccess system_collections_generic = new MemberAccess (new MemberAccess (
3645                                 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc), "Generic", loc);
3646
3647                         string_dictionary_type = new MemberAccess (system_collections_generic, "Dictionary",
3648                                 new TypeArguments (
3649                                         new TypeExpression (TypeManager.string_type, loc),
3650                                         new TypeExpression (TypeManager.int32_type, loc)), loc);
3651 #else
3652                         MemberAccess system_collections_generic = new MemberAccess (
3653                                 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc);
3654
3655                         string_dictionary_type = new MemberAccess (system_collections_generic, "Hashtable", loc);
3656 #endif
3657                         Field field = new Field (ec.TypeContainer, string_dictionary_type,
3658                                 Modifiers.STATIC | Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED,
3659                                 new MemberName (CompilerGeneratedClass.MakeName (null, "f", "switch$map", unique_counter++), loc), null);
3660                         if (!field.Define ())
3661                                 return;
3662                         ec.TypeContainer.PartialContainer.AddField (field);
3663
3664                         ArrayList init = new ArrayList ();
3665                         int counter = 0;
3666                         Elements.Clear ();
3667                         string value = null;
3668                         foreach (SwitchSection section in Sections) {
3669                                 foreach (SwitchLabel sl in section.Labels) {
3670                                         if (sl.Label == null || sl.Converted == SwitchLabel.NullStringCase) {
3671                                                 value = null;
3672                                                 continue;
3673                                         }
3674
3675                                         value = (string) sl.Converted;
3676                                         ArrayList init_args = new ArrayList (2);
3677                                         init_args.Add (new StringLiteral (value, sl.Location));
3678                                         init_args.Add (new IntConstant (counter, loc));
3679                                         init.Add (new CollectionElementInitializer (init_args, loc));
3680                                 }
3681
3682                                 if (value == null)
3683                                         continue;
3684
3685                                 Elements.Add (counter, section.Labels [0]);
3686                                 ++counter;
3687                         }
3688
3689                         ArrayList args = new ArrayList (1);
3690                         args.Add (new Argument (new IntConstant (Sections.Count, loc)));
3691                         Expression initializer = new NewInitialize (string_dictionary_type, args,
3692                                 new CollectionOrObjectInitializers (init, loc), loc);
3693
3694                         switch_cache_field = new FieldExpr (field.FieldBuilder, loc);
3695                         string_dictionary = new SimpleAssign (switch_cache_field, initializer.Resolve (ec));
3696                 }
3697
3698                 void DoEmitStringSwitch (LocalTemporary value, EmitContext ec)
3699                 {
3700                         ILGenerator ig = ec.ig;
3701                         Label l_initialized = ig.DefineLabel ();
3702
3703                         //
3704                         // Skip initialization when value is null
3705                         //
3706                         value.EmitBranchable (ec, null_target, false);
3707
3708                         //
3709                         // Check if string dictionary is initialized and initialize
3710                         //
3711                         switch_cache_field.EmitBranchable (ec, l_initialized, true);
3712                         string_dictionary.EmitStatement (ec);
3713                         ig.MarkLabel (l_initialized);
3714
3715                         LocalTemporary string_switch_variable = new LocalTemporary (TypeManager.int32_type);
3716
3717 #if GMCS_SOURCE
3718                         ArrayList get_value_args = new ArrayList (2);
3719                         get_value_args.Add (new Argument (value));
3720                         get_value_args.Add (new Argument (string_switch_variable, Argument.AType.Out));
3721                         Expression get_item = new Invocation (new MemberAccess (switch_cache_field, "TryGetValue", loc), get_value_args).Resolve (ec);
3722                         if (get_item == null)
3723                                 return;
3724
3725                         //
3726                         // A value was not found, go to default case
3727                         //
3728                         get_item.EmitBranchable (ec, default_target, false);
3729 #else
3730                         ArrayList get_value_args = new ArrayList (1);
3731                         get_value_args.Add (value);
3732
3733                         Expression get_item = new IndexerAccess (new ElementAccess (switch_cache_field, get_value_args), loc).Resolve (ec);
3734                         if (get_item == null)
3735                                 return;
3736
3737                         LocalTemporary get_item_object = new LocalTemporary (TypeManager.object_type);
3738                         get_item_object.EmitAssign (ec, get_item, true, false);
3739                         ec.ig.Emit (OpCodes.Brfalse, default_target);
3740
3741                         ExpressionStatement get_item_int = (ExpressionStatement) new SimpleAssign (string_switch_variable,
3742                                 new Cast (new TypeExpression (TypeManager.int32_type, loc), get_item_object, loc)).Resolve (ec);
3743
3744                         get_item_int.EmitStatement (ec);
3745                         get_item_object.Release (ec);
3746 #endif
3747                         TableSwitchEmit (ec, string_switch_variable);
3748                         string_switch_variable.Release (ec);
3749                 }
3750                 
3751                 protected override void DoEmit (EmitContext ec)
3752                 {
3753                         ILGenerator ig = ec.ig;
3754
3755                         default_target = ig.DefineLabel ();
3756                         null_target = ig.DefineLabel ();
3757
3758                         // Store variable for comparission purposes
3759                         // TODO: Don't duplicate non-captured VariableReference
3760                         LocalTemporary value;
3761                         if (HaveUnwrap) {
3762                                 value = new LocalTemporary (SwitchType);
3763 #if GMCS_SOURCE
3764                                 unwrap.EmitCheck (ec);
3765                                 ig.Emit (OpCodes.Brfalse, null_target);
3766                                 new_expr.Emit (ec);
3767                                 value.Store (ec);
3768 #endif
3769                         } else if (!is_constant) {
3770                                 value = new LocalTemporary (SwitchType);
3771                                 new_expr.Emit (ec);
3772                                 value.Store (ec);
3773                         } else
3774                                 value = null;
3775
3776                         //
3777                         // Setup the codegen context
3778                         //
3779                         Label old_end = ec.LoopEnd;
3780                         Switch old_switch = ec.Switch;
3781                         
3782                         ec.LoopEnd = ig.DefineLabel ();
3783                         ec.Switch = this;
3784
3785                         // Emit Code.
3786                         if (is_constant) {
3787                                 if (constant_section != null)
3788                                         constant_section.Block.Emit (ec);
3789                         } else if (string_dictionary != null) {
3790                                 DoEmitStringSwitch (value, ec);
3791                         } else {
3792                                 TableSwitchEmit (ec, value);
3793                         }
3794
3795                         if (value != null)
3796                                 value.Release (ec);
3797
3798                         // Restore context state. 
3799                         ig.MarkLabel (ec.LoopEnd);
3800
3801                         //
3802                         // Restore the previous context
3803                         //
3804                         ec.LoopEnd = old_end;
3805                         ec.Switch = old_switch;
3806                 }
3807
3808                 protected override void CloneTo (CloneContext clonectx, Statement t)
3809                 {
3810                         Switch target = (Switch) t;
3811
3812                         target.Expr = Expr.Clone (clonectx);
3813                         target.Sections = new ArrayList ();
3814                         foreach (SwitchSection ss in Sections){
3815                                 target.Sections.Add (ss.Clone (clonectx));
3816                         }
3817                 }
3818         }
3819
3820         // A place where execution can restart in an iterator
3821         public abstract class ResumableStatement : Statement
3822         {
3823                 bool prepared;
3824                 protected Label resume_point;
3825
3826                 public Label PrepareForEmit (EmitContext ec)
3827                 {
3828                         if (!prepared) {
3829                                 prepared = true;
3830                                 resume_point = ec.ig.DefineLabel ();
3831                         }
3832                         return resume_point;
3833                 }
3834
3835                 public virtual Label PrepareForDispose (EmitContext ec, Label end)
3836                 {
3837                         return end;
3838                 }
3839                 public virtual void EmitForDispose (EmitContext ec, Iterator iterator, Label end, bool have_dispatcher)
3840                 {
3841                 }
3842         }
3843
3844         // Base class for statements that are implemented in terms of try...finally
3845         public abstract class ExceptionStatement : ResumableStatement
3846         {
3847                 bool code_follows;
3848
3849                 protected abstract void EmitPreTryBody (EmitContext ec);
3850                 protected abstract void EmitTryBody (EmitContext ec);
3851                 protected abstract void EmitFinallyBody (EmitContext ec);
3852
3853                 protected sealed override void DoEmit (EmitContext ec)
3854                 {
3855                         ILGenerator ig = ec.ig;
3856
3857                         EmitPreTryBody (ec);
3858
3859                         if (resume_points != null) {
3860                                 IntConstant.EmitInt (ig, (int) Iterator.State.Running);
3861                                 ig.Emit (OpCodes.Stloc, ec.CurrentIterator.CurrentPC);
3862                         }
3863
3864                         ig.BeginExceptionBlock ();
3865
3866                         if (resume_points != null) {
3867                                 ig.MarkLabel (resume_point);
3868
3869                                 // For normal control flow, we want to fall-through the Switch
3870                                 // So, we use CurrentPC rather than the $PC field, and initialize it to an outside value above
3871                                 ig.Emit (OpCodes.Ldloc, ec.CurrentIterator.CurrentPC);
3872                                 IntConstant.EmitInt (ig, first_resume_pc);
3873                                 ig.Emit (OpCodes.Sub);
3874
3875                                 Label [] labels = new Label [resume_points.Count];
3876                                 for (int i = 0; i < resume_points.Count; ++i)
3877                                         labels [i] = ((ResumableStatement) resume_points [i]).PrepareForEmit (ec);
3878                                 ig.Emit (OpCodes.Switch, labels);
3879                         }
3880
3881                         EmitTryBody (ec);
3882
3883                         ig.BeginFinallyBlock ();
3884
3885                         Label start_finally = ec.ig.DefineLabel ();
3886                         if (resume_points != null) {
3887                                 ig.Emit (OpCodes.Ldloc, ec.CurrentIterator.SkipFinally);
3888                                 ig.Emit (OpCodes.Brfalse_S, start_finally);
3889                                 ig.Emit (OpCodes.Endfinally);
3890                         }
3891
3892                         ig.MarkLabel (start_finally);
3893                         EmitFinallyBody (ec);
3894
3895                         ig.EndExceptionBlock ();
3896                 }
3897
3898                 public void SomeCodeFollows ()
3899                 {
3900                         code_follows = true;
3901                 }
3902
3903                 protected void ResolveReachability (EmitContext ec)
3904                 {
3905                         // System.Reflection.Emit automatically emits a 'leave' at the end of a try clause
3906                         // So, ensure there's some IL code after this statement.
3907                         if (!code_follows && resume_points == null && ec.CurrentBranching.CurrentUsageVector.IsUnreachable)
3908                                 ec.NeedReturnLabel ();
3909
3910                 }
3911
3912                 ArrayList resume_points;
3913                 int first_resume_pc;
3914                 public void AddResumePoint (ResumableStatement stmt, int pc)
3915                 {
3916                         if (resume_points == null) {
3917                                 resume_points = new ArrayList ();
3918                                 first_resume_pc = pc;
3919                         }
3920
3921                         if (pc != first_resume_pc + resume_points.Count)
3922                                 throw new InternalErrorException ("missed an intervening AddResumePoint?");
3923
3924                         resume_points.Add (stmt);
3925                 }
3926
3927                 Label dispose_try_block;
3928                 bool prepared_for_dispose, emitted_dispose;
3929                 public override Label PrepareForDispose (EmitContext ec, Label end)
3930                 {
3931                         if (!prepared_for_dispose) {
3932                                 prepared_for_dispose = true;
3933                                 dispose_try_block = ec.ig.DefineLabel ();
3934                         }
3935                         return dispose_try_block;
3936                 }
3937
3938                 public override void EmitForDispose (EmitContext ec, Iterator iterator, Label end, bool have_dispatcher)
3939                 {
3940                         if (emitted_dispose)
3941                                 return;
3942
3943                         emitted_dispose = true;
3944
3945                         ILGenerator ig = ec.ig;
3946
3947                         Label end_of_try = ig.DefineLabel ();
3948
3949                         // Ensure that the only way we can get into this code is through a dispatcher
3950                         if (have_dispatcher)
3951                                 ig.Emit (OpCodes.Br, end);
3952
3953                         ig.BeginExceptionBlock ();
3954
3955                         ig.MarkLabel (dispose_try_block);
3956
3957                         Label [] labels = null;
3958                         for (int i = 0; i < resume_points.Count; ++i) {
3959                                 ResumableStatement s = (ResumableStatement) resume_points [i];
3960                                 Label ret = s.PrepareForDispose (ec, end_of_try);
3961                                 if (ret.Equals (end_of_try) && labels == null)
3962                                         continue;
3963                                 if (labels == null) {
3964                                         labels = new Label [resume_points.Count];
3965                                         for (int j = 0; j < i; ++j)
3966                                                 labels [j] = end_of_try;
3967                                 }
3968                                 labels [i] = ret;
3969                         }
3970
3971                         if (labels != null) {
3972                                 int j;
3973                                 for (j = 1; j < labels.Length; ++j)
3974                                         if (!labels [0].Equals (labels [j]))
3975                                                 break;
3976                                 bool emit_dispatcher = j < labels.Length;
3977
3978                                 if (emit_dispatcher) {
3979                                         //SymbolWriter.StartIteratorDispatcher (ec.ig);
3980                                         ig.Emit (OpCodes.Ldloc, iterator.CurrentPC);
3981                                         IntConstant.EmitInt (ig, first_resume_pc);
3982                                         ig.Emit (OpCodes.Sub);
3983                                         ig.Emit (OpCodes.Switch, labels);
3984                                         //SymbolWriter.EndIteratorDispatcher (ec.ig);
3985                                 }
3986
3987                                 foreach (ResumableStatement s in resume_points)
3988                                         s.EmitForDispose (ec, iterator, end_of_try, emit_dispatcher);
3989                         }
3990
3991                         ig.MarkLabel (end_of_try);
3992
3993                         ig.BeginFinallyBlock ();
3994
3995                         EmitFinallyBody (ec);
3996
3997                         ig.EndExceptionBlock ();
3998                 }
3999         }
4000
4001         public class Lock : ExceptionStatement {
4002                 Expression expr;
4003                 public Statement Statement;
4004                 TemporaryVariable temp;
4005                         
4006                 public Lock (Expression expr, Statement stmt, Location l)
4007                 {
4008                         this.expr = expr;
4009                         Statement = stmt;
4010                         loc = l;
4011                 }
4012
4013                 public override bool Resolve (EmitContext ec)
4014                 {
4015                         expr = expr.Resolve (ec);
4016                         if (expr == null)
4017                                 return false;
4018
4019                         if (expr.Type.IsValueType){
4020                                 Report.Error (185, loc,
4021                                               "`{0}' is not a reference type as required by the lock statement",
4022                                               TypeManager.CSharpName (expr.Type));
4023                                 return false;
4024                         }
4025
4026                         ec.StartFlowBranching (this);
4027                         bool ok = Statement.Resolve (ec);
4028                         ec.EndFlowBranching ();
4029
4030                         ResolveReachability (ec);
4031
4032                         // Avoid creating libraries that reference the internal
4033                         // mcs NullType:
4034                         Type t = expr.Type;
4035                         if (t == TypeManager.null_type)
4036                                 t = TypeManager.object_type;
4037                         
4038                         temp = new TemporaryVariable (t, loc);
4039                         temp.Resolve (ec);
4040
4041                         if (TypeManager.void_monitor_enter_object == null || TypeManager.void_monitor_exit_object == null) {
4042                                 Type monitor_type = TypeManager.CoreLookupType ("System.Threading", "Monitor", Kind.Class, true);
4043                                 TypeManager.void_monitor_enter_object = TypeManager.GetPredefinedMethod (
4044                                         monitor_type, "Enter", loc, TypeManager.object_type);
4045                                 TypeManager.void_monitor_exit_object = TypeManager.GetPredefinedMethod (
4046                                         monitor_type, "Exit", loc, TypeManager.object_type);
4047                         }
4048                         
4049                         return ok;
4050                 }
4051                 
4052                 protected override void EmitPreTryBody (EmitContext ec)
4053                 {
4054                         ILGenerator ig = ec.ig;
4055
4056                         temp.EmitAssign (ec, expr);
4057                         temp.Emit (ec);
4058                         ig.Emit (OpCodes.Call, TypeManager.void_monitor_enter_object);
4059                 }
4060
4061                 protected override void EmitTryBody (EmitContext ec)
4062                 {
4063                         Statement.Emit (ec);
4064                 }
4065
4066                 protected override void EmitFinallyBody (EmitContext ec)
4067                 {
4068                         temp.Emit (ec);
4069                         ec.ig.Emit (OpCodes.Call, TypeManager.void_monitor_exit_object);
4070                 }
4071
4072                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4073                 {
4074                         expr.MutateHoistedGenericType (storey);
4075                         temp.MutateHoistedGenericType (storey);
4076                         Statement.MutateHoistedGenericType (storey);
4077                 }
4078                 
4079                 protected override void CloneTo (CloneContext clonectx, Statement t)
4080                 {
4081                         Lock target = (Lock) t;
4082
4083                         target.expr = expr.Clone (clonectx);
4084                         target.Statement = Statement.Clone (clonectx);
4085                 }
4086         }
4087
4088         public class Unchecked : Statement {
4089                 public Block Block;
4090                 
4091                 public Unchecked (Block b)
4092                 {
4093                         Block = b;
4094                         b.Unchecked = true;
4095                 }
4096
4097                 public override bool Resolve (EmitContext ec)
4098                 {
4099                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
4100                                 return Block.Resolve (ec);
4101                 }
4102                 
4103                 protected override void DoEmit (EmitContext ec)
4104                 {
4105                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
4106                                 Block.Emit (ec);
4107                 }
4108
4109                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4110                 {
4111                         Block.MutateHoistedGenericType (storey);
4112                 }
4113
4114                 protected override void CloneTo (CloneContext clonectx, Statement t)
4115                 {
4116                         Unchecked target = (Unchecked) t;
4117
4118                         target.Block = clonectx.LookupBlock (Block);
4119                 }
4120         }
4121
4122         public class Checked : Statement {
4123                 public Block Block;
4124                 
4125                 public Checked (Block b)
4126                 {
4127                         Block = b;
4128                         b.Unchecked = false;
4129                 }
4130
4131                 public override bool Resolve (EmitContext ec)
4132                 {
4133                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
4134                                 return Block.Resolve (ec);
4135                 }
4136
4137                 protected override void DoEmit (EmitContext ec)
4138                 {
4139                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
4140                                 Block.Emit (ec);
4141                 }
4142
4143                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4144                 {
4145                         Block.MutateHoistedGenericType (storey);
4146                 }
4147
4148                 protected override void CloneTo (CloneContext clonectx, Statement t)
4149                 {
4150                         Checked target = (Checked) t;
4151
4152                         target.Block = clonectx.LookupBlock (Block);
4153                 }
4154         }
4155
4156         public class Unsafe : Statement {
4157                 public Block Block;
4158
4159                 public Unsafe (Block b)
4160                 {
4161                         Block = b;
4162                         Block.Unsafe = true;
4163                 }
4164
4165                 public override bool Resolve (EmitContext ec)
4166                 {
4167                         using (ec.With (EmitContext.Flags.InUnsafe, true))
4168                                 return Block.Resolve (ec);
4169                 }
4170                 
4171                 protected override void DoEmit (EmitContext ec)
4172                 {
4173                         using (ec.With (EmitContext.Flags.InUnsafe, true))
4174                                 Block.Emit (ec);
4175                 }
4176
4177                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4178                 {
4179                         Block.MutateHoistedGenericType (storey);
4180                 }
4181
4182                 protected override void CloneTo (CloneContext clonectx, Statement t)
4183                 {
4184                         Unsafe target = (Unsafe) t;
4185
4186                         target.Block = clonectx.LookupBlock (Block);
4187                 }
4188         }
4189
4190         // 
4191         // Fixed statement
4192         //
4193         public class Fixed : Statement {
4194                 Expression type;
4195                 ArrayList declarators;
4196                 Statement statement;
4197                 Type expr_type;
4198                 Emitter[] data;
4199                 bool has_ret;
4200
4201                 abstract class Emitter
4202                 {
4203                         protected LocalInfo vi;
4204                         protected Expression converted;
4205
4206                         protected Emitter (Expression expr, LocalInfo li)
4207                         {
4208                                 converted = expr;
4209                                 vi = li;
4210                         }
4211
4212                         public abstract void Emit (EmitContext ec);
4213                         public abstract void EmitExit (EmitContext ec);
4214                 }
4215
4216                 class ExpressionEmitter : Emitter {
4217                         public ExpressionEmitter (Expression converted, LocalInfo li) :
4218                                 base (converted, li)
4219                         {
4220                         }
4221
4222                         public override void Emit (EmitContext ec) {
4223                                 //
4224                                 // Store pointer in pinned location
4225                                 //
4226                                 converted.Emit (ec);
4227                                 vi.EmitAssign (ec);
4228                         }
4229
4230                         public override void EmitExit (EmitContext ec)
4231                         {
4232                                 ec.ig.Emit (OpCodes.Ldc_I4_0);
4233                                 ec.ig.Emit (OpCodes.Conv_U);
4234                                 vi.EmitAssign (ec);
4235                         }
4236                 }
4237
4238                 class StringEmitter : Emitter {
4239                         class StringPtr : Expression
4240                         {
4241                                 LocalBuilder b;
4242
4243                                 public StringPtr (LocalBuilder b, Location l)
4244                                 {
4245                                         this.b = b;
4246                                         eclass = ExprClass.Value;
4247                                         type = TypeManager.char_ptr_type;
4248                                         loc = l;
4249                                 }
4250
4251                                 public override Expression CreateExpressionTree (EmitContext ec)
4252                                 {
4253                                         throw new NotSupportedException ("ET");
4254                                 }
4255
4256                                 public override Expression DoResolve (EmitContext ec)
4257                                 {
4258                                         // This should never be invoked, we are born in fully
4259                                         // initialized state.
4260
4261                                         return this;
4262                                 }
4263
4264                                 public override void Emit (EmitContext ec)
4265                                 {
4266                                         if (TypeManager.int_get_offset_to_string_data == null) {
4267                                                 // TODO: Move to resolve !!
4268                                                 TypeManager.int_get_offset_to_string_data = TypeManager.GetPredefinedMethod (
4269                                                         TypeManager.runtime_helpers_type, "get_OffsetToStringData", loc, Type.EmptyTypes);
4270                                         }
4271
4272                                         ILGenerator ig = ec.ig;
4273
4274                                         ig.Emit (OpCodes.Ldloc, b);
4275                                         ig.Emit (OpCodes.Conv_I);
4276                                         ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
4277                                         ig.Emit (OpCodes.Add);
4278                                 }
4279                         }
4280
4281                         LocalBuilder pinned_string;
4282                         Location loc;
4283
4284                         public StringEmitter (Expression expr, LocalInfo li, Location loc):
4285                                 base (expr, li)
4286                         {
4287                                 this.loc = loc;
4288                         }
4289
4290                         public override void Emit (EmitContext ec)
4291                         {
4292                                 ILGenerator ig = ec.ig;
4293                                 pinned_string = TypeManager.DeclareLocalPinned (ig, TypeManager.string_type);
4294                                         
4295                                 converted.Emit (ec);
4296                                 ig.Emit (OpCodes.Stloc, pinned_string);
4297
4298                                 Expression sptr = new StringPtr (pinned_string, loc);
4299                                 converted = Convert.ImplicitConversionRequired (
4300                                         ec, sptr, vi.VariableType, loc);
4301                                         
4302                                 if (converted == null)
4303                                         return;
4304
4305                                 converted.Emit (ec);
4306                                 vi.EmitAssign (ec);
4307                         }
4308
4309                         public override void EmitExit (EmitContext ec)
4310                         {
4311                                 ec.ig.Emit (OpCodes.Ldnull);
4312                                 ec.ig.Emit (OpCodes.Stloc, pinned_string);
4313                         }
4314                 }
4315
4316                 public Fixed (Expression type, ArrayList decls, Statement stmt, Location l)
4317                 {
4318                         this.type = type;
4319                         declarators = decls;
4320                         statement = stmt;
4321                         loc = l;
4322                 }
4323
4324                 public Statement Statement {
4325                         get { return statement; }
4326                 }
4327
4328                 public override bool Resolve (EmitContext ec)
4329                 {
4330                         if (!ec.InUnsafe){
4331                                 Expression.UnsafeError (loc);
4332                                 return false;
4333                         }
4334                         
4335                         TypeExpr texpr = type.ResolveAsContextualType (ec, false);
4336                         if (texpr == null) {
4337                                 if (type is VarExpr)
4338                                         Report.Error (821, type.Location, "A fixed statement cannot use an implicitly typed local variable");
4339
4340                                 return false;
4341                         }
4342
4343                         expr_type = texpr.Type;
4344
4345                         data = new Emitter [declarators.Count];
4346
4347                         if (!expr_type.IsPointer){
4348                                 Report.Error (209, loc, "The type of locals declared in a fixed statement must be a pointer type");
4349                                 return false;
4350                         }
4351                         
4352                         int i = 0;
4353                         foreach (Pair p in declarators){
4354                                 LocalInfo vi = (LocalInfo) p.First;
4355                                 Expression e = (Expression) p.Second;
4356                                 
4357                                 vi.VariableInfo.SetAssigned (ec);
4358                                 vi.SetReadOnlyContext (LocalInfo.ReadOnlyContext.Fixed);
4359
4360                                 //
4361                                 // The rules for the possible declarators are pretty wise,
4362                                 // but the production on the grammar is more concise.
4363                                 //
4364                                 // So we have to enforce these rules here.
4365                                 //
4366                                 // We do not resolve before doing the case 1 test,
4367                                 // because the grammar is explicit in that the token &
4368                                 // is present, so we need to test for this particular case.
4369                                 //
4370
4371                                 if (e is Cast){
4372                                         Report.Error (254, loc, "The right hand side of a fixed statement assignment may not be a cast expression");
4373                                         return false;
4374                                 }
4375
4376                                 ec.InFixedInitializer = true;
4377                                 e = e.Resolve (ec);
4378                                 ec.InFixedInitializer = false;
4379                                 if (e == null)
4380                                         return false;
4381
4382                                 //
4383                                 // Case 2: Array
4384                                 //
4385                                 if (e.Type.IsArray){
4386                                         Type array_type = TypeManager.GetElementType (e.Type);
4387                                         
4388                                         //
4389                                         // Provided that array_type is unmanaged,
4390                                         //
4391                                         if (!TypeManager.VerifyUnManaged (array_type, loc))
4392                                                 return false;
4393
4394                                         //
4395                                         // and T* is implicitly convertible to the
4396                                         // pointer type given in the fixed statement.
4397                                         //
4398                                         ArrayPtr array_ptr = new ArrayPtr (e, array_type, loc);
4399                                         
4400                                         Expression converted = Convert.ImplicitConversionRequired (
4401                                                 ec, array_ptr, vi.VariableType, loc);
4402                                         if (converted == null)
4403                                                 return false;
4404                                         
4405                                         //
4406                                         // fixed (T* e_ptr = (e == null || e.Length == 0) ? null : converted [0])
4407                                         //
4408                                         converted = new Conditional (new Binary (Binary.Operator.LogicalOr,
4409                                                 new Binary (Binary.Operator.Equality, e, new NullLiteral (loc)),
4410                                                 new Binary (Binary.Operator.Equality, new MemberAccess (e, "Length"), new IntConstant (0, loc))),
4411                                                         new NullPointer (loc),
4412                                                         converted);
4413
4414                                         converted = converted.Resolve (ec);                                     
4415
4416                                         data [i] = new ExpressionEmitter (converted, vi);
4417                                         i++;
4418
4419                                         continue;
4420                                 }
4421
4422                                 //
4423                                 // Case 3: string
4424                                 //
4425                                 if (e.Type == TypeManager.string_type){
4426                                         data [i] = new StringEmitter (e, vi, loc);
4427                                         i++;
4428                                         continue;
4429                                 }
4430
4431                                 // Case 4: fixed buffer
4432                                 if (e is FixedBufferPtr) {
4433                                         data [i++] = new ExpressionEmitter (e, vi);
4434                                         continue;
4435                                 }
4436
4437                                 //
4438                                 // Case 1: & object.
4439                                 //
4440                                 Unary u = e as Unary;
4441                                 if (u != null && u.Oper == Unary.Operator.AddressOf) {
4442                                         IVariableReference vr = u.Expr as IVariableReference;
4443                                         if (vr == null || !vr.IsFixed) {
4444                                                 data [i] = new ExpressionEmitter (e, vi);
4445                                         }
4446                                 }
4447
4448                                 if (data [i++] == null)
4449                                         Report.Error (213, vi.Location, "You cannot use the fixed statement to take the address of an already fixed expression");
4450
4451                                 e = Convert.ImplicitConversionRequired (ec, e, expr_type, loc);
4452                         }
4453
4454                         ec.StartFlowBranching (FlowBranching.BranchingType.Conditional, loc);
4455                         bool ok = statement.Resolve (ec);
4456                         bool flow_unreachable = ec.EndFlowBranching ();
4457                         has_ret = flow_unreachable;
4458
4459                         return ok;
4460                 }
4461                 
4462                 protected override void DoEmit (EmitContext ec)
4463                 {
4464                         for (int i = 0; i < data.Length; i++) {
4465                                 data [i].Emit (ec);
4466                         }
4467
4468                         statement.Emit (ec);
4469
4470                         if (has_ret)
4471                                 return;
4472
4473                         //
4474                         // Clear the pinned variable
4475                         //
4476                         for (int i = 0; i < data.Length; i++) {
4477                                 data [i].EmitExit (ec);
4478                         }
4479                 }
4480
4481                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4482                 {
4483                         // Fixed statement cannot be used inside anonymous methods or lambdas
4484                         throw new NotSupportedException ();
4485                 }
4486
4487                 protected override void CloneTo (CloneContext clonectx, Statement t)
4488                 {
4489                         Fixed target = (Fixed) t;
4490
4491                         target.type = type.Clone (clonectx);
4492                         target.declarators = new ArrayList (declarators.Count);
4493                         foreach (Pair p in declarators) {
4494                                 LocalInfo vi = (LocalInfo) p.First;
4495                                 Expression e = (Expression) p.Second;
4496
4497                                 target.declarators.Add (
4498                                         new Pair (clonectx.LookupVariable (vi), e.Clone (clonectx)));                           
4499                         }
4500                         
4501                         target.statement = statement.Clone (clonectx);
4502                 }
4503         }
4504         
4505         public class Catch : Statement {
4506                 public readonly string Name;
4507                 public Block  Block;
4508                 public Block  VarBlock;
4509
4510                 Expression type_expr;
4511                 Type type;
4512                 
4513                 public Catch (Expression type, string name, Block block, Block var_block, Location l)
4514                 {
4515                         type_expr = type;
4516                         Name = name;
4517                         Block = block;
4518                         VarBlock = var_block;
4519                         loc = l;
4520                 }
4521
4522                 public Type CatchType {
4523                         get {
4524                                 return type;
4525                         }
4526                 }
4527
4528                 public bool IsGeneral {
4529                         get {
4530                                 return type_expr == null;
4531                         }
4532                 }
4533
4534                 protected override void DoEmit (EmitContext ec)
4535                 {
4536                         ILGenerator ig = ec.ig;
4537
4538                         if (CatchType != null)
4539                                 ig.BeginCatchBlock (CatchType);
4540                         else
4541                                 ig.BeginCatchBlock (TypeManager.object_type);
4542
4543                         if (VarBlock != null)
4544                                 VarBlock.Emit (ec);
4545
4546                         if (Name != null) {
4547                                 // TODO: Move to resolve
4548                                 LocalVariableReference lvr = new LocalVariableReference (Block, Name, loc);
4549                                 lvr.Resolve (ec);
4550
4551                                 Expression source;
4552                                 if (lvr.IsHoisted) {
4553                                         LocalTemporary lt = new LocalTemporary (lvr.Type);
4554                                         lt.Store (ec);
4555                                         source = lt;
4556                                 } else {
4557                                         // Variable is at the top of the stack
4558                                         source = EmptyExpression.Null;
4559                                 }
4560
4561                                 lvr.EmitAssign (ec, source, false, false);
4562                         } else
4563                                 ig.Emit (OpCodes.Pop);
4564
4565                         Block.Emit (ec);
4566                 }
4567
4568                 public override bool Resolve (EmitContext ec)
4569                 {
4570                         using (ec.With (EmitContext.Flags.InCatch, true)) {
4571                                 if (type_expr != null) {
4572                                         TypeExpr te = type_expr.ResolveAsTypeTerminal (ec, false);
4573                                         if (te == null)
4574                                                 return false;
4575
4576                                         type = te.Type;
4577
4578                                         if (type != TypeManager.exception_type && !TypeManager.IsSubclassOf (type, TypeManager.exception_type)){
4579                                                 Error (155, "The type caught or thrown must be derived from System.Exception");
4580                                                 return false;
4581                                         }
4582                                 } else
4583                                         type = null;
4584
4585                                 if (!Block.Resolve (ec))
4586                                         return false;
4587
4588                                 // Even though VarBlock surrounds 'Block' we resolve it later, so that we can correctly
4589                                 // emit the "unused variable" warnings.
4590                                 if (VarBlock != null)
4591                                         return VarBlock.Resolve (ec);
4592
4593                                 return true;
4594                         }
4595                 }
4596
4597                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4598                 {
4599                         if (type != null)
4600                                 type = storey.MutateType (type);
4601                         if (VarBlock != null)
4602                                 VarBlock.MutateHoistedGenericType (storey);
4603                         Block.MutateHoistedGenericType (storey);
4604                 }
4605
4606                 protected override void CloneTo (CloneContext clonectx, Statement t)
4607                 {
4608                         Catch target = (Catch) t;
4609
4610                         if (type_expr != null)
4611                                 target.type_expr = type_expr.Clone (clonectx);
4612                         if (VarBlock != null)
4613                                 target.VarBlock = clonectx.LookupBlock (VarBlock);                      
4614                         target.Block = clonectx.LookupBlock (Block);
4615                 }
4616         }
4617
4618         public class TryFinally : ExceptionStatement {
4619                 Statement stmt;
4620                 Block fini;
4621
4622                 public TryFinally (Statement stmt, Block fini, Location l)
4623                 {
4624                         this.stmt = stmt;
4625                         this.fini = fini;
4626                         loc = l;
4627                 }
4628
4629                 public override bool Resolve (EmitContext ec)
4630                 {
4631                         bool ok = true;
4632
4633                         ec.StartFlowBranching (this);
4634
4635                         if (!stmt.Resolve (ec))
4636                                 ok = false;
4637
4638                         if (ok)
4639                                 ec.CurrentBranching.CreateSibling (fini, FlowBranching.SiblingType.Finally);
4640                         using (ec.With (EmitContext.Flags.InFinally, true)) {
4641                                 if (!fini.Resolve (ec))
4642                                         ok = false;
4643                         }
4644
4645                         ec.EndFlowBranching ();
4646
4647                         ResolveReachability (ec);
4648
4649                         return ok;
4650                 }
4651
4652                 protected override void EmitPreTryBody (EmitContext ec)
4653                 {
4654                 }
4655
4656                 protected override void EmitTryBody (EmitContext ec)
4657                 {
4658                         stmt.Emit (ec);
4659                 }
4660
4661                 protected override void EmitFinallyBody (EmitContext ec)
4662                 {
4663                         fini.Emit (ec);
4664                 }
4665
4666                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4667                 {
4668                         stmt.MutateHoistedGenericType (storey);
4669                         fini.MutateHoistedGenericType (storey);
4670                 }
4671
4672                 protected override void CloneTo (CloneContext clonectx, Statement t)
4673                 {
4674                         TryFinally target = (TryFinally) t;
4675
4676                         target.stmt = (Statement) stmt.Clone (clonectx);
4677                         if (fini != null)
4678                                 target.fini = clonectx.LookupBlock (fini);
4679                 }
4680         }
4681
4682         public class TryCatch : Statement {
4683                 public Block Block;
4684                 public ArrayList Specific;
4685                 public Catch General;
4686                 bool inside_try_finally, code_follows;
4687
4688                 public TryCatch (Block block, ArrayList catch_clauses, Location l, bool inside_try_finally)
4689                 {
4690                         this.Block = block;
4691                         this.Specific = catch_clauses;
4692                         this.General = null;
4693                         this.inside_try_finally = inside_try_finally;
4694
4695                         for (int i = 0; i < catch_clauses.Count; ++i) {
4696                                 Catch c = (Catch) catch_clauses [i];
4697                                 if (c.IsGeneral) {
4698                                         if (i != catch_clauses.Count - 1)
4699                                                 Report.Error (1017, c.loc, "Try statement already has an empty catch block");
4700                                         this.General = c;
4701                                         catch_clauses.RemoveAt (i);
4702                                         i--;
4703                                 }
4704                         }
4705
4706                         loc = l;
4707                 }
4708
4709                 public override bool Resolve (EmitContext ec)
4710                 {
4711                         bool ok = true;
4712
4713                         ec.StartFlowBranching (this);
4714
4715                         if (!Block.Resolve (ec))
4716                                 ok = false;
4717
4718                         Type[] prev_catches = new Type [Specific.Count];
4719                         int last_index = 0;
4720                         foreach (Catch c in Specific){
4721                                 ec.CurrentBranching.CreateSibling (c.Block, FlowBranching.SiblingType.Catch);
4722
4723                                 if (c.Name != null) {
4724                                         LocalInfo vi = c.Block.GetLocalInfo (c.Name);
4725                                         if (vi == null)
4726                                                 throw new Exception ();
4727
4728                                         vi.VariableInfo = null;
4729                                 }
4730
4731                                 if (!c.Resolve (ec))
4732                                         ok = false;
4733
4734                                 Type resolved_type = c.CatchType;
4735                                 for (int ii = 0; ii < last_index; ++ii) {
4736                                         if (resolved_type == prev_catches [ii] || TypeManager.IsSubclassOf (resolved_type, prev_catches [ii])) {
4737                                                 Report.Error (160, c.loc, "A previous catch clause already catches all exceptions of this or a super type `{0}'", prev_catches [ii].FullName);
4738                                                 ok = false;
4739                                         }
4740                                 }
4741
4742                                 prev_catches [last_index++] = resolved_type;
4743                         }
4744
4745                         if (General != null) {
4746                                 if (CodeGen.Assembly.WrapNonExceptionThrows) {
4747                                         foreach (Catch c in Specific){
4748                                                 if (c.CatchType == TypeManager.exception_type) {
4749                                                         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'");
4750                                                 }
4751                                         }
4752                                 }
4753
4754                                 ec.CurrentBranching.CreateSibling (General.Block, FlowBranching.SiblingType.Catch);
4755
4756                                 if (!General.Resolve (ec))
4757                                         ok = false;
4758                         }
4759
4760                         ec.EndFlowBranching ();
4761
4762                         // System.Reflection.Emit automatically emits a 'leave' at the end of a try/catch clause
4763                         // So, ensure there's some IL code after this statement
4764                         if (!inside_try_finally && !code_follows && ec.CurrentBranching.CurrentUsageVector.IsUnreachable)
4765                                 ec.NeedReturnLabel ();
4766
4767                         return ok;
4768                 }
4769
4770                 public void SomeCodeFollows ()
4771                 {
4772                         code_follows = true;
4773                 }
4774                 
4775                 protected override void DoEmit (EmitContext ec)
4776                 {
4777                         ILGenerator ig = ec.ig;
4778
4779                         if (!inside_try_finally)
4780                                 ig.BeginExceptionBlock ();
4781
4782                         Block.Emit (ec);
4783
4784                         foreach (Catch c in Specific)
4785                                 c.Emit (ec);
4786
4787                         if (General != null)
4788                                 General.Emit (ec);
4789
4790                         if (!inside_try_finally)
4791                                 ig.EndExceptionBlock ();
4792                 }
4793
4794                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4795                 {
4796                         Block.MutateHoistedGenericType (storey);
4797
4798                         if (General != null)
4799                                 General.MutateHoistedGenericType (storey);
4800                         if (Specific != null) {
4801                                 foreach (Catch c in Specific)
4802                                         c.MutateHoistedGenericType (storey);
4803                         }
4804                 }
4805
4806                 protected override void CloneTo (CloneContext clonectx, Statement t)
4807                 {
4808                         TryCatch target = (TryCatch) t;
4809
4810                         target.Block = clonectx.LookupBlock (Block);
4811                         if (General != null)
4812                                 target.General = (Catch) General.Clone (clonectx);
4813                         if (Specific != null){
4814                                 target.Specific = new ArrayList ();
4815                                 foreach (Catch c in Specific)
4816                                         target.Specific.Add (c.Clone (clonectx));
4817                         }
4818                 }
4819         }
4820
4821         public class UsingTemporary : ExceptionStatement {
4822                 TemporaryVariable local_copy;
4823                 public Statement Statement;
4824                 Expression expr;
4825                 Type expr_type;
4826
4827                 public UsingTemporary (Expression expr, Statement stmt, Location l)
4828                 {
4829                         this.expr = expr;
4830                         Statement = stmt;
4831                         loc = l;
4832                 }
4833
4834                 public override bool Resolve (EmitContext ec)
4835                 {
4836                         expr = expr.Resolve (ec);
4837                         if (expr == null)
4838                                 return false;
4839
4840                         expr_type = expr.Type;
4841
4842                         if (!TypeManager.ImplementsInterface (expr_type, TypeManager.idisposable_type)) {
4843                                 if (Convert.ImplicitConversion (ec, expr, TypeManager.idisposable_type, loc) == null) {
4844                                         Using.Error_IsNotConvertibleToIDisposable (expr);
4845                                         return false;
4846                                 }
4847                         }
4848
4849                         local_copy = new TemporaryVariable (expr_type, loc);
4850                         local_copy.Resolve (ec);
4851
4852                         ec.StartFlowBranching (this);
4853
4854                         bool ok = Statement.Resolve (ec);
4855
4856                         ec.EndFlowBranching ();
4857
4858                         ResolveReachability (ec);
4859
4860                         if (TypeManager.void_dispose_void == null) {
4861                                 TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
4862                                         TypeManager.idisposable_type, "Dispose", loc, Type.EmptyTypes);
4863                         }
4864
4865                         return ok;
4866                 }
4867
4868                 protected override void EmitPreTryBody (EmitContext ec)
4869                 {
4870                         local_copy.EmitAssign (ec, expr);
4871                 }
4872
4873                 protected override void EmitTryBody (EmitContext ec)
4874                 {
4875                         Statement.Emit (ec);
4876                 }
4877
4878                 protected override void EmitFinallyBody (EmitContext ec)
4879                 {
4880                         ILGenerator ig = ec.ig;
4881                         if (!expr_type.IsValueType) {
4882                                 Label skip = ig.DefineLabel ();
4883                                 local_copy.Emit (ec);
4884                                 ig.Emit (OpCodes.Brfalse, skip);
4885                                 local_copy.Emit (ec);
4886                                 ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
4887                                 ig.MarkLabel (skip);
4888                                 return;
4889                         }
4890
4891                         Expression ml = Expression.MemberLookup (
4892                                 ec.ContainerType, TypeManager.idisposable_type, expr_type,
4893                                 "Dispose", Location.Null);
4894
4895                         if (!(ml is MethodGroupExpr)) {
4896                                 local_copy.Emit (ec);
4897                                 ig.Emit (OpCodes.Box, expr_type);
4898                                 ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
4899                                 return;
4900                         }
4901
4902                         MethodInfo mi = null;
4903
4904                         foreach (MethodInfo mk in ((MethodGroupExpr) ml).Methods) {
4905                                 if (TypeManager.GetParameterData (mk).Count == 0) {
4906                                         mi = mk;
4907                                         break;
4908                                 }
4909                         }
4910
4911                         if (mi == null) {
4912                                 Report.Error(-100, Mono.CSharp.Location.Null, "Internal error: No Dispose method which takes 0 parameters.");
4913                                 return;
4914                         }
4915
4916                         local_copy.AddressOf (ec, AddressOp.Load);
4917                         ig.Emit (OpCodes.Call, mi);
4918                 }
4919
4920                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4921                 {
4922                         expr_type = storey.MutateType (expr_type);
4923                         local_copy.MutateHoistedGenericType (storey);
4924                         Statement.MutateHoistedGenericType (storey);
4925                 }
4926
4927                 protected override void CloneTo (CloneContext clonectx, Statement t)
4928                 {
4929                         UsingTemporary target = (UsingTemporary) t;
4930
4931                         target.expr = expr.Clone (clonectx);
4932                         target.Statement = Statement.Clone (clonectx);
4933                 }
4934         }
4935
4936         public class Using : ExceptionStatement {
4937                 Statement stmt;
4938                 public Statement EmbeddedStatement {
4939                         get { return stmt is Using ? ((Using) stmt).EmbeddedStatement : stmt; }
4940                 }
4941
4942                 Expression var;
4943                 Expression init;
4944
4945                 Expression converted_var;
4946                 ExpressionStatement assign;
4947
4948                 public Using (Expression var, Expression init, Statement stmt, Location l)
4949                 {
4950                         this.var = var;
4951                         this.init = init;
4952                         this.stmt = stmt;
4953                         loc = l;
4954                 }
4955
4956                 bool ResolveVariable (EmitContext ec)
4957                 {
4958                         ExpressionStatement a = new SimpleAssign (var, init, loc);
4959                         a = a.ResolveStatement (ec);
4960                         if (a == null)
4961                                 return false;
4962
4963                         assign = a;
4964
4965                         if (TypeManager.ImplementsInterface (a.Type, TypeManager.idisposable_type)) {
4966                                 converted_var = var;
4967                                 return true;
4968                         }
4969
4970                         Expression e = Convert.ImplicitConversionStandard (ec, a, TypeManager.idisposable_type, var.Location);
4971                         if (e == null) {
4972                                 Error_IsNotConvertibleToIDisposable (var);
4973                                 return false;
4974                         }
4975
4976                         converted_var = e;
4977
4978                         return true;
4979                 }
4980
4981                 static public void Error_IsNotConvertibleToIDisposable (Expression expr)
4982                 {
4983                         Report.SymbolRelatedToPreviousError (expr.Type);
4984                         Report.Error (1674, expr.Location, "`{0}': type used in a using statement must be implicitly convertible to `System.IDisposable'",
4985                                 expr.GetSignatureForError ());
4986                 }
4987
4988                 protected override void EmitPreTryBody (EmitContext ec)
4989                 {
4990                         assign.EmitStatement (ec);
4991                 }
4992
4993                 protected override void EmitTryBody (EmitContext ec)
4994                 {
4995                         stmt.Emit (ec);
4996                 }
4997
4998                 protected override void EmitFinallyBody (EmitContext ec)
4999                 {
5000                         ILGenerator ig = ec.ig;
5001
5002                         if (!var.Type.IsValueType) {
5003                                 Label skip = ig.DefineLabel ();
5004                                 var.Emit (ec);
5005                                 ig.Emit (OpCodes.Brfalse, skip);
5006                                 converted_var.Emit (ec);
5007                                 ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
5008                                 ig.MarkLabel (skip);
5009                         } else {
5010                                 Expression ml = Expression.MemberLookup(ec.ContainerType, TypeManager.idisposable_type, var.Type, "Dispose", Mono.CSharp.Location.Null);
5011
5012                                 if (!(ml is MethodGroupExpr)) {
5013                                         var.Emit (ec);
5014                                         ig.Emit (OpCodes.Box, var.Type);
5015                                         ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
5016                                 } else {
5017                                         MethodInfo mi = null;
5018
5019                                         foreach (MethodInfo mk in ((MethodGroupExpr) ml).Methods) {
5020                                                 if (TypeManager.GetParameterData (mk).Count == 0) {
5021                                                         mi = mk;
5022                                                         break;
5023                                                 }
5024                                         }
5025
5026                                         if (mi == null) {
5027                                                 Report.Error(-100, Mono.CSharp.Location.Null, "Internal error: No Dispose method which takes 0 parameters.");
5028                                                 return;
5029                                         }
5030
5031                                         IMemoryLocation mloc = (IMemoryLocation) var;
5032
5033                                         mloc.AddressOf (ec, AddressOp.Load);
5034                                         ig.Emit (OpCodes.Call, mi);
5035                                 }
5036                         }
5037                 }
5038
5039                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5040                 {
5041                         assign.MutateHoistedGenericType (storey);
5042                         var.MutateHoistedGenericType (storey);
5043                         stmt.MutateHoistedGenericType (storey);
5044                 }
5045
5046                 public override bool Resolve (EmitContext ec)
5047                 {
5048                         if (!ResolveVariable (ec))
5049                                 return false;
5050
5051                         ec.StartFlowBranching (this);
5052
5053                         bool ok = stmt.Resolve (ec);
5054
5055                         ec.EndFlowBranching ();
5056
5057                         ResolveReachability (ec);
5058
5059                         if (TypeManager.void_dispose_void == null) {
5060                                 TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
5061                                         TypeManager.idisposable_type, "Dispose", loc, Type.EmptyTypes);
5062                         }
5063
5064                         return ok;
5065                 }
5066
5067                 protected override void CloneTo (CloneContext clonectx, Statement t)
5068                 {
5069                         Using target = (Using) t;
5070
5071                         target.var = var.Clone (clonectx);
5072                         target.init = init.Clone (clonectx);
5073                         target.stmt = stmt.Clone (clonectx);
5074                 }
5075         }
5076
5077         /// <summary>
5078         ///   Implementation of the foreach C# statement
5079         /// </summary>
5080         public class Foreach : Statement {
5081
5082                 sealed class ArrayForeach : Statement
5083                 {
5084                         class ArrayCounter : TemporaryVariable
5085                         {
5086                                 StatementExpression increment;
5087
5088                                 public ArrayCounter (Location loc)
5089                                         : base (TypeManager.int32_type, loc)
5090                                 {
5091                                 }
5092
5093                                 public void ResolveIncrement (EmitContext ec)
5094                                 {
5095                                         increment = new StatementExpression (new UnaryMutator (UnaryMutator.Mode.PostIncrement, this));
5096                                         increment.Resolve (ec);
5097                                 }
5098
5099                                 public void EmitIncrement (EmitContext ec)
5100                                 {
5101                                         increment.Emit (ec);
5102                                 }
5103                         }
5104
5105                         readonly Foreach for_each;
5106                         readonly Statement statement;
5107
5108                         Expression conv;
5109                         TemporaryVariable[] lengths;
5110                         Expression [] length_exprs;
5111                         ArrayCounter[] counter;
5112
5113                         TemporaryVariable copy;
5114                         Expression access;
5115
5116                         public ArrayForeach (Foreach @foreach, int rank)
5117                         {
5118                                 for_each = @foreach;
5119                                 statement = for_each.statement;
5120                                 loc = @foreach.loc;
5121
5122                                 counter = new ArrayCounter [rank];
5123                                 length_exprs = new Expression [rank];
5124
5125                                 //
5126                                 // Only use temporary length variables when dealing with
5127                                 // multi-dimensional arrays
5128                                 //
5129                                 if (rank > 1)
5130                                         lengths = new TemporaryVariable [rank];
5131                         }
5132
5133                         protected override void CloneTo (CloneContext clonectx, Statement target)
5134                         {
5135                                 throw new NotImplementedException ();
5136                         }
5137
5138                         public override bool Resolve (EmitContext ec)
5139                         {
5140                                 copy = new TemporaryVariable (for_each.expr.Type, loc);
5141                                 copy.Resolve (ec);
5142
5143                                 int rank = length_exprs.Length;
5144                                 ArrayList list = new ArrayList (rank);
5145                                 for (int i = 0; i < rank; i++) {
5146                                         counter [i] = new ArrayCounter (loc);
5147                                         counter [i].ResolveIncrement (ec);                                      
5148
5149                                         if (rank == 1) {
5150                                                 length_exprs [i] = new MemberAccess (copy, "Length").Resolve (ec);
5151                                         } else {
5152                                                 lengths [i] = new TemporaryVariable (TypeManager.int32_type, loc);
5153                                                 lengths [i].Resolve (ec);
5154
5155                                                 ArrayList args = new ArrayList (1);
5156                                                 args.Add (new Argument (new IntConstant (i, loc)));
5157                                                 length_exprs [i] = new Invocation (new MemberAccess (copy, "GetLength"), args).Resolve (ec);
5158                                         }
5159
5160                                         list.Add (counter [i]);
5161                                 }
5162
5163                                 access = new ElementAccess (copy, list).Resolve (ec);
5164                                 if (access == null)
5165                                         return false;
5166
5167                                 Expression var_type = for_each.type;
5168                                 VarExpr ve = var_type as VarExpr;
5169                                 if (ve != null) {
5170                                         // Infer implicitly typed local variable from foreach array type
5171                                         var_type = new TypeExpression (access.Type, ve.Location);
5172                                 }
5173
5174                                 var_type = var_type.ResolveAsTypeTerminal (ec, false);
5175                                 if (var_type == null)
5176                                         return false;
5177
5178                                 conv = Convert.ExplicitConversion (ec, access, var_type.Type, loc);
5179                                 if (conv == null)
5180                                         return false;
5181
5182                                 bool ok = true;
5183
5184                                 ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
5185                                 ec.CurrentBranching.CreateSibling ();
5186
5187                                 for_each.variable = for_each.variable.ResolveLValue (ec, conv, loc);
5188                                 if (for_each.variable == null)
5189                                         ok = false;
5190
5191                                 ec.StartFlowBranching (FlowBranching.BranchingType.Embedded, loc);
5192                                 if (!statement.Resolve (ec))
5193                                         ok = false;
5194                                 ec.EndFlowBranching ();
5195
5196                                 // There's no direct control flow from the end of the embedded statement to the end of the loop
5197                                 ec.CurrentBranching.CurrentUsageVector.Goto ();
5198
5199                                 ec.EndFlowBranching ();
5200
5201                                 return ok;
5202                         }
5203
5204                         protected override void DoEmit (EmitContext ec)
5205                         {
5206                                 ILGenerator ig = ec.ig;
5207
5208                                 copy.EmitAssign (ec, for_each.expr);
5209
5210                                 int rank = length_exprs.Length;
5211                                 Label[] test = new Label [rank];
5212                                 Label[] loop = new Label [rank];
5213
5214                                 for (int i = 0; i < rank; i++) {
5215                                         test [i] = ig.DefineLabel ();
5216                                         loop [i] = ig.DefineLabel ();
5217
5218                                         if (lengths != null)
5219                                                 lengths [i].EmitAssign (ec, length_exprs [i]);
5220                                 }
5221
5222                                 IntConstant zero = new IntConstant (0, loc);
5223                                 for (int i = 0; i < rank; i++) {
5224                                         counter [i].EmitAssign (ec, zero);
5225
5226                                         ig.Emit (OpCodes.Br, test [i]);
5227                                         ig.MarkLabel (loop [i]);
5228                                 }
5229
5230                                 ((IAssignMethod) for_each.variable).EmitAssign (ec, conv, false, false);
5231
5232                                 statement.Emit (ec);
5233
5234                                 ig.MarkLabel (ec.LoopBegin);
5235
5236                                 for (int i = rank - 1; i >= 0; i--){
5237                                         counter [i].EmitIncrement (ec);
5238
5239                                         ig.MarkLabel (test [i]);
5240                                         counter [i].Emit (ec);
5241
5242                                         if (lengths != null)
5243                                                 lengths [i].Emit (ec);
5244                                         else
5245                                                 length_exprs [i].Emit (ec);
5246
5247                                         ig.Emit (OpCodes.Blt, loop [i]);
5248                                 }
5249
5250                                 ig.MarkLabel (ec.LoopEnd);
5251                         }
5252
5253                         public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5254                         {
5255                                 for_each.expr.MutateHoistedGenericType (storey);
5256
5257                                 copy.MutateHoistedGenericType (storey);
5258                                 conv.MutateHoistedGenericType (storey);
5259                                 statement.MutateHoistedGenericType (storey);
5260
5261                                 for (int i = 0; i < counter.Length; i++) {
5262                                         counter [i].MutateHoistedGenericType (storey);
5263                                         if (lengths != null)
5264                                                 lengths [i].MutateHoistedGenericType (storey);
5265                                 }
5266                         }
5267                 }
5268
5269                 sealed class CollectionForeach : Statement
5270                 {
5271                         class CollectionForeachStatement : Statement
5272                         {
5273                                 Type type;
5274                                 Expression variable, current, conv;
5275                                 Statement statement;
5276                                 Assign assign;
5277
5278                                 public CollectionForeachStatement (Type type, Expression variable,
5279                                                                    Expression current, Statement statement,
5280                                                                    Location loc)
5281                                 {
5282                                         this.type = type;
5283                                         this.variable = variable;
5284                                         this.current = current;
5285                                         this.statement = statement;
5286                                         this.loc = loc;
5287                                 }
5288
5289                                 protected override void CloneTo (CloneContext clonectx, Statement target)
5290                                 {
5291                                         throw new NotImplementedException ();
5292                                 }
5293
5294                                 public override bool Resolve (EmitContext ec)
5295                                 {
5296                                         current = current.Resolve (ec);
5297                                         if (current == null)
5298                                                 return false;
5299
5300                                         conv = Convert.ExplicitConversion (ec, current, type, loc);
5301                                         if (conv == null)
5302                                                 return false;
5303
5304                                         assign = new SimpleAssign (variable, conv, loc);
5305                                         if (assign.Resolve (ec) == null)
5306                                                 return false;
5307
5308                                         if (!statement.Resolve (ec))
5309                                                 return false;
5310
5311                                         return true;
5312                                 }
5313
5314                                 protected override void DoEmit (EmitContext ec)
5315                                 {
5316                                         assign.EmitStatement (ec);
5317                                         statement.Emit (ec);
5318                                 }
5319
5320                                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5321                                 {
5322                                         assign.MutateHoistedGenericType (storey);
5323                                         statement.MutateHoistedGenericType (storey);
5324                                 }
5325                         }
5326
5327                         Expression variable, expr;
5328                         Statement statement;
5329
5330                         TemporaryVariable enumerator;
5331                         Expression init;
5332                         Statement loop;
5333                         Statement wrapper;
5334
5335                         MethodGroupExpr get_enumerator;
5336                         PropertyExpr get_current;
5337                         MethodInfo move_next;
5338                         Expression var_type;
5339                         Type enumerator_type;
5340                         bool enumerator_found;
5341
5342                         public CollectionForeach (Expression var_type, Expression var,
5343                                                   Expression expr, Statement stmt, Location l)
5344                         {
5345                                 this.var_type = var_type;
5346                                 this.variable = var;
5347                                 this.expr = expr;
5348                                 statement = stmt;
5349                                 loc = l;
5350                         }
5351
5352                         protected override void CloneTo (CloneContext clonectx, Statement target)
5353                         {
5354                                 throw new NotImplementedException ();
5355                         }
5356
5357                         bool GetEnumeratorFilter (EmitContext ec, MethodInfo mi)
5358                         {
5359                                 Type return_type = mi.ReturnType;
5360
5361                                 //
5362                                 // Ok, we can access it, now make sure that we can do something
5363                                 // with this `GetEnumerator'
5364                                 //
5365
5366                                 if (return_type == TypeManager.ienumerator_type ||
5367                                     TypeManager.ienumerator_type.IsAssignableFrom (return_type) ||
5368                                     (!RootContext.StdLib && TypeManager.ImplementsInterface (return_type, TypeManager.ienumerator_type))) {
5369                                         //
5370                                         // If it is not an interface, lets try to find the methods ourselves.
5371                                         // For example, if we have:
5372                                         // public class Foo : IEnumerator { public bool MoveNext () {} public int Current { get {}}}
5373                                         // We can avoid the iface call. This is a runtime perf boost.
5374                                         // even bigger if we have a ValueType, because we avoid the cost
5375                                         // of boxing.
5376                                         //
5377                                         // We have to make sure that both methods exist for us to take
5378                                         // this path. If one of the methods does not exist, we will just
5379                                         // use the interface. Sadly, this complex if statement is the only
5380                                         // way I could do this without a goto
5381                                         //
5382
5383                                         if (TypeManager.bool_movenext_void == null) {
5384                                                 TypeManager.bool_movenext_void = TypeManager.GetPredefinedMethod (
5385                                                         TypeManager.ienumerator_type, "MoveNext", loc, Type.EmptyTypes);
5386                                         }
5387
5388                                         if (TypeManager.ienumerator_getcurrent == null) {
5389                                                 TypeManager.ienumerator_getcurrent = TypeManager.GetPredefinedProperty (
5390                                                         TypeManager.ienumerator_type, "Current", loc, TypeManager.object_type);
5391                                         }
5392
5393 #if GMCS_SOURCE
5394                                         //
5395                                         // Prefer a generic enumerator over a non-generic one.
5396                                         //
5397                                         if (return_type.IsInterface && return_type.IsGenericType) {
5398                                                 enumerator_type = return_type;
5399                                                 if (!FetchGetCurrent (ec, return_type))
5400                                                         get_current = new PropertyExpr (
5401                                                                 ec.ContainerType, TypeManager.ienumerator_getcurrent, loc);
5402                                                 if (!FetchMoveNext (return_type))
5403                                                         move_next = TypeManager.bool_movenext_void;
5404                                                 return true;
5405                                         }
5406 #endif
5407
5408                                         if (return_type.IsInterface ||
5409                                             !FetchMoveNext (return_type) ||
5410                                             !FetchGetCurrent (ec, return_type)) {
5411                                                 enumerator_type = return_type;
5412                                                 move_next = TypeManager.bool_movenext_void;
5413                                                 get_current = new PropertyExpr (
5414                                                         ec.ContainerType, TypeManager.ienumerator_getcurrent, loc);
5415                                                 return true;
5416                                         }
5417                                 } else {
5418                                         //
5419                                         // Ok, so they dont return an IEnumerable, we will have to
5420                                         // find if they support the GetEnumerator pattern.
5421                                         //
5422
5423                                         if (TypeManager.HasElementType (return_type) || !FetchMoveNext (return_type) || !FetchGetCurrent (ec, return_type)) {
5424                                                 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",
5425                                                         TypeManager.CSharpName (return_type), TypeManager.CSharpSignature (mi));
5426                                                 return false;
5427                                         }
5428                                 }
5429
5430                                 enumerator_type = return_type;
5431
5432                                 return true;
5433                         }
5434
5435                         //
5436                         // Retrieves a `public bool MoveNext ()' method from the Type `t'
5437                         //
5438                         bool FetchMoveNext (Type t)
5439                         {
5440                                 MemberList move_next_list;
5441
5442                                 move_next_list = TypeContainer.FindMembers (
5443                                         t, MemberTypes.Method,
5444                                         BindingFlags.Public | BindingFlags.Instance,
5445                                         Type.FilterName, "MoveNext");
5446                                 if (move_next_list.Count == 0)
5447                                         return false;
5448
5449                                 foreach (MemberInfo m in move_next_list){
5450                                         MethodInfo mi = (MethodInfo) m;
5451                                 
5452                                         if ((TypeManager.GetParameterData (mi).Count == 0) &&
5453                                             TypeManager.TypeToCoreType (mi.ReturnType) == TypeManager.bool_type) {
5454                                                 move_next = mi;
5455                                                 return true;
5456                                         }
5457                                 }
5458
5459                                 return false;
5460                         }
5461                 
5462                         //
5463                         // Retrieves a `public T get_Current ()' method from the Type `t'
5464                         //
5465                         bool FetchGetCurrent (EmitContext ec, Type t)
5466                         {
5467                                 PropertyExpr pe = Expression.MemberLookup (
5468                                         ec.ContainerType, t, "Current", MemberTypes.Property,
5469                                         Expression.AllBindingFlags, loc) as PropertyExpr;
5470                                 if (pe == null)
5471                                         return false;
5472
5473                                 get_current = pe;
5474                                 return true;
5475                         }
5476
5477                         // 
5478                         // Retrieves a `public void Dispose ()' method from the Type `t'
5479                         //
5480                         static MethodInfo FetchMethodDispose (Type t)
5481                         {
5482                                 MemberList dispose_list;
5483
5484                                 dispose_list = TypeContainer.FindMembers (
5485                                         t, MemberTypes.Method,
5486                                         BindingFlags.Public | BindingFlags.Instance,
5487                                         Type.FilterName, "Dispose");
5488                                 if (dispose_list.Count == 0)
5489                                         return null;
5490
5491                                 foreach (MemberInfo m in dispose_list){
5492                                         MethodInfo mi = (MethodInfo) m;
5493
5494                                         if (TypeManager.GetParameterData (mi).Count == 0){
5495                                                 if (mi.ReturnType == TypeManager.void_type)
5496                                                         return mi;
5497                                         }
5498                                 }
5499                                 return null;
5500                         }
5501
5502                         void Error_Enumerator ()
5503                         {
5504                                 if (enumerator_found) {
5505                                         return;
5506                                 }
5507
5508                             Report.Error (1579, loc,
5509                                         "foreach statement cannot operate on variables of type `{0}' because it does not contain a definition for `GetEnumerator' or is not accessible",
5510                                         TypeManager.CSharpName (expr.Type));
5511                         }
5512
5513                         bool IsOverride (MethodInfo m)
5514                         {
5515                                 m = (MethodInfo) TypeManager.DropGenericMethodArguments (m);
5516
5517                                 if (!m.IsVirtual || ((m.Attributes & MethodAttributes.NewSlot) != 0))
5518                                         return false;
5519                                 if (m is MethodBuilder)
5520                                         return true;
5521
5522                                 MethodInfo base_method = m.GetBaseDefinition ();
5523                                 return base_method != m;
5524                         }
5525
5526                         bool TryType (EmitContext ec, Type t)
5527                         {
5528                                 MethodGroupExpr mg = Expression.MemberLookup (
5529                                         ec.ContainerType, t, "GetEnumerator", MemberTypes.Method,
5530                                         Expression.AllBindingFlags, loc) as MethodGroupExpr;
5531                                 if (mg == null)
5532                                         return false;
5533
5534                                 MethodInfo result = null;
5535                                 MethodInfo tmp_move_next = null;
5536                                 PropertyExpr tmp_get_cur = null;
5537                                 Type tmp_enumerator_type = enumerator_type;
5538                                 foreach (MethodInfo mi in mg.Methods) {
5539                                         if (TypeManager.GetParameterData (mi).Count != 0)
5540                                                 continue;
5541                         
5542                                         // Check whether GetEnumerator is public
5543                                         if ((mi.Attributes & MethodAttributes.Public) != MethodAttributes.Public)
5544                                                 continue;
5545
5546                                         if (IsOverride (mi))
5547                                                 continue;
5548
5549                                         enumerator_found = true;
5550
5551                                         if (!GetEnumeratorFilter (ec, mi))
5552                                                 continue;
5553
5554                                         if (result != null) {
5555                                                 if (TypeManager.IsGenericType (result.ReturnType)) {
5556                                                         if (!TypeManager.IsGenericType (mi.ReturnType))
5557                                                                 continue;
5558
5559                                                         MethodBase mb = TypeManager.DropGenericMethodArguments (mi);
5560                                                         Report.SymbolRelatedToPreviousError (t);
5561                                                         Report.Error(1640, loc, "foreach statement cannot operate on variables of type `{0}' " +
5562                                                                      "because it contains multiple implementation of `{1}'. Try casting to a specific implementation",
5563                                                                      TypeManager.CSharpName (t), TypeManager.CSharpSignature (mb));
5564                                                         return false;
5565                                                 }
5566
5567                                                 // Always prefer generics enumerators
5568                                                 if (!TypeManager.IsGenericType (mi.ReturnType)) {
5569                                                         if (TypeManager.ImplementsInterface (mi.DeclaringType, result.DeclaringType) ||
5570                                                             TypeManager.ImplementsInterface (result.DeclaringType, mi.DeclaringType))
5571                                                                 continue;
5572
5573                                                         Report.SymbolRelatedToPreviousError (result);
5574                                                         Report.SymbolRelatedToPreviousError (mi);
5575                                                         Report.Warning (278, 2, loc, "`{0}' contains ambiguous implementation of `{1}' pattern. Method `{2}' is ambiguous with method `{3}'",
5576                                                                         TypeManager.CSharpName (t), "enumerable", TypeManager.CSharpSignature (result), TypeManager.CSharpSignature (mi));
5577                                                         return false;
5578                                                 }
5579                                         }
5580                                         result = mi;
5581                                         tmp_move_next = move_next;
5582                                         tmp_get_cur = get_current;
5583                                         tmp_enumerator_type = enumerator_type;
5584                                         if (mi.DeclaringType == t)
5585                                                 break;
5586                                 }
5587
5588                                 if (result != null) {
5589                                         move_next = tmp_move_next;
5590                                         get_current = tmp_get_cur;
5591                                         enumerator_type = tmp_enumerator_type;
5592                                         MethodInfo[] mi = new MethodInfo[] { (MethodInfo) result };
5593                                         get_enumerator = new MethodGroupExpr (mi, enumerator_type, loc);
5594
5595                                         if (t != expr.Type) {
5596                                                 expr = Convert.ExplicitConversion (
5597                                                         ec, expr, t, loc);
5598                                                 if (expr == null)
5599                                                         throw new InternalErrorException ();
5600                                         }
5601
5602                                         get_enumerator.InstanceExpression = expr;
5603                                         get_enumerator.IsBase = t != expr.Type;
5604
5605                                         return true;
5606                                 }
5607
5608                                 return false;
5609                         }               
5610
5611                         bool ProbeCollectionType (EmitContext ec, Type t)
5612                         {
5613                                 int errors = Report.Errors;
5614                                 for (Type tt = t; tt != null && tt != TypeManager.object_type;){
5615                                         if (TryType (ec, tt))
5616                                                 return true;
5617                                         tt = tt.BaseType;
5618                                 }
5619
5620                                 if (Report.Errors > errors)
5621                                         return false;
5622
5623                                 //
5624                                 // Now try to find the method in the interfaces
5625                                 //
5626                                 Type [] ifaces = TypeManager.GetInterfaces (t);
5627                                 foreach (Type i in ifaces){
5628                                         if (TryType (ec, i))
5629                                                 return true;
5630                                 }
5631
5632                                 return false;
5633                         }
5634
5635                         public override bool Resolve (EmitContext ec)
5636                         {
5637                                 enumerator_type = TypeManager.ienumerator_type;
5638
5639                                 if (!ProbeCollectionType (ec, expr.Type)) {
5640                                         Error_Enumerator ();
5641                                         return false;
5642                                 }
5643
5644                                 bool is_disposable = !enumerator_type.IsSealed ||
5645                                         TypeManager.ImplementsInterface (enumerator_type, TypeManager.idisposable_type);
5646
5647                                 VarExpr ve = var_type as VarExpr;
5648                                 if (ve != null) {
5649                                         // Infer implicitly typed local variable from foreach enumerable type
5650                                         var_type = new TypeExpression (get_current.PropertyInfo.PropertyType, var_type.Location);
5651                                 }
5652
5653                                 var_type = var_type.ResolveAsTypeTerminal (ec, false);
5654                                 if (var_type == null)
5655                                         return false;
5656                                                                 
5657                                 enumerator = new TemporaryVariable (enumerator_type, loc);
5658                                 enumerator.Resolve (ec);
5659
5660                                 init = new Invocation (get_enumerator, null);
5661                                 init = init.Resolve (ec);
5662                                 if (init == null)
5663                                         return false;
5664
5665                                 Expression move_next_expr;
5666                                 {
5667                                         MemberInfo[] mi = new MemberInfo[] { move_next };
5668                                         MethodGroupExpr mg = new MethodGroupExpr (mi, var_type.Type, loc);
5669                                         mg.InstanceExpression = enumerator;
5670
5671                                         move_next_expr = new Invocation (mg, null);
5672                                 }
5673
5674                                 get_current.InstanceExpression = enumerator;
5675
5676                                 Statement block = new CollectionForeachStatement (
5677                                         var_type.Type, variable, get_current, statement, loc);
5678
5679                                 loop = new While (move_next_expr, block, loc);
5680
5681                                 wrapper = is_disposable ?
5682                                         (Statement) new DisposableWrapper (this) :
5683                                         (Statement) new NonDisposableWrapper (this);
5684                                 return wrapper.Resolve (ec);
5685                         }
5686
5687                         protected override void DoEmit (EmitContext ec)
5688                         {
5689                                 wrapper.Emit (ec);
5690                         }
5691
5692                         class NonDisposableWrapper : Statement {
5693                                 CollectionForeach parent;
5694
5695                                 internal NonDisposableWrapper (CollectionForeach parent)
5696                                 {
5697                                         this.parent = parent;
5698                                 }
5699
5700                                 protected override void CloneTo (CloneContext clonectx, Statement target)
5701                                 {
5702                                         throw new NotSupportedException ();
5703                                 }
5704
5705                                 public override bool Resolve (EmitContext ec)
5706                                 {
5707                                         return parent.ResolveLoop (ec);
5708                                 }
5709
5710                                 protected override void DoEmit (EmitContext ec)
5711                                 {
5712                                         parent.EmitLoopInit (ec);
5713                                         parent.EmitLoopBody (ec);
5714                                 }
5715
5716                                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5717                                 {
5718                                         throw new NotSupportedException ();
5719                                 }
5720                         }
5721
5722                         class DisposableWrapper : ExceptionStatement {
5723                                 CollectionForeach parent;
5724
5725                                 internal DisposableWrapper (CollectionForeach parent)
5726                                 {
5727                                         this.parent = parent;
5728                                 }
5729
5730                                 protected override void CloneTo (CloneContext clonectx, Statement target)
5731                                 {
5732                                         throw new NotSupportedException ();
5733                                 }
5734
5735                                 public override bool Resolve (EmitContext ec)
5736                                 {
5737                                         bool ok = true;
5738
5739                                         ec.StartFlowBranching (this);
5740
5741                                         if (!parent.ResolveLoop (ec))
5742                                                 ok = false;
5743
5744                                         ec.EndFlowBranching ();
5745
5746                                         ResolveReachability (ec);
5747
5748                                         if (TypeManager.void_dispose_void == null) {
5749                                                 TypeManager.void_dispose_void = TypeManager.GetPredefinedMethod (
5750                                                         TypeManager.idisposable_type, "Dispose", loc, Type.EmptyTypes);
5751                                         }
5752                                         return ok;
5753                                 }
5754
5755                                 protected override void EmitPreTryBody (EmitContext ec)
5756                                 {
5757                                         parent.EmitLoopInit (ec);
5758                                 }
5759
5760                                 protected override void EmitTryBody (EmitContext ec)
5761                                 {
5762                                         parent.EmitLoopBody (ec);
5763                                 }
5764
5765                                 protected override void EmitFinallyBody (EmitContext ec)
5766                                 {
5767                                         parent.EmitFinallyBody (ec);
5768                                 }
5769
5770                                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5771                                 {
5772                                         throw new NotSupportedException ();
5773                                 }
5774                         }
5775
5776                         bool ResolveLoop (EmitContext ec)
5777                         {
5778                                 return loop.Resolve (ec);
5779                         }
5780
5781                         void EmitLoopInit (EmitContext ec)
5782                         {
5783                                 enumerator.EmitAssign (ec, init);
5784                         }
5785
5786                         void EmitLoopBody (EmitContext ec)
5787                         {
5788                                 loop.Emit (ec);
5789                         }
5790
5791                         void EmitFinallyBody (EmitContext ec)
5792                         {
5793                                 ILGenerator ig = ec.ig;
5794
5795                                 if (enumerator_type.IsValueType) {
5796                                         MethodInfo mi = FetchMethodDispose (enumerator_type);
5797                                         if (mi != null) {
5798                                                 enumerator.AddressOf (ec, AddressOp.Load);
5799                                                 ig.Emit (OpCodes.Call, mi);
5800                                         } else {
5801                                                 enumerator.Emit (ec);
5802                                                 ig.Emit (OpCodes.Box, enumerator_type);
5803                                                 ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
5804                                         }
5805                                 } else {
5806                                         Label call_dispose = ig.DefineLabel ();
5807
5808                                         enumerator.Emit (ec);
5809                                         ig.Emit (OpCodes.Isinst, TypeManager.idisposable_type);
5810                                         ig.Emit (OpCodes.Dup);
5811                                         ig.Emit (OpCodes.Brtrue_S, call_dispose);
5812
5813                                         // 'endfinally' empties the evaluation stack, and can appear anywhere inside a finally block
5814                                         // (Partition III, Section 3.35)
5815                                         ig.Emit (OpCodes.Endfinally);
5816
5817                                         ig.MarkLabel (call_dispose);
5818                                         ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
5819                                 }
5820                         }
5821
5822                         public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5823                         {
5824                                 enumerator_type = storey.MutateType (enumerator_type);
5825                                 init.MutateHoistedGenericType (storey);
5826                                 loop.MutateHoistedGenericType (storey);
5827                         }
5828                 }
5829
5830                 Expression type;
5831                 Expression variable;
5832                 Expression expr;
5833                 Statement statement;
5834
5835                 public Foreach (Expression type, LocalVariableReference var, Expression expr,
5836                                 Statement stmt, Location l)
5837                 {
5838                         this.type = type;
5839                         this.variable = var;
5840                         this.expr = expr;
5841                         statement = stmt;
5842                         loc = l;
5843                 }
5844
5845                 public Statement Statement {
5846                         get { return statement; }
5847                 }
5848
5849                 public override bool Resolve (EmitContext ec)
5850                 {
5851                         expr = expr.Resolve (ec);
5852                         if (expr == null)
5853                                 return false;
5854
5855                         if (expr.IsNull) {
5856                                 Report.Error (186, loc, "Use of null is not valid in this context");
5857                                 return false;
5858                         }
5859
5860                         if (expr.Type == TypeManager.string_type) {
5861                                 statement = new ArrayForeach (this, 1);
5862                         } else if (expr.Type.IsArray) {
5863                                 statement = new ArrayForeach (this, expr.Type.GetArrayRank ());
5864                         } else {
5865                                 if (expr.eclass == ExprClass.MethodGroup || expr is AnonymousMethodExpression) {
5866                                         Report.Error (446, expr.Location, "Foreach statement cannot operate on a `{0}'",
5867                                                 expr.ExprClassName);
5868                                         return false;
5869                                 }
5870
5871                                 statement = new CollectionForeach (type, variable, expr, statement, loc);
5872                         }
5873
5874                         return statement.Resolve (ec);
5875                 }
5876
5877                 protected override void DoEmit (EmitContext ec)
5878                 {
5879                         ILGenerator ig = ec.ig;
5880
5881                         Label old_begin = ec.LoopBegin, old_end = ec.LoopEnd;
5882                         ec.LoopBegin = ig.DefineLabel ();
5883                         ec.LoopEnd = ig.DefineLabel ();
5884
5885                         statement.Emit (ec);
5886
5887                         ec.LoopBegin = old_begin;
5888                         ec.LoopEnd = old_end;
5889                 }
5890
5891                 protected override void CloneTo (CloneContext clonectx, Statement t)
5892                 {
5893                         Foreach target = (Foreach) t;
5894
5895                         target.type = type.Clone (clonectx);
5896                         target.variable = variable.Clone (clonectx);
5897                         target.expr = expr.Clone (clonectx);
5898                         target.statement = statement.Clone (clonectx);
5899                 }
5900
5901                 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5902                 {
5903                         statement.MutateHoistedGenericType (storey);
5904                 }
5905         }
5906 }