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