c64f6d50f540ece79b081a19b9ba011a6f9eff82
[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 //
7 // (C) 2001, 2002 Ximian, Inc.
8 //
9
10 using System;
11 using System.Text;
12 using System.Reflection;
13 using System.Reflection.Emit;
14 using System.Diagnostics;
15
16 namespace Mono.CSharp {
17
18         using System.Collections;
19         
20         public abstract class Statement {
21                 public Location loc;
22                 
23                 ///
24                 /// Resolves the statement, true means that all sub-statements
25                 /// did resolve ok.
26                 //
27                 public virtual bool Resolve (EmitContext ec)
28                 {
29                         return true;
30                 }
31                 
32                 /// <summary>
33                 ///   Return value indicates whether all code paths emitted return.
34                 /// </summary>
35                 public abstract bool Emit (EmitContext ec);
36                 
37                 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
38                 {
39                         e = e.Resolve (ec);
40                         if (e == null)
41                                 return null;
42                         
43                         if (e.Type != TypeManager.bool_type){
44                                 e = Expression.ConvertImplicit (ec, e, TypeManager.bool_type,
45                                                                 new Location (-1));
46                         }
47
48                         if (e == null){
49                                 Report.Error (
50                                         31, loc, "Can not convert the expression to a boolean");
51                         }
52
53                         if (CodeGen.SymbolWriter != null)
54                                 ec.Mark (loc);
55
56                         return e;
57                 }
58                 
59                 /// <remarks>
60                 ///    Encapsulates the emission of a boolean test and jumping to a
61                 ///    destination.
62                 ///
63                 ///    This will emit the bool expression in `bool_expr' and if
64                 ///    `target_is_for_true' is true, then the code will generate a 
65                 ///    brtrue to the target.   Otherwise a brfalse. 
66                 /// </remarks>
67                 public static void EmitBoolExpression (EmitContext ec, Expression bool_expr,
68                                                        Label target, bool target_is_for_true)
69                 {
70                         ILGenerator ig = ec.ig;
71                         
72                         bool invert = false;
73                         if (bool_expr is Unary){
74                                 Unary u = (Unary) bool_expr;
75                                 
76                                 if (u.Oper == Unary.Operator.LogicalNot){
77                                         invert = true;
78
79                                         u.EmitLogicalNot (ec);
80                                 }
81                         } else if (bool_expr is Binary){
82                                 Binary b = (Binary) bool_expr;
83
84                                 if (b.EmitBranchable (ec, target, target_is_for_true))
85                                         return;
86                         }
87
88                         if (!invert)
89                                 bool_expr.Emit (ec);
90
91                         if (target_is_for_true){
92                                 if (invert)
93                                         ig.Emit (OpCodes.Brfalse, target);
94                                 else
95                                         ig.Emit (OpCodes.Brtrue, target);
96                         } else {
97                                 if (invert)
98                                         ig.Emit (OpCodes.Brtrue, target);
99                                 else
100                                         ig.Emit (OpCodes.Brfalse, target);
101                         }
102                 }
103
104                 public static void Warning_DeadCodeFound (Location loc)
105                 {
106                         Report.Warning (162, loc, "Unreachable code detected");
107                 }
108         }
109
110         public class EmptyStatement : Statement {
111                 public override bool Resolve (EmitContext ec)
112                 {
113                         return true;
114                 }
115                 
116                 public override bool Emit (EmitContext ec)
117                 {
118                         return false;
119                 }
120         }
121         
122         public class If : Statement {
123                 Expression expr;
124                 public Statement TrueStatement;
125                 public Statement FalseStatement;
126                 
127                 public If (Expression expr, Statement trueStatement, Location l)
128                 {
129                         this.expr = expr;
130                         TrueStatement = trueStatement;
131                         loc = l;
132                 }
133
134                 public If (Expression expr,
135                            Statement trueStatement,
136                            Statement falseStatement,
137                            Location l)
138                 {
139                         this.expr = expr;
140                         TrueStatement = trueStatement;
141                         FalseStatement = falseStatement;
142                         loc = l;
143                 }
144
145                 public override bool Resolve (EmitContext ec)
146                 {
147                         Report.Debug (1, "START IF BLOCK");
148
149                         expr = ResolveBoolean (ec, expr, loc);
150                         if (expr == null){
151                                 return false;
152                         }
153                         
154                         ec.StartFlowBranching (FlowBranchingType.BLOCK, loc);
155                         
156                         if (!TrueStatement.Resolve (ec)) {
157                                 ec.KillFlowBranching ();
158                                 return false;
159                         }
160
161                         ec.CurrentBranching.CreateSibling ();
162
163                         if ((FalseStatement != null) && !FalseStatement.Resolve (ec)) {
164                                 ec.KillFlowBranching ();
165                                 return false;
166                         }
167                                         
168                         ec.EndFlowBranching ();
169
170                         Report.Debug (1, "END IF BLOCK");
171
172                         return true;
173                 }
174                 
175                 public override bool Emit (EmitContext ec)
176                 {
177                         ILGenerator ig = ec.ig;
178                         Label false_target = ig.DefineLabel ();
179                         Label end;
180                         bool is_true_ret, is_false_ret;
181
182                         //
183                         // Dead code elimination
184                         //
185                         if (expr is BoolConstant){
186                                 bool take = ((BoolConstant) expr).Value;
187
188                                 if (take){
189                                         if (FalseStatement != null){
190                                                 Warning_DeadCodeFound (FalseStatement.loc);
191                                         }
192                                         return TrueStatement.Emit (ec);
193                                 } else {
194                                         Warning_DeadCodeFound (TrueStatement.loc);
195                                         if (FalseStatement != null)
196                                                 return FalseStatement.Emit (ec);
197                                 }
198                         }
199                         
200                         EmitBoolExpression (ec, expr, false_target, false);
201
202                         is_true_ret = TrueStatement.Emit (ec);
203                         is_false_ret = is_true_ret;
204
205                         if (FalseStatement != null){
206                                 bool branch_emitted = false;
207                                 
208                                 end = ig.DefineLabel ();
209                                 if (!is_true_ret){
210                                         ig.Emit (OpCodes.Br, end);
211                                         branch_emitted = true;
212                                 }
213
214                                 ig.MarkLabel (false_target);
215                                 is_false_ret = FalseStatement.Emit (ec);
216
217                                 if (branch_emitted)
218                                         ig.MarkLabel (end);
219                         } else {
220                                 ig.MarkLabel (false_target);
221                                 is_false_ret = false;
222                         }
223
224                         return is_true_ret && is_false_ret;
225                 }
226         }
227
228         public class Do : Statement {
229                 public Expression expr;
230                 public readonly Statement  EmbeddedStatement;
231                 
232                 public Do (Statement statement, Expression boolExpr, Location l)
233                 {
234                         expr = boolExpr;
235                         EmbeddedStatement = statement;
236                         loc = l;
237                 }
238
239                 public override bool Resolve (EmitContext ec)
240                 {
241                         if (!EmbeddedStatement.Resolve (ec))
242                                 return false;
243
244                         expr = ResolveBoolean (ec, expr, loc);
245                         if (expr == null)
246                                 return false;
247                         
248                         return true;
249                 }
250                 
251                 public override bool Emit (EmitContext ec)
252                 {
253                         ILGenerator ig = ec.ig;
254                         Label loop = ig.DefineLabel ();
255                         Label old_begin = ec.LoopBegin;
256                         Label old_end = ec.LoopEnd;
257                         bool  old_inloop = ec.InLoop;
258                         bool old_breaks = ec.Breaks;
259                         int old_loop_begin_try_catch_level = ec.LoopBeginTryCatchLevel;
260                         
261                         ec.LoopBegin = ig.DefineLabel ();
262                         ec.LoopEnd = ig.DefineLabel ();
263                         ec.InLoop = true;
264                         ec.LoopBeginTryCatchLevel = ec.TryCatchLevel;
265                                 
266                         ig.MarkLabel (loop);
267                         ec.Breaks = false;
268                         EmbeddedStatement.Emit (ec);
269                         bool breaks = ec.Breaks;
270                         ig.MarkLabel (ec.LoopBegin);
271
272                         //
273                         // Dead code elimination
274                         //
275                         if (expr is BoolConstant){
276                                 bool res = ((BoolConstant) expr).Value;
277
278                                 if (res)
279                                         ec.ig.Emit (OpCodes.Br, loop); 
280                         } else
281                                 EmitBoolExpression (ec, expr, loop, true);
282                         
283                         ig.MarkLabel (ec.LoopEnd);
284
285                         ec.LoopBeginTryCatchLevel = old_loop_begin_try_catch_level;
286                         ec.LoopBegin = old_begin;
287                         ec.LoopEnd = old_end;
288                         ec.InLoop = old_inloop;
289                         ec.Breaks = old_breaks;
290
291                         //
292                         // Inform whether we are infinite or not
293                         //
294                         if (expr is BoolConstant){
295                                 BoolConstant bc = (BoolConstant) expr;
296
297                                 if (bc.Value == true)
298                                         return breaks == false;
299                         }
300                         
301                         return false;
302                 }
303         }
304
305         public class While : Statement {
306                 public Expression expr;
307                 public readonly Statement Statement;
308                 
309                 public While (Expression boolExpr, Statement statement, Location l)
310                 {
311                         this.expr = boolExpr;
312                         Statement = statement;
313                         loc = l;
314                 }
315
316                 public override bool Resolve (EmitContext ec)
317                 {
318                         expr = ResolveBoolean (ec, expr, loc);
319                         if (expr == null)
320                                 return false;
321                         
322                         return Statement.Resolve (ec);
323                 }
324                 
325                 public override bool Emit (EmitContext ec)
326                 {
327                         ILGenerator ig = ec.ig;
328                         Label old_begin = ec.LoopBegin;
329                         Label old_end = ec.LoopEnd;
330                         bool old_inloop = ec.InLoop;
331                         bool old_breaks = ec.Breaks;
332                         Label while_loop = ig.DefineLabel ();
333                         int old_loop_begin_try_catch_level = ec.LoopBeginTryCatchLevel;
334                         bool ret;
335                         
336                         ec.LoopBegin = ig.DefineLabel ();
337                         ec.LoopEnd = ig.DefineLabel ();
338                         ec.InLoop = true;
339                         ec.LoopBeginTryCatchLevel = ec.TryCatchLevel;
340
341                         ig.Emit (OpCodes.Br, ec.LoopBegin);
342                         ig.MarkLabel (while_loop);
343
344                         //
345                         // Inform whether we are infinite or not
346                         //
347                         if (expr is BoolConstant){
348                                 BoolConstant bc = (BoolConstant) expr;
349
350                                 ig.MarkLabel (ec.LoopBegin);
351                                 if (bc.Value == false){
352                                         Warning_DeadCodeFound (Statement.loc);
353                                         ret = false;
354                                 } else {
355                                         bool breaks;
356                                         
357                                         ec.Breaks = false;
358                                         Statement.Emit (ec);
359                                         breaks = ec.Breaks;
360                                         ig.Emit (OpCodes.Br, ec.LoopBegin);
361                                         
362                                         //
363                                         // Inform that we are infinite (ie, `we return'), only
364                                         // if we do not `break' inside the code.
365                                         //
366                                         ret = breaks == false;
367                                 }
368                                 ig.MarkLabel (ec.LoopEnd);
369                         } else {
370                                 Statement.Emit (ec);
371                         
372                                 ig.MarkLabel (ec.LoopBegin);
373
374                                 EmitBoolExpression (ec, expr, while_loop, true);
375                                 ig.MarkLabel (ec.LoopEnd);
376
377                                 ret = false;
378                         }       
379
380                         ec.LoopBegin = old_begin;
381                         ec.LoopEnd = old_end;
382                         ec.InLoop = old_inloop;
383                         ec.Breaks = old_breaks;
384                         ec.LoopBeginTryCatchLevel = old_loop_begin_try_catch_level;
385
386                         return ret;
387                 }
388         }
389
390         public class For : Statement {
391                 Expression Test;
392                 readonly Statement InitStatement;
393                 readonly Statement Increment;
394                 readonly Statement Statement;
395                 
396                 public For (Statement initStatement,
397                             Expression test,
398                             Statement increment,
399                             Statement statement,
400                             Location l)
401                 {
402                         InitStatement = initStatement;
403                         Test = test;
404                         Increment = increment;
405                         Statement = statement;
406                         loc = l;
407                 }
408
409                 public override bool Resolve (EmitContext ec)
410                 {
411                         bool ok = true;
412
413                         if (InitStatement != null){
414                                 if (!InitStatement.Resolve (ec))
415                                         ok = false;
416                         }
417
418                         if (Test != null){
419                                 Test = ResolveBoolean (ec, Test, loc);
420                                 if (Test == null)
421                                         ok = false;
422                         }
423
424                         if (Increment != null){
425                                 if (!Increment.Resolve (ec))
426                                         ok = false;
427                         }
428                         
429                         return Statement.Resolve (ec) && ok;
430                 }
431                 
432                 public override bool Emit (EmitContext ec)
433                 {
434                         ILGenerator ig = ec.ig;
435                         Label old_begin = ec.LoopBegin;
436                         Label old_end = ec.LoopEnd;
437                         bool old_inloop = ec.InLoop;
438                         bool old_breaks = ec.Breaks;
439                         int old_loop_begin_try_catch_level = ec.LoopBeginTryCatchLevel;
440                         Label loop = ig.DefineLabel ();
441                         Label test = ig.DefineLabel ();
442                         
443                         if (InitStatement != null)
444                                 if (! (InitStatement is EmptyStatement))
445                                         InitStatement.Emit (ec);
446
447                         ec.LoopBegin = ig.DefineLabel ();
448                         ec.LoopEnd = ig.DefineLabel ();
449                         ec.InLoop = true;
450                         ec.LoopBeginTryCatchLevel = ec.TryCatchLevel;
451
452                         ig.Emit (OpCodes.Br, test);
453                         ig.MarkLabel (loop);
454                         ec.Breaks = false;
455                         Statement.Emit (ec);
456                         bool breaks = ec.Breaks;
457
458                         ig.MarkLabel (ec.LoopBegin);
459                         if (!(Increment is EmptyStatement))
460                                 Increment.Emit (ec);
461
462                         ig.MarkLabel (test);
463                         //
464                         // If test is null, there is no test, and we are just
465                         // an infinite loop
466                         //
467                         if (Test != null)
468                                 EmitBoolExpression (ec, Test, loop, true);
469                         else
470                                 ig.Emit (OpCodes.Br, loop);
471                         ig.MarkLabel (ec.LoopEnd);
472
473                         ec.LoopBegin = old_begin;
474                         ec.LoopEnd = old_end;
475                         ec.InLoop = old_inloop;
476                         ec.Breaks = old_breaks;
477                         ec.LoopBeginTryCatchLevel = old_loop_begin_try_catch_level;
478                         
479                         //
480                         // Inform whether we are infinite or not
481                         //
482                         if (Test != null){
483                                 if (Test is BoolConstant){
484                                         BoolConstant bc = (BoolConstant) Test;
485
486                                         if (bc.Value)
487                                                 return breaks == false;
488                                 }
489                                 return false;
490                         } else
491                                 return true;
492                 }
493         }
494         
495         public class StatementExpression : Statement {
496                 Expression expr;
497                 
498                 public StatementExpression (ExpressionStatement expr, Location l)
499                 {
500                         this.expr = expr;
501                         loc = l;
502                 }
503
504                 public override bool Resolve (EmitContext ec)
505                 {
506                         expr = (Expression) expr.Resolve (ec);
507                         return expr != null;
508                 }
509                 
510                 public override bool Emit (EmitContext ec)
511                 {
512                         ILGenerator ig = ec.ig;
513                         
514                         if (expr is ExpressionStatement)
515                                 ((ExpressionStatement) expr).EmitStatement (ec);
516                         else {
517                                 expr.Emit (ec);
518                                 ig.Emit (OpCodes.Pop);
519                         }
520
521                         return false;
522                 }
523
524                 public override string ToString ()
525                 {
526                         return "StatementExpression (" + expr + ")";
527                 }
528         }
529
530         /// <summary>
531         ///   Implements the return statement
532         /// </summary>
533         public class Return : Statement {
534                 public Expression Expr;
535                 
536                 public Return (Expression expr, Location l)
537                 {
538                         Expr = expr;
539                         loc = l;
540                 }
541
542                 public override bool Resolve (EmitContext ec)
543                 {
544                         if (Expr != null){
545                                 Expr = Expr.Resolve (ec);
546                                 if (Expr == null)
547                                         return false;
548                         }
549
550                         FlowBranching.UsageVector vector = ec.CurrentBranching.CurrentUsageVector;
551
552                         if (ec.CurrentBranching.InTryBlock ())
553                                 ec.CurrentBranching.AddFinallyVector (vector);
554
555                         vector.Returns = FlowReturns.ALWAYS;
556                         vector.Breaks = FlowReturns.ALWAYS;
557
558                         return true;
559                 }
560                 
561                 public override bool Emit (EmitContext ec)
562                 {
563                         if (ec.InFinally){
564                                 Report.Error (157,loc,"Control can not leave the body of the finally block");
565                                 return false;
566                         }
567                         
568                         if (ec.ReturnType == null){
569                                 if (Expr != null){
570                                         Report.Error (127, loc, "Return with a value not allowed here");
571                                         return false;
572                                 }
573                         } else {
574                                 if (Expr == null){
575                                         Report.Error (126, loc, "An object of type `" +
576                                                       TypeManager.CSharpName (ec.ReturnType) + "' is " +
577                                                       "expected for the return statement");
578                                         return false;
579                                 }
580
581                                 if (Expr.Type != ec.ReturnType)
582                                         Expr = Expression.ConvertImplicitRequired (
583                                                 ec, Expr, ec.ReturnType, loc);
584
585                                 if (Expr == null)
586                                         return false;
587
588                                 Expr.Emit (ec);
589
590                                 if (ec.InTry || ec.InCatch)
591                                         ec.ig.Emit (OpCodes.Stloc, ec.TemporaryReturn ());
592                         }
593
594                         if (ec.InTry || ec.InCatch) {
595                                 if (!ec.HasReturnLabel) {
596                                         ec.ReturnLabel = ec.ig.DefineLabel ();
597                                         ec.HasReturnLabel = true;
598                                 }
599                                 ec.ig.Emit (OpCodes.Leave, ec.ReturnLabel);
600                         } else
601                                 ec.ig.Emit (OpCodes.Ret);
602
603                         return true; 
604                 }
605         }
606
607         public class Goto : Statement {
608                 string target;
609                 Block block;
610                 LabeledStatement label;
611                 
612                 public override bool Resolve (EmitContext ec)
613                 {
614                         label = block.LookupLabel (target);
615                         if (label == null){
616                                 Report.Error (
617                                         159, loc,
618                                         "No such label `" + target + "' in this scope");
619                                 return false;
620                         }
621
622                         // If this is a forward goto.
623                         if (!label.IsDefined)
624                                 label.AddUsageVector (ec.CurrentBranching.CurrentUsageVector);
625
626                         ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.ALWAYS;
627
628                         return true;
629                 }
630                 
631                 public Goto (Block parent_block, string label, Location l)
632                 {
633                         block = parent_block;
634                         loc = l;
635                         target = label;
636                 }
637
638                 public string Target {
639                         get {
640                                 return target;
641                         }
642                 }
643
644                 public override bool Emit (EmitContext ec)
645                 {
646                         Label l = label.LabelTarget (ec);
647                         ec.ig.Emit (OpCodes.Br, l);
648                         
649                         return false;
650                 }
651         }
652
653         public class LabeledStatement : Statement {
654                 string label_name;
655                 bool defined;
656                 Label label;
657
658                 ArrayList vectors;
659                 
660                 public LabeledStatement (string label_name)
661                 {
662                         this.label_name = label_name;
663                 }
664
665                 public Label LabelTarget (EmitContext ec)
666                 {
667                         if (defined)
668                                 return label;
669                         label = ec.ig.DefineLabel ();
670                         defined = true;
671
672                         return label;
673                 }
674
675                 public bool IsDefined {
676                         get {
677                                 return defined;
678                         }
679                 }
680
681                 public void AddUsageVector (FlowBranching.UsageVector vector)
682                 {
683                         if (vectors == null)
684                                 vectors = new ArrayList ();
685
686                         vectors.Add (vector.Clone ());
687                 }
688
689                 public override bool Resolve (EmitContext ec)
690                 {
691                         if (vectors != null)
692                                 ec.CurrentBranching.CurrentUsageVector.MergeJumpOrigins (vectors);
693
694                         return true;
695                 }
696
697                 public override bool Emit (EmitContext ec)
698                 {
699                         LabelTarget (ec);
700                         ec.ig.MarkLabel (label);
701
702                         return false;
703                 }
704         }
705         
706
707         /// <summary>
708         ///   `goto default' statement
709         /// </summary>
710         public class GotoDefault : Statement {
711                 
712                 public GotoDefault (Location l)
713                 {
714                         loc = l;
715                 }
716
717                 public override bool Resolve (EmitContext ec)
718                 {
719                         ec.CurrentBranching.CurrentUsageVector.Returns = FlowReturns.UNREACHABLE;
720                         ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.ALWAYS;
721                         return true;
722                 }
723
724                 public override bool Emit (EmitContext ec)
725                 {
726                         if (ec.Switch == null){
727                                 Report.Error (153, loc, "goto default is only valid in a switch statement");
728                                 return false;
729                         }
730
731                         if (!ec.Switch.GotDefault){
732                                 Report.Error (159, loc, "No default target on switch statement");
733                                 return false;
734                         }
735                         ec.ig.Emit (OpCodes.Br, ec.Switch.DefaultTarget);
736                         return false;
737                 }
738         }
739
740         /// <summary>
741         ///   `goto case' statement
742         /// </summary>
743         public class GotoCase : Statement {
744                 Expression expr;
745                 Label label;
746                 
747                 public GotoCase (Expression e, Location l)
748                 {
749                         expr = e;
750                         loc = l;
751                 }
752
753                 public override bool Resolve (EmitContext ec)
754                 {
755                         if (ec.Switch == null){
756                                 Report.Error (153, loc, "goto case is only valid in a switch statement");
757                                 return false;
758                         }
759
760                         expr = expr.Resolve (ec);
761                         if (expr == null)
762                                 return false;
763
764                         if (!(expr is Constant)){
765                                 Report.Error (159, loc, "Target expression for goto case is not constant");
766                                 return false;
767                         }
768
769                         object val = Expression.ConvertIntLiteral (
770                                 (Constant) expr, ec.Switch.SwitchType, loc);
771
772                         if (val == null)
773                                 return false;
774                                         
775                         SwitchLabel sl = (SwitchLabel) ec.Switch.Elements [val];
776
777                         if (sl == null){
778                                 Report.Error (
779                                         159, loc,
780                                         "No such label 'case " + val + "': for the goto case");
781                         }
782
783                         label = sl.ILLabelCode;
784
785                         ec.CurrentBranching.CurrentUsageVector.Returns = FlowReturns.UNREACHABLE;
786                         ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.ALWAYS;
787                         return true;
788                 }
789
790                 public override bool Emit (EmitContext ec)
791                 {
792                         ec.ig.Emit (OpCodes.Br, label);
793                         return true;
794                 }
795         }
796         
797         public class Throw : Statement {
798                 Expression expr;
799                 
800                 public Throw (Expression expr, Location l)
801                 {
802                         this.expr = expr;
803                         loc = l;
804                 }
805
806                 public override bool Resolve (EmitContext ec)
807                 {
808                         if (expr != null){
809                                 expr = expr.Resolve (ec);
810                                 if (expr == null)
811                                         return false;
812                         }
813
814                         ec.CurrentBranching.CurrentUsageVector.Returns = FlowReturns.EXCEPTION;
815                         ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.EXCEPTION;
816                         return true;
817                 }
818                         
819                 public override bool Emit (EmitContext ec)
820                 {
821                         if (expr == null){
822                                 if (ec.InCatch)
823                                         ec.ig.Emit (OpCodes.Rethrow);
824                                 else {
825                                         Report.Error (
826                                                 156, loc,
827                                                 "A throw statement with no argument is only " +
828                                                 "allowed in a catch clause");
829                                 }
830                                 return false;
831                         }
832
833                         expr.Emit (ec);
834
835                         ec.ig.Emit (OpCodes.Throw);
836
837                         return true;
838                 }
839         }
840
841         public class Break : Statement {
842                 
843                 public Break (Location l)
844                 {
845                         loc = l;
846                 }
847
848                 public override bool Resolve (EmitContext ec)
849                 {
850                         ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.ALWAYS;
851                         return true;
852                 }
853
854                 public override bool Emit (EmitContext ec)
855                 {
856                         ILGenerator ig = ec.ig;
857
858                         if (ec.InLoop == false && ec.Switch == null){
859                                 Report.Error (139, loc, "No enclosing loop or switch to continue to");
860                                 return false;
861                         }
862
863                         ec.Breaks = true;
864                         if (ec.InTry || ec.InCatch)
865                                 ig.Emit (OpCodes.Leave, ec.LoopEnd);
866                         else
867                                 ig.Emit (OpCodes.Br, ec.LoopEnd);
868
869                         return false;
870                 }
871         }
872
873         public class Continue : Statement {
874                 
875                 public Continue (Location l)
876                 {
877                         loc = l;
878                 }
879
880                 public override bool Resolve (EmitContext ec)
881                 {
882                         ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.ALWAYS;
883                         return true;
884                 }
885
886                 public override bool Emit (EmitContext ec)
887                 {
888                         Label begin = ec.LoopBegin;
889                         
890                         if (!ec.InLoop){
891                                 Report.Error (139, loc, "No enclosing loop to continue to");
892                                 return false;
893                         } 
894
895                         //
896                         // UGH: Non trivial.  This Br might cross a try/catch boundary
897                         // How can we tell?
898                         //
899                         // while () {
900                         //   try { ... } catch { continue; }
901                         // }
902                         //
903                         // From:
904                         // try {} catch { while () { continue; }}
905                         //
906                         if (ec.TryCatchLevel > ec.LoopBeginTryCatchLevel)
907                                 ec.ig.Emit (OpCodes.Leave, begin);
908                         else if (ec.TryCatchLevel < ec.LoopBeginTryCatchLevel)
909                                 throw new Exception ("Should never happen");
910                         else
911                                 ec.ig.Emit (OpCodes.Br, begin);
912                         return false;
913                 }
914         }
915
916         // <summary>
917         //   This is used in the control flow analysis code to specify whether the
918         //   current code block may return to its enclosing block before reaching
919         //   its end.
920         // </summary>
921         public enum FlowReturns {
922                 // It can never return.
923                 NEVER,
924
925                 // This means that the block contains a conditional return statement
926                 // somewhere.
927                 SOMETIMES,
928
929                 // The code always returns, ie. there's an unconditional return / break
930                 // statement in it.
931                 ALWAYS,
932
933                 // The code always throws an exception.
934                 EXCEPTION,
935
936                 // The current code block is unreachable.  This happens if it's immediately
937                 // following a FlowReturns.ALWAYS block.
938                 UNREACHABLE
939         }
940
941         // <summary>
942         //   This is a special bit vector which can inherit from another bit vector doing a
943         //   copy-on-write strategy.  The inherited vector may have a smaller size than the
944         //   current one.
945         // </summary>
946         public class MyBitVector {
947                 public readonly int Count;
948                 public readonly MyBitVector InheritsFrom;
949
950                 bool is_dirty;
951                 BitArray vector;
952
953                 public MyBitVector (int Count)
954                         : this (null, Count)
955                 { }
956
957                 public MyBitVector (MyBitVector InheritsFrom, int Count)
958                 {
959                         this.InheritsFrom = InheritsFrom;
960                         this.Count = Count;
961                 }
962
963                 // <summary>
964                 //   Checks whether this bit vector has been modified.  After setting this to true,
965                 //   we won't use the inherited vector anymore, but our own copy of it.
966                 // </summary>
967                 public bool IsDirty {
968                         get {
969                                 return is_dirty;
970                         }
971
972                         set {
973                                 if (!is_dirty)
974                                         initialize_vector ();
975                         }
976                 }
977
978                 // <summary>
979                 //   Get/set bit `index' in the bit vector.
980                 // </summary>
981                 public bool this [int index]
982                 {
983                         get {
984                                 if (index > Count)
985                                         throw new ArgumentOutOfRangeException ();
986
987                                 // We're doing a "copy-on-write" strategy here; as long
988                                 // as nobody writes to the array, we can use our parent's
989                                 // copy instead of duplicating the vector.
990
991                                 if (vector != null)
992                                         return vector [index];
993                                 else if (InheritsFrom != null) {
994                                         BitArray inherited = InheritsFrom.Vector;
995
996                                         if (index < inherited.Count)
997                                                 return inherited [index];
998                                         else
999                                                 return false;
1000                                 } else
1001                                         return false;
1002                         }
1003
1004                         set {
1005                                 if (index > Count)
1006                                         throw new ArgumentOutOfRangeException ();
1007
1008                                 // Only copy the vector if we're actually modifying it.
1009
1010                                 if (this [index] != value) {
1011                                         initialize_vector ();
1012
1013                                         vector [index] = value;
1014                                 }
1015                         }
1016                 }
1017
1018                 // <summary>
1019                 //   If you explicitly convert the MyBitVector to a BitArray, you will get a deep
1020                 //   copy of the bit vector.
1021                 // </summary>
1022                 public static explicit operator BitArray (MyBitVector vector)
1023                 {
1024                         vector.initialize_vector ();
1025                         return vector.Vector;
1026                 }
1027
1028                 // <summary>
1029                 //   Performs an `or' operation on the bit vector.  The `new_vector' may have a
1030                 //   different size than the current one.
1031                 // </summary>
1032                 public void Or (MyBitVector new_vector)
1033                 {
1034                         BitArray new_array = new_vector.Vector;
1035
1036                         initialize_vector ();
1037
1038                         int upper;
1039                         if (vector.Count < new_array.Count)
1040                                 upper = vector.Count;
1041                         else
1042                                 upper = new_array.Count;
1043
1044                         for (int i = 0; i < upper; i++)
1045                                 vector [i] = vector [i] | new_array [i];
1046                 }
1047
1048                 // <summary>
1049                 //   Perfonrms an `and' operation on the bit vector.  The `new_vector' may have
1050                 //   a different size than the current one.
1051                 // </summary>
1052                 public void And (MyBitVector new_vector)
1053                 {
1054                         BitArray new_array = new_vector.Vector;
1055
1056                         initialize_vector ();
1057
1058                         int lower, upper;
1059                         if (vector.Count < new_array.Count)
1060                                 lower = upper = vector.Count;
1061                         else {
1062                                 lower = new_array.Count;
1063                                 upper = vector.Count;
1064                         }
1065
1066                         for (int i = 0; i < lower; i++)
1067                                 vector [i] = vector [i] & new_array [i];
1068
1069                         for (int i = lower; i < upper; i++)
1070                                 vector [i] = false;
1071                 }
1072
1073                 // <summary>
1074                 //   This does a deep copy of the bit vector.
1075                 // </summary>
1076                 public MyBitVector Clone ()
1077                 {
1078                         MyBitVector retval = new MyBitVector (Count);
1079
1080                         retval.Vector = Vector;
1081
1082                         return retval;
1083                 }
1084
1085                 BitArray Vector {
1086                         get {
1087                                 if (vector != null)
1088                                         return vector;
1089                                 else if (!is_dirty && (InheritsFrom != null))
1090                                         return InheritsFrom.Vector;
1091
1092                                 initialize_vector ();
1093
1094                                 return vector;
1095                         }
1096
1097                         set {
1098                                 initialize_vector ();
1099
1100                                 for (int i = 0; i < Math.Min (vector.Count, value.Count); i++)
1101                                         vector [i] = value [i];
1102                         }
1103                 }
1104
1105                 void initialize_vector ()
1106                 {
1107                         if (vector != null)
1108                                 return;
1109
1110                         vector = new BitArray (Count, false);
1111                         if (InheritsFrom != null)
1112                                 Vector = InheritsFrom.Vector;
1113
1114                         is_dirty = true;
1115                 }
1116
1117                 public override string ToString ()
1118                 {
1119                         StringBuilder sb = new StringBuilder ("MyBitVector (");
1120
1121                         BitArray vector = Vector;
1122                         sb.Append (Count);
1123                         sb.Append (",");
1124                         if (!IsDirty)
1125                                 sb.Append ("INHERITED - ");
1126                         for (int i = 0; i < vector.Count; i++) {
1127                                 if (i > 0)
1128                                         sb.Append (",");
1129                                 sb.Append (vector [i]);
1130                         }
1131                         
1132                         sb.Append (")");
1133                         return sb.ToString ();
1134                 }
1135         }
1136
1137         // <summary>
1138         //   The type of a FlowBranching.
1139         // </summary>
1140         public enum FlowBranchingType {
1141                 // Normal (conditional or toplevel) block.
1142                 BLOCK,
1143
1144                 // Try/Catch block.
1145                 EXCEPTION,
1146
1147                 // Switch block.
1148                 SWITCH,
1149
1150                 // Switch section.
1151                 SWITCH_SECTION
1152         }
1153
1154         // <summary>
1155         //   A new instance of this class is created every time a new block is resolved
1156         //   and if there's branching in the block's control flow.
1157         // </summary>
1158         public class FlowBranching {
1159                 // <summary>
1160                 //   The type of this flow branching.
1161                 // </summary>
1162                 public readonly FlowBranchingType Type;
1163
1164                 // <summary>
1165                 //   The block this branching is contained in.  This may be null if it's not
1166                 //   a top-level block and it doesn't declare any local variables.
1167                 // </summary>
1168                 public readonly Block Block;
1169
1170                 // <summary>
1171                 //   The parent of this branching or null if this is the top-block.
1172                 // </summary>
1173                 public readonly FlowBranching Parent;
1174
1175                 // <summary>
1176                 //   Start-Location of this flow branching.
1177                 // </summary>
1178                 public readonly Location Location;
1179
1180                 // <summary>
1181                 //   A list of UsageVectors.  A new vector is added each time control flow may
1182                 //   take a different path.
1183                 // </summary>
1184                 public ArrayList Siblings;
1185
1186                 //
1187                 // Private
1188                 //
1189                 InternalParameters param_info;
1190                 int[] param_map;
1191                 int num_params;
1192                 ArrayList finally_vectors;
1193
1194                 static int next_id = 0;
1195                 int id;
1196
1197                 // <summary>
1198                 //   Performs an `And' operation on the FlowReturns status
1199                 //   (for instance, a block only returns ALWAYS if all its siblings
1200                 //   always return).
1201                 // </summary>
1202                 public static FlowReturns AndFlowReturns (FlowReturns a, FlowReturns b)
1203                 {
1204                         if (b == FlowReturns.UNREACHABLE)
1205                                 return a;
1206
1207                         switch (a) {
1208                         case FlowReturns.NEVER:
1209                                 if (b == FlowReturns.NEVER)
1210                                         return FlowReturns.NEVER;
1211                                 else
1212                                         return FlowReturns.SOMETIMES;
1213                                 break;
1214
1215                         case FlowReturns.SOMETIMES:
1216                                 return FlowReturns.SOMETIMES;
1217
1218                         case FlowReturns.ALWAYS:
1219                                 if ((b == FlowReturns.ALWAYS) || (b == FlowReturns.EXCEPTION))
1220                                         return FlowReturns.ALWAYS;
1221                                 else
1222                                         return FlowReturns.SOMETIMES;
1223                                 break;
1224
1225                         case FlowReturns.EXCEPTION:
1226                                 if (b == FlowReturns.EXCEPTION)
1227                                         return FlowReturns.EXCEPTION;
1228                                 else if (b == FlowReturns.ALWAYS)
1229                                         return FlowReturns.ALWAYS;
1230                                 else
1231                                         return FlowReturns.SOMETIMES;
1232                                 break;
1233                         }
1234
1235                         return b;
1236                 }
1237
1238                 // <summary>
1239                 //   The vector contains a BitArray with information about which local variables
1240                 //   and parameters are already initialized at the current code position.
1241                 // </summary>
1242                 public class UsageVector {
1243                         // <summary>
1244                         //   If this is true, then the usage vector has been modified and must be
1245                         //   merged when we're done with this branching.
1246                         // </summary>
1247                         public bool IsDirty;
1248
1249                         // <summary>
1250                         //   The number of parameters in this block.
1251                         // </summary>
1252                         public readonly int CountParameters;
1253
1254                         // <summary>
1255                         //   The number of locals in this block.
1256                         // </summary>
1257                         public readonly int CountLocals;
1258
1259                         // <summary>
1260                         //   If not null, then we inherit our state from this vector and do a
1261                         //   copy-on-write.  If null, then we're the first sibling in a top-level
1262                         //   block and inherit from the empty vector.
1263                         // </summary>
1264                         public readonly UsageVector InheritsFrom;
1265
1266                         //
1267                         // Private.
1268                         //
1269                         MyBitVector locals, parameters;
1270                         FlowReturns real_returns, real_breaks;
1271                         bool returns_set, breaks_set, is_finally;
1272
1273                         static int next_id = 0;
1274                         int id;
1275
1276                         //
1277                         // Normally, you should not use any of these constructors.
1278                         //
1279                         public UsageVector (UsageVector parent, int num_params, int num_locals)
1280                         {
1281                                 this.InheritsFrom = parent;
1282                                 this.CountParameters = num_params;
1283                                 this.CountLocals = num_locals;
1284                                 this.real_returns = FlowReturns.NEVER;
1285                                 this.real_breaks = FlowReturns.NEVER;
1286
1287                                 if (parent != null) {
1288                                         locals = new MyBitVector (parent.locals, CountLocals);
1289                                         parameters = new MyBitVector (parent.parameters, num_params);
1290                                 } else {
1291                                         locals = new MyBitVector (null, CountLocals);
1292                                         parameters = new MyBitVector (null, num_params);
1293                                 }
1294
1295                                 id = ++next_id;
1296                         }
1297
1298                         public UsageVector (UsageVector parent)
1299                                 : this (parent, parent.CountParameters, parent.CountLocals)
1300                         { }
1301
1302                         // <summary>
1303                         //   This does a deep copy of the usage vector.
1304                         // </summary>
1305                         public UsageVector Clone ()
1306                         {
1307                                 UsageVector retval = new UsageVector (null, CountParameters, CountLocals);
1308
1309                                 retval.locals = locals.Clone ();
1310                                 if (parameters != null)
1311                                         retval.parameters = parameters.Clone ();
1312                                 retval.real_returns = real_returns;
1313                                 retval.real_breaks = real_breaks;
1314
1315                                 return retval;
1316                         }
1317
1318                         // 
1319                         // State of parameter `number'.
1320                         //
1321                         public bool this [int number]
1322                         {
1323                                 get {
1324                                         if (number == -1)
1325                                                 return true;
1326                                         else if (number == 0)
1327                                                 throw new ArgumentException ();
1328
1329                                         return parameters [number - 1];
1330                                 }
1331
1332                                 set {
1333                                         if (number == -1)
1334                                                 return;
1335                                         else if (number == 0)
1336                                                 throw new ArgumentException ();
1337
1338                                         parameters [number - 1] = value;
1339                                 }
1340                         }
1341
1342                         //
1343                         // State of the local variable `vi'.
1344                         //
1345                         public bool this [VariableInfo vi]
1346                         {
1347                                 get {
1348                                         if (vi.Number == -1)
1349                                                 return true;
1350                                         else if (vi.Number == 0)
1351                                                 throw new ArgumentException ();
1352
1353                                         return locals [vi.Number - 1];
1354                                 }
1355
1356                                 set {
1357                                         if (vi.Number == -1)
1358                                                 return;
1359                                         else if (vi.Number == 0)
1360                                                 throw new ArgumentException ();
1361
1362                                         locals [vi.Number - 1] = value;
1363                                 }
1364                         }
1365
1366                         // <summary>
1367                         //   Specifies when the current block returns.
1368                         // </summary>
1369                         public FlowReturns Returns {
1370                                 get {
1371                                         return real_returns;
1372                                 }
1373
1374                                 set {
1375                                         real_returns = value;
1376                                         returns_set = true;
1377                                 }
1378                         }
1379
1380                         // <summary>
1381                         //   Specifies whether control may return to our containing block
1382                         //   before reaching the end of this block.  This happens if there
1383                         //   is a break/continue/goto/return in it.
1384                         // </summary>
1385                         public FlowReturns Breaks {
1386                                 get {
1387                                         return real_breaks;
1388                                 }
1389
1390                                 set {
1391                                         real_breaks = value;
1392                                         breaks_set = true;
1393                                 }
1394                         }
1395
1396                         // <summary>
1397                         //   Merge a child branching.
1398                         // </summary>
1399                         public FlowReturns MergeChildren (FlowBranching branching, ICollection children)
1400                         {
1401                                 MyBitVector new_locals = null;
1402                                 MyBitVector new_params = null;
1403
1404                                 FlowReturns new_returns = FlowReturns.NEVER;
1405                                 FlowReturns new_breaks = FlowReturns.NEVER;
1406                                 bool new_returns_set = false, new_breaks_set = false;
1407                                 FlowReturns breaks;
1408
1409                                 Report.Debug (1, "MERGING CHILDREN", branching, this);
1410
1411                                 foreach (UsageVector child in children) {
1412                                         Report.Debug (1, "  MERGING CHILD", child);
1413
1414                                         // If Returns is already set, perform an `And' operation on it,
1415                                         // otherwise just set just.
1416                                         if (!new_returns_set) {
1417                                                 new_returns = child.Returns;
1418                                                 new_returns_set = true;
1419                                         } else
1420                                                 new_returns = AndFlowReturns (new_returns, child.Returns);
1421
1422                                         // If Breaks is already set, perform an `And' operation on it,
1423                                         // otherwise just set just.
1424                                         if (!new_breaks_set) {
1425                                                 new_breaks = child.Breaks;
1426                                                 new_breaks_set = true;
1427                                         } else
1428                                                 new_breaks = AndFlowReturns (new_breaks, child.Breaks);
1429
1430                                         // Ignore unreachable children.
1431                                         if (child.Returns == FlowReturns.UNREACHABLE)
1432                                                 continue;
1433
1434                                         // If we're a switch section, `break' won't leave the current
1435                                         // branching (NOTE: the type check here means that we're "a"
1436                                         // switch section, not that we're "in" a switch section!).
1437                                         breaks = (branching.Type == FlowBranchingType.SWITCH_SECTION) ?
1438                                                 child.Returns : child.Breaks;
1439
1440                                         // A local variable is initialized after a flow branching if it
1441                                         // has been initialized in all its branches which do neither
1442                                         // always return or always throw an exception.
1443                                         //
1444                                         // If a branch may return, but does not always return, then we
1445                                         // can treat it like a never-returning branch here: control will
1446                                         // only reach the code position after the branching if we did not
1447                                         // return here.
1448                                         //
1449                                         // It's important to distinguish between always and sometimes
1450                                         // returning branches here:
1451                                         //
1452                                         //    1   int a;
1453                                         //    2   if (something) {
1454                                         //    3      return;
1455                                         //    4      a = 5;
1456                                         //    5   }
1457                                         //    6   Console.WriteLine (a);
1458                                         //
1459                                         // The if block in lines 3-4 always returns, so we must not look
1460                                         // at the initialization of `a' in line 4 - thus it'll still be
1461                                         // uninitialized in line 6.
1462                                         //
1463                                         // On the other hand, the following is allowed:
1464                                         //
1465                                         //    1   int a;
1466                                         //    2   if (something)
1467                                         //    3      a = 5;
1468                                         //    4   else
1469                                         //    5      return;
1470                                         //    6   Console.WriteLine (a);
1471                                         //
1472                                         // Here, `a' is initialized in line 3 and we must not look at
1473                                         // line 5 since it always returns.
1474                                         // 
1475                                         if ((breaks != FlowReturns.EXCEPTION) &&
1476                                             (breaks != FlowReturns.ALWAYS)) {
1477                                                 if (new_locals != null)
1478                                                         new_locals.And (child.locals);
1479                                                 else {
1480                                                         new_locals = locals.Clone ();
1481                                                         new_locals.Or (child.locals);
1482                                                 }
1483                                         }
1484
1485                                         // An `out' parameter must be assigned in all branches which do
1486                                         // not always throw an exception.
1487                                         if (!child.is_finally && (child.Returns != FlowReturns.EXCEPTION)) {
1488                                                 if (new_params != null)
1489                                                         new_params.And (child.parameters);
1490                                                 else {
1491                                                         new_params = parameters.Clone ();
1492                                                         new_params.Or (child.parameters);
1493                                                 }
1494                                         }
1495
1496                                         // If we always return, check whether all `out' parameters have
1497                                         // been assigned.
1498                                         if (child.Returns == FlowReturns.ALWAYS) {
1499                                                 branching.CheckOutParameters (
1500                                                         child.parameters, branching.Location);
1501                                         }
1502                                 }
1503
1504                                 // Set new `Returns' status.
1505                                 if (!returns_set) {
1506                                         Returns = new_returns;
1507                                         returns_set = true;
1508                                 } else
1509                                         Returns = AndFlowReturns (Returns, new_returns);
1510
1511                                 //
1512                                 // We've now either reached the point after the branching or we will
1513                                 // never get there since we always return or always throw an exception.
1514                                 //
1515                                 // If we can reach the point after the branching, mark all locals and
1516                                 // parameters as initialized which have been initialized in all branches
1517                                 // we need to look at (see above).
1518                                 //
1519
1520                                 breaks = (branching.Type == FlowBranchingType.SWITCH_SECTION) ?
1521                                         Returns : Breaks;
1522
1523                                 if ((new_locals != null) &&
1524                                     ((breaks == FlowReturns.NEVER) || (breaks == FlowReturns.SOMETIMES))) {
1525                                         locals.Or (new_locals);
1526                                 }
1527
1528                                 if ((new_params != null) && (Breaks == FlowReturns.NEVER))
1529                                         parameters.Or (new_params);
1530
1531                                 //
1532                                 // If we may have returned (this only happens if there was a reachable
1533                                 // `return' statement in one of the branches), then we may return to our
1534                                 // parent block before reaching the end of the block, so set `Breaks'.
1535                                 //
1536
1537                                 if ((Returns != FlowReturns.NEVER) && (Returns != FlowReturns.SOMETIMES)) {
1538                                         real_breaks = Returns;
1539                                         breaks_set = true;
1540                                 }
1541
1542                                 Report.Debug (1, "MERGING CHILDREN DONE", new_params, new_locals,
1543                                               new_returns, new_breaks, this);
1544
1545                                 return new_returns;
1546                         }
1547
1548                         // <summary>
1549                         //   Tells control flow analysis that the current code position may be reached with
1550                         //   a forward jump from any of the origins listed in `origin_vectors' which is a
1551                         //   list of UsageVectors.
1552                         //
1553                         //   This is used when resolving forward gotos - in the following example, the
1554                         //   variable `a' is uninitialized in line 8 becase this line may be reached via
1555                         //   the goto in line 4:
1556                         //
1557                         //      1     int a;
1558                         //
1559                         //      3     if (something)
1560                         //      4        goto World;
1561                         //
1562                         //      6     a = 5;
1563                         //
1564                         //      7  World:
1565                         //      8     Console.WriteLine (a);
1566                         //
1567                         // </summary>
1568                         public void MergeJumpOrigins (ICollection origin_vectors)
1569                         {
1570                                 Report.Debug (1, "MERGING JUMP ORIGIN", this);
1571
1572                                 real_breaks = FlowReturns.NEVER;
1573                                 breaks_set = false;
1574
1575                                 foreach (UsageVector vector in origin_vectors) {
1576                                         Report.Debug (1, "  MERGING JUMP ORIGIN", vector);
1577
1578                                         locals.And (vector.locals);
1579                                         parameters.And (vector.parameters);
1580                                         Breaks = AndFlowReturns (Breaks, vector.Breaks);
1581                                 }
1582
1583                                 Report.Debug (1, "MERGING JUMP ORIGIN DONE", this);
1584                         }
1585
1586                         // <summary>
1587                         //   This is used at the beginning of a finally block if there were
1588                         //   any return statements in the try block or one of the catch blocks.
1589                         // </summary>
1590                         public void MergeFinallyOrigins (ICollection finally_vectors)
1591                         {
1592                                 Report.Debug (1, "MERGING FINALLY ORIGIN", this);
1593
1594                                 real_breaks = FlowReturns.NEVER;
1595                                 breaks_set = false;
1596
1597                                 foreach (UsageVector vector in finally_vectors) {
1598                                         Report.Debug (1, "  MERGING FINALLY ORIGIN", vector);
1599
1600                                         parameters.And (vector.parameters);
1601                                         Breaks = AndFlowReturns (Breaks, vector.Breaks);
1602                                 }
1603
1604                                 is_finally = true;
1605
1606                                 Report.Debug (1, "MERGING FINALLY ORIGIN DONE", this);
1607                         }
1608
1609                         // <summary>
1610                         //   Performs an `or' operation on the locals and the parameters.
1611                         // </summary>
1612                         public void Or (UsageVector new_vector)
1613                         {
1614                                 locals.Or (new_vector.locals);
1615                                 parameters.Or (new_vector.parameters);
1616                         }
1617
1618                         // <summary>
1619                         //   Performs an `and' operation on the locals.
1620                         // </summary>
1621                         public void AndLocals (UsageVector new_vector)
1622                         {
1623                                 locals.And (new_vector.locals);
1624                         }
1625
1626                         // <summary>
1627                         //   Returns a deep copy of the parameters.
1628                         // </summary>
1629                         public MyBitVector Parameters {
1630                                 get {
1631                                         return parameters.Clone ();
1632                                 }
1633                         }
1634
1635                         // <summary>
1636                         //   Returns a deep copy of the locals.
1637                         // </summary>
1638                         public MyBitVector Locals {
1639                                 get {
1640                                         return locals.Clone ();
1641                                 }
1642                         }
1643
1644                         //
1645                         // Debugging stuff.
1646                         //
1647
1648                         public override string ToString ()
1649                         {
1650                                 StringBuilder sb = new StringBuilder ();
1651
1652                                 sb.Append ("Vector (");
1653                                 sb.Append (id);
1654                                 sb.Append (",");
1655                                 sb.Append (Returns);
1656                                 sb.Append (",");
1657                                 sb.Append (Breaks);
1658                                 sb.Append (" - ");
1659                                 sb.Append (parameters);
1660                                 sb.Append (" - ");
1661                                 sb.Append (locals);
1662                                 sb.Append (")");
1663
1664                                 return sb.ToString ();
1665                         }
1666                 }
1667
1668                 FlowBranching (FlowBranchingType type, Location loc)
1669                 {
1670                         this.Siblings = new ArrayList ();
1671                         this.Block = null;
1672                         this.Location = loc;
1673                         this.Type = type;
1674                         id = ++next_id;
1675                 }
1676
1677                 // <summary>
1678                 //   Creates a new flow branching for `block'.
1679                 //   This is used from Block.Resolve to create the top-level branching of
1680                 //   the block.
1681                 // </summary>
1682                 public FlowBranching (Block block, InternalParameters ip, Location loc)
1683                         : this (FlowBranchingType.BLOCK, loc)
1684                 {
1685                         Block = block;
1686                         Parent = null;
1687
1688                         param_info = ip;
1689                         param_map = new int [(param_info != null) ? param_info.Count : 0];
1690                         num_params = 0;
1691
1692                         for (int i = 0; i < param_map.Length; i++) {
1693                                 Parameter.Modifier mod = param_info.ParameterModifier (i);
1694
1695                                 if ((mod & Parameter.Modifier.OUT) == 0)
1696                                         continue;
1697
1698                                 param_map [i] = ++num_params;
1699                         }
1700
1701                         Siblings = new ArrayList ();
1702                         Siblings.Add (new UsageVector (null, num_params, block.CountVariables));
1703                 }
1704
1705                 // <summary>
1706                 //   Creates a new flow branching which is contained in `parent'.
1707                 //   You should only pass non-null for the `block' argument if this block
1708                 //   introduces any new variables - in this case, we need to create a new
1709                 //   usage vector with a different size than our parent's one.
1710                 // </summary>
1711                 public FlowBranching (FlowBranching parent, FlowBranchingType type,
1712                                       Block block, Location loc)
1713                         : this (type, loc)
1714                 {
1715                         Parent = parent;
1716                         Block = block;
1717
1718                         if (parent != null) {
1719                                 param_info = parent.param_info;
1720                                 param_map = parent.param_map;
1721                                 num_params = parent.num_params;
1722                         }
1723
1724                         UsageVector vector;
1725                         if (Block != null)
1726                                 vector = new UsageVector (parent.CurrentUsageVector, num_params,
1727                                                           Block.CountVariables);
1728                         else
1729                                 vector = new UsageVector (Parent.CurrentUsageVector);
1730
1731                         Siblings.Add (vector);
1732
1733                         switch (Type) {
1734                         case FlowBranchingType.EXCEPTION:
1735                                 finally_vectors = new ArrayList ();
1736                                 break;
1737
1738                         default:
1739                                 break;
1740                         }
1741                 }
1742
1743                 // <summary>
1744                 //   Returns the branching's current usage vector.
1745                 // </summary>
1746                 public UsageVector CurrentUsageVector
1747                 {
1748                         get {
1749                                 return (UsageVector) Siblings [Siblings.Count - 1];
1750                         }
1751                 }
1752
1753                 // <summary>
1754                 //   Creates a sibling of the current usage vector.
1755                 // </summary>
1756                 public void CreateSibling ()
1757                 {
1758                         Siblings.Add (new UsageVector (Parent.CurrentUsageVector));
1759
1760                         Report.Debug (1, "CREATED SIBLING", CurrentUsageVector);
1761                 }
1762
1763                 // <summary>
1764                 //   Creates a sibling for a `finally' block.
1765                 // </summary>
1766                 public void CreateSiblingForFinally ()
1767                 {
1768                         if (Type != FlowBranchingType.EXCEPTION)
1769                                 throw new NotSupportedException ();
1770
1771                         CreateSibling ();
1772
1773                         CurrentUsageVector.MergeFinallyOrigins (finally_vectors);
1774                 }
1775
1776                 // <summary>
1777                 //   Check whether all `out' parameters have been assigned.
1778                 // </summary>
1779                 public void CheckOutParameters (MyBitVector parameters, Location loc)
1780                 {
1781                         if (InTryBlock ())
1782                                 return;
1783
1784                         for (int i = 0; i < param_map.Length; i++) {
1785                                 if (param_map [i] == 0)
1786                                         continue;
1787
1788                                 if (!parameters [param_map [i] - 1]) {
1789                                         Report.Error (
1790                                                 177, loc, "The out parameter `" +
1791                                                 param_info.ParameterName (i) + "` must be " +
1792                                                 "assigned before control leave the current method.");
1793                                         param_map [i] = 0;
1794                                 }
1795                         }
1796                 }
1797
1798                 // <summary>
1799                 //   Merge a child branching.
1800                 // </summary>
1801                 public FlowReturns MergeChild (FlowBranching child)
1802                 {
1803                         return CurrentUsageVector.MergeChildren (child, child.Siblings);
1804                 }
1805
1806                 // <summary>
1807                 //   Does the toplevel merging.
1808                 // </summary>
1809                 public FlowReturns MergeTopBlock ()
1810                 {
1811                         if ((Type != FlowBranchingType.BLOCK) || (Block == null))
1812                                 throw new NotSupportedException ();
1813
1814                         UsageVector vector = new UsageVector (null, num_params, Block.CountVariables);
1815
1816                         vector.MergeChildren (this, Siblings);
1817
1818                         Siblings.Clear ();
1819                         Siblings.Add (vector);
1820
1821                         Report.Debug (1, "MERGING TOP BLOCK", vector);
1822
1823                         if (vector.Returns != FlowReturns.EXCEPTION)
1824                                 CheckOutParameters (CurrentUsageVector.Parameters, Location);
1825
1826                         return vector.Returns;
1827                 }
1828
1829                 public bool InTryBlock ()
1830                 {
1831                         if (finally_vectors != null)
1832                                 return true;
1833                         else if (Parent != null)
1834                                 return Parent.InTryBlock ();
1835                         else
1836                                 return false;
1837                 }
1838
1839                 public void AddFinallyVector (UsageVector vector)
1840                 {
1841                         if (finally_vectors != null) {
1842                                 finally_vectors.Add (vector.Clone ());
1843                                 return;
1844                         }
1845
1846                         if (Parent != null)
1847                                 Parent.AddFinallyVector (vector);
1848                         else
1849                                 throw new NotSupportedException ();
1850                 }
1851
1852                 public bool IsVariableAssigned (VariableInfo vi)
1853                 {
1854                         Report.Debug (2, "CHECK VARIABLE ACCESS", this, vi);
1855
1856                         if (CurrentUsageVector.Breaks == FlowReturns.UNREACHABLE)
1857                                 return true;
1858                         else
1859                                 return CurrentUsageVector [vi];
1860                 }
1861
1862                 public void SetVariableAssigned (VariableInfo vi)
1863                 {
1864                         Report.Debug (2, "SET VARIABLE ACCESS", this, vi, CurrentUsageVector);
1865
1866                         if (CurrentUsageVector.Breaks == FlowReturns.UNREACHABLE)
1867                                 return;
1868
1869                         CurrentUsageVector [vi] = true;
1870                 }
1871
1872                 public bool IsParameterAssigned (int number)
1873                 {
1874                         Report.Debug (2, "IS PARAMETER ASSIGNED", this, number);
1875
1876                         if (param_map [number] == 0)
1877                                 return true;
1878                         else
1879                                 return CurrentUsageVector [param_map [number]];
1880                 }
1881
1882                 public void SetParameterAssigned (int number)
1883                 {
1884                         Report.Debug (2, "SET PARAMETER ACCESS", this, number, param_map [number],
1885                                       CurrentUsageVector);
1886
1887                         if (param_map [number] == 0)
1888                                 return;
1889
1890                         if (CurrentUsageVector.Breaks == FlowReturns.NEVER)
1891                                 CurrentUsageVector [param_map [number]] = true;
1892                 }
1893
1894                 public override string ToString ()
1895                 {
1896                         StringBuilder sb = new StringBuilder ("FlowBranching (");
1897
1898                         sb.Append (id);
1899                         sb.Append (",");
1900                         sb.Append (Type);
1901                         if (Block != null) {
1902                                 sb.Append (" - ");
1903                                 sb.Append (Block.ID);
1904                                 sb.Append (" - ");
1905                                 sb.Append (Block.StartLocation);
1906                         }
1907                         sb.Append (" - ");
1908                         sb.Append (Siblings.Count);
1909                         sb.Append (" - ");
1910                         sb.Append (CurrentUsageVector);
1911                         sb.Append (")");
1912                         return sb.ToString ();
1913                 }
1914         }
1915         
1916         public class VariableInfo {
1917                 public Expression Type;
1918                 public LocalBuilder LocalBuilder;
1919                 public Type VariableType;
1920                 public readonly Location Location;
1921
1922                 public int Number;
1923                 
1924                 public bool Used;
1925                 public bool Assigned;
1926                 public bool ReadOnly;
1927                 
1928                 public VariableInfo (Expression type, Location l)
1929                 {
1930                         Type = type;
1931                         LocalBuilder = null;
1932                         Location = l;
1933                 }
1934
1935                 public void MakePinned ()
1936                 {
1937                         TypeManager.MakePinned (LocalBuilder);
1938                 }
1939
1940                 public override string ToString ()
1941                 {
1942                         return "VariableInfo (" + Number + "," + Type + "," + Location + ")";
1943                 }
1944         }
1945                 
1946         /// <summary>
1947         ///   Block represents a C# block.
1948         /// </summary>
1949         ///
1950         /// <remarks>
1951         ///   This class is used in a number of places: either to represent
1952         ///   explicit blocks that the programmer places or implicit blocks.
1953         ///
1954         ///   Implicit blocks are used as labels or to introduce variable
1955         ///   declarations.
1956         /// </remarks>
1957         public class Block : Statement {
1958                 public readonly Block     Parent;
1959                 public readonly bool      Implicit;
1960                 public readonly Location  StartLocation;
1961                 public Location           EndLocation;
1962
1963                 //
1964                 // The statements in this block
1965                 //
1966                 ArrayList statements;
1967
1968                 //
1969                 // An array of Blocks.  We keep track of children just
1970                 // to generate the local variable declarations.
1971                 //
1972                 // Statements and child statements are handled through the
1973                 // statements.
1974                 //
1975                 ArrayList children;
1976                 
1977                 //
1978                 // Labels.  (label, block) pairs.
1979                 //
1980                 Hashtable labels;
1981
1982                 //
1983                 // Keeps track of (name, type) pairs
1984                 //
1985                 Hashtable variables;
1986
1987                 //
1988                 // Keeps track of constants
1989                 Hashtable constants;
1990
1991                 //
1992                 // Maps variable names to ILGenerator.LocalBuilders
1993                 //
1994                 Hashtable local_builders;
1995
1996                 bool used = false;
1997
1998                 static int id;
1999
2000                 int this_id;
2001                 
2002                 public Block (Block parent)
2003                         : this (parent, false, Location.Null, Location.Null)
2004                 { }
2005
2006                 public Block (Block parent, bool implicit_block)
2007                         : this (parent, implicit_block, Location.Null, Location.Null)
2008                 { }
2009
2010                 public Block (Block parent, Location start, Location end)
2011                         : this (parent, false, start, end)
2012                 { }
2013
2014                 public Block (Block parent, bool implicit_block, Location start, Location end)
2015                 {
2016                         if (parent != null)
2017                                 parent.AddChild (this);
2018                         
2019                         this.Parent = parent;
2020                         this.Implicit = implicit_block;
2021                         this.StartLocation = start;
2022                         this.EndLocation = end;
2023                         this.loc = start;
2024                         this_id = id++;
2025                         statements = new ArrayList ();
2026                 }
2027
2028                 public int ID {
2029                         get {
2030                                 return this_id;
2031                         }
2032                 }
2033                 
2034                 void AddChild (Block b)
2035                 {
2036                         if (children == null)
2037                                 children = new ArrayList ();
2038                         
2039                         children.Add (b);
2040                 }
2041
2042                 public void SetEndLocation (Location loc)
2043                 {
2044                         EndLocation = loc;
2045                 }
2046
2047                 /// <summary>
2048                 ///   Adds a label to the current block. 
2049                 /// </summary>
2050                 ///
2051                 /// <returns>
2052                 ///   false if the name already exists in this block. true
2053                 ///   otherwise.
2054                 /// </returns>
2055                 ///
2056                 public bool AddLabel (string name, LabeledStatement target)
2057                 {
2058                         if (labels == null)
2059                                 labels = new Hashtable ();
2060                         if (labels.Contains (name))
2061                                 return false;
2062                         
2063                         labels.Add (name, target);
2064                         return true;
2065                 }
2066
2067                 public LabeledStatement LookupLabel (string name)
2068                 {
2069                         if (labels != null){
2070                                 if (labels.Contains (name))
2071                                         return ((LabeledStatement) labels [name]);
2072                         }
2073
2074                         if (Parent != null)
2075                                 return Parent.LookupLabel (name);
2076
2077                         return null;
2078                 }
2079
2080                 public VariableInfo AddVariable (Expression type, string name, Parameters pars, Location l)
2081                 {
2082                         if (variables == null)
2083                                 variables = new Hashtable ();
2084
2085                         if (GetVariableType (name) != null)
2086                                 return null;
2087
2088                         if (pars != null) {
2089                                 int idx = 0;
2090                                 Parameter p = pars.GetParameterByName (name, out idx);
2091                                 if (p != null) 
2092                                         return null;
2093                         }
2094                         
2095                         VariableInfo vi = new VariableInfo (type, l);
2096
2097                         variables.Add (name, vi);
2098
2099                         if (variables_initialized)
2100                                 throw new Exception ();
2101
2102                         // Console.WriteLine ("Adding {0} to {1}", name, ID);
2103                         return vi;
2104                 }
2105
2106                 public bool AddConstant (Expression type, string name, Expression value, Parameters pars, Location l)
2107                 {
2108                         if (AddVariable (type, name, pars, l) == null)
2109                                 return false;
2110                         
2111                         if (constants == null)
2112                                 constants = new Hashtable ();
2113
2114                         constants.Add (name, value);
2115                         return true;
2116                 }
2117
2118                 public Hashtable Variables {
2119                         get {
2120                                 return variables;
2121                         }
2122                 }
2123
2124                 public VariableInfo GetVariableInfo (string name)
2125                 {
2126                         if (variables != null) {
2127                                 object temp;
2128                                 temp = variables [name];
2129
2130                                 if (temp != null){
2131                                         return (VariableInfo) temp;
2132                                 }
2133                         }
2134
2135                         if (Parent != null)
2136                                 return Parent.GetVariableInfo (name);
2137
2138                         return null;
2139                 }
2140                 
2141                 public Expression GetVariableType (string name)
2142                 {
2143                         VariableInfo vi = GetVariableInfo (name);
2144
2145                         if (vi != null)
2146                                 return vi.Type;
2147
2148                         return null;
2149                 }
2150
2151                 public Expression GetConstantExpression (string name)
2152                 {
2153                         if (constants != null) {
2154                                 object temp;
2155                                 temp = constants [name];
2156                                 
2157                                 if (temp != null)
2158                                         return (Expression) temp;
2159                         }
2160                         
2161                         if (Parent != null)
2162                                 return Parent.GetConstantExpression (name);
2163
2164                         return null;
2165                 }
2166                 
2167                 /// <summary>
2168                 ///   True if the variable named @name has been defined
2169                 ///   in this block
2170                 /// </summary>
2171                 public bool IsVariableDefined (string name)
2172                 {
2173                         // Console.WriteLine ("Looking up {0} in {1}", name, ID);
2174                         if (variables != null) {
2175                                 if (variables.Contains (name))
2176                                         return true;
2177                         }
2178                         
2179                         if (Parent != null)
2180                                 return Parent.IsVariableDefined (name);
2181
2182                         return false;
2183                 }
2184
2185                 /// <summary>
2186                 ///   True if the variable named @name is a constant
2187                 ///  </summary>
2188                 public bool IsConstant (string name)
2189                 {
2190                         Expression e = null;
2191                         
2192                         e = GetConstantExpression (name);
2193                         
2194                         return e != null;
2195                 }
2196                 
2197                 /// <summary>
2198                 ///   Use to fetch the statement associated with this label
2199                 /// </summary>
2200                 public Statement this [string name] {
2201                         get {
2202                                 return (Statement) labels [name];
2203                         }
2204                 }
2205
2206                 /// <returns>
2207                 ///   A list of labels that were not used within this block
2208                 /// </returns>
2209                 public string [] GetUnreferenced ()
2210                 {
2211                         // FIXME: Implement me
2212                         return null;
2213                 }
2214
2215                 public void AddStatement (Statement s)
2216                 {
2217                         statements.Add (s);
2218                         used = true;
2219                 }
2220
2221                 public bool Used {
2222                         get {
2223                                 return used;
2224                         }
2225                 }
2226
2227                 public void Use ()
2228                 {
2229                         used = true;
2230                 }
2231
2232                 bool variables_initialized = false;
2233                 int count_variables = 0, first_variable = 0;
2234
2235                 void UpdateVariableInfo (EmitContext ec)
2236                 {
2237                         DeclSpace ds = ec.DeclSpace;
2238
2239                         first_variable = 0;
2240
2241                         if (Parent != null)
2242                                 first_variable += Parent.CountVariables;
2243
2244                         count_variables = first_variable;
2245                         if (variables != null) {
2246                                 foreach (VariableInfo vi in variables.Values) {
2247                                         Report.Debug (2, "VARIABLE", vi);
2248
2249                                         Type type = ds.ResolveType (vi.Type, false, vi.Location);
2250                                         if (type == null) {
2251                                                 vi.Number = -1;
2252                                                 continue;
2253                                         }
2254
2255                                         vi.VariableType = type;
2256
2257                                         Report.Debug (2, "VARIABLE", vi, type, type.IsValueType,
2258                                                       TypeManager.IsValueType (type),
2259                                                       TypeManager.IsBuiltinType (type));
2260
2261                                         // FIXME: we don't have support for structs yet.
2262                                         if (TypeManager.IsValueType (type) && !TypeManager.IsBuiltinType (type))
2263                                                 vi.Number = -1;
2264                                         else
2265                                                 vi.Number = ++count_variables;
2266                                 }
2267                         }
2268
2269                         variables_initialized = true;
2270                 }
2271
2272                 //
2273                 // <returns>
2274                 //   The number of local variables in this block
2275                 // </returns>
2276                 public int CountVariables
2277                 {
2278                         get {
2279                                 if (!variables_initialized)
2280                                         throw new Exception ();
2281
2282                                 return count_variables;
2283                         }
2284                 }
2285
2286                 /// <summary>
2287                 ///   Emits the variable declarations and labels.
2288                 /// </summary>
2289                 /// <remarks>
2290                 ///   tc: is our typecontainer (to resolve type references)
2291                 ///   ig: is the code generator:
2292                 ///   toplevel: the toplevel block.  This is used for checking 
2293                 ///             that no two labels with the same name are used.
2294                 /// </remarks>
2295                 public void EmitMeta (EmitContext ec, Block toplevel)
2296                 {
2297                         DeclSpace ds = ec.DeclSpace;
2298                         ILGenerator ig = ec.ig;
2299
2300                         if (!variables_initialized)
2301                                 UpdateVariableInfo (ec);
2302
2303                         //
2304                         // Process this block variables
2305                         //
2306                         if (variables != null){
2307                                 local_builders = new Hashtable ();
2308                                 
2309                                 foreach (DictionaryEntry de in variables){
2310                                         string name = (string) de.Key;
2311                                         VariableInfo vi = (VariableInfo) de.Value;
2312
2313                                         if (vi.VariableType == null)
2314                                                 continue;
2315
2316                                         vi.LocalBuilder = ig.DeclareLocal (vi.VariableType);
2317
2318                                         if (CodeGen.SymbolWriter != null)
2319                                                 vi.LocalBuilder.SetLocalSymInfo (name);
2320
2321                                         if (constants == null)
2322                                                 continue;
2323
2324                                         Expression cv = (Expression) constants [name];
2325                                         if (cv == null)
2326                                                 continue;
2327
2328                                         Expression e = cv.Resolve (ec);
2329                                         if (e == null)
2330                                                 continue;
2331
2332                                         if (!(e is Constant)){
2333                                                 Report.Error (133, vi.Location,
2334                                                               "The expression being assigned to `" +
2335                                                               name + "' must be constant (" + e + ")");
2336                                                 continue;
2337                                         }
2338
2339                                         constants.Remove (name);
2340                                         constants.Add (name, e);
2341                                 }
2342                         }
2343
2344                         //
2345                         // Now, handle the children
2346                         //
2347                         if (children != null){
2348                                 foreach (Block b in children)
2349                                         b.EmitMeta (ec, toplevel);
2350                         }
2351                 }
2352
2353                 public void UsageWarning ()
2354                 {
2355                         string name;
2356                         
2357                         if (variables != null){
2358                                 foreach (DictionaryEntry de in variables){
2359                                         VariableInfo vi = (VariableInfo) de.Value;
2360                                         
2361                                         if (vi.Used)
2362                                                 continue;
2363                                         
2364                                         name = (string) de.Key;
2365                                                 
2366                                         if (vi.Assigned){
2367                                                 Report.Warning (
2368                                                         219, vi.Location, "The variable `" + name +
2369                                                         "' is assigned but its value is never used");
2370                                         } else {
2371                                                 Report.Warning (
2372                                                         168, vi.Location, "The variable `" +
2373                                                         name +
2374                                                         "' is declared but never used");
2375                                         } 
2376                                 }
2377                         }
2378
2379                         if (children != null)
2380                                 foreach (Block b in children)
2381                                         b.UsageWarning ();
2382                 }
2383
2384                 public override bool Resolve (EmitContext ec)
2385                 {
2386                         Block prev_block = ec.CurrentBlock;
2387                         bool ok = true;
2388
2389                         ec.CurrentBlock = this;
2390                         ec.StartFlowBranching (this);
2391
2392                         Report.Debug (1, "RESOLVE BLOCK", StartLocation);
2393
2394                         if (!variables_initialized)
2395                                 UpdateVariableInfo (ec);
2396
2397                         foreach (Statement s in statements){
2398                                 if (s.Resolve (ec) == false)
2399                                         ok = false;
2400                         }
2401
2402                         Report.Debug (1, "RESOLVE BLOCK DONE", StartLocation);
2403
2404                         ec.EndFlowBranching ();
2405                         ec.CurrentBlock = prev_block;
2406                         return ok;
2407                 }
2408                 
2409                 public override bool Emit (EmitContext ec)
2410                 {
2411                         bool is_ret = false, this_ret = false;
2412                         Block prev_block = ec.CurrentBlock;
2413                         bool warning_shown = false;
2414
2415                         ec.CurrentBlock = this;
2416
2417                         if (CodeGen.SymbolWriter != null) {
2418                                 ec.Mark (StartLocation);
2419                                 
2420                                 foreach (Statement s in statements) {
2421                                         ec.Mark (s.loc);
2422                                         
2423                                         if (is_ret && !warning_shown){
2424                                                 warning_shown = true;
2425                                                 Warning_DeadCodeFound (s.loc);
2426                                         }
2427                                         this_ret = s.Emit (ec);
2428                                         if (this_ret)
2429                                                 is_ret = true;
2430                                 }
2431
2432                                 ec.Mark (EndLocation); 
2433                         } else {
2434                                 foreach (Statement s in statements){
2435                                         if (is_ret && !warning_shown){
2436                                                 warning_shown = true;
2437                                                 Warning_DeadCodeFound (s.loc);
2438                                         }
2439                                         this_ret = s.Emit (ec);
2440                                         if (this_ret)
2441                                                 is_ret = true;
2442                                 }
2443                         }
2444                         
2445                         ec.CurrentBlock = prev_block;
2446                         return is_ret;
2447                 }
2448         }
2449
2450         public class SwitchLabel {
2451                 Expression label;
2452                 object converted;
2453                 public Location loc;
2454                 public Label ILLabel;
2455                 public Label ILLabelCode;
2456
2457                 //
2458                 // if expr == null, then it is the default case.
2459                 //
2460                 public SwitchLabel (Expression expr, Location l)
2461                 {
2462                         label = expr;
2463                         loc = l;
2464                 }
2465
2466                 public Expression Label {
2467                         get {
2468                                 return label;
2469                         }
2470                 }
2471
2472                 public object Converted {
2473                         get {
2474                                 return converted;
2475                         }
2476                 }
2477
2478                 //
2479                 // Resolves the expression, reduces it to a literal if possible
2480                 // and then converts it to the requested type.
2481                 //
2482                 public bool ResolveAndReduce (EmitContext ec, Type required_type)
2483                 {
2484                         ILLabel = ec.ig.DefineLabel ();
2485                         ILLabelCode = ec.ig.DefineLabel ();
2486
2487                         if (label == null)
2488                                 return true;
2489                         
2490                         Expression e = label.Resolve (ec);
2491
2492                         if (e == null)
2493                                 return false;
2494
2495                         if (!(e is Constant)){
2496                                 Console.WriteLine ("Value is: " + label);
2497                                 Report.Error (150, loc, "A constant value is expected");
2498                                 return false;
2499                         }
2500
2501                         if (e is StringConstant || e is NullLiteral){
2502                                 if (required_type == TypeManager.string_type){
2503                                         converted = label;
2504                                         ILLabel = ec.ig.DefineLabel ();
2505                                         return true;
2506                                 }
2507                         }
2508
2509                         converted = Expression.ConvertIntLiteral ((Constant) e, required_type, loc);
2510                         if (converted == null)
2511                                 return false;
2512
2513                         return true;
2514                 }
2515         }
2516
2517         public class SwitchSection {
2518                 // An array of SwitchLabels.
2519                 public readonly ArrayList Labels;
2520                 public readonly Block Block;
2521                 
2522                 public SwitchSection (ArrayList labels, Block block)
2523                 {
2524                         Labels = labels;
2525                         Block = block;
2526                 }
2527         }
2528         
2529         public class Switch : Statement {
2530                 public readonly ArrayList Sections;
2531                 public Expression Expr;
2532
2533                 /// <summary>
2534                 ///   Maps constants whose type type SwitchType to their  SwitchLabels.
2535                 /// </summary>
2536                 public Hashtable Elements;
2537
2538                 /// <summary>
2539                 ///   The governing switch type
2540                 /// </summary>
2541                 public Type SwitchType;
2542
2543                 //
2544                 // Computed
2545                 //
2546                 bool got_default;
2547                 Label default_target;
2548                 Expression new_expr;
2549
2550                 //
2551                 // The types allowed to be implicitly cast from
2552                 // on the governing type
2553                 //
2554                 static Type [] allowed_types;
2555                 
2556                 public Switch (Expression e, ArrayList sects, Location l)
2557                 {
2558                         Expr = e;
2559                         Sections = sects;
2560                         loc = l;
2561                 }
2562
2563                 public bool GotDefault {
2564                         get {
2565                                 return got_default;
2566                         }
2567                 }
2568
2569                 public Label DefaultTarget {
2570                         get {
2571                                 return default_target;
2572                         }
2573                 }
2574
2575                 //
2576                 // Determines the governing type for a switch.  The returned
2577                 // expression might be the expression from the switch, or an
2578                 // expression that includes any potential conversions to the
2579                 // integral types or to string.
2580                 //
2581                 Expression SwitchGoverningType (EmitContext ec, Type t)
2582                 {
2583                         if (t == TypeManager.int32_type ||
2584                             t == TypeManager.uint32_type ||
2585                             t == TypeManager.char_type ||
2586                             t == TypeManager.byte_type ||
2587                             t == TypeManager.sbyte_type ||
2588                             t == TypeManager.ushort_type ||
2589                             t == TypeManager.short_type ||
2590                             t == TypeManager.uint64_type ||
2591                             t == TypeManager.int64_type ||
2592                             t == TypeManager.string_type ||
2593                                 t == TypeManager.bool_type ||
2594                                 t.IsSubclassOf (TypeManager.enum_type))
2595                                 return Expr;
2596
2597                         if (allowed_types == null){
2598                                 allowed_types = new Type [] {
2599                                         TypeManager.sbyte_type,
2600                                         TypeManager.byte_type,
2601                                         TypeManager.short_type,
2602                                         TypeManager.ushort_type,
2603                                         TypeManager.int32_type,
2604                                         TypeManager.uint32_type,
2605                                         TypeManager.int64_type,
2606                                         TypeManager.uint64_type,
2607                                         TypeManager.char_type,
2608                                         TypeManager.bool_type,
2609                                         TypeManager.string_type
2610                                 };
2611                         }
2612
2613                         //
2614                         // Try to find a *user* defined implicit conversion.
2615                         //
2616                         // If there is no implicit conversion, or if there are multiple
2617                         // conversions, we have to report an error
2618                         //
2619                         Expression converted = null;
2620                         foreach (Type tt in allowed_types){
2621                                 Expression e;
2622                                 
2623                                 e = Expression.ImplicitUserConversion (ec, Expr, tt, loc);
2624                                 if (e == null)
2625                                         continue;
2626
2627                                 if (converted != null){
2628                                         Report.Error (-12, loc, "More than one conversion to an integral " +
2629                                                       " type exists for type `" +
2630                                                       TypeManager.CSharpName (Expr.Type)+"'");
2631                                         return null;
2632                                 } else
2633                                         converted = e;
2634                         }
2635                         return converted;
2636                 }
2637
2638                 void error152 (string n)
2639                 {
2640                         Report.Error (
2641                                 152, "The label `" + n + ":' " +
2642                                 "is already present on this switch statement");
2643                 }
2644                 
2645                 //
2646                 // Performs the basic sanity checks on the switch statement
2647                 // (looks for duplicate keys and non-constant expressions).
2648                 //
2649                 // It also returns a hashtable with the keys that we will later
2650                 // use to compute the switch tables
2651                 //
2652                 bool CheckSwitch (EmitContext ec)
2653                 {
2654                         Type compare_type;
2655                         bool error = false;
2656                         Elements = new Hashtable ();
2657                                 
2658                         got_default = false;
2659
2660                         if (TypeManager.IsEnumType (SwitchType)){
2661                                 compare_type = TypeManager.EnumToUnderlying (SwitchType);
2662                         } else
2663                                 compare_type = SwitchType;
2664                         
2665                         foreach (SwitchSection ss in Sections){
2666                                 foreach (SwitchLabel sl in ss.Labels){
2667                                         if (!sl.ResolveAndReduce (ec, SwitchType)){
2668                                                 error = true;
2669                                                 continue;
2670                                         }
2671
2672                                         if (sl.Label == null){
2673                                                 if (got_default){
2674                                                         error152 ("default");
2675                                                         error = true;
2676                                                 }
2677                                                 got_default = true;
2678                                                 continue;
2679                                         }
2680                                         
2681                                         object key = sl.Converted;
2682
2683                                         if (key is Constant)
2684                                                 key = ((Constant) key).GetValue ();
2685
2686                                         if (key == null)
2687                                                 key = NullLiteral.Null;
2688                                         
2689                                         string lname = null;
2690                                         if (compare_type == TypeManager.uint64_type){
2691                                                 ulong v = (ulong) key;
2692
2693                                                 if (Elements.Contains (v))
2694                                                         lname = v.ToString ();
2695                                                 else
2696                                                         Elements.Add (v, sl);
2697                                         } else if (compare_type == TypeManager.int64_type){
2698                                                 long v = (long) key;
2699
2700                                                 if (Elements.Contains (v))
2701                                                         lname = v.ToString ();
2702                                                 else
2703                                                         Elements.Add (v, sl);
2704                                         } else if (compare_type == TypeManager.uint32_type){
2705                                                 uint v = (uint) key;
2706
2707                                                 if (Elements.Contains (v))
2708                                                         lname = v.ToString ();
2709                                                 else
2710                                                         Elements.Add (v, sl);
2711                                         } else if (compare_type == TypeManager.char_type){
2712                                                 char v = (char) key;
2713                                                 
2714                                                 if (Elements.Contains (v))
2715                                                         lname = v.ToString ();
2716                                                 else
2717                                                         Elements.Add (v, sl);
2718                                         } else if (compare_type == TypeManager.byte_type){
2719                                                 byte v = (byte) key;
2720                                                 
2721                                                 if (Elements.Contains (v))
2722                                                         lname = v.ToString ();
2723                                                 else
2724                                                         Elements.Add (v, sl);
2725                                         } else if (compare_type == TypeManager.sbyte_type){
2726                                                 sbyte v = (sbyte) key;
2727                                                 
2728                                                 if (Elements.Contains (v))
2729                                                         lname = v.ToString ();
2730                                                 else
2731                                                         Elements.Add (v, sl);
2732                                         } else if (compare_type == TypeManager.short_type){
2733                                                 short v = (short) key;
2734                                                 
2735                                                 if (Elements.Contains (v))
2736                                                         lname = v.ToString ();
2737                                                 else
2738                                                         Elements.Add (v, sl);
2739                                         } else if (compare_type == TypeManager.ushort_type){
2740                                                 ushort v = (ushort) key;
2741                                                 
2742                                                 if (Elements.Contains (v))
2743                                                         lname = v.ToString ();
2744                                                 else
2745                                                         Elements.Add (v, sl);
2746                                         } else if (compare_type == TypeManager.string_type){
2747                                                 if (key is NullLiteral){
2748                                                         if (Elements.Contains (NullLiteral.Null))
2749                                                                 lname = "null";
2750                                                         else
2751                                                                 Elements.Add (NullLiteral.Null, null);
2752                                                 } else {
2753                                                         string s = (string) key;
2754
2755                                                         if (Elements.Contains (s))
2756                                                                 lname = s;
2757                                                         else
2758                                                                 Elements.Add (s, sl);
2759                                                 }
2760                                         } else if (compare_type == TypeManager.int32_type) {
2761                                                 int v = (int) key;
2762
2763                                                 if (Elements.Contains (v))
2764                                                         lname = v.ToString ();
2765                                                 else
2766                                                         Elements.Add (v, sl);
2767                                         } else if (compare_type == TypeManager.bool_type) {
2768                                                 bool v = (bool) key;
2769
2770                                                 if (Elements.Contains (v))
2771                                                         lname = v.ToString ();
2772                                                 else
2773                                                         Elements.Add (v, sl);
2774                                         }
2775                                         else
2776                                         {
2777                                                 throw new Exception ("Unknown switch type!" +
2778                                                                      SwitchType + " " + compare_type);
2779                                         }
2780
2781                                         if (lname != null){
2782                                                 error152 ("case + " + lname);
2783                                                 error = true;
2784                                         }
2785                                 }
2786                         }
2787                         if (error)
2788                                 return false;
2789                         
2790                         return true;
2791                 }
2792
2793                 void EmitObjectInteger (ILGenerator ig, object k)
2794                 {
2795                         if (k is int)
2796                                 IntConstant.EmitInt (ig, (int) k);
2797                         else if (k is Constant) {
2798                                 EmitObjectInteger (ig, ((Constant) k).GetValue ());
2799                         } 
2800                         else if (k is uint)
2801                                 IntConstant.EmitInt (ig, unchecked ((int) (uint) k));
2802                         else if (k is long)
2803                         {
2804                                 if ((long) k >= int.MinValue && (long) k <= int.MaxValue)
2805                                 {
2806                                         IntConstant.EmitInt (ig, (int) (long) k);
2807                                         ig.Emit (OpCodes.Conv_I8);
2808                                 }
2809                                 else
2810                                         LongConstant.EmitLong (ig, (long) k);
2811                         }
2812                         else if (k is ulong)
2813                         {
2814                                 if ((ulong) k < (1L<<32))
2815                                 {
2816                                         IntConstant.EmitInt (ig, (int) (long) k);
2817                                         ig.Emit (OpCodes.Conv_U8);
2818                                 }
2819                                 else
2820                                 {
2821                                         LongConstant.EmitLong (ig, unchecked ((long) (ulong) k));
2822                                 }
2823                         }
2824                         else if (k is char)
2825                                 IntConstant.EmitInt (ig, (int) ((char) k));
2826                         else if (k is sbyte)
2827                                 IntConstant.EmitInt (ig, (int) ((sbyte) k));
2828                         else if (k is byte)
2829                                 IntConstant.EmitInt (ig, (int) ((byte) k));
2830                         else if (k is short)
2831                                 IntConstant.EmitInt (ig, (int) ((short) k));
2832                         else if (k is ushort)
2833                                 IntConstant.EmitInt (ig, (int) ((ushort) k));
2834                         else if (k is bool)
2835                                 IntConstant.EmitInt (ig, ((bool) k) ? 1 : 0);
2836                         else
2837                                 throw new Exception ("Unhandled case");
2838                 }
2839                 
2840                 // structure used to hold blocks of keys while calculating table switch
2841                 class KeyBlock : IComparable
2842                 {
2843                         public KeyBlock (long _nFirst)
2844                         {
2845                                 nFirst = nLast = _nFirst;
2846                         }
2847                         public long nFirst;
2848                         public long nLast;
2849                         public ArrayList rgKeys = null;
2850                         public int Length
2851                         {
2852                                 get { return (int) (nLast - nFirst + 1); }
2853                         }
2854                         public static long TotalLength (KeyBlock kbFirst, KeyBlock kbLast)
2855                         {
2856                                 return kbLast.nLast - kbFirst.nFirst + 1;
2857                         }
2858                         public int CompareTo (object obj)
2859                         {
2860                                 KeyBlock kb = (KeyBlock) obj;
2861                                 int nLength = Length;
2862                                 int nLengthOther = kb.Length;
2863                                 if (nLengthOther == nLength)
2864                                         return (int) (kb.nFirst - nFirst);
2865                                 return nLength - nLengthOther;
2866                         }
2867                 }
2868
2869                 /// <summary>
2870                 /// This method emits code for a lookup-based switch statement (non-string)
2871                 /// Basically it groups the cases into blocks that are at least half full,
2872                 /// and then spits out individual lookup opcodes for each block.
2873                 /// It emits the longest blocks first, and short blocks are just
2874                 /// handled with direct compares.
2875                 /// </summary>
2876                 /// <param name="ec"></param>
2877                 /// <param name="val"></param>
2878                 /// <returns></returns>
2879                 bool TableSwitchEmit (EmitContext ec, LocalBuilder val)
2880                 {
2881                         int cElements = Elements.Count;
2882                         object [] rgKeys = new object [cElements];
2883                         Elements.Keys.CopyTo (rgKeys, 0);
2884                         Array.Sort (rgKeys);
2885
2886                         // initialize the block list with one element per key
2887                         ArrayList rgKeyBlocks = new ArrayList ();
2888                         foreach (object key in rgKeys)
2889                                 rgKeyBlocks.Add (new KeyBlock (Convert.ToInt64 (key)));
2890
2891                         KeyBlock kbCurr;
2892                         // iteratively merge the blocks while they are at least half full
2893                         // there's probably a really cool way to do this with a tree...
2894                         while (rgKeyBlocks.Count > 1)
2895                         {
2896                                 ArrayList rgKeyBlocksNew = new ArrayList ();
2897                                 kbCurr = (KeyBlock) rgKeyBlocks [0];
2898                                 for (int ikb = 1; ikb < rgKeyBlocks.Count; ikb++)
2899                                 {
2900                                         KeyBlock kb = (KeyBlock) rgKeyBlocks [ikb];
2901                                         if ((kbCurr.Length + kb.Length) * 2 >=  KeyBlock.TotalLength (kbCurr, kb))
2902                                         {
2903                                                 // merge blocks
2904                                                 kbCurr.nLast = kb.nLast;
2905                                         }
2906                                         else
2907                                         {
2908                                                 // start a new block
2909                                                 rgKeyBlocksNew.Add (kbCurr);
2910                                                 kbCurr = kb;
2911                                         }
2912                                 }
2913                                 rgKeyBlocksNew.Add (kbCurr);
2914                                 if (rgKeyBlocks.Count == rgKeyBlocksNew.Count)
2915                                         break;
2916                                 rgKeyBlocks = rgKeyBlocksNew;
2917                         }
2918
2919                         // initialize the key lists
2920                         foreach (KeyBlock kb in rgKeyBlocks)
2921                                 kb.rgKeys = new ArrayList ();
2922
2923                         // fill the key lists
2924                         int iBlockCurr = 0;
2925                         if (rgKeyBlocks.Count > 0) {
2926                                 kbCurr = (KeyBlock) rgKeyBlocks [0];
2927                                 foreach (object key in rgKeys)
2928                                 {
2929                                         bool fNextBlock = (key is UInt64) ? (ulong) key > (ulong) kbCurr.nLast : Convert.ToInt64 (key) > kbCurr.nLast;
2930                                         if (fNextBlock)
2931                                                 kbCurr = (KeyBlock) rgKeyBlocks [++iBlockCurr];
2932                                         kbCurr.rgKeys.Add (key);
2933                                 }
2934                         }
2935
2936                         // sort the blocks so we can tackle the largest ones first
2937                         rgKeyBlocks.Sort ();
2938
2939                         // okay now we can start...
2940                         ILGenerator ig = ec.ig;
2941                         Label lblEnd = ig.DefineLabel ();       // at the end ;-)
2942                         Label lblDefault = ig.DefineLabel ();
2943
2944                         Type typeKeys = null;
2945                         if (rgKeys.Length > 0)
2946                                 typeKeys = rgKeys [0].GetType ();       // used for conversions
2947
2948                         for (int iBlock = rgKeyBlocks.Count - 1; iBlock >= 0; --iBlock)
2949                         {
2950                                 KeyBlock kb = ((KeyBlock) rgKeyBlocks [iBlock]);
2951                                 lblDefault = (iBlock == 0) ? DefaultTarget : ig.DefineLabel ();
2952                                 if (kb.Length <= 2)
2953                                 {
2954                                         foreach (object key in kb.rgKeys)
2955                                         {
2956                                                 ig.Emit (OpCodes.Ldloc, val);
2957                                                 EmitObjectInteger (ig, key);
2958                                                 SwitchLabel sl = (SwitchLabel) Elements [key];
2959                                                 ig.Emit (OpCodes.Beq, sl.ILLabel);
2960                                         }
2961                                 }
2962                                 else
2963                                 {
2964                                         // TODO: if all the keys in the block are the same and there are
2965                                         //       no gaps/defaults then just use a range-check.
2966                                         if (SwitchType == TypeManager.int64_type ||
2967                                                 SwitchType == TypeManager.uint64_type)
2968                                         {
2969                                                 // TODO: optimize constant/I4 cases
2970
2971                                                 // check block range (could be > 2^31)
2972                                                 ig.Emit (OpCodes.Ldloc, val);
2973                                                 EmitObjectInteger (ig, Convert.ChangeType (kb.nFirst, typeKeys));
2974                                                 ig.Emit (OpCodes.Blt, lblDefault);
2975                                                 ig.Emit (OpCodes.Ldloc, val);
2976                                                 EmitObjectInteger (ig, Convert.ChangeType (kb.nFirst, typeKeys));
2977                                                 ig.Emit (OpCodes.Bgt, lblDefault);
2978
2979                                                 // normalize range
2980                                                 ig.Emit (OpCodes.Ldloc, val);
2981                                                 if (kb.nFirst != 0)
2982                                                 {
2983                                                         EmitObjectInteger (ig, Convert.ChangeType (kb.nFirst, typeKeys));
2984                                                         ig.Emit (OpCodes.Sub);
2985                                                 }
2986                                                 ig.Emit (OpCodes.Conv_I4);      // assumes < 2^31 labels!
2987                                         }
2988                                         else
2989                                         {
2990                                                 // normalize range
2991                                                 ig.Emit (OpCodes.Ldloc, val);
2992                                                 int nFirst = (int) kb.nFirst;
2993                                                 if (nFirst > 0)
2994                                                 {
2995                                                         IntConstant.EmitInt (ig, nFirst);
2996                                                         ig.Emit (OpCodes.Sub);
2997                                                 }
2998                                                 else if (nFirst < 0)
2999                                                 {
3000                                                         IntConstant.EmitInt (ig, -nFirst);
3001                                                         ig.Emit (OpCodes.Add);
3002                                                 }
3003                                         }
3004
3005                                         // first, build the list of labels for the switch
3006                                         int iKey = 0;
3007                                         int cJumps = kb.Length;
3008                                         Label [] rgLabels = new Label [cJumps];
3009                                         for (int iJump = 0; iJump < cJumps; iJump++)
3010                                         {
3011                                                 object key = kb.rgKeys [iKey];
3012                                                 if (Convert.ToInt64 (key) == kb.nFirst + iJump)
3013                                                 {
3014                                                         SwitchLabel sl = (SwitchLabel) Elements [key];
3015                                                         rgLabels [iJump] = sl.ILLabel;
3016                                                         iKey++;
3017                                                 }
3018                                                 else
3019                                                         rgLabels [iJump] = lblDefault;
3020                                         }
3021                                         // emit the switch opcode
3022                                         ig.Emit (OpCodes.Switch, rgLabels);
3023                                 }
3024
3025                                 // mark the default for this block
3026                                 if (iBlock != 0)
3027                                         ig.MarkLabel (lblDefault);
3028                         }
3029
3030                         // TODO: find the default case and emit it here,
3031                         //       to prevent having to do the following jump.
3032                         //       make sure to mark other labels in the default section
3033
3034                         // the last default just goes to the end
3035                         ig.Emit (OpCodes.Br, lblDefault);
3036
3037                         // now emit the code for the sections
3038                         bool fFoundDefault = false;
3039                         bool fAllReturn = true;
3040                         foreach (SwitchSection ss in Sections)
3041                         {
3042                                 foreach (SwitchLabel sl in ss.Labels)
3043                                 {
3044                                         ig.MarkLabel (sl.ILLabel);
3045                                         ig.MarkLabel (sl.ILLabelCode);
3046                                         if (sl.Label == null)
3047                                         {
3048                                                 ig.MarkLabel (lblDefault);
3049                                                 fFoundDefault = true;
3050                                         }
3051                                 }
3052                                 fAllReturn &= ss.Block.Emit (ec);
3053                                 //ig.Emit (OpCodes.Br, lblEnd);
3054                         }
3055                         
3056                         if (!fFoundDefault) {
3057                                 ig.MarkLabel (lblDefault);
3058                                 fAllReturn = false;
3059                         }
3060                         ig.MarkLabel (lblEnd);
3061
3062                         return fAllReturn;
3063                 }
3064                 //
3065                 // This simple emit switch works, but does not take advantage of the
3066                 // `switch' opcode. 
3067                 // TODO: remove non-string logic from here
3068                 // TODO: binary search strings?
3069                 //
3070                 bool SimpleSwitchEmit (EmitContext ec, LocalBuilder val)
3071                 {
3072                         ILGenerator ig = ec.ig;
3073                         Label end_of_switch = ig.DefineLabel ();
3074                         Label next_test = ig.DefineLabel ();
3075                         Label null_target = ig.DefineLabel ();
3076                         bool default_found = false;
3077                         bool first_test = true;
3078                         bool pending_goto_end = false;
3079                         bool all_return = true;
3080                         bool is_string = false;
3081                         bool null_found;
3082                         
3083                         //
3084                         // Special processing for strings: we cant compare
3085                         // against null.
3086                         //
3087                         if (SwitchType == TypeManager.string_type){
3088                                 ig.Emit (OpCodes.Ldloc, val);
3089                                 is_string = true;
3090                                 
3091                                 if (Elements.Contains (NullLiteral.Null)){
3092                                         ig.Emit (OpCodes.Brfalse, null_target);
3093                                 } else
3094                                         ig.Emit (OpCodes.Brfalse, default_target);
3095
3096                                 ig.Emit (OpCodes.Ldloc, val);
3097                                 ig.Emit (OpCodes.Call, TypeManager.string_isinterneted_string);
3098                                 ig.Emit (OpCodes.Stloc, val);
3099                         }
3100
3101                         SwitchSection last_section;
3102                         last_section = (SwitchSection) Sections [Sections.Count-1];
3103                         
3104                         foreach (SwitchSection ss in Sections){
3105                                 Label sec_begin = ig.DefineLabel ();
3106
3107                                 if (pending_goto_end)
3108                                         ig.Emit (OpCodes.Br, end_of_switch);
3109
3110                                 int label_count = ss.Labels.Count;
3111                                 null_found = false;
3112                                 foreach (SwitchLabel sl in ss.Labels){
3113                                         ig.MarkLabel (sl.ILLabel);
3114                                         
3115                                         if (!first_test){
3116                                                 ig.MarkLabel (next_test);
3117                                                 next_test = ig.DefineLabel ();
3118                                         }
3119                                         //
3120                                         // If we are the default target
3121                                         //
3122                                         if (sl.Label == null){
3123                                                 ig.MarkLabel (default_target);
3124                                                 default_found = true;
3125                                         } else {
3126                                                 object lit = sl.Converted;
3127
3128                                                 if (lit is NullLiteral){
3129                                                         null_found = true;
3130                                                         if (label_count == 1)
3131                                                                 ig.Emit (OpCodes.Br, next_test);
3132                                                         continue;
3133                                                                               
3134                                                 }
3135                                                 if (is_string){
3136                                                         StringConstant str = (StringConstant) lit;
3137
3138                                                         ig.Emit (OpCodes.Ldloc, val);
3139                                                         ig.Emit (OpCodes.Ldstr, str.Value);
3140                                                         if (label_count == 1)
3141                                                                 ig.Emit (OpCodes.Bne_Un, next_test);
3142                                                         else
3143                                                                 ig.Emit (OpCodes.Beq, sec_begin);
3144                                                 } else {
3145                                                         ig.Emit (OpCodes.Ldloc, val);
3146                                                         EmitObjectInteger (ig, lit);
3147                                                         ig.Emit (OpCodes.Ceq);
3148                                                         if (label_count == 1)
3149                                                                 ig.Emit (OpCodes.Brfalse, next_test);
3150                                                         else
3151                                                                 ig.Emit (OpCodes.Brtrue, sec_begin);
3152                                                 }
3153                                         }
3154                                 }
3155                                 if (label_count != 1 && ss != last_section)
3156                                         ig.Emit (OpCodes.Br, next_test);
3157                                 
3158                                 if (null_found)
3159                                         ig.MarkLabel (null_target);
3160                                 ig.MarkLabel (sec_begin);
3161                                 foreach (SwitchLabel sl in ss.Labels)\r
3162                                         ig.MarkLabel (sl.ILLabelCode);
3163                                 if (ss.Block.Emit (ec))
3164                                         pending_goto_end = false;
3165                                 else {
3166                                         all_return = false;
3167                                         pending_goto_end = true;
3168                                 }
3169                                 first_test = false;
3170                         }
3171                         if (!default_found){
3172                                 ig.MarkLabel (default_target);
3173                                 all_return = false;
3174                         }
3175                         ig.MarkLabel (next_test);
3176                         ig.MarkLabel (end_of_switch);
3177                         
3178                         return all_return;
3179                 }
3180
3181                 public override bool Resolve (EmitContext ec)
3182                 {
3183                         Expr = Expr.Resolve (ec);
3184                         if (Expr == null)
3185                                 return false;
3186
3187                         new_expr = SwitchGoverningType (ec, Expr.Type);
3188                         if (new_expr == null){
3189                                 Report.Error (151, loc, "An integer type or string was expected for switch");
3190                                 return false;
3191                         }
3192
3193                         // Validate switch.
3194                         SwitchType = new_expr.Type;
3195
3196                         if (!CheckSwitch (ec))
3197                                 return false;
3198
3199                         Switch old_switch = ec.Switch;
3200                         ec.Switch = this;
3201                         ec.Switch.SwitchType = SwitchType;
3202
3203                         ec.StartFlowBranching (FlowBranchingType.SWITCH, loc);
3204
3205                         bool first = true;
3206                         foreach (SwitchSection ss in Sections){
3207                                 if (!first)
3208                                         ec.CurrentBranching.CreateSibling ();
3209                                 else
3210                                         first = false;
3211
3212                                 if (ss.Block.Resolve (ec) != true)
3213                                         return false;
3214                         }
3215
3216                         ec.EndFlowBranching ();
3217                         ec.Switch = old_switch;
3218
3219                         return true;
3220                 }
3221                 
3222                 public override bool Emit (EmitContext ec)
3223                 {
3224                         // Store variable for comparission purposes
3225                         LocalBuilder value = ec.ig.DeclareLocal (SwitchType);
3226                         new_expr.Emit (ec);
3227                         ec.ig.Emit (OpCodes.Stloc, value);
3228
3229                         ILGenerator ig = ec.ig;
3230
3231                         default_target = ig.DefineLabel ();
3232
3233                         //
3234                         // Setup the codegen context
3235                         //
3236                         Label old_end = ec.LoopEnd;
3237                         Switch old_switch = ec.Switch;
3238                         
3239                         ec.LoopEnd = ig.DefineLabel ();
3240                         ec.Switch = this;
3241
3242                         // Emit Code.
3243                         bool all_return;
3244                         if (SwitchType == TypeManager.string_type)
3245                                 all_return = SimpleSwitchEmit (ec, value);
3246                         else
3247                                 all_return = TableSwitchEmit (ec, value);
3248
3249                         // Restore context state. 
3250                         ig.MarkLabel (ec.LoopEnd);
3251
3252                         //
3253                         // Restore the previous context
3254                         //
3255                         ec.LoopEnd = old_end;
3256                         ec.Switch = old_switch;
3257                         
3258                         return all_return;
3259                 }
3260         }
3261
3262         public class Lock : Statement {
3263                 Expression expr;
3264                 Statement Statement;
3265                         
3266                 public Lock (Expression expr, Statement stmt, Location l)
3267                 {
3268                         this.expr = expr;
3269                         Statement = stmt;
3270                         loc = l;
3271                 }
3272
3273                 public override bool Resolve (EmitContext ec)
3274                 {
3275                         expr = expr.Resolve (ec);
3276                         return Statement.Resolve (ec) && expr != null;
3277                 }
3278                 
3279                 public override bool Emit (EmitContext ec)
3280                 {
3281                         Type type = expr.Type;
3282                         bool val;
3283                         
3284                         if (type.IsValueType){
3285                                 Report.Error (185, loc, "lock statement requires the expression to be " +
3286                                               " a reference type (type is: `" +
3287                                               TypeManager.CSharpName (type) + "'");
3288                                 return false;
3289                         }
3290
3291                         ILGenerator ig = ec.ig;
3292                         LocalBuilder temp = ig.DeclareLocal (type);
3293                                 
3294                         expr.Emit (ec);
3295                         ig.Emit (OpCodes.Dup);
3296                         ig.Emit (OpCodes.Stloc, temp);
3297                         ig.Emit (OpCodes.Call, TypeManager.void_monitor_enter_object);
3298
3299                         // try
3300                         Label end = ig.BeginExceptionBlock ();
3301                         bool old_in_try = ec.InTry;
3302                         ec.InTry = true;
3303                         Label finish = ig.DefineLabel ();
3304                         val = Statement.Emit (ec);
3305                         ec.InTry = old_in_try;
3306                         // ig.Emit (OpCodes.Leave, finish);
3307
3308                         ig.MarkLabel (finish);
3309                         
3310                         // finally
3311                         ig.BeginFinallyBlock ();
3312                         ig.Emit (OpCodes.Ldloc, temp);
3313                         ig.Emit (OpCodes.Call, TypeManager.void_monitor_exit_object);
3314                         ig.EndExceptionBlock ();
3315                         
3316                         return val;
3317                 }
3318         }
3319
3320         public class Unchecked : Statement {
3321                 public readonly Block Block;
3322                 
3323                 public Unchecked (Block b)
3324                 {
3325                         Block = b;
3326                 }
3327
3328                 public override bool Resolve (EmitContext ec)
3329                 {
3330                         return Block.Resolve (ec);
3331                 }
3332                 
3333                 public override bool Emit (EmitContext ec)
3334                 {
3335                         bool previous_state = ec.CheckState;
3336                         bool previous_state_const = ec.ConstantCheckState;
3337                         bool val;
3338                         
3339                         ec.CheckState = false;
3340                         ec.ConstantCheckState = false;
3341                         val = Block.Emit (ec);
3342                         ec.CheckState = previous_state;
3343                         ec.ConstantCheckState = previous_state_const;
3344
3345                         return val;
3346                 }
3347         }
3348
3349         public class Checked : Statement {
3350                 public readonly Block Block;
3351                 
3352                 public Checked (Block b)
3353                 {
3354                         Block = b;
3355                 }
3356
3357                 public override bool Resolve (EmitContext ec)
3358                 {
3359                         bool previous_state = ec.CheckState;
3360                         bool previous_state_const = ec.ConstantCheckState;
3361                         
3362                         ec.CheckState = true;
3363                         ec.ConstantCheckState = true;
3364                         bool ret = Block.Resolve (ec);
3365                         ec.CheckState = previous_state;
3366                         ec.ConstantCheckState = previous_state_const;
3367
3368                         return ret;
3369                 }
3370
3371                 public override bool Emit (EmitContext ec)
3372                 {
3373                         bool previous_state = ec.CheckState;
3374                         bool previous_state_const = ec.ConstantCheckState;
3375                         bool val;
3376                         
3377                         ec.CheckState = true;
3378                         ec.ConstantCheckState = true;
3379                         val = Block.Emit (ec);
3380                         ec.CheckState = previous_state;
3381                         ec.ConstantCheckState = previous_state_const;
3382
3383                         return val;
3384                 }
3385         }
3386
3387         public class Unsafe : Statement {
3388                 public readonly Block Block;
3389
3390                 public Unsafe (Block b)
3391                 {
3392                         Block = b;
3393                 }
3394
3395                 public override bool Resolve (EmitContext ec)
3396                 {
3397                         bool previous_state = ec.InUnsafe;
3398                         bool val;
3399                         
3400                         ec.InUnsafe = true;
3401                         val = Block.Resolve (ec);
3402                         ec.InUnsafe = previous_state;
3403
3404                         return val;
3405                 }
3406                 
3407                 public override bool Emit (EmitContext ec)
3408                 {
3409                         bool previous_state = ec.InUnsafe;
3410                         bool val;
3411                         
3412                         ec.InUnsafe = true;
3413                         val = Block.Emit (ec);
3414                         ec.InUnsafe = previous_state;
3415
3416                         return val;
3417                 }
3418         }
3419
3420         // 
3421         // Fixed statement
3422         //
3423         public class Fixed : Statement {
3424                 Expression type;
3425                 ArrayList declarators;
3426                 Statement statement;
3427                 Type expr_type;
3428                 FixedData[] data;
3429
3430                 struct FixedData {
3431                         public bool is_object;
3432                         public VariableInfo vi;
3433                         public Expression expr;
3434                         public Expression converted;
3435                 }                       
3436
3437                 public Fixed (Expression type, ArrayList decls, Statement stmt, Location l)
3438                 {
3439                         this.type = type;
3440                         declarators = decls;
3441                         statement = stmt;
3442                         loc = l;
3443                 }
3444
3445                 public override bool Resolve (EmitContext ec)
3446                 {
3447                         expr_type = ec.DeclSpace.ResolveType (type, false, loc);
3448                         if (expr_type == null)
3449                                 return false;
3450
3451                         data = new FixedData [declarators.Count];
3452
3453                         int i = 0;
3454                         foreach (Pair p in declarators){
3455                                 VariableInfo vi = (VariableInfo) p.First;
3456                                 Expression e = (Expression) p.Second;
3457
3458                                 vi.Number = -1;
3459
3460                                 //
3461                                 // The rules for the possible declarators are pretty wise,
3462                                 // but the production on the grammar is more concise.
3463                                 //
3464                                 // So we have to enforce these rules here.
3465                                 //
3466                                 // We do not resolve before doing the case 1 test,
3467                                 // because the grammar is explicit in that the token &
3468                                 // is present, so we need to test for this particular case.
3469                                 //
3470
3471                                 //
3472                                 // Case 1: & object.
3473                                 //
3474                                 if (e is Unary && ((Unary) e).Oper == Unary.Operator.AddressOf){
3475                                         Expression child = ((Unary) e).Expr;
3476
3477                                         vi.MakePinned ();
3478                                         if (child is ParameterReference || child is LocalVariableReference){
3479                                                 Report.Error (
3480                                                         213, loc, 
3481                                                         "No need to use fixed statement for parameters or " +
3482                                                         "local variable declarations (address is already " +
3483                                                         "fixed)");
3484                                                 return false;
3485                                         }
3486                                         
3487                                         e = e.Resolve (ec);
3488                                         if (e == null)
3489                                                 return false;
3490
3491                                         child = ((Unary) e).Expr;
3492                                         
3493                                         if (!TypeManager.VerifyUnManaged (child.Type, loc))
3494                                                 return false;
3495
3496                                         data [i].is_object = true;
3497                                         data [i].expr = e;
3498                                         data [i].converted = null;
3499                                         data [i].vi = vi;
3500                                         i++;
3501
3502                                         continue;
3503                                 }
3504
3505                                 e = e.Resolve (ec);
3506                                 if (e == null)
3507                                         return false;
3508
3509                                 //
3510                                 // Case 2: Array
3511                                 //
3512                                 if (e.Type.IsArray){
3513                                         Type array_type = e.Type.GetElementType ();
3514                                         
3515                                         vi.MakePinned ();
3516                                         //
3517                                         // Provided that array_type is unmanaged,
3518                                         //
3519                                         if (!TypeManager.VerifyUnManaged (array_type, loc))
3520                                                 return false;
3521
3522                                         //
3523                                         // and T* is implicitly convertible to the
3524                                         // pointer type given in the fixed statement.
3525                                         //
3526                                         ArrayPtr array_ptr = new ArrayPtr (e);
3527                                         
3528                                         Expression converted = Expression.ConvertImplicitRequired (
3529                                                 ec, array_ptr, vi.VariableType, loc);
3530                                         if (converted == null)
3531                                                 return false;
3532
3533                                         data [i].is_object = false;
3534                                         data [i].expr = e;
3535                                         data [i].converted = converted;
3536                                         data [i].vi = vi;
3537                                         i++;
3538
3539                                         continue;
3540                                 }
3541
3542                                 //
3543                                 // Case 3: string
3544                                 //
3545                                 if (e.Type == TypeManager.string_type){
3546                                         data [i].is_object = false;
3547                                         data [i].expr = e;
3548                                         data [i].converted = null;
3549                                         data [i].vi = vi;
3550                                         i++;
3551                                 }
3552                         }
3553
3554                         return statement.Resolve (ec);
3555                 }
3556                 
3557                 public override bool Emit (EmitContext ec)
3558                 {
3559                         ILGenerator ig = ec.ig;
3560
3561                         bool is_ret = false;
3562
3563                         for (int i = 0; i < data.Length; i++) {
3564                                 VariableInfo vi = data [i].vi;
3565
3566                                 //
3567                                 // Case 1: & object.
3568                                 //
3569                                 if (data [i].is_object) {
3570                                         //
3571                                         // Store pointer in pinned location
3572                                         //
3573                                         data [i].expr.Emit (ec);
3574                                         ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
3575
3576                                         is_ret = statement.Emit (ec);
3577
3578                                         // Clear the pinned variable.
3579                                         ig.Emit (OpCodes.Ldc_I4_0);
3580                                         ig.Emit (OpCodes.Conv_U);
3581                                         ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
3582
3583                                         continue;
3584                                 }
3585
3586                                 //
3587                                 // Case 2: Array
3588                                 //
3589                                 if (data [i].expr.Type.IsArray){
3590                                         //
3591                                         // Store pointer in pinned location
3592                                         //
3593                                         data [i].converted.Emit (ec);
3594                                         
3595                                         ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
3596
3597                                         is_ret = statement.Emit (ec);
3598                                         
3599                                         // Clear the pinned variable.
3600                                         ig.Emit (OpCodes.Ldc_I4_0);
3601                                         ig.Emit (OpCodes.Conv_U);
3602                                         ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
3603
3604                                         continue;
3605                                 }
3606
3607                                 //
3608                                 // Case 3: string
3609                                 //
3610                                 if (data [i].expr.Type == TypeManager.string_type){
3611                                         LocalBuilder pinned_string = ig.DeclareLocal (TypeManager.string_type);
3612                                         TypeManager.MakePinned (pinned_string);
3613                                         
3614                                         data [i].expr.Emit (ec);
3615                                         ig.Emit (OpCodes.Stloc, pinned_string);
3616
3617                                         Expression sptr = new StringPtr (pinned_string);
3618                                         Expression converted = Expression.ConvertImplicitRequired (
3619                                                 ec, sptr, vi.VariableType, loc);
3620                                         
3621                                         if (converted == null)
3622                                                 continue;
3623
3624                                         converted.Emit (ec);
3625                                         ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
3626                                         
3627                                         is_ret = statement.Emit (ec);
3628
3629                                         // Clear the pinned variable
3630                                         ig.Emit (OpCodes.Ldnull);
3631                                         ig.Emit (OpCodes.Stloc, pinned_string);
3632                                 }
3633                         }
3634
3635                         return is_ret;
3636                 }
3637         }
3638         
3639         public class Catch {
3640                 public readonly Expression Type;
3641                 public readonly string Name;
3642                 public readonly Block  Block;
3643                 public readonly Location Location;
3644                 
3645                 public Catch (Expression type, string name, Block block, Location l)
3646                 {
3647                         Type = type;
3648                         Name = name;
3649                         Block = block;
3650                         Location = l;
3651                 }
3652         }
3653
3654         public class Try : Statement {
3655                 public readonly Block Fini, Block;
3656                 public readonly ArrayList Specific;
3657                 public readonly Catch General;
3658                 
3659                 //
3660                 // specific, general and fini might all be null.
3661                 //
3662                 public Try (Block block, ArrayList specific, Catch general, Block fini, Location l)
3663                 {
3664                         if (specific == null && general == null){
3665                                 Console.WriteLine ("CIR.Try: Either specific or general have to be non-null");
3666                         }
3667                         
3668                         this.Block = block;
3669                         this.Specific = specific;
3670                         this.General = general;
3671                         this.Fini = fini;
3672                         loc = l;
3673                 }
3674
3675                 public override bool Resolve (EmitContext ec)
3676                 {
3677                         bool ok = true;
3678                         
3679                         ec.StartFlowBranching (FlowBranchingType.EXCEPTION, Block.StartLocation);
3680
3681                         Report.Debug (1, "START OF TRY BLOCK", Block.StartLocation);
3682
3683                         if (!Block.Resolve (ec))
3684                                 ok = false;
3685
3686                         FlowBranching.UsageVector vector = ec.CurrentBranching.CurrentUsageVector;
3687
3688                         Report.Debug (1, "START OF CATCH BLOCKS", vector);
3689
3690                         foreach (Catch c in Specific){
3691                                 ec.CurrentBranching.CreateSibling ();
3692                                 Report.Debug (1, "STARTED SIBLING FOR CATCH", ec.CurrentBranching);
3693
3694                                 if (c.Name != null) {
3695                                         VariableInfo vi = c.Block.GetVariableInfo (c.Name);
3696                                         if (vi == null)
3697                                                 throw new Exception ();
3698
3699                                         vi.Number = -1;
3700                                 }
3701
3702                                 if (!c.Block.Resolve (ec))
3703                                         ok = false;
3704
3705                                 FlowBranching.UsageVector current = ec.CurrentBranching.CurrentUsageVector;
3706
3707                                 if ((current.Returns == FlowReturns.NEVER) ||
3708                                     (current.Returns == FlowReturns.SOMETIMES)) {
3709                                         vector.AndLocals (current);
3710                                 }
3711                         }
3712
3713                         if (General != null){
3714                                 ec.CurrentBranching.CreateSibling ();
3715                                 Report.Debug (1, "STARTED SIBLING FOR GENERAL", ec.CurrentBranching);
3716
3717                                 if (!General.Block.Resolve (ec))
3718                                         ok = false;
3719
3720                                 FlowBranching.UsageVector current = ec.CurrentBranching.CurrentUsageVector;
3721
3722                                 if ((current.Returns == FlowReturns.NEVER) ||
3723                                     (current.Returns == FlowReturns.SOMETIMES)) {
3724                                         vector.AndLocals (current);
3725                                 }
3726                         }
3727
3728                         ec.CurrentBranching.CreateSiblingForFinally ();
3729                         Report.Debug (1, "STARTED SIBLING FOR FINALLY", ec.CurrentBranching, vector);
3730
3731                         if (Fini != null)
3732                                 if (!Fini.Resolve (ec))
3733                                         ok = false;
3734
3735                         FlowBranching.UsageVector f_vector = ec.CurrentBranching.CurrentUsageVector;
3736
3737                         FlowReturns returns = ec.EndFlowBranching ();
3738
3739                         Report.Debug (1, "END OF FINALLY", ec.CurrentBranching, returns, vector, f_vector);
3740
3741                         if ((returns == FlowReturns.SOMETIMES) || (returns == FlowReturns.ALWAYS)) {
3742                                 ec.CurrentBranching.CheckOutParameters (f_vector.Parameters, loc);
3743                         }
3744
3745                         ec.CurrentBranching.CurrentUsageVector.Or (vector);
3746
3747                         Report.Debug (1, "END OF TRY", ec.CurrentBranching);
3748
3749                         return ok;
3750                 }
3751                 
3752                 public override bool Emit (EmitContext ec)
3753                 {
3754                         ILGenerator ig = ec.ig;
3755                         Label end;
3756                         Label finish = ig.DefineLabel ();;
3757                         bool returns;
3758
3759                         ec.TryCatchLevel++;
3760                         end = ig.BeginExceptionBlock ();
3761                         bool old_in_try = ec.InTry;
3762                         ec.InTry = true;
3763                         returns = Block.Emit (ec);
3764                         ec.InTry = old_in_try;
3765
3766                         //
3767                         // System.Reflection.Emit provides this automatically:
3768                         // ig.Emit (OpCodes.Leave, finish);
3769
3770                         bool old_in_catch = ec.InCatch;
3771                         ec.InCatch = true;
3772                         DeclSpace ds = ec.DeclSpace;
3773
3774                         foreach (Catch c in Specific){
3775                                 Type catch_type = ds.ResolveType (c.Type, false, c.Location);
3776                                 VariableInfo vi;
3777                                 
3778                                 if (catch_type == null)
3779                                         return false;
3780
3781                                 ig.BeginCatchBlock (catch_type);
3782
3783                                 if (c.Name != null){
3784                                         vi = c.Block.GetVariableInfo (c.Name);
3785                                         if (vi == null)
3786                                                 throw new Exception ("Variable does not exist in this block");
3787
3788                                         ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
3789                                 } else
3790                                         ig.Emit (OpCodes.Pop);
3791                                 
3792                                 if (!c.Block.Emit (ec))
3793                                         returns = false;
3794                         }
3795
3796                         if (General != null){
3797                                 ig.BeginCatchBlock (TypeManager.object_type);
3798                                 ig.Emit (OpCodes.Pop);
3799                                 if (!General.Block.Emit (ec))
3800                                         returns = false;
3801                         }
3802                         ec.InCatch = old_in_catch;
3803
3804                         ig.MarkLabel (finish);
3805                         if (Fini != null){
3806                                 ig.BeginFinallyBlock ();
3807                                 bool old_in_finally = ec.InFinally;
3808                                 ec.InFinally = true;
3809                                 Fini.Emit (ec);
3810                                 ec.InFinally = old_in_finally;
3811                         }
3812                         
3813                         ig.EndExceptionBlock ();
3814                         ec.TryCatchLevel--;
3815
3816                         if (!returns || ec.InTry || ec.InCatch)
3817                                 return returns;
3818
3819                         // Unfortunately, System.Reflection.Emit automatically emits a leave
3820                         // to the end of the finally block.  This is a problem if `returns'
3821                         // is true since we may jump to a point after the end of the method.
3822                         // As a workaround, emit an explicit ret here.
3823
3824                         if (ec.ReturnType != null)
3825                                 ec.ig.Emit (OpCodes.Ldloc, ec.TemporaryReturn ());
3826                         ec.ig.Emit (OpCodes.Ret);
3827
3828                         return true;
3829                 }
3830         }
3831
3832         //
3833         // FIXME: We still do not support the expression variant of the using
3834         // statement.
3835         //
3836         public class Using : Statement {
3837                 object expression_or_block;
3838                 Statement Statement;
3839                 ArrayList var_list;
3840                 Expression expr;
3841                 Type expr_type;
3842                 Expression conv;
3843                 Expression [] converted_vars;
3844                 ExpressionStatement [] assign;
3845                 
3846                 public Using (object expression_or_block, Statement stmt, Location l)
3847                 {
3848                         this.expression_or_block = expression_or_block;
3849                         Statement = stmt;
3850                         loc = l;
3851                 }
3852
3853                 //
3854                 // Resolves for the case of using using a local variable declaration.
3855                 //
3856                 bool ResolveLocalVariableDecls (EmitContext ec)
3857                 {
3858                         bool need_conv = false;
3859                         expr_type = ec.DeclSpace.ResolveType (expr, false, loc);
3860                         int i = 0;
3861
3862                         if (expr_type == null)
3863                                 return false;
3864
3865                         //
3866                         // The type must be an IDisposable or an implicit conversion
3867                         // must exist.
3868                         //
3869                         converted_vars = new Expression [var_list.Count];
3870                         assign = new ExpressionStatement [var_list.Count];
3871                         if (!TypeManager.ImplementsInterface (expr_type, TypeManager.idisposable_type)){
3872                                 foreach (DictionaryEntry e in var_list){
3873                                         Expression var = (Expression) e.Key;
3874
3875                                         var = var.ResolveLValue (ec, new EmptyExpression ());
3876                                         if (var == null)
3877                                                 return false;
3878                                         
3879                                         converted_vars [i] = Expression.ConvertImplicit (
3880                                                 ec, var, TypeManager.idisposable_type, loc);
3881
3882                                         if (converted_vars [i] == null)
3883                                                 return false;
3884                                         i++;
3885                                 }
3886                                 need_conv = true;
3887                         }
3888
3889                         i = 0;
3890                         foreach (DictionaryEntry e in var_list){
3891                                 LocalVariableReference var = (LocalVariableReference) e.Key;
3892                                 Expression new_expr = (Expression) e.Value;
3893                                 Expression a;
3894
3895                                 a = new Assign (var, new_expr, loc);
3896                                 a = a.Resolve (ec);
3897                                 if (a == null)
3898                                         return false;
3899
3900                                 if (!need_conv)
3901                                         converted_vars [i] = var;
3902                                 assign [i] = (ExpressionStatement) a;
3903                                 i++;
3904                         }
3905
3906                         return true;
3907                 }
3908
3909                 bool ResolveExpression (EmitContext ec)
3910                 {
3911                         if (!TypeManager.ImplementsInterface (expr_type, TypeManager.idisposable_type)){
3912                                 conv = Expression.ConvertImplicit (
3913                                         ec, expr, TypeManager.idisposable_type, loc);
3914
3915                                 if (conv == null)
3916                                         return false;
3917                         }
3918
3919                         return true;
3920                 }
3921                 
3922                 //
3923                 // Emits the code for the case of using using a local variable declaration.
3924                 //
3925                 bool EmitLocalVariableDecls (EmitContext ec)
3926                 {
3927                         ILGenerator ig = ec.ig;
3928                         int i = 0;
3929
3930                         bool old_in_try = ec.InTry;
3931                         ec.InTry = true;
3932                         for (i = 0; i < assign.Length; i++) {
3933                                 assign [i].EmitStatement (ec);
3934                                 
3935                                 ig.BeginExceptionBlock ();
3936                         }
3937                         Statement.Emit (ec);
3938                         ec.InTry = old_in_try;
3939
3940                         bool old_in_finally = ec.InFinally;
3941                         ec.InFinally = true;
3942                         var_list.Reverse ();
3943                         foreach (DictionaryEntry e in var_list){
3944                                 LocalVariableReference var = (LocalVariableReference) e.Key;
3945                                 Label skip = ig.DefineLabel ();
3946                                 i--;
3947                                 
3948                                 ig.BeginFinallyBlock ();
3949                                 
3950                                 var.Emit (ec);
3951                                 ig.Emit (OpCodes.Brfalse, skip);
3952                                 converted_vars [i].Emit (ec);
3953                                 ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
3954                                 ig.MarkLabel (skip);
3955                                 ig.EndExceptionBlock ();
3956                         }
3957                         ec.InFinally = old_in_finally;
3958
3959                         return false;
3960                 }
3961
3962                 bool EmitExpression (EmitContext ec)
3963                 {
3964                         //
3965                         // Make a copy of the expression and operate on that.
3966                         //
3967                         ILGenerator ig = ec.ig;
3968                         LocalBuilder local_copy = ig.DeclareLocal (expr_type);
3969                         if (conv != null)
3970                                 conv.Emit (ec);
3971                         else
3972                                 expr.Emit (ec);
3973                         ig.Emit (OpCodes.Stloc, local_copy);
3974
3975                         bool old_in_try = ec.InTry;
3976                         ec.InTry = true;
3977                         ig.BeginExceptionBlock ();
3978                         Statement.Emit (ec);
3979                         ec.InTry = old_in_try;
3980                         
3981                         Label skip = ig.DefineLabel ();
3982                         bool old_in_finally = ec.InFinally;
3983                         ig.BeginFinallyBlock ();
3984                         ig.Emit (OpCodes.Ldloc, local_copy);
3985                         ig.Emit (OpCodes.Brfalse, skip);
3986                         ig.Emit (OpCodes.Ldloc, local_copy);
3987                         ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
3988                         ig.MarkLabel (skip);
3989                         ec.InFinally = old_in_finally;
3990                         ig.EndExceptionBlock ();
3991
3992                         return false;
3993                 }
3994                 
3995                 public override bool Resolve (EmitContext ec)
3996                 {
3997                         if (expression_or_block is DictionaryEntry){
3998                                 expr = (Expression) ((DictionaryEntry) expression_or_block).Key;
3999                                 var_list = (ArrayList)((DictionaryEntry)expression_or_block).Value;
4000
4001                                 if (!ResolveLocalVariableDecls (ec))
4002                                         return false;
4003
4004                         } else if (expression_or_block is Expression){
4005                                 expr = (Expression) expression_or_block;
4006
4007                                 expr = expr.Resolve (ec);
4008                                 if (expr == null)
4009                                         return false;
4010
4011                                 expr_type = expr.Type;
4012
4013                                 if (!ResolveExpression (ec))
4014                                         return false;
4015                         }                       
4016
4017                         return Statement.Resolve (ec);
4018                 }
4019                 
4020                 public override bool Emit (EmitContext ec)
4021                 {
4022                         if (expression_or_block is DictionaryEntry)
4023                                 return EmitLocalVariableDecls (ec);
4024                         else if (expression_or_block is Expression)
4025                                 return EmitExpression (ec);
4026
4027                         return false;
4028                 }
4029         }
4030
4031         /// <summary>
4032         ///   Implementation of the foreach C# statement
4033         /// </summary>
4034         public class Foreach : Statement {
4035                 Expression type;
4036                 LocalVariableReference variable;
4037                 Expression expr;
4038                 Statement statement;
4039                 ForeachHelperMethods hm;
4040                 Expression empty, conv;
4041                 Type array_type, element_type;
4042                 Type var_type;
4043                 
4044                 public Foreach (Expression type, LocalVariableReference var, Expression expr,
4045                                 Statement stmt, Location l)
4046                 {
4047                         this.type = type;
4048                         this.variable = var;
4049                         this.expr = expr;
4050                         statement = stmt;
4051                         loc = l;
4052                 }
4053                 
4054                 public override bool Resolve (EmitContext ec)
4055                 {
4056                         expr = expr.Resolve (ec);
4057                         if (expr == null)
4058                                 return false;
4059
4060                         var_type = ec.DeclSpace.ResolveType (type, false, loc);
4061                         if (var_type == null)
4062                                 return false;
4063                         
4064                         //
4065                         // We need an instance variable.  Not sure this is the best
4066                         // way of doing this.
4067                         //
4068                         // FIXME: When we implement propertyaccess, will those turn
4069                         // out to return values in ExprClass?  I think they should.
4070                         //
4071                         if (!(expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.Value ||
4072                               expr.eclass == ExprClass.PropertyAccess)){
4073                                 error1579 (expr.Type);
4074                                 return false;
4075                         }
4076
4077                         if (expr.Type.IsArray) {
4078                                 array_type = expr.Type;
4079                                 element_type = array_type.GetElementType ();
4080
4081                                 empty = new EmptyExpression (element_type);
4082                         } else {
4083                                 hm = ProbeCollectionType (ec, expr.Type);
4084                                 if (hm == null){
4085                                         error1579 (expr.Type);
4086                                         return false;
4087                                 }
4088
4089                                 array_type = expr.Type;
4090                                 element_type = hm.element_type;
4091
4092                                 empty = new EmptyExpression (hm.element_type);
4093                         }
4094
4095                         //
4096                         // FIXME: maybe we can apply the same trick we do in the
4097                         // array handling to avoid creating empty and conv in some cases.
4098                         //
4099                         // Although it is not as important in this case, as the type
4100                         // will not likely be object (what the enumerator will return).
4101                         //
4102                         conv = Expression.ConvertExplicit (ec, empty, var_type, loc);
4103                         if (conv == null)
4104                                 return false;
4105
4106                         if (variable.ResolveLValue (ec, empty) == null)
4107                                 return false;
4108
4109                         if (!statement.Resolve (ec))
4110                                 return false;
4111
4112                         return true;
4113                 }
4114                 
4115                 //
4116                 // Retrieves a `public bool MoveNext ()' method from the Type `t'
4117                 //
4118                 static MethodInfo FetchMethodMoveNext (Type t)
4119                 {
4120                         MemberInfo [] move_next_list;
4121                         
4122                         move_next_list = TypeContainer.FindMembers (
4123                                 t, MemberTypes.Method,
4124                                 BindingFlags.Public | BindingFlags.Instance,
4125                                 Type.FilterName, "MoveNext");
4126                         if (move_next_list == null || move_next_list.Length == 0)
4127                                 return null;
4128
4129                         foreach (MemberInfo m in move_next_list){
4130                                 MethodInfo mi = (MethodInfo) m;
4131                                 Type [] args;
4132                                 
4133                                 args = TypeManager.GetArgumentTypes (mi);
4134                                 if (args != null && args.Length == 0){
4135                                         if (mi.ReturnType == TypeManager.bool_type)
4136                                                 return mi;
4137                                 }
4138                         }
4139                         return null;
4140                 }
4141                 
4142                 //
4143                 // Retrieves a `public T get_Current ()' method from the Type `t'
4144                 //
4145                 static MethodInfo FetchMethodGetCurrent (Type t)
4146                 {
4147                         MemberInfo [] move_next_list;
4148                         
4149                         move_next_list = TypeContainer.FindMembers (
4150                                 t, MemberTypes.Method,
4151                                 BindingFlags.Public | BindingFlags.Instance,
4152                                 Type.FilterName, "get_Current");
4153                         if (move_next_list == null || move_next_list.Length == 0)
4154                                 return null;
4155
4156                         foreach (MemberInfo m in move_next_list){
4157                                 MethodInfo mi = (MethodInfo) m;
4158                                 Type [] args;
4159
4160                                 args = TypeManager.GetArgumentTypes (mi);
4161                                 if (args != null && args.Length == 0)
4162                                         return mi;
4163                         }
4164                         return null;
4165                 }
4166
4167                 // 
4168                 // This struct records the helper methods used by the Foreach construct
4169                 //
4170                 class ForeachHelperMethods {
4171                         public EmitContext ec;
4172                         public MethodInfo get_enumerator;
4173                         public MethodInfo move_next;
4174                         public MethodInfo get_current;
4175                         public Type element_type;
4176
4177                         public ForeachHelperMethods (EmitContext ec)
4178                         {
4179                                 this.ec = ec;
4180                                 this.element_type = TypeManager.object_type;
4181                         }
4182                 }
4183                 
4184                 static bool GetEnumeratorFilter (MemberInfo m, object criteria)
4185                 {
4186                         if (m == null)
4187                                 return false;
4188                         
4189                         if (!(m is MethodInfo))
4190                                 return false;
4191                         
4192                         if (m.Name != "GetEnumerator")
4193                                 return false;
4194
4195                         MethodInfo mi = (MethodInfo) m;
4196                         Type [] args = TypeManager.GetArgumentTypes (mi);
4197                         if (args != null){
4198                                 if (args.Length != 0)
4199                                         return false;
4200                         }
4201                         ForeachHelperMethods hm = (ForeachHelperMethods) criteria;
4202                         EmitContext ec = hm.ec;
4203
4204                         //
4205                         // Check whether GetEnumerator is accessible to us
4206                         //
4207                         MethodAttributes prot = mi.Attributes & MethodAttributes.MemberAccessMask;
4208
4209                         Type declaring = mi.DeclaringType;
4210                         if (prot == MethodAttributes.Private){
4211                                 if (declaring != ec.ContainerType)
4212                                         return false;
4213                         } else if (prot == MethodAttributes.FamANDAssem){
4214                                 // If from a different assembly, false
4215                                 if (!(mi is MethodBuilder))
4216                                         return false;
4217                                 //
4218                                 // Are we being invoked from the same class, or from a derived method?
4219                                 //
4220                                 if (ec.ContainerType != declaring){
4221                                         if (!ec.ContainerType.IsSubclassOf (declaring))
4222                                                 return false;
4223                                 }
4224                         } else if (prot == MethodAttributes.FamORAssem){
4225                                 if (!(mi is MethodBuilder ||
4226                                       ec.ContainerType == declaring ||
4227                                       ec.ContainerType.IsSubclassOf (declaring)))
4228                                         return false;
4229                         } if (prot == MethodAttributes.Family){
4230                                 if (!(ec.ContainerType == declaring ||
4231                                       ec.ContainerType.IsSubclassOf (declaring)))
4232                                         return false;
4233                         }
4234
4235                         //
4236                         // Ok, we can access it, now make sure that we can do something
4237                         // with this `GetEnumerator'
4238                         //
4239
4240                         if (mi.ReturnType == TypeManager.ienumerator_type ||
4241                             TypeManager.ienumerator_type.IsAssignableFrom (mi.ReturnType) ||
4242                             (!RootContext.StdLib && TypeManager.ImplementsInterface (mi.ReturnType, TypeManager.ienumerator_type))) {
4243                                 hm.move_next = TypeManager.bool_movenext_void;
4244                                 hm.get_current = TypeManager.object_getcurrent_void;
4245                                 return true;
4246                         }
4247
4248                         //
4249                         // Ok, so they dont return an IEnumerable, we will have to
4250                         // find if they support the GetEnumerator pattern.
4251                         //
4252                         Type return_type = mi.ReturnType;
4253
4254                         hm.move_next = FetchMethodMoveNext (return_type);
4255                         if (hm.move_next == null)
4256                                 return false;
4257                         hm.get_current = FetchMethodGetCurrent (return_type);
4258                         if (hm.get_current == null)
4259                                 return false;
4260
4261                         hm.element_type = hm.get_current.ReturnType;
4262
4263                         return true;
4264                 }
4265                 
4266                 /// <summary>
4267                 ///   This filter is used to find the GetEnumerator method
4268                 ///   on which IEnumerator operates
4269                 /// </summary>
4270                 static MemberFilter FilterEnumerator;
4271                 
4272                 static Foreach ()
4273                 {
4274                         FilterEnumerator = new MemberFilter (GetEnumeratorFilter);
4275                 }
4276
4277                 void error1579 (Type t)
4278                 {
4279                         Report.Error (1579, loc,
4280                                       "foreach statement cannot operate on variables of type `" +
4281                                       t.FullName + "' because that class does not provide a " +
4282                                       " GetEnumerator method or it is inaccessible");
4283                 }
4284
4285                 static bool TryType (Type t, ForeachHelperMethods hm)
4286                 {
4287                         MemberInfo [] mi;
4288                         
4289                         mi = TypeContainer.FindMembers (t, MemberTypes.Method,
4290                                                         BindingFlags.Public | BindingFlags.NonPublic |
4291                                                         BindingFlags.Instance,
4292                                                         FilterEnumerator, hm);
4293
4294                         if (mi == null || mi.Length == 0)
4295                                 return false;
4296
4297                         hm.get_enumerator = (MethodInfo) mi [0];
4298                         return true;    
4299                 }
4300                 
4301                 //
4302                 // Looks for a usable GetEnumerator in the Type, and if found returns
4303                 // the three methods that participate: GetEnumerator, MoveNext and get_Current
4304                 //
4305                 ForeachHelperMethods ProbeCollectionType (EmitContext ec, Type t)
4306                 {
4307                         ForeachHelperMethods hm = new ForeachHelperMethods (ec);
4308
4309                         if (TryType (t, hm))
4310                                 return hm;
4311
4312                         //
4313                         // Now try to find the method in the interfaces
4314                         //
4315                         while (t != null){
4316                                 Type [] ifaces = t.GetInterfaces ();
4317
4318                                 foreach (Type i in ifaces){
4319                                         if (TryType (i, hm))
4320                                                 return hm;
4321                                 }
4322                                 
4323                                 //
4324                                 // Since TypeBuilder.GetInterfaces only returns the interface
4325                                 // types for this type, we have to keep looping, but once
4326                                 // we hit a non-TypeBuilder (ie, a Type), then we know we are
4327                                 // done, because it returns all the types
4328                                 //
4329                                 if ((t is TypeBuilder))
4330                                         t = t.BaseType;
4331                                 else
4332                                         break;
4333                         } 
4334
4335                         return null;
4336                 }
4337
4338                 //
4339                 // FIXME: possible optimization.
4340                 // We might be able to avoid creating `empty' if the type is the sam
4341                 //
4342                 bool EmitCollectionForeach (EmitContext ec)
4343                 {
4344                         ILGenerator ig = ec.ig;
4345                         LocalBuilder enumerator, disposable;
4346
4347                         enumerator = ig.DeclareLocal (TypeManager.ienumerator_type);
4348                         disposable = ig.DeclareLocal (TypeManager.idisposable_type);
4349                         
4350                         //
4351                         // Instantiate the enumerator
4352                         //
4353                         if (expr.Type.IsValueType){
4354                                 if (expr is IMemoryLocation){
4355                                         IMemoryLocation ml = (IMemoryLocation) expr;
4356
4357                                         ml.AddressOf (ec, AddressOp.Load);
4358                                 } else
4359                                         throw new Exception ("Expr " + expr + " of type " + expr.Type +
4360                                                              " does not implement IMemoryLocation");
4361                                 ig.Emit (OpCodes.Call, hm.get_enumerator);
4362                         } else {
4363                                 expr.Emit (ec);
4364                                 ig.Emit (OpCodes.Callvirt, hm.get_enumerator);
4365                         }
4366                         ig.Emit (OpCodes.Stloc, enumerator);
4367
4368                         //
4369                         // Protect the code in a try/finalize block, so that
4370                         // if the beast implement IDisposable, we get rid of it
4371                         //
4372                         Label l = ig.BeginExceptionBlock ();
4373                         bool old_in_try = ec.InTry;
4374                         ec.InTry = true;
4375                         
4376                         Label end_try = ig.DefineLabel ();
4377                         
4378                         ig.MarkLabel (ec.LoopBegin);
4379                         ig.Emit (OpCodes.Ldloc, enumerator);
4380                         ig.Emit (OpCodes.Callvirt, hm.move_next);
4381                         ig.Emit (OpCodes.Brfalse, end_try);
4382                         ig.Emit (OpCodes.Ldloc, enumerator);
4383                         ig.Emit (OpCodes.Callvirt, hm.get_current);
4384                         variable.EmitAssign (ec, conv);
4385                         statement.Emit (ec);
4386                         ig.Emit (OpCodes.Br, ec.LoopBegin);
4387                         ig.MarkLabel (end_try);
4388                         ec.InTry = old_in_try;
4389                         
4390                         // The runtime provides this for us.
4391                         // ig.Emit (OpCodes.Leave, end);
4392
4393                         //
4394                         // Now the finally block
4395                         //
4396                         Label end_finally = ig.DefineLabel ();
4397                         bool old_in_finally = ec.InFinally;
4398                         ec.InFinally = true;
4399                         ig.BeginFinallyBlock ();
4400                         
4401                         ig.Emit (OpCodes.Ldloc, enumerator);
4402                         ig.Emit (OpCodes.Isinst, TypeManager.idisposable_type);
4403                         ig.Emit (OpCodes.Stloc, disposable);
4404                         ig.Emit (OpCodes.Ldloc, disposable);
4405                         ig.Emit (OpCodes.Brfalse, end_finally);
4406                         ig.Emit (OpCodes.Ldloc, disposable);
4407                         ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
4408                         ig.MarkLabel (end_finally);
4409                         ec.InFinally = old_in_finally;
4410
4411                         // The runtime generates this anyways.
4412                         // ig.Emit (OpCodes.Endfinally);
4413
4414                         ig.EndExceptionBlock ();
4415
4416                         ig.MarkLabel (ec.LoopEnd);
4417                         return false;
4418                 }
4419
4420                 //
4421                 // FIXME: possible optimization.
4422                 // We might be able to avoid creating `empty' if the type is the sam
4423                 //
4424                 bool EmitArrayForeach (EmitContext ec)
4425                 {
4426                         int rank = array_type.GetArrayRank ();
4427                         ILGenerator ig = ec.ig;
4428
4429                         LocalBuilder copy = ig.DeclareLocal (array_type);
4430                         
4431                         //
4432                         // Make our copy of the array
4433                         //
4434                         expr.Emit (ec);
4435                         ig.Emit (OpCodes.Stloc, copy);
4436                         
4437                         if (rank == 1){
4438                                 LocalBuilder counter = ig.DeclareLocal (TypeManager.int32_type);
4439
4440                                 Label loop, test;
4441                                 
4442                                 ig.Emit (OpCodes.Ldc_I4_0);
4443                                 ig.Emit (OpCodes.Stloc, counter);
4444                                 test = ig.DefineLabel ();
4445                                 ig.Emit (OpCodes.Br, test);
4446
4447                                 loop = ig.DefineLabel ();
4448                                 ig.MarkLabel (loop);
4449
4450                                 ig.Emit (OpCodes.Ldloc, copy);
4451                                 ig.Emit (OpCodes.Ldloc, counter);
4452                                 ArrayAccess.EmitLoadOpcode (ig, var_type);
4453
4454                                 variable.EmitAssign (ec, conv);
4455
4456                                 statement.Emit (ec);
4457
4458                                 ig.MarkLabel (ec.LoopBegin);
4459                                 ig.Emit (OpCodes.Ldloc, counter);
4460                                 ig.Emit (OpCodes.Ldc_I4_1);
4461                                 ig.Emit (OpCodes.Add);
4462                                 ig.Emit (OpCodes.Stloc, counter);
4463
4464                                 ig.MarkLabel (test);
4465                                 ig.Emit (OpCodes.Ldloc, counter);
4466                                 ig.Emit (OpCodes.Ldloc, copy);
4467                                 ig.Emit (OpCodes.Ldlen);
4468                                 ig.Emit (OpCodes.Conv_I4);
4469                                 ig.Emit (OpCodes.Blt, loop);
4470                         } else {
4471                                 LocalBuilder [] dim_len   = new LocalBuilder [rank];
4472                                 LocalBuilder [] dim_count = new LocalBuilder [rank];
4473                                 Label [] loop = new Label [rank];
4474                                 Label [] test = new Label [rank];
4475                                 int dim;
4476                                 
4477                                 for (dim = 0; dim < rank; dim++){
4478                                         dim_len [dim] = ig.DeclareLocal (TypeManager.int32_type);
4479                                         dim_count [dim] = ig.DeclareLocal (TypeManager.int32_type);
4480                                         test [dim] = ig.DefineLabel ();
4481                                         loop [dim] = ig.DefineLabel ();
4482                                 }
4483                                         
4484                                 for (dim = 0; dim < rank; dim++){
4485                                         ig.Emit (OpCodes.Ldloc, copy);
4486                                         IntLiteral.EmitInt (ig, dim);
4487                                         ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int);
4488                                         ig.Emit (OpCodes.Stloc, dim_len [dim]);
4489                                 }
4490
4491                                 for (dim = 0; dim < rank; dim++){
4492                                         ig.Emit (OpCodes.Ldc_I4_0);
4493                                         ig.Emit (OpCodes.Stloc, dim_count [dim]);
4494                                         ig.Emit (OpCodes.Br, test [dim]);
4495                                         ig.MarkLabel (loop [dim]);
4496                                 }
4497
4498                                 ig.Emit (OpCodes.Ldloc, copy);
4499                                 for (dim = 0; dim < rank; dim++)
4500                                         ig.Emit (OpCodes.Ldloc, dim_count [dim]);
4501
4502                                 //
4503                                 // FIXME: Maybe we can cache the computation of `get'?
4504                                 //
4505                                 Type [] args = new Type [rank];
4506                                 MethodInfo get;
4507
4508                                 for (int i = 0; i < rank; i++)
4509                                         args [i] = TypeManager.int32_type;
4510
4511                                 ModuleBuilder mb = CodeGen.ModuleBuilder;
4512                                 get = mb.GetArrayMethod (
4513                                         array_type, "Get",
4514                                         CallingConventions.HasThis| CallingConventions.Standard,
4515                                         var_type, args);
4516                                 ig.Emit (OpCodes.Call, get);
4517                                 variable.EmitAssign (ec, conv);
4518                                 statement.Emit (ec);
4519                                 ig.MarkLabel (ec.LoopBegin);
4520                                 for (dim = rank - 1; dim >= 0; dim--){
4521                                         ig.Emit (OpCodes.Ldloc, dim_count [dim]);
4522                                         ig.Emit (OpCodes.Ldc_I4_1);
4523                                         ig.Emit (OpCodes.Add);
4524                                         ig.Emit (OpCodes.Stloc, dim_count [dim]);
4525
4526                                         ig.MarkLabel (test [dim]);
4527                                         ig.Emit (OpCodes.Ldloc, dim_count [dim]);
4528                                         ig.Emit (OpCodes.Ldloc, dim_len [dim]);
4529                                         ig.Emit (OpCodes.Blt, loop [dim]);
4530                                 }
4531                         }
4532                         ig.MarkLabel (ec.LoopEnd);
4533                         
4534                         return false;
4535                 }
4536                 
4537                 public override bool Emit (EmitContext ec)
4538                 {
4539                         bool ret_val;
4540                         
4541                         ILGenerator ig = ec.ig;
4542                         
4543                         Label old_begin = ec.LoopBegin, old_end = ec.LoopEnd;
4544                         bool old_inloop = ec.InLoop;
4545                         int old_loop_begin_try_catch_level = ec.LoopBeginTryCatchLevel;
4546                         ec.LoopBegin = ig.DefineLabel ();
4547                         ec.LoopEnd = ig.DefineLabel ();
4548                         ec.InLoop = true;
4549                         ec.LoopBeginTryCatchLevel = ec.TryCatchLevel;
4550                         
4551                         if (hm != null)
4552                                 ret_val = EmitCollectionForeach (ec);
4553                         else
4554                                 ret_val = EmitArrayForeach (ec);
4555                         
4556                         ec.LoopBegin = old_begin;
4557                         ec.LoopEnd = old_end;
4558                         ec.InLoop = old_inloop;
4559                         ec.LoopBeginTryCatchLevel = old_loop_begin_try_catch_level;
4560
4561                         return ret_val;
4562                 }
4563         }
4564 }
4565