c7ef137b709788bd3863ca9705490ffdf1a34cc6
[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.Reflection;
12 using System.Reflection.Emit;
13 using System.Diagnostics;
14
15 namespace Mono.CSharp {
16
17         using System.Collections;
18         
19         public abstract class Statement {
20                 public Location loc;
21                 
22                 ///
23                 /// Resolves the statement, true means that all sub-statements
24                 /// did resolve ok.
25                 //
26                 public virtual bool Resolve (EmitContext ec)
27                 {
28                         return true;
29                 }
30                 
31                 /// <summary>
32                 ///   Return value indicates whether all code paths emitted return.
33                 /// </summary>
34                 public abstract bool Emit (EmitContext ec);
35                 
36                 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
37                 {
38                         e = e.Resolve (ec);
39                         if (e == null)
40                                 return null;
41                         
42                         if (e.Type != TypeManager.bool_type){
43                                 e = Expression.ConvertImplicit (ec, e, TypeManager.bool_type,
44                                                                 new Location (-1));
45                         }
46
47                         if (e == null){
48                                 Report.Error (
49                                         31, loc, "Can not convert the expression to a boolean");
50                         }
51
52                         if (CodeGen.SymbolWriter != null)
53                                 ec.Mark (loc);
54
55                         return e;
56                 }
57                 
58                 /// <remarks>
59                 ///    Emits a bool expression.
60                 /// </remarks>
61                 public static void EmitBoolExpression (EmitContext ec, Expression bool_expr,
62                                                        Label target, bool isTrue)
63                 {
64                         ILGenerator ig = ec.ig;
65                         
66                         bool invert = false;
67                         if (bool_expr is Unary){
68                                 Unary u = (Unary) bool_expr;
69                                 
70                                 if (u.Oper == Unary.Operator.LogicalNot){
71                                         invert = true;
72
73                                         u.EmitLogicalNot (ec);
74                                 }
75                         } 
76
77                         if (!invert)
78                                 bool_expr.Emit (ec);
79
80                         if (isTrue){
81                                 if (invert)
82                                         ig.Emit (OpCodes.Brfalse, target);
83                                 else
84                                         ig.Emit (OpCodes.Brtrue, target);
85                         } else {
86                                 if (invert)
87                                         ig.Emit (OpCodes.Brtrue, target);
88                                 else
89                                         ig.Emit (OpCodes.Brfalse, target);
90                         }
91                 }
92
93                 public static void Warning_DeadCodeFound (Location loc)
94                 {
95                         Report.Warning (162, loc, "Unreachable code detected");
96                 }
97         }
98
99         public class EmptyStatement : Statement {
100                 public override bool Resolve (EmitContext ec)
101                 {
102                         return true;
103                 }
104                 
105                 public override bool Emit (EmitContext ec)
106                 {
107                         return false;
108                 }
109         }
110         
111         public class If : Statement {
112                 Expression expr;
113                 public Statement TrueStatement;
114                 public Statement FalseStatement;
115                 
116                 public If (Expression expr, Statement trueStatement, Location l)
117                 {
118                         this.expr = expr;
119                         TrueStatement = trueStatement;
120                         loc = l;
121                 }
122
123                 public If (Expression expr,
124                            Statement trueStatement,
125                            Statement falseStatement,
126                            Location l)
127                 {
128                         this.expr = expr;
129                         TrueStatement = trueStatement;
130                         FalseStatement = falseStatement;
131                         loc = l;
132                 }
133
134                 public override bool Resolve (EmitContext ec)
135                 {
136                         expr = ResolveBoolean (ec, expr, loc);
137                         if (expr == null){
138                                 return false;
139                         }
140                         
141                         if (TrueStatement.Resolve (ec)){
142                                 if (FalseStatement != null){
143                                         if (FalseStatement.Resolve (ec))
144                                                 return true;
145                                         
146                                         return false;
147                                 }
148                                 return true;
149                         }
150                         return false;
151                 }
152                 
153                 public override bool Emit (EmitContext ec)
154                 {
155                         ILGenerator ig = ec.ig;
156                         Label false_target = ig.DefineLabel ();
157                         Label end;
158                         bool is_true_ret, is_false_ret;
159
160                         //
161                         // Dead code elimination
162                         //
163                         if (expr is BoolConstant){
164                                 bool take = ((BoolConstant) expr).Value;
165
166                                 if (take){
167                                         if (FalseStatement != null){
168                                                 Warning_DeadCodeFound (FalseStatement.loc);
169                                         }
170                                         return TrueStatement.Emit (ec);
171                                 } else {
172                                         Warning_DeadCodeFound (TrueStatement.loc);
173                                         if (FalseStatement != null)
174                                                 return FalseStatement.Emit (ec);
175                                 }
176                         }
177                         
178                         EmitBoolExpression (ec, expr, false_target, false);
179                         
180                         is_true_ret = TrueStatement.Emit (ec);
181                         is_false_ret = is_true_ret;
182
183                         if (FalseStatement != null){
184                                 bool branch_emitted = false;
185                                 
186                                 end = ig.DefineLabel ();
187                                 if (!is_true_ret){
188                                         ig.Emit (OpCodes.Br, end);
189                                         branch_emitted = true;
190                                 }
191                         
192                                 ig.MarkLabel (false_target);
193                                 is_false_ret = FalseStatement.Emit (ec);
194
195                                 if (branch_emitted)
196                                         ig.MarkLabel (end);
197                         } else {
198                                 ig.MarkLabel (false_target);
199                                 is_false_ret = false;
200                         }
201
202                         return is_true_ret && is_false_ret;
203                 }
204         }
205
206         public class Do : Statement {
207                 public Expression expr;
208                 public readonly Statement  EmbeddedStatement;
209                 
210                 public Do (Statement statement, Expression boolExpr, Location l)
211                 {
212                         expr = boolExpr;
213                         EmbeddedStatement = statement;
214                         loc = l;
215                 }
216
217                 public override bool Resolve (EmitContext ec)
218                 {
219                         expr = ResolveBoolean (ec, expr, loc);
220                         if (expr == null)
221                                 return false;
222                         
223                         return EmbeddedStatement.Resolve (ec);
224                 }
225                 
226                 public override bool Emit (EmitContext ec)
227                 {
228                         ILGenerator ig = ec.ig;
229                         Label loop = ig.DefineLabel ();
230                         Label old_begin = ec.LoopBegin;
231                         Label old_end = ec.LoopEnd;
232                         bool  old_inloop = ec.InLoop;
233                         bool old_breaks = ec.Breaks;
234                         
235                         ec.LoopBegin = ig.DefineLabel ();
236                         ec.LoopEnd = ig.DefineLabel ();
237                         ec.InLoop = true;
238                                 
239                         ig.MarkLabel (loop);
240                         ec.Breaks = false;
241                         EmbeddedStatement.Emit (ec);
242                         bool breaks = ec.Breaks;
243                         ig.MarkLabel (ec.LoopBegin);
244
245                         //
246                         // Dead code elimination
247                         //
248                         if (expr is BoolConstant){
249                                 bool res = ((BoolConstant) expr).Value;
250
251                                 if (res)
252                                         ec.ig.Emit (OpCodes.Br, loop); 
253                         } else
254                                 EmitBoolExpression (ec, expr, loop, true);
255                         
256                         ig.MarkLabel (ec.LoopEnd);
257
258                         ec.LoopBegin = old_begin;
259                         ec.LoopEnd = old_end;
260                         ec.InLoop = old_inloop;
261                         ec.Breaks = old_breaks;
262
263                         //
264                         // Inform whether we are infinite or not
265                         //
266                         if (expr is BoolConstant){
267                                 BoolConstant bc = (BoolConstant) expr;
268
269                                 if (bc.Value == true)
270                                         return breaks == false;
271                         }
272                         
273                         return false;
274                 }
275         }
276
277         public class While : Statement {
278                 public Expression expr;
279                 public readonly Statement Statement;
280                 
281                 public While (Expression boolExpr, Statement statement, Location l)
282                 {
283                         this.expr = boolExpr;
284                         Statement = statement;
285                         loc = l;
286                 }
287
288                 public override bool Resolve (EmitContext ec)
289                 {
290                         expr = ResolveBoolean (ec, expr, loc);
291                         if (expr == null)
292                                 return false;
293                         
294                         return Statement.Resolve (ec);
295                 }
296                 
297                 public override bool Emit (EmitContext ec)
298                 {
299                         ILGenerator ig = ec.ig;
300                         Label old_begin = ec.LoopBegin;
301                         Label old_end = ec.LoopEnd;
302                         bool old_inloop = ec.InLoop;
303                         bool old_breaks = ec.Breaks;
304                         Label while_loop = ig.DefineLabel ();
305                         bool ret;
306                         
307                         ec.LoopBegin = ig.DefineLabel ();
308                         ec.LoopEnd = ig.DefineLabel ();
309                         ec.InLoop = true;
310
311                         ig.Emit (OpCodes.Br, ec.LoopBegin);
312                         ig.MarkLabel (while_loop);
313
314                         //
315                         // Inform whether we are infinite or not
316                         //
317                         if (expr is BoolConstant){
318                                 BoolConstant bc = (BoolConstant) expr;
319
320                                 ig.MarkLabel (ec.LoopBegin);
321                                 if (bc.Value == false){
322                                         Warning_DeadCodeFound (Statement.loc);
323                                         ret = false;
324                                 } else {
325                                         bool breaks;
326                                         
327                                         ec.Breaks = false;
328                                         Statement.Emit (ec);
329                                         breaks = ec.Breaks;
330                                         ig.Emit (OpCodes.Br, ec.LoopBegin);
331                                         
332                                         //
333                                         // Inform that we are infinite (ie, `we return'), only
334                                         // if we do not `break' inside the code.
335                                         //
336                                         ret = breaks == false;
337                                 }
338                                 ig.MarkLabel (ec.LoopEnd);
339                         } else {
340                                 Statement.Emit (ec);
341                         
342                                 ig.MarkLabel (ec.LoopBegin);
343
344                                 EmitBoolExpression (ec, expr, while_loop, true);
345                                 ig.MarkLabel (ec.LoopEnd);
346
347                                 ret = false;
348                         }       
349
350                         ec.LoopBegin = old_begin;
351                         ec.LoopEnd = old_end;
352                         ec.InLoop = old_inloop;
353                         ec.Breaks = old_breaks;
354
355                         return ret;
356                 }
357         }
358
359         public class For : Statement {
360                 Expression Test;
361                 readonly Statement InitStatement;
362                 readonly Statement Increment;
363                 readonly Statement Statement;
364                 
365                 public For (Statement initStatement,
366                             Expression test,
367                             Statement increment,
368                             Statement statement,
369                             Location l)
370                 {
371                         InitStatement = initStatement;
372                         Test = test;
373                         Increment = increment;
374                         Statement = statement;
375                         loc = l;
376                 }
377
378                 public override bool Resolve (EmitContext ec)
379                 {
380                         bool ok = true;
381
382                         if (Test != null){
383                                 Test = ResolveBoolean (ec, Test, loc);
384                                 if (Test == null)
385                                         ok = false;
386                         }
387
388                         if (InitStatement != null){
389                                 if (!InitStatement.Resolve (ec))
390                                         ok = false;
391                         }
392
393                         if (Increment != null){
394                                 if (!Increment.Resolve (ec))
395                                         ok = false;
396                         }
397                         
398                         return Statement.Resolve (ec) && ok;
399                 }
400                 
401                 public override bool Emit (EmitContext ec)
402                 {
403                         ILGenerator ig = ec.ig;
404                         Label old_begin = ec.LoopBegin;
405                         Label old_end = ec.LoopEnd;
406                         bool old_inloop = ec.InLoop;
407                         bool old_breaks = ec.Breaks;
408                         Label loop = ig.DefineLabel ();
409
410                         if (InitStatement != null)
411                                 if (! (InitStatement is EmptyStatement))
412                                         InitStatement.Emit (ec);
413
414                         ec.LoopBegin = ig.DefineLabel ();
415                         ec.LoopEnd = ig.DefineLabel ();
416                         ec.InLoop = true;
417
418                         ig.MarkLabel (loop);
419
420                         //
421                         // If test is null, there is no test, and we are just
422                         // an infinite loop
423                         //
424                         if (Test != null)
425                                 EmitBoolExpression (ec, Test, ec.LoopEnd, false);
426
427                         ec.Breaks = false;
428                         Statement.Emit (ec);
429                         bool breaks = ec.Breaks;
430
431                         ig.MarkLabel (ec.LoopBegin);
432                         if (!(Increment is EmptyStatement))
433                                 Increment.Emit (ec);
434                         ig.Emit (OpCodes.Br, loop);
435                         ig.MarkLabel (ec.LoopEnd);
436
437                         ec.LoopBegin = old_begin;
438                         ec.LoopEnd = old_end;
439                         ec.InLoop = old_inloop;
440                         ec.Breaks = old_breaks;
441                         
442                         //
443                         // Inform whether we are infinite or not
444                         //
445                         if (Test != null){
446                                 if (Test is BoolConstant){
447                                         BoolConstant bc = (BoolConstant) Test;
448
449                                         if (bc.Value)
450                                                 return breaks == false;
451                                 }
452                                 return false;
453                         } else
454                                 return true;
455                 }
456         }
457         
458         public class StatementExpression : Statement {
459                 Expression expr;
460                 
461                 public StatementExpression (ExpressionStatement expr, Location l)
462                 {
463                         this.expr = expr;
464                         loc = l;
465                 }
466
467                 public override bool Resolve (EmitContext ec)
468                 {
469                         expr = (Expression) expr.Resolve (ec);
470                         return expr != null;
471                 }
472                 
473                 public override bool Emit (EmitContext ec)
474                 {
475                         ILGenerator ig = ec.ig;
476                         
477                         if (expr is ExpressionStatement)
478                                 ((ExpressionStatement) expr).EmitStatement (ec);
479                         else {
480                                 expr.Emit (ec);
481                                 ig.Emit (OpCodes.Pop);
482                         }
483
484                         return false;
485                 }
486
487                 public override string ToString ()
488                 {
489                         return "StatementExpression (" + expr + ")";
490                 }
491         }
492
493         /// <summary>
494         ///   Implements the return statement
495         /// </summary>
496         public class Return : Statement {
497                 public Expression Expr;
498                 
499                 public Return (Expression expr, Location l)
500                 {
501                         Expr = expr;
502                         loc = l;
503                 }
504
505                 public override bool Resolve (EmitContext ec)
506                 {
507                         if (Expr != null){
508                                 Expr = Expr.Resolve (ec);
509                                 if (Expr == null)
510                                         return false;
511                         }
512                         return true;
513                 }
514                 
515                 public override bool Emit (EmitContext ec)
516                 {
517                         if (ec.InFinally){
518                                 Report.Error (157,loc,"Control can not leave the body of the finally block");
519                                 return false;
520                         }
521                         
522                         if (ec.ReturnType == null){
523                                 if (Expr != null){
524                                         Report.Error (127, loc, "Return with a value not allowed here");
525                                         return false;
526                                 }
527                         } else {
528                                 if (Expr == null){
529                                         Report.Error (126, loc, "An object of type `" +
530                                                       TypeManager.CSharpName (ec.ReturnType) + "' is " +
531                                                       "expected for the return statement");
532                                         return false;
533                                 }
534
535                                 if (Expr.Type != ec.ReturnType)
536                                         Expr = Expression.ConvertImplicitRequired (
537                                                 ec, Expr, ec.ReturnType, loc);
538
539                                 if (Expr == null)
540                                         return false;
541
542                                 Expr.Emit (ec);
543
544                                 if (ec.InTry || ec.InCatch)
545                                         ec.ig.Emit (OpCodes.Stloc, ec.TemporaryReturn ());
546                         }
547
548                         if (ec.InTry || ec.InCatch)
549                                 ec.ig.Emit (OpCodes.Leave, ec.ReturnLabel);
550                         else
551                                 ec.ig.Emit (OpCodes.Ret);
552
553                         return true; 
554                 }
555         }
556
557         public class Goto : Statement {
558                 string target;
559                 Block block;
560                 
561                 public override bool Resolve (EmitContext ec)
562                 {
563                         return true;
564                 }
565                 
566                 public Goto (Block parent_block, string label, Location l)
567                 {
568                         block = parent_block;
569                         loc = l;
570                         target = label;
571                 }
572
573                 public string Target {
574                         get {
575                                 return target;
576                         }
577                 }
578
579                 public override bool Emit (EmitContext ec)
580                 {
581                         LabeledStatement label = block.LookupLabel (target);
582
583                         if (label == null){
584                                 //
585                                 // Maybe we should catch this before?
586                                 //
587                                 Report.Error (
588                                         159, loc,
589                                         "No such label `" + target + "' in this scope");
590                                 return false;
591                         }
592                         Label l = label.LabelTarget (ec);
593                         ec.ig.Emit (OpCodes.Br, l);
594                         
595                         return false;
596                 }
597         }
598
599         public class LabeledStatement : Statement {
600                 string label_name;
601                 bool defined;
602                 Label label;
603                 
604                 public LabeledStatement (string label_name)
605                 {
606                         this.label_name = label_name;
607                 }
608
609                 public Label LabelTarget (EmitContext ec)
610                 {
611                         if (defined)
612                                 return label;
613                         label = ec.ig.DefineLabel ();
614                         defined = true;
615
616                         return label;
617                 }
618
619                 public override bool Emit (EmitContext ec)
620                 {
621                         LabelTarget (ec);
622                         ec.ig.MarkLabel (label);
623
624                         return false;
625                 }
626         }
627         
628
629         /// <summary>
630         ///   `goto default' statement
631         /// </summary>
632         public class GotoDefault : Statement {
633                 
634                 public GotoDefault (Location l)
635                 {
636                         loc = l;
637                 }
638
639                 public override bool Emit (EmitContext ec)
640                 {
641                         if (ec.Switch == null){
642                                 Report.Error (153, loc, "goto default is only valid in a switch statement");
643                                 return false;
644                         }
645
646                         if (!ec.Switch.GotDefault){
647                                 Report.Error (159, loc, "No default target on switch statement");
648                                 return false;
649                         }
650                         ec.ig.Emit (OpCodes.Br, ec.Switch.DefaultTarget);
651                         return false;
652                 }
653         }
654
655         /// <summary>
656         ///   `goto case' statement
657         /// </summary>
658         public class GotoCase : Statement {
659                 Expression expr;
660                 
661                 public GotoCase (Expression e, Location l)
662                 {
663                         expr = e;
664                         loc = l;
665                 }
666
667                 public override bool Emit (EmitContext ec)
668                 {
669                         if (ec.Switch == null){
670                                 Report.Error (153, loc, "goto case is only valid in a switch statement");
671                                 return false;
672                         }
673
674                         expr = expr.Resolve (ec);
675                         if (expr == null)
676                                 return false;
677
678                         if (!(expr is Constant)){
679                                 Report.Error (159, loc, "Target expression for goto case is not constant");
680                                 return false;
681                         }
682
683                         object val = Expression.ConvertIntLiteral (
684                                 (Constant) expr, ec.Switch.SwitchType, loc);
685
686                         if (val == null)
687                                 return false;
688                                         
689                         SwitchLabel sl = (SwitchLabel) ec.Switch.Elements [val];
690
691                         if (sl == null){
692                                 Report.Error (
693                                         159, loc,
694                                         "No such label 'case " + val + "': for the goto case");
695                         }
696
697                         ec.ig.Emit (OpCodes.Br, sl.ILLabelCode);
698                         return true;
699                 }
700         }
701         
702         public class Throw : Statement {
703                 Expression expr;
704                 
705                 public Throw (Expression expr, Location l)
706                 {
707                         this.expr = expr;
708                         loc = l;
709                 }
710
711                 public override bool Resolve (EmitContext ec)
712                 {
713                         if (expr != null){
714                                 expr = expr.Resolve (ec);
715                                 if (expr == null)
716                                         return false;
717                         }
718                         return true;
719                 }
720                         
721                 public override bool Emit (EmitContext ec)
722                 {
723                         if (expr == null){
724                                 if (ec.InCatch)
725                                         ec.ig.Emit (OpCodes.Rethrow);
726                                 else {
727                                         Report.Error (
728                                                 156, loc,
729                                                 "A throw statement with no argument is only " +
730                                                 "allowed in a catch clause");
731                                 }
732                                 return false;
733                         }
734                         
735                         expr.Emit (ec);
736
737                         ec.ig.Emit (OpCodes.Throw);
738
739                         return true;
740                 }
741         }
742
743         public class Break : Statement {
744                 
745                 public Break (Location l)
746                 {
747                         loc = l;
748                 }
749
750                 public override bool Emit (EmitContext ec)
751                 {
752                         ILGenerator ig = ec.ig;
753
754                         if (ec.InLoop == false && ec.Switch == null){
755                                 Report.Error (139, loc, "No enclosing loop or switch to continue to");
756                                 return false;
757                         }
758
759                         ec.Breaks = true;
760                         ig.Emit (OpCodes.Br, ec.LoopEnd);
761
762                         return false;
763                 }
764         }
765
766         public class Continue : Statement {
767                 
768                 public Continue (Location l)
769                 {
770                         loc = l;
771                 }
772
773                 public override bool Emit (EmitContext ec)
774                 {
775                         Label begin = ec.LoopBegin;
776                         
777                         if (!ec.InLoop){
778                                 Report.Error (139, loc, "No enclosing loop to continue to");
779                                 return false;
780                         } 
781
782                         //
783                         // UGH: Non trivial.  This Br might cross a try/catch boundary
784                         // How can we tell?
785                         //
786                         // while () {
787                         //   try { ... } catch { continue; }
788                         // }
789                         //
790                         // From:
791                         // try {} catch { while () { continue; }}
792                         //
793                         ec.ig.Emit (OpCodes.Br, begin);
794                         return false;
795                 }
796         }
797         
798         public class VariableInfo {
799                 public readonly string Type;
800                 public LocalBuilder LocalBuilder;
801                 public Type VariableType;
802                 public readonly Location Location;
803                 
804                 public bool Used;
805                 public bool Assigned;
806                 public bool ReadOnly;
807                 
808                 public VariableInfo (string type, Location l)
809                 {
810                         Type = type;
811                         LocalBuilder = null;
812                         Location = l;
813                 }
814
815                 public void MakePinned ()
816                 {
817                         TypeManager.MakePinned (LocalBuilder);
818                 }                               
819         }
820                 
821         /// <summary>
822         ///   Block represents a C# block.
823         /// </summary>
824         ///
825         /// <remarks>
826         ///   This class is used in a number of places: either to represent
827         ///   explicit blocks that the programmer places or implicit blocks.
828         ///
829         ///   Implicit blocks are used as labels or to introduce variable
830         ///   declarations.
831         /// </remarks>
832         public class Block : Statement {
833                 public readonly Block     Parent;
834                 public readonly bool      Implicit;
835                 public readonly Location  StartLocation;
836                 public Location           EndLocation;
837
838                 //
839                 // The statements in this block
840                 //
841                 ArrayList statements;
842
843                 //
844                 // An array of Blocks.  We keep track of children just
845                 // to generate the local variable declarations.
846                 //
847                 // Statements and child statements are handled through the
848                 // statements.
849                 //
850                 ArrayList children;
851                 
852                 //
853                 // Labels.  (label, block) pairs.
854                 //
855                 Hashtable labels;
856
857                 //
858                 // Keeps track of (name, type) pairs
859                 //
860                 Hashtable variables;
861
862                 //
863                 // Keeps track of constants
864                 Hashtable constants;
865
866                 //
867                 // Maps variable names to ILGenerator.LocalBuilders
868                 //
869                 Hashtable local_builders;
870
871                 bool used = false;
872
873                 static int id;
874
875                 int this_id;
876                 
877                 public Block (Block parent)
878                         : this (parent, false, Location.Null, Location.Null)
879                 { }
880
881                 public Block (Block parent, bool implicit_block)
882                         : this (parent, implicit_block, Location.Null, Location.Null)
883                 { }
884
885                 public Block (Block parent, Location start, Location end)
886                         : this (parent, false, start, end)
887                 { }
888
889                 public Block (Block parent, bool implicit_block, Location start, Location end)
890                 {
891                         if (parent != null)
892                                 parent.AddChild (this);
893                         
894                         this.Parent = parent;
895                         this.Implicit = implicit_block;
896                         this.StartLocation = start;
897                         this.EndLocation = end;
898                         this.loc = start;
899                         this_id = id++;
900                         statements = new ArrayList ();
901                 }
902
903                 public int ID {
904                         get {
905                                 return this_id;
906                         }
907                 }
908                 
909                 void AddChild (Block b)
910                 {
911                         if (children == null)
912                                 children = new ArrayList ();
913                         
914                         children.Add (b);
915                 }
916
917                 public void SetEndLocation (Location loc)
918                 {
919                         EndLocation = loc;
920                 }
921
922                 /// <summary>
923                 ///   Adds a label to the current block. 
924                 /// </summary>
925                 ///
926                 /// <returns>
927                 ///   false if the name already exists in this block. true
928                 ///   otherwise.
929                 /// </returns>
930                 ///
931                 public bool AddLabel (string name, LabeledStatement target)
932                 {
933                         if (labels == null)
934                                 labels = new Hashtable ();
935                         if (labels.Contains (name))
936                                 return false;
937                         
938                         labels.Add (name, target);
939                         return true;
940                 }
941
942                 public LabeledStatement LookupLabel (string name)
943                 {
944                         if (labels != null){
945                                 if (labels.Contains (name))
946                                         return ((LabeledStatement) labels [name]);
947                         }
948
949                         if (Parent != null)
950                                 return Parent.LookupLabel (name);
951
952                         return null;
953                 }
954
955                 public VariableInfo AddVariable (string type, string name, Parameters pars, Location l)
956                 {
957                         if (variables == null)
958                                 variables = new Hashtable ();
959
960                         if (GetVariableType (name) != null)
961                                 return null;
962
963                         if (pars != null) {
964                                 int idx = 0;
965                                 Parameter p = pars.GetParameterByName (name, out idx);
966                                 if (p != null) 
967                                         return null;
968                         }
969                         
970                         VariableInfo vi = new VariableInfo (type, l);
971
972                         variables.Add (name, vi);
973
974                         // Console.WriteLine ("Adding {0} to {1}", name, ID);
975                         return vi;
976                 }
977
978                 public bool AddConstant (string type, string name, Expression value, Parameters pars, Location l)
979                 {
980                         if (AddVariable (type, name, pars, l) == null)
981                                 return false;
982                         
983                         if (constants == null)
984                                 constants = new Hashtable ();
985
986                         constants.Add (name, value);
987                         return true;
988                 }
989
990                 public Hashtable Variables {
991                         get {
992                                 return variables;
993                         }
994                 }
995
996                 public VariableInfo GetVariableInfo (string name)
997                 {
998                         if (variables != null) {
999                                 object temp;
1000                                 temp = variables [name];
1001
1002                                 if (temp != null){
1003                                         return (VariableInfo) temp;
1004                                 }
1005                         }
1006
1007                         if (Parent != null)
1008                                 return Parent.GetVariableInfo (name);
1009
1010                         return null;
1011                 }
1012                 
1013                 public string GetVariableType (string name)
1014                 {
1015                         VariableInfo vi = GetVariableInfo (name);
1016
1017                         if (vi != null)
1018                                 return vi.Type;
1019
1020                         return null;
1021                 }
1022
1023                 public Expression GetConstantExpression (string name)
1024                 {
1025                         if (constants != null) {
1026                                 object temp;
1027                                 temp = constants [name];
1028                                 
1029                                 if (temp != null)
1030                                         return (Expression) temp;
1031                         }
1032                         
1033                         if (Parent != null)
1034                                 return Parent.GetConstantExpression (name);
1035
1036                         return null;
1037                 }
1038                 
1039                 /// <summary>
1040                 ///   True if the variable named @name has been defined
1041                 ///   in this block
1042                 /// </summary>
1043                 public bool IsVariableDefined (string name)
1044                 {
1045                         // Console.WriteLine ("Looking up {0} in {1}", name, ID);
1046                         if (variables != null) {
1047                                 if (variables.Contains (name))
1048                                         return true;
1049                         }
1050                         
1051                         if (Parent != null)
1052                                 return Parent.IsVariableDefined (name);
1053
1054                         return false;
1055                 }
1056
1057                 /// <summary>
1058                 ///   True if the variable named @name is a constant
1059                 ///  </summary>
1060                 public bool IsConstant (string name)
1061                 {
1062                         Expression e = null;
1063                         
1064                         e = GetConstantExpression (name);
1065                         
1066                         return e != null;
1067                 }
1068                 
1069                 /// <summary>
1070                 ///   Use to fetch the statement associated with this label
1071                 /// </summary>
1072                 public Statement this [string name] {
1073                         get {
1074                                 return (Statement) labels [name];
1075                         }
1076                 }
1077
1078                 /// <returns>
1079                 ///   A list of labels that were not used within this block
1080                 /// </returns>
1081                 public string [] GetUnreferenced ()
1082                 {
1083                         // FIXME: Implement me
1084                         return null;
1085                 }
1086
1087                 public void AddStatement (Statement s)
1088                 {
1089                         statements.Add (s);
1090                         used = true;
1091                 }
1092
1093                 public bool Used {
1094                         get {
1095                                 return used;
1096                         }
1097                 }
1098
1099                 public void Use ()
1100                 {
1101                         used = true;
1102                 }
1103                 
1104                 /// <summary>
1105                 ///   Emits the variable declarations and labels.
1106                 /// </summary>
1107                 /// <remarks>
1108                 ///   tc: is our typecontainer (to resolve type references)
1109                 ///   ig: is the code generator:
1110                 ///   toplevel: the toplevel block.  This is used for checking 
1111                 ///             that no two labels with the same name are used.
1112                 /// </remarks>
1113                 public void EmitMeta (EmitContext ec, Block toplevel)
1114                 {
1115                         DeclSpace ds = ec.DeclSpace;
1116                         ILGenerator ig = ec.ig;
1117                                 
1118                         //
1119                         // Process this block variables
1120                         //
1121                         if (variables != null){
1122                                 local_builders = new Hashtable ();
1123                                 
1124                                 foreach (DictionaryEntry de in variables){
1125                                         string name = (string) de.Key;
1126                                         VariableInfo vi = (VariableInfo) de.Value;
1127                                         Type t;
1128
1129                                         t = RootContext.LookupType (ds, vi.Type, false, vi.Location);
1130                                         if (t == null)
1131                                                 continue;
1132
1133                                         vi.VariableType = t;
1134                                         vi.LocalBuilder = ig.DeclareLocal (t);
1135
1136                                         if (CodeGen.SymbolWriter != null)
1137                                                 vi.LocalBuilder.SetLocalSymInfo (name);
1138
1139                                         if (constants == null)
1140                                                 continue;
1141
1142                                         Expression cv = (Expression) constants [name];
1143                                         if (cv == null)
1144                                                 continue;
1145
1146                                         Expression e = cv.Resolve (ec);
1147                                         if (e == null)
1148                                                 continue;
1149
1150                                         if (!(e is Constant)){
1151                                                 Report.Error (133, vi.Location,
1152                                                               "The expression being assigned to `" +
1153                                                               name + "' must be constant (" + e + ")");
1154                                                 continue;
1155                                         }
1156
1157                                         constants.Remove (name);
1158                                         constants.Add (name, e);
1159                                 }
1160                         }
1161
1162                         //
1163                         // Now, handle the children
1164                         //
1165                         if (children != null){
1166                                 foreach (Block b in children)
1167                                         b.EmitMeta (ec, toplevel);
1168                         }
1169                 }
1170
1171                 public void UsageWarning ()
1172                 {
1173                         string name;
1174                         
1175                         if (variables != null){
1176                                 foreach (DictionaryEntry de in variables){
1177                                         VariableInfo vi = (VariableInfo) de.Value;
1178                                         
1179                                         if (vi.Used)
1180                                                 continue;
1181                                         
1182                                         name = (string) de.Key;
1183                                                 
1184                                         if (vi.Assigned){
1185                                                 Report.Warning (
1186                                                         219, vi.Location, "The variable `" + name +
1187                                                         "' is assigned but its value is never used");
1188                                         } else {
1189                                                 Report.Warning (
1190                                                         168, vi.Location, "The variable `" +
1191                                                         name +
1192                                                         "' is declared but never used");
1193                                         } 
1194                                 }
1195                         }
1196
1197                         if (children != null)
1198                                 foreach (Block b in children)
1199                                         b.UsageWarning ();
1200                 }
1201
1202                 public override bool Resolve (EmitContext ec)
1203                 {
1204                         Block prev_block = ec.CurrentBlock;
1205
1206                         ec.CurrentBlock = this;
1207                         foreach (Statement s in statements){
1208                                 if (s.Resolve (ec) == false){
1209                                         ec.CurrentBlock = prev_block;
1210                                         return false;
1211                                 }
1212                         }
1213
1214                         ec.CurrentBlock = prev_block;
1215                         return true;
1216                 }
1217                 
1218                 public override bool Emit (EmitContext ec)
1219                 {
1220                         bool is_ret = false;
1221                         Block prev_block = ec.CurrentBlock;
1222                         
1223                         ec.CurrentBlock = this;
1224
1225                         if (CodeGen.SymbolWriter != null) {
1226                                 ec.Mark (StartLocation);
1227                                 
1228                                 foreach (Statement s in statements) {
1229                                         ec.Mark (s.loc);
1230                                         
1231                                         is_ret = s.Emit (ec);
1232                                 }
1233
1234                                 ec.Mark (EndLocation); 
1235                         } else {
1236                                 foreach (Statement s in statements)
1237                                         is_ret = s.Emit (ec);
1238                         }
1239                         
1240                         ec.CurrentBlock = prev_block;
1241                         return is_ret;
1242                 }
1243         }
1244
1245         public class SwitchLabel {
1246                 Expression label;
1247                 object converted;
1248                 public Location loc;
1249                 public Label ILLabel;
1250                 public Label ILLabelCode;
1251                 
1252                 //
1253                 // if expr == null, then it is the default case.
1254                 //
1255                 public SwitchLabel (Expression expr, Location l)
1256                 {
1257                         label = expr;
1258                         loc = l;
1259                 }
1260
1261                 public Expression Label {
1262                         get {
1263                                 return label;
1264                         }
1265                 }
1266
1267                 public object Converted {
1268                         get {
1269                                 return converted;
1270                         }
1271                 }
1272                 
1273                 //
1274                 // Resolves the expression, reduces it to a literal if possible
1275                 // and then converts it to the requested type.
1276                 //
1277                 public bool ResolveAndReduce (EmitContext ec, Type required_type)
1278                 {
1279                         ILLabel = ec.ig.DefineLabel ();
1280                         ILLabelCode = ec.ig.DefineLabel ();
1281
1282                         if (label == null)
1283                                 return true;
1284                         
1285                         Expression e = label.Resolve (ec);
1286
1287                         if (e == null)
1288                                 return false;
1289
1290                         if (!(e is Constant)){
1291                                 Console.WriteLine ("Value is: " + label);
1292                                 Report.Error (150, loc, "A constant value is expected");
1293                                 return false;
1294                         }
1295
1296                         if (e is StringConstant || e is NullLiteral){
1297                                 if (required_type == TypeManager.string_type){
1298                                         converted = label;
1299                                         ILLabel = ec.ig.DefineLabel ();
1300                                         return true;
1301                                 }
1302                         }
1303
1304                         converted = Expression.ConvertIntLiteral ((Constant) e, required_type, loc);
1305                         if (converted == null)
1306                                 return false;
1307
1308                         return true;
1309                 }
1310         }
1311
1312         public class SwitchSection {
1313                 // An array of SwitchLabels.
1314                 public readonly ArrayList Labels;
1315                 public readonly Block Block;
1316                 
1317                 public SwitchSection (ArrayList labels, Block block)
1318                 {
1319                         Labels = labels;
1320                         Block = block;
1321                 }
1322         }
1323         
1324         public class Switch : Statement {
1325                 public readonly ArrayList Sections;
1326                 public Expression Expr;
1327
1328                 /// <summary>
1329                 ///   Maps constants whose type type SwitchType to their  SwitchLabels.
1330                 /// </summary>
1331                 public Hashtable Elements;
1332
1333                 /// <summary>
1334                 ///   The governing switch type
1335                 /// </summary>
1336                 public Type SwitchType;
1337
1338                 //
1339                 // Computed
1340                 //
1341                 bool got_default;
1342                 Label default_target;
1343                 
1344                 //
1345                 // The types allowed to be implicitly cast from
1346                 // on the governing type
1347                 //
1348                 static Type [] allowed_types;
1349                 
1350                 public Switch (Expression e, ArrayList sects, Location l)
1351                 {
1352                         Expr = e;
1353                         Sections = sects;
1354                         loc = l;
1355                 }
1356
1357                 public bool GotDefault {
1358                         get {
1359                                 return got_default;
1360                         }
1361                 }
1362
1363                 public Label DefaultTarget {
1364                         get {
1365                                 return default_target;
1366                         }
1367                 }
1368
1369                 //
1370                 // Determines the governing type for a switch.  The returned
1371                 // expression might be the expression from the switch, or an
1372                 // expression that includes any potential conversions to the
1373                 // integral types or to string.
1374                 //
1375                 Expression SwitchGoverningType (EmitContext ec, Type t)
1376                 {
1377                         if (t == TypeManager.int32_type ||
1378                             t == TypeManager.uint32_type ||
1379                             t == TypeManager.char_type ||
1380                             t == TypeManager.byte_type ||
1381                             t == TypeManager.sbyte_type ||
1382                             t == TypeManager.ushort_type ||
1383                             t == TypeManager.short_type ||
1384                             t == TypeManager.uint64_type ||
1385                             t == TypeManager.int64_type ||
1386                             t == TypeManager.string_type ||
1387                                 t == TypeManager.bool_type ||
1388                                 t.IsSubclassOf (TypeManager.enum_type))
1389                                 return Expr;
1390
1391                         if (allowed_types == null){
1392                                 allowed_types = new Type [] {
1393                                         TypeManager.sbyte_type,
1394                                         TypeManager.byte_type,
1395                                         TypeManager.short_type,
1396                                         TypeManager.ushort_type,
1397                                         TypeManager.int32_type,
1398                                         TypeManager.uint32_type,
1399                                         TypeManager.int64_type,
1400                                         TypeManager.uint64_type,
1401                                         TypeManager.char_type,
1402                                         TypeManager.bool_type,
1403                                         TypeManager.string_type
1404                                 };
1405                         }
1406
1407                         //
1408                         // Try to find a *user* defined implicit conversion.
1409                         //
1410                         // If there is no implicit conversion, or if there are multiple
1411                         // conversions, we have to report an error
1412                         //
1413                         Expression converted = null;
1414                         foreach (Type tt in allowed_types){
1415                                 Expression e;
1416                                 
1417                                 e = Expression.ImplicitUserConversion (ec, Expr, tt, loc);
1418                                 if (e == null)
1419                                         continue;
1420
1421                                 if (converted != null){
1422                                         Report.Error (-12, loc, "More than one conversion to an integral " +
1423                                                       " type exists for type `" +
1424                                                       TypeManager.CSharpName (Expr.Type)+"'");
1425                                         return null;
1426                                 } else
1427                                         converted = e;
1428                         }
1429                         return converted;
1430                 }
1431
1432                 void error152 (string n)
1433                 {
1434                         Report.Error (
1435                                 152, "The label `" + n + ":' " +
1436                                 "is already present on this switch statement");
1437                 }
1438                 
1439                 //
1440                 // Performs the basic sanity checks on the switch statement
1441                 // (looks for duplicate keys and non-constant expressions).
1442                 //
1443                 // It also returns a hashtable with the keys that we will later
1444                 // use to compute the switch tables
1445                 //
1446                 bool CheckSwitch (EmitContext ec)
1447                 {
1448                         Type compare_type;
1449                         bool error = false;
1450                         Elements = new Hashtable ();
1451                                 
1452                         got_default = false;
1453
1454                         if (TypeManager.IsEnumType (SwitchType)){
1455                                 compare_type = TypeManager.EnumToUnderlying (SwitchType);
1456                         } else
1457                                 compare_type = SwitchType;
1458                         
1459                         foreach (SwitchSection ss in Sections){
1460                                 foreach (SwitchLabel sl in ss.Labels){
1461                                         if (!sl.ResolveAndReduce (ec, SwitchType)){
1462                                                 error = true;
1463                                                 continue;
1464                                         }
1465
1466                                         if (sl.Label == null){
1467                                                 if (got_default){
1468                                                         error152 ("default");
1469                                                         error = true;
1470                                                 }
1471                                                 got_default = true;
1472                                                 continue;
1473                                         }
1474                                         
1475                                         object key = sl.Converted;
1476
1477                                         if (key is Constant)
1478                                                 key = ((Constant) key).GetValue ();
1479
1480                                         if (key == null)
1481                                                 key = NullLiteral.Null;
1482                                         
1483                                         string lname = null;
1484                                         if (compare_type == TypeManager.uint64_type){
1485                                                 ulong v = (ulong) key;
1486
1487                                                 if (Elements.Contains (v))
1488                                                         lname = v.ToString ();
1489                                                 else
1490                                                         Elements.Add (v, sl);
1491                                         } else if (compare_type == TypeManager.int64_type){
1492                                                 long v = (long) key;
1493
1494                                                 if (Elements.Contains (v))
1495                                                         lname = v.ToString ();
1496                                                 else
1497                                                         Elements.Add (v, sl);
1498                                         } else if (compare_type == TypeManager.uint32_type){
1499                                                 uint v = (uint) key;
1500
1501                                                 if (Elements.Contains (v))
1502                                                         lname = v.ToString ();
1503                                                 else
1504                                                         Elements.Add (v, sl);
1505                                         } else if (compare_type == TypeManager.char_type){
1506                                                 char v = (char) key;
1507                                                 
1508                                                 if (Elements.Contains (v))
1509                                                         lname = v.ToString ();
1510                                                 else
1511                                                         Elements.Add (v, sl);
1512                                         } else if (compare_type == TypeManager.byte_type){
1513                                                 byte v = (byte) key;
1514                                                 
1515                                                 if (Elements.Contains (v))
1516                                                         lname = v.ToString ();
1517                                                 else
1518                                                         Elements.Add (v, sl);
1519                                         } else if (compare_type == TypeManager.sbyte_type){
1520                                                 sbyte v = (sbyte) key;
1521                                                 
1522                                                 if (Elements.Contains (v))
1523                                                         lname = v.ToString ();
1524                                                 else
1525                                                         Elements.Add (v, sl);
1526                                         } else if (compare_type == TypeManager.short_type){
1527                                                 short v = (short) key;
1528                                                 
1529                                                 if (Elements.Contains (v))
1530                                                         lname = v.ToString ();
1531                                                 else
1532                                                         Elements.Add (v, sl);
1533                                         } else if (compare_type == TypeManager.ushort_type){
1534                                                 ushort v = (ushort) key;
1535                                                 
1536                                                 if (Elements.Contains (v))
1537                                                         lname = v.ToString ();
1538                                                 else
1539                                                         Elements.Add (v, sl);
1540                                         } else if (compare_type == TypeManager.string_type){
1541                                                 if (key is NullLiteral){
1542                                                         if (Elements.Contains (NullLiteral.Null))
1543                                                                 lname = "null";
1544                                                         else
1545                                                                 Elements.Add (NullLiteral.Null, null);
1546                                                 } else {
1547                                                         string s = (string) key;
1548
1549                                                         if (Elements.Contains (s))
1550                                                                 lname = s;
1551                                                         else
1552                                                                 Elements.Add (s, sl);
1553                                                 }
1554                                         } else if (compare_type == TypeManager.int32_type) {
1555                                                 int v = (int) key;
1556
1557                                                 if (Elements.Contains (v))
1558                                                         lname = v.ToString ();
1559                                                 else
1560                                                         Elements.Add (v, sl);
1561                                         } else if (compare_type == TypeManager.bool_type) {
1562                                                 bool v = (bool) key;
1563
1564                                                 if (Elements.Contains (v))
1565                                                         lname = v.ToString ();
1566                                                 else
1567                                                         Elements.Add (v, sl);
1568                                         }
1569                                         else
1570                                         {
1571                                                 throw new Exception ("Unknown switch type!" +
1572                                                                      SwitchType + " " + compare_type);
1573                                         }
1574
1575                                         if (lname != null){
1576                                                 error152 ("case + " + lname);
1577                                                 error = true;
1578                                         }
1579                                 }
1580                         }
1581                         if (error)
1582                                 return false;
1583                         
1584                         return true;
1585                 }
1586
1587                 void EmitObjectInteger (ILGenerator ig, object k)
1588                 {
1589                         if (k is int)
1590                                 IntConstant.EmitInt (ig, (int) k);
1591                         else if (k is Constant) {
1592                                 EmitObjectInteger (ig, ((Constant) k).GetValue ());
1593                         } 
1594                         else if (k is uint)
1595                                 IntConstant.EmitInt (ig, unchecked ((int) (uint) k));
1596                         else if (k is long)
1597                         {
1598                                 if ((long) k >= int.MinValue && (long) k <= int.MaxValue)
1599                                 {
1600                                         IntConstant.EmitInt (ig, (int) (long) k);
1601                                         ig.Emit (OpCodes.Conv_I8);
1602                                 }
1603                                 else
1604                                         LongConstant.EmitLong (ig, (long) k);
1605                         }
1606                         else if (k is ulong)
1607                         {
1608                                 if ((ulong) k < (1L<<32))
1609                                 {
1610                                         IntConstant.EmitInt (ig, (int) (long) k);
1611                                         ig.Emit (OpCodes.Conv_U8);
1612                                 }
1613                                 else
1614                                 {
1615                                         LongConstant.EmitLong (ig, unchecked ((long) (ulong) k));
1616                                 }
1617                         }
1618                         else if (k is char)
1619                                 IntConstant.EmitInt (ig, (int) ((char) k));
1620                         else if (k is sbyte)
1621                                 IntConstant.EmitInt (ig, (int) ((sbyte) k));
1622                         else if (k is byte)
1623                                 IntConstant.EmitInt (ig, (int) ((byte) k));
1624                         else if (k is short)
1625                                 IntConstant.EmitInt (ig, (int) ((short) k));
1626                         else if (k is ushort)
1627                                 IntConstant.EmitInt (ig, (int) ((ushort) k));
1628                         else if (k is bool)
1629                                 IntConstant.EmitInt (ig, ((bool) k) ? 1 : 0);
1630                         else
1631                                 throw new Exception ("Unhandled case");
1632                 }
1633                 
1634                 // structure used to hold blocks of keys while calculating table switch
1635                 class KeyBlock : IComparable
1636                 {
1637                         public KeyBlock (long _nFirst)
1638                         {
1639                                 nFirst = nLast = _nFirst;
1640                         }
1641                         public long nFirst;
1642                         public long nLast;
1643                         public ArrayList rgKeys = null;
1644                         public int Length
1645                         {
1646                                 get { return (int) (nLast - nFirst + 1); }
1647                         }
1648                         public static long TotalLength (KeyBlock kbFirst, KeyBlock kbLast)
1649                         {
1650                                 return kbLast.nLast - kbFirst.nFirst + 1;
1651                         }
1652                         public int CompareTo (object obj)
1653                         {
1654                                 KeyBlock kb = (KeyBlock) obj;
1655                                 int nLength = Length;
1656                                 int nLengthOther = kb.Length;
1657                                 if (nLengthOther == nLength)
1658                                         return (int) (kb.nFirst - nFirst);
1659                                 return nLength - nLengthOther;
1660                         }
1661                 }
1662
1663                 /// <summary>
1664                 /// This method emits code for a lookup-based switch statement (non-string)
1665                 /// Basically it groups the cases into blocks that are at least half full,
1666                 /// and then spits out individual lookup opcodes for each block.
1667                 /// It emits the longest blocks first, and short blocks are just
1668                 /// handled with direct compares.
1669                 /// </summary>
1670                 /// <param name="ec"></param>
1671                 /// <param name="val"></param>
1672                 /// <returns></returns>
1673                 bool TableSwitchEmit (EmitContext ec, LocalBuilder val)
1674                 {
1675                         int cElements = Elements.Count;
1676                         object [] rgKeys = new object [cElements];
1677                         Elements.Keys.CopyTo (rgKeys, 0);
1678                         Array.Sort (rgKeys);
1679
1680                         // initialize the block list with one element per key
1681                         ArrayList rgKeyBlocks = new ArrayList ();
1682                         foreach (object key in rgKeys)
1683                                 rgKeyBlocks.Add (new KeyBlock (Convert.ToInt64 (key)));
1684
1685                         KeyBlock kbCurr;
1686                         // iteratively merge the blocks while they are at least half full
1687                         // there's probably a really cool way to do this with a tree...
1688                         while (rgKeyBlocks.Count > 1)
1689                         {
1690                                 ArrayList rgKeyBlocksNew = new ArrayList ();
1691                                 kbCurr = (KeyBlock) rgKeyBlocks [0];
1692                                 for (int ikb = 1; ikb < rgKeyBlocks.Count; ikb++)
1693                                 {
1694                                         KeyBlock kb = (KeyBlock) rgKeyBlocks [ikb];
1695                                         if ((kbCurr.Length + kb.Length) * 2 >=  KeyBlock.TotalLength (kbCurr, kb))
1696                                         {
1697                                                 // merge blocks
1698                                                 kbCurr.nLast = kb.nLast;
1699                                         }
1700                                         else
1701                                         {
1702                                                 // start a new block
1703                                                 rgKeyBlocksNew.Add (kbCurr);
1704                                                 kbCurr = kb;
1705                                         }
1706                                 }
1707                                 rgKeyBlocksNew.Add (kbCurr);
1708                                 if (rgKeyBlocks.Count == rgKeyBlocksNew.Count)
1709                                         break;
1710                                 rgKeyBlocks = rgKeyBlocksNew;
1711                         }
1712
1713                         // initialize the key lists
1714                         foreach (KeyBlock kb in rgKeyBlocks)
1715                                 kb.rgKeys = new ArrayList ();
1716
1717                         // fill the key lists
1718                         int iBlockCurr = 0;
1719                         if (rgKeyBlocks.Count > 0) {
1720                                 kbCurr = (KeyBlock) rgKeyBlocks [0];
1721                                 foreach (object key in rgKeys)
1722                                 {
1723                                         bool fNextBlock = (key is UInt64) ? (ulong) key > (ulong) kbCurr.nLast : Convert.ToInt64 (key) > kbCurr.nLast;
1724                                         if (fNextBlock)
1725                                                 kbCurr = (KeyBlock) rgKeyBlocks [++iBlockCurr];
1726                                         kbCurr.rgKeys.Add (key);
1727                                 }
1728                         }
1729
1730                         // sort the blocks so we can tackle the largest ones first
1731                         rgKeyBlocks.Sort ();
1732
1733                         // okay now we can start...
1734                         ILGenerator ig = ec.ig;
1735                         Label lblEnd = ig.DefineLabel ();       // at the end ;-)
1736                         Label lblDefault = ig.DefineLabel ();
1737
1738                         Type typeKeys = null;
1739                         if (rgKeys.Length > 0)
1740                                 typeKeys = rgKeys [0].GetType ();       // used for conversions
1741
1742                         for (int iBlock = rgKeyBlocks.Count - 1; iBlock >= 0; --iBlock)
1743                         {
1744                                 KeyBlock kb = ((KeyBlock) rgKeyBlocks [iBlock]);
1745                                 lblDefault = (iBlock == 0) ? DefaultTarget : ig.DefineLabel ();
1746                                 if (kb.Length <= 2)
1747                                 {
1748                                         foreach (object key in kb.rgKeys)
1749                                         {
1750                                                 ig.Emit (OpCodes.Ldloc, val);
1751                                                 EmitObjectInteger (ig, key);
1752                                                 SwitchLabel sl = (SwitchLabel) Elements [key];
1753                                                 ig.Emit (OpCodes.Beq, sl.ILLabel);
1754                                         }
1755                                 }
1756                                 else
1757                                 {
1758                                         // TODO: if all the keys in the block are the same and there are
1759                                         //       no gaps/defaults then just use a range-check.
1760                                         if (SwitchType == TypeManager.int64_type ||
1761                                                 SwitchType == TypeManager.uint64_type)
1762                                         {
1763                                                 // TODO: optimize constant/I4 cases
1764
1765                                                 // check block range (could be > 2^31)
1766                                                 ig.Emit (OpCodes.Ldloc, val);
1767                                                 EmitObjectInteger (ig, Convert.ChangeType (kb.nFirst, typeKeys));
1768                                                 ig.Emit (OpCodes.Blt, lblDefault);
1769                                                 ig.Emit (OpCodes.Ldloc, val);
1770                                                 EmitObjectInteger (ig, Convert.ChangeType (kb.nFirst, typeKeys));
1771                                                 ig.Emit (OpCodes.Bgt, lblDefault);
1772
1773                                                 // normalize range
1774                                                 ig.Emit (OpCodes.Ldloc, val);
1775                                                 if (kb.nFirst != 0)
1776                                                 {
1777                                                         EmitObjectInteger (ig, Convert.ChangeType (kb.nFirst, typeKeys));
1778                                                         ig.Emit (OpCodes.Sub);
1779                                                 }
1780                                                 ig.Emit (OpCodes.Conv_I4);      // assumes < 2^31 labels!
1781                                         }
1782                                         else
1783                                         {
1784                                                 // normalize range
1785                                                 ig.Emit (OpCodes.Ldloc, val);
1786                                                 int nFirst = (int) kb.nFirst;
1787                                                 if (nFirst > 0)
1788                                                 {
1789                                                         IntConstant.EmitInt (ig, nFirst);
1790                                                         ig.Emit (OpCodes.Sub);
1791                                                 }
1792                                                 else if (nFirst < 0)
1793                                                 {
1794                                                         IntConstant.EmitInt (ig, -nFirst);
1795                                                         ig.Emit (OpCodes.Add);
1796                                                 }
1797                                         }
1798
1799                                         // first, build the list of labels for the switch
1800                                         int iKey = 0;
1801                                         int cJumps = kb.Length;
1802                                         Label [] rgLabels = new Label [cJumps];
1803                                         for (int iJump = 0; iJump < cJumps; iJump++)
1804                                         {
1805                                                 object key = kb.rgKeys [iKey];
1806                                                 if (Convert.ToInt64 (key) == kb.nFirst + iJump)
1807                                                 {
1808                                                         SwitchLabel sl = (SwitchLabel) Elements [key];
1809                                                         rgLabels [iJump] = sl.ILLabel;
1810                                                         iKey++;
1811                                                 }
1812                                                 else
1813                                                         rgLabels [iJump] = lblDefault;
1814                                         }
1815                                         // emit the switch opcode
1816                                         ig.Emit (OpCodes.Switch, rgLabels);
1817                                 }
1818
1819                                 // mark the default for this block
1820                                 if (iBlock != 0)
1821                                         ig.MarkLabel (lblDefault);
1822                         }
1823
1824                         // TODO: find the default case and emit it here,
1825                         //       to prevent having to do the following jump.
1826                         //       make sure to mark other labels in the default section
1827
1828                         // the last default just goes to the end
1829                         ig.Emit (OpCodes.Br, lblDefault);
1830
1831                         // now emit the code for the sections
1832                         bool fFoundDefault = false;
1833                         bool fAllReturn = true;
1834                         foreach (SwitchSection ss in Sections)
1835                         {
1836                                 foreach (SwitchLabel sl in ss.Labels)
1837                                 {
1838                                         ig.MarkLabel (sl.ILLabel);
1839                                         ig.MarkLabel (sl.ILLabelCode);
1840                                         if (sl.Label == null)
1841                                         {
1842                                                 ig.MarkLabel (lblDefault);
1843                                                 fFoundDefault = true;
1844                                         }
1845                                 }
1846                                 fAllReturn &= ss.Block.Emit (ec);
1847                                 //ig.Emit (OpCodes.Br, lblEnd);
1848                         }
1849                         
1850                         if (!fFoundDefault)
1851                                 ig.MarkLabel (lblDefault);
1852                         ig.MarkLabel (lblEnd);
1853
1854                         return fAllReturn;
1855                 }
1856                 //
1857                 // This simple emit switch works, but does not take advantage of the
1858                 // `switch' opcode. 
1859                 // TODO: remove non-string logic from here
1860                 // TODO: binary search strings?
1861                 //
1862                 bool SimpleSwitchEmit (EmitContext ec, LocalBuilder val)
1863                 {
1864                         ILGenerator ig = ec.ig;
1865                         Label end_of_switch = ig.DefineLabel ();
1866                         Label next_test = ig.DefineLabel ();
1867                         Label null_target = ig.DefineLabel ();
1868                         bool default_found = false;
1869                         bool first_test = true;
1870                         bool pending_goto_end = false;
1871                         bool all_return = true;
1872                         bool is_string = false;
1873                         bool null_found;
1874                         
1875                         //
1876                         // Special processing for strings: we cant compare
1877                         // against null.
1878                         //
1879                         if (SwitchType == TypeManager.string_type){
1880                                 ig.Emit (OpCodes.Ldloc, val);
1881                                 is_string = true;
1882                                 
1883                                 if (Elements.Contains (NullLiteral.Null)){
1884                                         ig.Emit (OpCodes.Brfalse, null_target);
1885                                 } else
1886                                         ig.Emit (OpCodes.Brfalse, default_target);
1887
1888                                 ig.Emit (OpCodes.Ldloc, val);
1889                                 ig.Emit (OpCodes.Call, TypeManager.string_isinterneted_string);
1890                                 ig.Emit (OpCodes.Stloc, val);
1891                         }
1892
1893                         SwitchSection last_section;
1894                         last_section = (SwitchSection) Sections [Sections.Count-1];
1895                         
1896                         foreach (SwitchSection ss in Sections){
1897                                 Label sec_begin = ig.DefineLabel ();
1898
1899                                 if (pending_goto_end)
1900                                         ig.Emit (OpCodes.Br, end_of_switch);
1901
1902                                 int label_count = ss.Labels.Count;
1903                                 null_found = false;
1904                                 foreach (SwitchLabel sl in ss.Labels){
1905                                         ig.MarkLabel (sl.ILLabel);
1906                                         
1907                                         if (!first_test){
1908                                                 ig.MarkLabel (next_test);
1909                                                 next_test = ig.DefineLabel ();
1910                                         }
1911                                         //
1912                                         // If we are the default target
1913                                         //
1914                                         if (sl.Label == null){
1915                                                 ig.MarkLabel (default_target);
1916                                                 default_found = true;
1917                                         } else {
1918                                                 object lit = sl.Converted;
1919
1920                                                 if (lit is NullLiteral){
1921                                                         null_found = true;
1922                                                         if (label_count == 1)
1923                                                                 ig.Emit (OpCodes.Br, next_test);
1924                                                         continue;
1925                                                                               
1926                                                 }
1927                                                 if (is_string){
1928                                                         StringConstant str = (StringConstant) lit;
1929
1930                                                         ig.Emit (OpCodes.Ldloc, val);
1931                                                         ig.Emit (OpCodes.Ldstr, str.Value);
1932                                                         if (label_count == 1)
1933                                                                 ig.Emit (OpCodes.Bne_Un, next_test);
1934                                                         else
1935                                                                 ig.Emit (OpCodes.Beq, sec_begin);
1936                                                 } else {
1937                                                         ig.Emit (OpCodes.Ldloc, val);
1938                                                         EmitObjectInteger (ig, lit);
1939                                                         ig.Emit (OpCodes.Ceq);
1940                                                         if (label_count == 1)
1941                                                                 ig.Emit (OpCodes.Brfalse, next_test);
1942                                                         else
1943                                                                 ig.Emit (OpCodes.Brtrue, sec_begin);
1944                                                 }
1945                                         }
1946                                 }
1947                                 if (label_count != 1 && ss != last_section)
1948                                         ig.Emit (OpCodes.Br, next_test);
1949                                 
1950                                 if (null_found)
1951                                         ig.MarkLabel (null_target);
1952                                 ig.MarkLabel (sec_begin);
1953                                 foreach (SwitchLabel sl in ss.Labels)\r
1954                                         ig.MarkLabel (sl.ILLabelCode);
1955                                 if (ss.Block.Emit (ec))
1956                                         pending_goto_end = false;
1957                                 else {
1958                                         all_return = false;
1959                                         pending_goto_end = true;
1960                                 }
1961                                 first_test = false;
1962                         }
1963                         if (!default_found){
1964                                 ig.MarkLabel (default_target);
1965                                 all_return = false;
1966                         }
1967                         ig.MarkLabel (next_test);
1968                         ig.MarkLabel (end_of_switch);
1969                         
1970                         return all_return;
1971                 }
1972
1973                 public override bool Resolve (EmitContext ec)
1974                 {
1975                         foreach (SwitchSection ss in Sections){
1976                                 if (ss.Block.Resolve (ec) != true)
1977                                         return false;
1978                         }
1979
1980                         return true;
1981                 }
1982                 
1983                 public override bool Emit (EmitContext ec)
1984                 {
1985                         Expr = Expr.Resolve (ec);
1986                         if (Expr == null)
1987                                 return false;
1988
1989                         Expression new_expr = SwitchGoverningType (ec, Expr.Type);
1990                         if (new_expr == null){
1991                                 Report.Error (151, loc, "An integer type or string was expected for switch");
1992                                 return false;
1993                         }
1994
1995                         // Validate switch.
1996                         SwitchType = new_expr.Type;
1997
1998                         if (!CheckSwitch (ec))
1999                                 return false;
2000
2001                         // Store variable for comparission purposes
2002                         LocalBuilder value = ec.ig.DeclareLocal (SwitchType);
2003                         new_expr.Emit (ec);
2004                         ec.ig.Emit (OpCodes.Stloc, value);
2005
2006                         ILGenerator ig = ec.ig;
2007
2008                         default_target = ig.DefineLabel ();
2009
2010                         //
2011                         // Setup the codegen context
2012                         //
2013                         Label old_end = ec.LoopEnd;
2014                         Switch old_switch = ec.Switch;
2015                         
2016                         ec.LoopEnd = ig.DefineLabel ();
2017                         ec.Switch = this;
2018
2019                         // Emit Code.
2020                         bool all_return;
2021                         if (SwitchType == TypeManager.string_type)
2022                                 all_return = SimpleSwitchEmit (ec, value);
2023                         else
2024                                 all_return = TableSwitchEmit (ec, value);
2025
2026                         // Restore context state. 
2027                         ig.MarkLabel (ec.LoopEnd);
2028
2029                         //
2030                         // Restore the previous context
2031                         //
2032                         ec.LoopEnd = old_end;
2033                         ec.Switch = old_switch;
2034                         
2035                         return all_return;
2036                 }
2037         }
2038
2039         public class Lock : Statement {
2040                 Expression expr;
2041                 Statement Statement;
2042                         
2043                 public Lock (Expression expr, Statement stmt, Location l)
2044                 {
2045                         this.expr = expr;
2046                         Statement = stmt;
2047                         loc = l;
2048                 }
2049
2050                 public override bool Resolve (EmitContext ec)
2051                 {
2052                         expr = expr.Resolve (ec);
2053                         return Statement.Resolve (ec) && expr != null;
2054                 }
2055                 
2056                 public override bool Emit (EmitContext ec)
2057                 {
2058                         Type type = expr.Type;
2059                         bool val;
2060                         
2061                         if (type.IsValueType){
2062                                 Report.Error (185, loc, "lock statement requires the expression to be " +
2063                                               " a reference type (type is: `" +
2064                                               TypeManager.CSharpName (type) + "'");
2065                                 return false;
2066                         }
2067
2068                         ILGenerator ig = ec.ig;
2069                         LocalBuilder temp = ig.DeclareLocal (type);
2070                                 
2071                         expr.Emit (ec);
2072                         ig.Emit (OpCodes.Dup);
2073                         ig.Emit (OpCodes.Stloc, temp);
2074                         ig.Emit (OpCodes.Call, TypeManager.void_monitor_enter_object);
2075
2076                         // try
2077                         Label end = ig.BeginExceptionBlock ();
2078                         bool old_in_try = ec.InTry;
2079                         ec.InTry = true;
2080                         Label finish = ig.DefineLabel ();
2081                         val = Statement.Emit (ec);
2082                         ec.InTry = old_in_try;
2083                         // ig.Emit (OpCodes.Leave, finish);
2084
2085                         ig.MarkLabel (finish);
2086                         
2087                         // finally
2088                         ig.BeginFinallyBlock ();
2089                         ig.Emit (OpCodes.Ldloc, temp);
2090                         ig.Emit (OpCodes.Call, TypeManager.void_monitor_exit_object);
2091                         ig.EndExceptionBlock ();
2092                         
2093                         return val;
2094                 }
2095         }
2096
2097         public class Unchecked : Statement {
2098                 public readonly Block Block;
2099                 
2100                 public Unchecked (Block b)
2101                 {
2102                         Block = b;
2103                 }
2104
2105                 public override bool Resolve (EmitContext ec)
2106                 {
2107                         return Block.Resolve (ec);
2108                 }
2109                 
2110                 public override bool Emit (EmitContext ec)
2111                 {
2112                         bool previous_state = ec.CheckState;
2113                         bool previous_state_const = ec.ConstantCheckState;
2114                         bool val;
2115                         
2116                         ec.CheckState = false;
2117                         ec.ConstantCheckState = false;
2118                         val = Block.Emit (ec);
2119                         ec.CheckState = previous_state;
2120                         ec.ConstantCheckState = previous_state_const;
2121
2122                         return val;
2123                 }
2124         }
2125
2126         public class Checked : Statement {
2127                 public readonly Block Block;
2128                 
2129                 public Checked (Block b)
2130                 {
2131                         Block = b;
2132                 }
2133
2134                 public override bool Resolve (EmitContext ec)
2135                 {
2136                         return Block.Resolve (ec);
2137                 }
2138                 
2139                 public override bool Emit (EmitContext ec)
2140                 {
2141                         bool previous_state = ec.CheckState;
2142                         bool previous_state_const = ec.ConstantCheckState;
2143                         bool val;
2144                         
2145                         ec.CheckState = true;
2146                         ec.ConstantCheckState = true;
2147                         val = Block.Emit (ec);
2148                         ec.CheckState = previous_state;
2149                         ec.ConstantCheckState = previous_state_const;
2150
2151                         return val;
2152                 }
2153         }
2154
2155         public class Unsafe : Statement {
2156                 public readonly Block Block;
2157
2158                 public Unsafe (Block b)
2159                 {
2160                         Block = b;
2161                 }
2162
2163                 public override bool Resolve (EmitContext ec)
2164                 {
2165                         return Block.Resolve (ec);
2166                 }
2167                 
2168                 public override bool Emit (EmitContext ec)
2169                 {
2170                         bool previous_state = ec.InUnsafe;
2171                         bool val;
2172                         
2173                         ec.InUnsafe = true;
2174                         val = Block.Emit (ec);
2175                         ec.InUnsafe = previous_state;
2176
2177                         return val;
2178                 }
2179         }
2180
2181         // 
2182         // Fixed statement
2183         //
2184         public class Fixed : Statement {
2185                 string    type;
2186                 ArrayList declarators;
2187                 Statement statement;
2188
2189                 public Fixed (string type, ArrayList decls, Statement stmt, Location l)
2190                 {
2191                         this.type = type;
2192                         declarators = decls;
2193                         statement = stmt;
2194                         loc = l;
2195                 }
2196
2197                 public override bool Resolve (EmitContext ec)
2198                 {
2199                         return statement.Resolve (ec);
2200                 }
2201                 
2202                 public override bool Emit (EmitContext ec)
2203                 {
2204                         ILGenerator ig = ec.ig;
2205                         Type t;
2206                         
2207                         t = RootContext.LookupType (ec.DeclSpace, type, false, loc);
2208                         if (t == null)
2209                                 return false;
2210
2211                         bool is_ret = false;
2212
2213                         foreach (Pair p in declarators){
2214                                 VariableInfo vi = (VariableInfo) p.First;
2215                                 Expression e = (Expression) p.Second;
2216
2217                                 //
2218                                 // The rules for the possible declarators are pretty wise,
2219                                 // but the production on the grammar is more concise.
2220                                 //
2221                                 // So we have to enforce these rules here.
2222                                 //
2223                                 // We do not resolve before doing the case 1 test,
2224                                 // because the grammar is explicit in that the token &
2225                                 // is present, so we need to test for this particular case.
2226                                 //
2227
2228                                 //
2229                                 // Case 1: & object.
2230                                 //
2231                                 if (e is Unary && ((Unary) e).Oper == Unary.Operator.AddressOf){
2232                                         Expression child = ((Unary) e).Expr;
2233
2234                                         vi.MakePinned ();
2235                                         if (child is ParameterReference || child is LocalVariableReference){
2236                                                 Report.Error (
2237                                                         213, loc, 
2238                                                         "No need to use fixed statement for parameters or " +
2239                                                         "local variable declarations (address is already " +
2240                                                         "fixed)");
2241                                                 continue;
2242                                         }
2243                                         
2244                                         e = e.Resolve (ec);
2245                                         if (e == null)
2246                                                 continue;
2247
2248                                         child = ((Unary) e).Expr;
2249                                         
2250                                         if (!TypeManager.VerifyUnManaged (child.Type, loc))
2251                                                 continue;
2252
2253                                         //
2254                                         // Store pointer in pinned location
2255                                         //
2256                                         e.Emit (ec);
2257                                         ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
2258
2259                                         is_ret = statement.Emit (ec);
2260
2261                                         // Clear the pinned variable.
2262                                         ig.Emit (OpCodes.Ldc_I4_0);
2263                                         ig.Emit (OpCodes.Conv_U);
2264                                         ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
2265
2266                                         continue;
2267                                 }
2268
2269                                 e = e.Resolve (ec);
2270                                 if (e == null)
2271                                         continue;
2272
2273                                 //
2274                                 // Case 2: Array
2275                                 //
2276                                 if (e.Type.IsArray){
2277                                         Type array_type = e.Type.GetElementType ();
2278                                         
2279                                         vi.MakePinned ();
2280                                         //
2281                                         // Provided that array_type is unmanaged,
2282                                         //
2283                                         if (!TypeManager.VerifyUnManaged (array_type, loc))
2284                                                 continue;
2285
2286                                         //
2287                                         // and T* is implicitly convertible to the
2288                                         // pointer type given in the fixed statement.
2289                                         //
2290                                         ArrayPtr array_ptr = new ArrayPtr (e);
2291                                         
2292                                         Expression converted = Expression.ConvertImplicitRequired (
2293                                                 ec, array_ptr, vi.VariableType, loc);
2294                                         if (converted == null)
2295                                                 continue;
2296
2297                                         //
2298                                         // Store pointer in pinned location
2299                                         //
2300                                         converted.Emit (ec);
2301                                         
2302                                         ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
2303
2304                                         is_ret = statement.Emit (ec);
2305                                         
2306                                         // Clear the pinned variable.
2307                                         ig.Emit (OpCodes.Ldc_I4_0);
2308                                         ig.Emit (OpCodes.Conv_U);
2309                                         ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
2310
2311                                         continue;
2312                                 }
2313
2314                                 //
2315                                 // Case 3: string
2316                                 //
2317                                 if (e.Type == TypeManager.string_type){
2318                                         LocalBuilder pinned_string = ig.DeclareLocal (TypeManager.string_type);
2319                                         TypeManager.MakePinned (pinned_string);
2320                                         
2321                                         e.Emit (ec);
2322                                         ig.Emit (OpCodes.Stloc, pinned_string);
2323
2324                                         Expression sptr = new StringPtr (pinned_string);
2325                                         Expression converted = Expression.ConvertImplicitRequired (
2326                                                 ec, sptr, vi.VariableType, loc);
2327                                         
2328                                         if (converted == null)
2329                                                 continue;
2330
2331                                         converted.Emit (ec);
2332                                         ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
2333                                         
2334                                         is_ret = statement.Emit (ec);
2335
2336                                         // Clear the pinned variable
2337                                         ig.Emit (OpCodes.Ldnull);
2338                                         ig.Emit (OpCodes.Stloc, pinned_string);
2339                                 }
2340                         }
2341
2342                         return is_ret;
2343                 }
2344         }
2345         
2346         public class Catch {
2347                 public readonly string Type;
2348                 public readonly string Name;
2349                 public readonly Block  Block;
2350                 public readonly Location Location;
2351                 
2352                 public Catch (string type, string name, Block block, Location l)
2353                 {
2354                         Type = type;
2355                         Name = name;
2356                         Block = block;
2357                         Location = l;
2358                 }
2359         }
2360
2361         public class Try : Statement {
2362                 public readonly Block Fini, Block;
2363                 public readonly ArrayList Specific;
2364                 public readonly Catch General;
2365                 
2366                 //
2367                 // specific, general and fini might all be null.
2368                 //
2369                 public Try (Block block, ArrayList specific, Catch general, Block fini)
2370                 {
2371                         if (specific == null && general == null){
2372                                 Console.WriteLine ("CIR.Try: Either specific or general have to be non-null");
2373                         }
2374                         
2375                         this.Block = block;
2376                         this.Specific = specific;
2377                         this.General = general;
2378                         this.Fini = fini;
2379                 }
2380
2381                 public override bool Resolve (EmitContext ec)
2382                 {
2383                         bool ok = true;
2384                         
2385                         if (General != null)
2386                                 if (!General.Block.Resolve (ec))
2387                                         ok = false;
2388
2389                         foreach (Catch c in Specific){
2390                                 if (!c.Block.Resolve (ec))
2391                                         ok = false;
2392                         }
2393
2394                         if (!Block.Resolve (ec))
2395                                 ok = false;
2396
2397                         if (Fini != null)
2398                                 if (!Fini.Resolve (ec))
2399                                         ok = false;
2400                         
2401                         return ok;
2402                 }
2403                 
2404                 public override bool Emit (EmitContext ec)
2405                 {
2406                         ILGenerator ig = ec.ig;
2407                         Label end;
2408                         Label finish = ig.DefineLabel ();;
2409                         bool returns;
2410                         
2411                         end = ig.BeginExceptionBlock ();
2412                         bool old_in_try = ec.InTry;
2413                         ec.InTry = true;
2414                         returns = Block.Emit (ec);
2415                         ec.InTry = old_in_try;
2416
2417                         //
2418                         // System.Reflection.Emit provides this automatically:
2419                         // ig.Emit (OpCodes.Leave, finish);
2420
2421                         bool old_in_catch = ec.InCatch;
2422                         ec.InCatch = true;
2423                         DeclSpace ds = ec.DeclSpace;
2424
2425                         foreach (Catch c in Specific){
2426                                 Type catch_type = RootContext.LookupType (ds, c.Type, false, c.Location);
2427                                 VariableInfo vi;
2428                                 
2429                                 if (catch_type == null)
2430                                         return false;
2431
2432                                 ig.BeginCatchBlock (catch_type);
2433
2434                                 if (c.Name != null){
2435                                         vi = c.Block.GetVariableInfo (c.Name);
2436                                         if (vi == null){
2437                                                 Console.WriteLine ("This should not happen! variable does not exist in this block");
2438                                                 Environment.Exit (0);
2439                                         }
2440                                 
2441                                         ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
2442                                 } else
2443                                         ig.Emit (OpCodes.Pop);
2444                                 
2445                                 if (!c.Block.Emit (ec))
2446                                         returns = false;
2447                         }
2448
2449                         if (General != null){
2450                                 ig.BeginCatchBlock (TypeManager.object_type);
2451                                 ig.Emit (OpCodes.Pop);
2452                                 if (!General.Block.Emit (ec))
2453                                         returns = false;
2454                         }
2455                         ec.InCatch = old_in_catch;
2456
2457                         ig.MarkLabel (finish);
2458                         if (Fini != null){
2459                                 ig.BeginFinallyBlock ();
2460                                 bool old_in_finally = ec.InFinally;
2461                                 ec.InFinally = true;
2462                                 Fini.Emit (ec);
2463                                 ec.InFinally = old_in_finally;
2464                         }
2465                         
2466                         ig.EndExceptionBlock ();
2467
2468                         //
2469                         // FIXME: Is this correct?
2470                         // Replace with `returns' and check test-18, maybe we can
2471                         // perform an optimization here.
2472                         //
2473                         return returns;
2474                 }
2475         }
2476
2477         //
2478         // FIXME: We still do not support the expression variant of the using
2479         // statement.
2480         //
2481         public class Using : Statement {
2482                 object expression_or_block;
2483                 Statement Statement;
2484                 
2485                 public Using (object expression_or_block, Statement stmt, Location l)
2486                 {
2487                         this.expression_or_block = expression_or_block;
2488                         Statement = stmt;
2489                         loc = l;
2490                 }
2491
2492                 //
2493                 // Emits the code for the case of using using a local variable declaration.
2494                 //
2495                 bool EmitLocalVariableDecls (EmitContext ec, string type_name, ArrayList var_list)
2496                 {
2497                         ILGenerator ig = ec.ig;
2498                         Expression [] converted_vars;
2499                         bool need_conv = false;
2500                         Type type = RootContext.LookupType (ec.DeclSpace, type_name, false, loc);
2501                         int i = 0;
2502
2503                         if (type == null)
2504                                 return false;
2505                         
2506                         //
2507                         // The type must be an IDisposable or an implicit conversion
2508                         // must exist.
2509                         //
2510                         converted_vars = new Expression [var_list.Count];
2511                         if (!TypeManager.ImplementsInterface (type, TypeManager.idisposable_type)){
2512                                 foreach (DictionaryEntry e in var_list){
2513                                         Expression var = (Expression) e.Key;
2514
2515                                         var = var.Resolve (ec);
2516                                         if (var == null)
2517                                                 return false;
2518                                         
2519                                         converted_vars [i] = Expression.ConvertImplicit (
2520                                                 ec, var, TypeManager.idisposable_type, loc);
2521
2522                                         if (converted_vars [i] == null)
2523                                                 return false;
2524                                         i++;
2525                                 }
2526                                 need_conv = true;
2527                         }
2528                         
2529                         i = 0;
2530                         bool old_in_try = ec.InTry;
2531                         ec.InTry = true;
2532                         bool error = false;
2533                         foreach (DictionaryEntry e in var_list){
2534                                 LocalVariableReference var = (LocalVariableReference) e.Key;
2535                                 Expression expr = (Expression) e.Value;
2536                                 Expression a;
2537
2538                                 a = new Assign (var, expr, loc);
2539                                 a = a.Resolve (ec);
2540                                 if (!need_conv)
2541                                         converted_vars [i] = var;
2542                                 i++;
2543                                 if (a == null){
2544                                         error = true;
2545                                         continue;
2546                                 }
2547                                 ((ExpressionStatement) a).EmitStatement (ec);
2548                                 
2549                                 ig.BeginExceptionBlock ();
2550
2551                         }
2552                         if (error)
2553                                 return false;
2554                         Statement.Emit (ec);
2555                         ec.InTry = old_in_try;
2556
2557                         bool old_in_finally = ec.InFinally;
2558                         ec.InFinally = true;
2559                         var_list.Reverse ();
2560                         foreach (DictionaryEntry e in var_list){
2561                                 LocalVariableReference var = (LocalVariableReference) e.Key;
2562                                 Label skip = ig.DefineLabel ();
2563                                 i--;
2564                                 
2565                                 ig.BeginFinallyBlock ();
2566                                 
2567                                 var.Emit (ec);
2568                                 ig.Emit (OpCodes.Brfalse, skip);
2569                                 converted_vars [i].Emit (ec);
2570                                 ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
2571                                 ig.MarkLabel (skip);
2572                                 ig.EndExceptionBlock ();
2573                         }
2574                         ec.InFinally = old_in_finally;
2575
2576                         return false;
2577                 }
2578
2579                 bool EmitExpression (EmitContext ec, Expression expr)
2580                 {
2581                         Type expr_type = expr.Type;
2582                         Expression conv = null;
2583                         
2584                         if (!TypeManager.ImplementsInterface (expr_type, TypeManager.idisposable_type)){
2585                                 conv = Expression.ConvertImplicit (
2586                                         ec, expr, TypeManager.idisposable_type, loc);
2587
2588                                 if (conv == null)
2589                                         return false;
2590                         }
2591
2592                         //
2593                         // Make a copy of the expression and operate on that.
2594                         //
2595                         ILGenerator ig = ec.ig;
2596                         LocalBuilder local_copy = ig.DeclareLocal (expr_type);
2597                         if (conv != null)
2598                                 conv.Emit (ec);
2599                         else
2600                                 expr.Emit (ec);
2601                         ig.Emit (OpCodes.Stloc, local_copy);
2602
2603                         bool old_in_try = ec.InTry;
2604                         ec.InTry = true;
2605                         ig.BeginExceptionBlock ();
2606                         Statement.Emit (ec);
2607                         ec.InTry = old_in_try;
2608                         
2609                         Label skip = ig.DefineLabel ();
2610                         bool old_in_finally = ec.InFinally;
2611                         ig.BeginFinallyBlock ();
2612                         ig.Emit (OpCodes.Ldloc, local_copy);
2613                         ig.Emit (OpCodes.Brfalse, skip);
2614                         ig.Emit (OpCodes.Ldloc, local_copy);
2615                         ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
2616                         ig.MarkLabel (skip);
2617                         ec.InFinally = old_in_finally;
2618                         ig.EndExceptionBlock ();
2619
2620                         return false;
2621                 }
2622                 
2623                 public override bool Resolve (EmitContext ec)
2624                 {
2625                         return Statement.Resolve (ec);
2626                 }
2627                 
2628                 public override bool Emit (EmitContext ec)
2629                 {
2630                         if (expression_or_block is DictionaryEntry){
2631                                 string t = (string) ((DictionaryEntry) expression_or_block).Key;
2632                                 ArrayList var_list = (ArrayList)((DictionaryEntry)expression_or_block).Value;
2633
2634                                 return EmitLocalVariableDecls (ec, t, var_list);
2635                         } if (expression_or_block is Expression){
2636                                 Expression e = (Expression) expression_or_block;
2637
2638                                 e = e.Resolve (ec);
2639                                 if (e == null)
2640                                         return false;
2641
2642                                 return EmitExpression (ec, e);
2643                         }
2644                         return false;
2645                 }
2646         }
2647
2648         /// <summary>
2649         ///   Implementation of the foreach C# statement
2650         /// </summary>
2651         public class Foreach : Statement {
2652                 string type;
2653                 LocalVariableReference variable;
2654                 Expression expr;
2655                 Statement statement;
2656                 
2657                 public Foreach (string type, LocalVariableReference var, Expression expr,
2658                                 Statement stmt, Location l)
2659                 {
2660                         this.type = type;
2661                         this.variable = var;
2662                         this.expr = expr;
2663                         statement = stmt;
2664                         loc = l;
2665                 }
2666                 
2667                 public override bool Resolve (EmitContext ec)
2668                 {
2669                         expr = expr.Resolve (ec);
2670                         return statement.Resolve (ec) && expr != null;
2671                 }
2672                 
2673                 //
2674                 // Retrieves a `public bool MoveNext ()' method from the Type `t'
2675                 //
2676                 static MethodInfo FetchMethodMoveNext (Type t)
2677                 {
2678                         MemberInfo [] move_next_list;
2679                         
2680                         move_next_list = TypeContainer.FindMembers (
2681                                 t, MemberTypes.Method,
2682                                 BindingFlags.Public | BindingFlags.Instance,
2683                                 Type.FilterName, "MoveNext");
2684                         if (move_next_list == null || move_next_list.Length == 0)
2685                                 return null;
2686
2687                         foreach (MemberInfo m in move_next_list){
2688                                 MethodInfo mi = (MethodInfo) m;
2689                                 Type [] args;
2690                                 
2691                                 args = TypeManager.GetArgumentTypes (mi);
2692                                 if (args != null && args.Length == 0){
2693                                         if (mi.ReturnType == TypeManager.bool_type)
2694                                                 return mi;
2695                                 }
2696                         }
2697                         return null;
2698                 }
2699                 
2700                 //
2701                 // Retrieves a `public T get_Current ()' method from the Type `t'
2702                 //
2703                 static MethodInfo FetchMethodGetCurrent (Type t)
2704                 {
2705                         MemberInfo [] move_next_list;
2706                         
2707                         move_next_list = TypeContainer.FindMembers (
2708                                 t, MemberTypes.Method,
2709                                 BindingFlags.Public | BindingFlags.Instance,
2710                                 Type.FilterName, "get_Current");
2711                         if (move_next_list == null || move_next_list.Length == 0)
2712                                 return null;
2713
2714                         foreach (MemberInfo m in move_next_list){
2715                                 MethodInfo mi = (MethodInfo) m;
2716                                 Type [] args;
2717                                 
2718                                 args = TypeManager.GetArgumentTypes (mi);
2719                                 if (args != null && args.Length == 0)
2720                                         return mi;
2721                         }
2722                         return null;
2723                 }
2724
2725                 // 
2726                 // This struct records the helper methods used by the Foreach construct
2727                 //
2728                 class ForeachHelperMethods {
2729                         public EmitContext ec;
2730                         public MethodInfo get_enumerator;
2731                         public MethodInfo move_next;
2732                         public MethodInfo get_current;
2733
2734                         public ForeachHelperMethods (EmitContext ec)
2735                         {
2736                                 this.ec = ec;
2737                         }
2738                 }
2739                 
2740                 static bool GetEnumeratorFilter (MemberInfo m, object criteria)
2741                 {
2742                         if (m == null)
2743                                 return false;
2744                         
2745                         if (!(m is MethodInfo))
2746                                 return false;
2747                         
2748                         if (m.Name != "GetEnumerator")
2749                                 return false;
2750
2751                         MethodInfo mi = (MethodInfo) m;
2752                         Type [] args = TypeManager.GetArgumentTypes (mi);
2753                         if (args != null){
2754                                 if (args.Length != 0)
2755                                         return false;
2756                         }
2757                         ForeachHelperMethods hm = (ForeachHelperMethods) criteria;
2758                         EmitContext ec = hm.ec;
2759                         
2760                         //
2761                         // Check whether GetEnumerator is accessible to us
2762                         //
2763                         MethodAttributes prot = mi.Attributes & MethodAttributes.MemberAccessMask;
2764
2765                         Type declaring = mi.DeclaringType;
2766                         if (prot == MethodAttributes.Private){
2767                                 if (declaring != ec.ContainerType)
2768                                         return false;
2769                         } else if (prot == MethodAttributes.FamANDAssem){
2770                                 // If from a different assembly, false
2771                                 if (!(mi is MethodBuilder))
2772                                         return false;
2773                                 //
2774                                 // Are we being invoked from the same class, or from a derived method?
2775                                 //
2776                                 if (ec.ContainerType != declaring){
2777                                         if (!ec.ContainerType.IsSubclassOf (declaring))
2778                                                 return false;
2779                                 }
2780                         } else if (prot == MethodAttributes.FamORAssem){
2781                                 if (!(mi is MethodBuilder ||
2782                                       ec.ContainerType == declaring ||
2783                                       ec.ContainerType.IsSubclassOf (declaring)))
2784                                         return false;
2785                         } if (prot == MethodAttributes.Family){
2786                                 if (!(ec.ContainerType == declaring ||
2787                                       ec.ContainerType.IsSubclassOf (declaring)))
2788                                         return false;
2789                         }
2790
2791                         //
2792                         // Ok, we can access it, now make sure that we can do something
2793                         // with this `GetEnumerator'
2794                         //
2795                         if (mi.ReturnType == TypeManager.ienumerator_type || 
2796                             TypeManager.ienumerator_type.IsAssignableFrom (mi.ReturnType)){
2797                                 hm.move_next = TypeManager.bool_movenext_void;
2798                                 hm.get_current = TypeManager.object_getcurrent_void;
2799                                 return true;
2800                         }
2801
2802                         //
2803                         // Ok, so they dont return an IEnumerable, we will have to
2804                         // find if they support the GetEnumerator pattern.
2805                         //
2806                         Type return_type = mi.ReturnType;
2807
2808                         hm.move_next = FetchMethodMoveNext (return_type);
2809                         if (hm.move_next == null)
2810                                 return false;
2811                         hm.get_current = FetchMethodGetCurrent (return_type);
2812                         if (hm.get_current == null)
2813                                 return false;
2814
2815                         return true;
2816                 }
2817                 
2818                 /// <summary>
2819                 ///   This filter is used to find the GetEnumerator method
2820                 ///   on which IEnumerator operates
2821                 /// </summary>
2822                 static MemberFilter FilterEnumerator;
2823                 
2824                 static Foreach ()
2825                 {
2826                         FilterEnumerator = new MemberFilter (GetEnumeratorFilter);
2827                 }
2828
2829                 void error1579 (Type t)
2830                 {
2831                         Report.Error (1579, loc,
2832                                       "foreach statement cannot operate on variables of type `" +
2833                                       t.FullName + "' because that class does not provide a " +
2834                                       " GetEnumerator method or it is inaccessible");
2835                 }
2836
2837                 static bool TryType (Type t, ForeachHelperMethods hm)
2838                 {
2839                         MemberInfo [] mi;
2840                         
2841                         mi = TypeContainer.FindMembers (t, MemberTypes.Method,
2842                                                         BindingFlags.Public | BindingFlags.NonPublic |
2843                                                         BindingFlags.Instance,
2844                                                         FilterEnumerator, hm);
2845
2846                         if (mi == null || mi.Length == 0)
2847                                 return false;
2848
2849                         hm.get_enumerator = (MethodInfo) mi [0];
2850                         return true;    
2851                 }
2852                 
2853                 //
2854                 // Looks for a usable GetEnumerator in the Type, and if found returns
2855                 // the three methods that participate: GetEnumerator, MoveNext and get_Current
2856                 //
2857                 ForeachHelperMethods ProbeCollectionType (EmitContext ec, Type t)
2858                 {
2859                         ForeachHelperMethods hm = new ForeachHelperMethods (ec);
2860
2861                         if (TryType (t, hm))
2862                                 return hm;
2863
2864                         //
2865                         // Now try to find the method in the interfaces
2866                         //
2867                         while (t != null){
2868                                 Type [] ifaces = t.GetInterfaces ();
2869
2870                                 foreach (Type i in ifaces){
2871                                         if (TryType (i, hm))
2872                                                 return hm;
2873                                 }
2874                                 
2875                                 //
2876                                 // Since TypeBuilder.GetInterfaces only returns the interface
2877                                 // types for this type, we have to keep looping, but once
2878                                 // we hit a non-TypeBuilder (ie, a Type), then we know we are
2879                                 // done, because it returns all the types
2880                                 //
2881                                 if ((t is TypeBuilder))
2882                                         t = t.BaseType;
2883                                 else
2884                                         break;
2885                         } 
2886
2887                         return null;
2888                 }
2889
2890                 //
2891                 // FIXME: possible optimization.
2892                 // We might be able to avoid creating `empty' if the type is the sam
2893                 //
2894                 bool EmitCollectionForeach (EmitContext ec, Type var_type, ForeachHelperMethods hm)
2895                 {
2896                         ILGenerator ig = ec.ig;
2897                         LocalBuilder enumerator, disposable;
2898                         Expression empty = new EmptyExpression ();
2899                         Expression conv;
2900
2901                         //
2902                         // FIXME: maybe we can apply the same trick we do in the
2903                         // array handling to avoid creating empty and conv in some cases.
2904                         //
2905                         // Although it is not as important in this case, as the type
2906                         // will not likely be object (what the enumerator will return).
2907                         //
2908                         conv = Expression.ConvertExplicit (ec, empty, var_type, loc);
2909                         if (conv == null)
2910                                 return false;
2911                         
2912                         enumerator = ig.DeclareLocal (TypeManager.ienumerator_type);
2913                         disposable = ig.DeclareLocal (TypeManager.idisposable_type);
2914                         
2915                         //
2916                         // Instantiate the enumerator
2917                         //
2918                         if (expr.Type.IsValueType){
2919                                 if (expr is IMemoryLocation){
2920                                         IMemoryLocation ml = (IMemoryLocation) expr;
2921
2922                                         ml.AddressOf (ec, AddressOp.Load);
2923                                 } else
2924                                         throw new Exception ("Expr " + expr + " of type " + expr.Type +
2925                                                              " does not implement IMemoryLocation");
2926                                 ig.Emit (OpCodes.Call, hm.get_enumerator);
2927                         } else {
2928                                 expr.Emit (ec);
2929                                 ig.Emit (OpCodes.Callvirt, hm.get_enumerator);
2930                         }
2931                         ig.Emit (OpCodes.Stloc, enumerator);
2932
2933                         //
2934                         // Protect the code in a try/finalize block, so that
2935                         // if the beast implement IDisposable, we get rid of it
2936                         //
2937                         Label l = ig.BeginExceptionBlock ();
2938                         bool old_in_try = ec.InTry;
2939                         ec.InTry = true;
2940                         
2941                         Label end_try = ig.DefineLabel ();
2942                         
2943                         ig.MarkLabel (ec.LoopBegin);
2944                         ig.Emit (OpCodes.Ldloc, enumerator);
2945                         ig.Emit (OpCodes.Callvirt, hm.move_next);
2946                         ig.Emit (OpCodes.Brfalse, end_try);
2947                         ig.Emit (OpCodes.Ldloc, enumerator);
2948                         ig.Emit (OpCodes.Callvirt, hm.get_current);
2949                         variable.EmitAssign (ec, conv);
2950                         statement.Emit (ec);
2951                         ig.Emit (OpCodes.Br, ec.LoopBegin);
2952                         ig.MarkLabel (end_try);
2953                         ec.InTry = old_in_try;
2954                         
2955                         // The runtime provides this for us.
2956                         // ig.Emit (OpCodes.Leave, end);
2957
2958                         //
2959                         // Now the finally block
2960                         //
2961                         Label end_finally = ig.DefineLabel ();
2962                         bool old_in_finally = ec.InFinally;
2963                         ec.InFinally = true;
2964                         ig.BeginFinallyBlock ();
2965                         
2966                         ig.Emit (OpCodes.Ldloc, enumerator);
2967                         ig.Emit (OpCodes.Isinst, TypeManager.idisposable_type);
2968                         ig.Emit (OpCodes.Stloc, disposable);
2969                         ig.Emit (OpCodes.Ldloc, disposable);
2970                         ig.Emit (OpCodes.Brfalse, end_finally);
2971                         ig.Emit (OpCodes.Ldloc, disposable);
2972                         ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
2973                         ig.MarkLabel (end_finally);
2974                         ec.InFinally = old_in_finally;
2975
2976                         // The runtime generates this anyways.
2977                         // ig.Emit (OpCodes.Endfinally);
2978
2979                         ig.EndExceptionBlock ();
2980
2981                         ig.MarkLabel (ec.LoopEnd);
2982                         return false;
2983                 }
2984
2985                 //
2986                 // FIXME: possible optimization.
2987                 // We might be able to avoid creating `empty' if the type is the sam
2988                 //
2989                 bool EmitArrayForeach (EmitContext ec, Type var_type)
2990                 {
2991                         Type array_type = expr.Type;
2992                         Type element_type = array_type.GetElementType ();
2993                         Expression conv = null;
2994                         Expression empty = new EmptyExpression (element_type);
2995                         
2996                         conv = Expression.ConvertExplicit (ec, empty, var_type, loc);
2997                         if (conv == null)
2998                                 return false;
2999
3000                         int rank = array_type.GetArrayRank ();
3001                         ILGenerator ig = ec.ig;
3002
3003                         LocalBuilder copy = ig.DeclareLocal (array_type);
3004                         
3005                         //
3006                         // Make our copy of the array
3007                         //
3008                         expr.Emit (ec);
3009                         ig.Emit (OpCodes.Stloc, copy);
3010                         
3011                         if (rank == 1){
3012                                 LocalBuilder counter = ig.DeclareLocal (TypeManager.int32_type);
3013
3014                                 Label loop, test;
3015                                 
3016                                 ig.Emit (OpCodes.Ldc_I4_0);
3017                                 ig.Emit (OpCodes.Stloc, counter);
3018                                 test = ig.DefineLabel ();
3019                                 ig.Emit (OpCodes.Br, test);
3020
3021                                 loop = ig.DefineLabel ();
3022                                 ig.MarkLabel (loop);
3023
3024                                 ig.Emit (OpCodes.Ldloc, copy);
3025                                 ig.Emit (OpCodes.Ldloc, counter);
3026                                 ArrayAccess.EmitLoadOpcode (ig, var_type);
3027
3028                                 variable.EmitAssign (ec, conv);
3029
3030                                 statement.Emit (ec);
3031
3032                                 ig.MarkLabel (ec.LoopBegin);
3033                                 ig.Emit (OpCodes.Ldloc, counter);
3034                                 ig.Emit (OpCodes.Ldc_I4_1);
3035                                 ig.Emit (OpCodes.Add);
3036                                 ig.Emit (OpCodes.Stloc, counter);
3037
3038                                 ig.MarkLabel (test);
3039                                 ig.Emit (OpCodes.Ldloc, counter);
3040                                 ig.Emit (OpCodes.Ldloc, copy);
3041                                 ig.Emit (OpCodes.Ldlen);
3042                                 ig.Emit (OpCodes.Conv_I4);
3043                                 ig.Emit (OpCodes.Blt, loop);
3044                         } else {
3045                                 LocalBuilder [] dim_len   = new LocalBuilder [rank];
3046                                 LocalBuilder [] dim_count = new LocalBuilder [rank];
3047                                 Label [] loop = new Label [rank];
3048                                 Label [] test = new Label [rank];
3049                                 int dim;
3050                                 
3051                                 for (dim = 0; dim < rank; dim++){
3052                                         dim_len [dim] = ig.DeclareLocal (TypeManager.int32_type);
3053                                         dim_count [dim] = ig.DeclareLocal (TypeManager.int32_type);
3054                                         test [dim] = ig.DefineLabel ();
3055                                         loop [dim] = ig.DefineLabel ();
3056                                 }
3057                                         
3058                                 for (dim = 0; dim < rank; dim++){
3059                                         ig.Emit (OpCodes.Ldloc, copy);
3060                                         IntLiteral.EmitInt (ig, dim);
3061                                         ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int);
3062                                         ig.Emit (OpCodes.Stloc, dim_len [dim]);
3063                                 }
3064
3065                                 for (dim = 0; dim < rank; dim++){
3066                                         ig.Emit (OpCodes.Ldc_I4_0);
3067                                         ig.Emit (OpCodes.Stloc, dim_count [dim]);
3068                                         ig.Emit (OpCodes.Br, test [dim]);
3069                                         ig.MarkLabel (loop [dim]);
3070                                 }
3071
3072                                 ig.Emit (OpCodes.Ldloc, copy);
3073                                 for (dim = 0; dim < rank; dim++)
3074                                         ig.Emit (OpCodes.Ldloc, dim_count [dim]);
3075
3076                                 //
3077                                 // FIXME: Maybe we can cache the computation of `get'?
3078                                 //
3079                                 Type [] args = new Type [rank];
3080                                 MethodInfo get;
3081
3082                                 for (int i = 0; i < rank; i++)
3083                                         args [i] = TypeManager.int32_type;
3084
3085                                 ModuleBuilder mb = CodeGen.ModuleBuilder;
3086                                 get = mb.GetArrayMethod (
3087                                         array_type, "Get",
3088                                         CallingConventions.HasThis| CallingConventions.Standard,
3089                                         var_type, args);
3090                                 ig.Emit (OpCodes.Call, get);
3091                                 variable.EmitAssign (ec, conv);
3092                                 statement.Emit (ec);
3093                                 ig.MarkLabel (ec.LoopBegin);
3094                                 for (dim = rank - 1; dim >= 0; dim--){
3095                                         ig.Emit (OpCodes.Ldloc, dim_count [dim]);
3096                                         ig.Emit (OpCodes.Ldc_I4_1);
3097                                         ig.Emit (OpCodes.Add);
3098                                         ig.Emit (OpCodes.Stloc, dim_count [dim]);
3099
3100                                         ig.MarkLabel (test [dim]);
3101                                         ig.Emit (OpCodes.Ldloc, dim_count [dim]);
3102                                         ig.Emit (OpCodes.Ldloc, dim_len [dim]);
3103                                         ig.Emit (OpCodes.Blt, loop [dim]);
3104                                 }
3105                         }
3106                         ig.MarkLabel (ec.LoopEnd);
3107                         
3108                         return false;
3109                 }
3110                 
3111                 public override bool Emit (EmitContext ec)
3112                 {
3113                         Type var_type;
3114                         bool ret_val;
3115                         
3116                         var_type = RootContext.LookupType (ec.DeclSpace, type, false, loc);
3117                         if (var_type == null)
3118                                 return false;
3119                         
3120                         //
3121                         // We need an instance variable.  Not sure this is the best
3122                         // way of doing this.
3123                         //
3124                         // FIXME: When we implement propertyaccess, will those turn
3125                         // out to return values in ExprClass?  I think they should.
3126                         //
3127                         if (!(expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.Value ||
3128                               expr.eclass == ExprClass.PropertyAccess)){
3129                                 error1579 (expr.Type);
3130                                 return false;
3131                         }
3132
3133                         ILGenerator ig = ec.ig;
3134                         
3135                         Label old_begin = ec.LoopBegin, old_end = ec.LoopEnd;
3136                         bool old_inloop = ec.InLoop;
3137                         ec.LoopBegin = ig.DefineLabel ();
3138                         ec.LoopEnd = ig.DefineLabel ();
3139                         ec.InLoop = true;
3140                         
3141                         if (expr.Type.IsArray)
3142                                 ret_val = EmitArrayForeach (ec, var_type);
3143                         else {
3144                                 ForeachHelperMethods hm;
3145                                 
3146                                 hm = ProbeCollectionType (ec, expr.Type);
3147                                 if (hm == null){
3148                                         error1579 (expr.Type);
3149                                         return false;
3150                                 }
3151
3152                                 ret_val = EmitCollectionForeach (ec, var_type, hm);
3153                         }
3154                         
3155                         ec.LoopBegin = old_begin;
3156                         ec.LoopEnd = old_end;
3157                         ec.InLoop = old_inloop;
3158
3159                         return ret_val;
3160                 }
3161         }
3162 }
3163