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