Add new test
[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 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
21                 /// <summary>
22                 ///   Return value indicates whether all code paths emitted return.
23                 /// </summary>
24                 public abstract bool Emit (EmitContext ec);
25
26                 /// <remarks>
27                 ///    Emits a bool expression.
28                 /// </remarks>
29                 public static Expression EmitBoolExpression (EmitContext ec, Expression e,
30                                                              Label l, bool isTrue)
31                 {
32                         e = e.Resolve (ec);
33
34                         if (e == null)
35                                 return null;
36
37                         if (e.Type != TypeManager.bool_type)
38                                 e = Expression.ConvertImplicit (ec, e, TypeManager.bool_type,
39                                                                 new Location (-1));
40
41                         if (e == null){
42                                 Report.Error (
43                                         31, "Can not convert the expression to a boolean");
44                                 return null;
45                         }
46
47                         bool invert = false;
48                         if (e is Unary){
49                                 Unary u = (Unary) e;
50                                 
51                                 if (u.Oper == Unary.Operator.LogicalNot){
52                                         invert = true;
53
54                                         u.EmitLogicalNot (ec);
55                                 }
56                         } 
57
58                         if (!invert)
59                                 e.Emit (ec);
60
61                         if (isTrue){
62                                 if (invert)
63                                         ec.ig.Emit (OpCodes.Brfalse, l);
64                                 else
65                                         ec.ig.Emit (OpCodes.Brtrue, l);
66                         } else {
67                                 if (invert)
68                                         ec.ig.Emit (OpCodes.Brtrue, l);
69                                 else
70                                         ec.ig.Emit (OpCodes.Brfalse, l);
71                         }
72                         
73                         return e;
74                 }
75
76         }
77
78         public class EmptyStatement : Statement {
79                 public override bool Emit (EmitContext ec)
80                 {
81                         return false;
82                 }
83         }
84         
85         public class If : Statement {
86                 public readonly Expression  Expr;
87                 public readonly Statement   TrueStatement;
88                 public readonly Statement   FalseStatement;
89                 
90                 public If (Expression expr, Statement trueStatement)
91                 {
92                         Expr = expr;
93                         TrueStatement = trueStatement;
94                 }
95
96                 public If (Expression expr,
97                            Statement trueStatement,
98                            Statement falseStatement)
99                 {
100                         Expr = expr;
101                         TrueStatement = trueStatement;
102                         FalseStatement = falseStatement;
103                 }
104
105                 public override bool Emit (EmitContext ec)
106                 {
107                         ILGenerator ig = ec.ig;
108                         Label false_target = ig.DefineLabel ();
109                         Label end;
110                         bool is_true_ret, is_false_ret;
111                         
112                         if (EmitBoolExpression (ec, Expr, false_target, false) == null)
113                                 return false;
114                         
115                         is_true_ret = TrueStatement.Emit (ec);
116                         is_false_ret = is_true_ret;
117
118                         if (FalseStatement != null){
119                                 bool branch_emitted = false;
120                                 
121                                 end = ig.DefineLabel ();
122                                 if (!is_true_ret){
123                                         ig.Emit (OpCodes.Br, end);
124                                         branch_emitted = true;
125                                 }
126                         
127                                 ig.MarkLabel (false_target);
128                                 is_false_ret = FalseStatement.Emit (ec);
129
130                                 if (branch_emitted)
131                                         ig.MarkLabel (end);
132                         } else {
133                                 ig.MarkLabel (false_target);
134                                 is_false_ret = false;
135                         }
136
137                         return is_true_ret && is_false_ret;
138                 }
139         }
140
141         public class Do : Statement {
142                 public readonly Expression Expr;
143                 public readonly Statement  EmbeddedStatement;
144                 
145                 public Do (Statement statement, Expression boolExpr)
146                 {
147                         Expr = boolExpr;
148                         EmbeddedStatement = statement;
149                 }
150
151                 public override bool Emit (EmitContext ec)
152                 {
153                         ILGenerator ig = ec.ig;
154                         Label loop = ig.DefineLabel ();
155                         Label old_begin = ec.LoopBegin;
156                         Label old_end = ec.LoopEnd;
157                         bool  old_inloop = ec.InLoop;
158                         Expression e;
159                         
160                         ec.LoopBegin = ig.DefineLabel ();
161                         ec.LoopEnd = ig.DefineLabel ();
162                         ec.InLoop = true;
163                                 
164                         ig.MarkLabel (loop);
165                         EmbeddedStatement.Emit (ec);
166                         ig.MarkLabel (ec.LoopBegin);
167                         e = EmitBoolExpression (ec, Expr, loop, true);
168                         ig.MarkLabel (ec.LoopEnd);
169
170                         ec.LoopBegin = old_begin;
171                         ec.LoopEnd = old_end;
172                         ec.InLoop = old_inloop;
173
174                         //
175                         // Inform whether we are infinite or not
176                         //
177                         if (e is BoolConstant){
178                                 BoolConstant bc = (BoolConstant) e;
179
180                                 if (bc.Value == true)
181                                         return true;
182                         }
183                         
184                         return false;
185                 }
186         }
187
188         public class While : Statement {
189                 public readonly Expression Expr;
190                 public readonly Statement Statement;
191                 
192                 public While (Expression boolExpr, Statement statement)
193                 {
194                         Expr = boolExpr;
195                         Statement = statement;
196                 }
197
198                 public override bool Emit (EmitContext ec)
199                 {
200                         ILGenerator ig = ec.ig;
201                         Label old_begin = ec.LoopBegin;
202                         Label old_end = ec.LoopEnd;
203                         bool old_inloop = ec.InLoop;
204                         Expression e;
205                         
206                         ec.LoopBegin = ig.DefineLabel ();
207                         ec.LoopEnd = ig.DefineLabel ();
208                         ec.InLoop = true;
209                         
210                         ig.MarkLabel (ec.LoopBegin);
211                         e = EmitBoolExpression (ec, Expr, ec.LoopEnd, false);
212                         Statement.Emit (ec);
213                         ig.Emit (OpCodes.Br, ec.LoopBegin);
214                         ig.MarkLabel (ec.LoopEnd);
215
216                         ec.LoopBegin = old_begin;
217                         ec.LoopEnd = old_end;
218                         ec.InLoop = old_inloop;
219
220                         //
221                         // Inform whether we are infinite or not
222                         //
223                         if (e is BoolConstant){
224                                 BoolConstant bc = (BoolConstant) e;
225
226                                 if (bc.Value == true)
227                                         return true;
228                         }
229                         return false;
230                 }
231         }
232
233         public class For : Statement {
234                 public readonly Statement InitStatement;
235                 public readonly Expression Test;
236                 public readonly Statement Increment;
237                 public readonly Statement Statement;
238                 
239                 public For (Statement initStatement,
240                             Expression test,
241                             Statement increment,
242                             Statement statement)
243                 {
244                         InitStatement = initStatement;
245                         Test = test;
246                         Increment = increment;
247                         Statement = statement;
248                 }
249
250                 public override bool Emit (EmitContext ec)
251                 {
252                         ILGenerator ig = ec.ig;
253                         Label old_begin = ec.LoopBegin;
254                         Label old_end = ec.LoopEnd;
255                         bool old_inloop = ec.InLoop;
256                         Label loop = ig.DefineLabel ();
257                         Expression e = null;
258
259                         if (InitStatement != null)
260                                 if (! (InitStatement is EmptyStatement))
261                                         InitStatement.Emit (ec);
262
263                         ec.LoopBegin = ig.DefineLabel ();
264                         ec.LoopEnd = ig.DefineLabel ();
265                         ec.InLoop = true;
266
267                         ig.MarkLabel (loop);
268
269                         //
270                         // If test is null, there is no test, and we are just
271                         // an infinite loop
272                         //
273                         if (Test != null)
274                                 e = EmitBoolExpression (ec, Test, ec.LoopEnd, false);
275                 
276                         Statement.Emit (ec);
277                         ig.MarkLabel (ec.LoopBegin);
278                         if (!(Increment is EmptyStatement))
279                                 Increment.Emit (ec);
280                         ig.Emit (OpCodes.Br, loop);
281                         ig.MarkLabel (ec.LoopEnd);
282
283                         ec.LoopBegin = old_begin;
284                         ec.LoopEnd = old_end;
285                         ec.InLoop = old_inloop;
286
287                         //
288                         // Inform whether we are infinite or not
289                         //
290                         if (Test != null){
291                                 if (e is BoolConstant){
292                                         BoolConstant bc = (BoolConstant) e;
293
294                                         if (bc.Value)
295                                                 return true;
296                                 }
297                                 return false;
298                         } else
299                                 return true;
300                 }
301         }
302         
303         public class StatementExpression : Statement {
304                 public readonly ExpressionStatement Expr;
305                 
306                 public StatementExpression (ExpressionStatement expr)
307                 {
308                         Expr = expr;
309                 }
310
311                 public override bool Emit (EmitContext ec)
312                 {
313                         ILGenerator ig = ec.ig;
314                         Expression ne;
315                         
316                         ne = Expr.Resolve (ec);
317                         if (ne != null){
318                                 if (ne is ExpressionStatement)
319                                         ((ExpressionStatement) ne).EmitStatement (ec);
320                                 else {
321                                         ne.Emit (ec);
322                                         ig.Emit (OpCodes.Pop);
323                                 }
324                         }
325
326                         return false;
327                 }
328
329                 public override string ToString ()
330                 {
331                         return "StatementExpression (" + Expr + ")";
332                 }
333         }
334
335         /// <summary>
336         ///   Implements the return statement
337         /// </summary>
338         public class Return : Statement {
339                 public Expression Expr;
340                 public readonly Location loc;
341                 
342                 public Return (Expression expr, Location l)
343                 {
344                         Expr = expr;
345                         loc = l;
346                 }
347
348                 public override bool Emit (EmitContext ec)
349                 {
350                         if (ec.InFinally){
351                                 Report.Error (157,loc,"Control can not leave the body of the finally block");
352                                 return false;
353                         }
354                         
355                         if (ec.ReturnType == null){
356                                 if (Expr != null){
357                                         Report.Error (127, loc, "Return with a value not allowed here");
358                                         return false;
359                                 }
360                         } else {
361                                 if (Expr == null){
362                                         Report.Error (126, loc, "An object of type `" +
363                                                       TypeManager.CSharpName (ec.ReturnType) + "' is " +
364                                                       "expected for the return statement");
365                                         return false;
366                                 }
367
368                                 Expr = Expr.Resolve (ec);
369                                 if (Expr == null)
370                                         return false;
371
372                                 if (Expr.Type != ec.ReturnType)
373                                         Expr = Expression.ConvertImplicitRequired (
374                                                 ec, Expr, ec.ReturnType, loc);
375
376                                 if (Expr == null)
377                                         return false;
378
379                                 Expr.Emit (ec);
380
381                                 if (ec.InTry || ec.InCatch)
382                                         ec.ig.Emit (OpCodes.Stloc, ec.TemporaryReturn ());
383                         }
384
385                         if (ec.InTry || ec.InCatch){
386                                 ec.ig.Emit (OpCodes.Leave, ec.ReturnLabel);
387                                 return false; 
388                         } else {
389                                 ec.ig.Emit (OpCodes.Ret);
390                                 return true;
391                         }
392                 }
393         }
394
395         public class Goto : Statement {
396                 string target;
397                 Location loc;
398                 Block block;
399                 
400                 public Goto (Block parent_block, string label, Location l)
401                 {
402                         block = parent_block;
403                         loc = l;
404                         target = label;
405                 }
406
407                 public string Target {
408                         get {
409                                 return target;
410                         }
411                 }
412
413                 public override bool Emit (EmitContext ec)
414                 {
415                         LabeledStatement label = block.LookupLabel (target);
416
417                         if (label == null){
418                                 //
419                                 // Maybe we should catch this before?
420                                 //
421                                 Report.Error (
422                                         159, loc,
423                                         "No such label `" + target + "' in this scope");
424                                 return false;
425                         }
426                         Label l = label.LabelTarget (ec);
427                         ec.ig.Emit (OpCodes.Br, l);
428                         
429                         return false;
430                 }
431         }
432
433         public class LabeledStatement : Statement {
434                 string label_name;
435                 bool defined;
436                 Label label;
437                 
438                 public LabeledStatement (string label_name)
439                 {
440                         this.label_name = label_name;
441                 }
442
443                 public Label LabelTarget (EmitContext ec)
444                 {
445                         if (defined)
446                                 return label;
447                         label = ec.ig.DefineLabel ();
448                         defined = true;
449
450                         return label;
451                 }
452                 
453                 public override bool Emit (EmitContext ec)
454                 {
455                         LabelTarget (ec);
456                         ec.ig.MarkLabel (label);
457
458                         return false;
459                 }
460         }
461         
462
463         /// <summary>
464         ///   `goto default' statement
465         /// </summary>
466         public class GotoDefault : Statement {
467                 Location loc;
468                 
469                 public GotoDefault (Location l)
470                 {
471                         loc = l;
472                 }
473
474                 public override bool Emit (EmitContext ec)
475                 {
476                         if (ec.Switch == null){
477                                 Report.Error (153, loc, "goto default is only valid in a switch statement");
478                                 return false;
479                         }
480
481                         if (!ec.Switch.GotDefault){
482                                 Report.Error (159, loc, "No default target on switch statement");
483                                 return false;
484                         }
485                         ec.ig.Emit (OpCodes.Br, ec.Switch.DefaultTarget);
486                         return false;
487                 }
488         }
489
490         /// <summary>
491         ///   `goto case' statement
492         /// </summary>
493         public class GotoCase : Statement {
494                 Location loc;
495                 Expression expr;
496                 
497                 public GotoCase (Expression e, Location l)
498                 {
499                         expr = e;
500                         loc = l;
501                 }
502
503                 public override bool Emit (EmitContext ec)
504                 {
505                         if (ec.Switch == null){
506                                 Report.Error (153, loc, "goto case is only valid in a switch statement");
507                                 return false;
508                         }
509
510                         expr = expr.Resolve (ec);
511                         if (expr == null)
512                                 return false;
513
514                         if (!(expr is Constant)){
515                                 Report.Error (159, loc, "Target expression for goto case is not constant");
516                                 return false;
517                         }
518
519                         object val = Expression.ConvertIntLiteral (
520                                 (Constant) expr, ec.Switch.SwitchType, loc);
521
522                         if (val == null)
523                                 return false;
524                                         
525                         SwitchLabel sl = (SwitchLabel) ec.Switch.Elements [val];
526
527                         if (sl == null){
528                                 Report.Error (
529                                         159, loc,
530                                         "No such label 'case " + val + "': for the goto case");
531                         }
532
533                         ec.ig.Emit (OpCodes.Br, sl.ILLabel);
534                         return false;
535                 }
536         }
537         
538         public class Throw : Statement {
539                 public readonly Expression Expr;
540                 Location loc;
541                 
542                 public Throw (Expression expr, Location l)
543                 {
544                         Expr = expr;
545                         loc = l;
546                 }
547
548                 public override bool Emit (EmitContext ec)
549                 {
550                         if (Expr == null){
551                                 if (ec.InCatch)
552                                         ec.ig.Emit (OpCodes.Rethrow);
553                                 else {
554                                         Report.Error (
555                                                 156, loc,
556                                                 "A throw statement with no argument is only " +
557                                                 "allowed in a catch clause");
558                                 }
559                                 return false;
560                         }
561                         
562                         Expression e = Expr.Resolve (ec);
563
564                         if (e == null)
565                                 return false;
566                         
567                         e.Emit (ec);
568
569                         ec.ig.Emit (OpCodes.Throw);
570
571                         return true;
572                 }
573         }
574
575         public class Break : Statement {
576                 Location loc;
577                 
578                 public Break (Location l)
579                 {
580                         loc = l;
581                 }
582
583                 public override bool Emit (EmitContext ec)
584                 {
585                         ILGenerator ig = ec.ig;
586
587                         if (ec.InLoop == false && ec.Switch == null){
588                                 Report.Error (139, loc, "No enclosing loop or switch to continue to");
589                                 return false;
590                         }
591                         
592                         ig.Emit (OpCodes.Br, ec.LoopEnd);
593                         return false;
594                 }
595         }
596
597         public class Continue : Statement {
598                 Location loc;
599                 
600                 public Continue (Location l)
601                 {
602                         loc = l;
603                 }
604
605                 public override bool Emit (EmitContext ec)
606                 {
607                         Label begin = ec.LoopBegin;
608                         
609                         if (!ec.InLoop){
610                                 Report.Error (139, loc, "No enclosing loop to continue to");
611                                 return false;
612                         } 
613
614                         //
615                         // UGH: Non trivial.  This Br might cross a try/catch boundary
616                         // How can we tell?
617                         //
618                         // while () {
619                         //   try { ... } catch { continue; }
620                         // }
621                         //
622                         // From:
623                         // try {} catch { while () { continue; }}
624                         //
625                         ec.ig.Emit (OpCodes.Br, begin);
626                         return false;
627                 }
628         }
629         
630         public class VariableInfo {
631                 public readonly string Type;
632                 public LocalBuilder LocalBuilder;
633                 public Type VariableType;
634                 public readonly Location Location;
635                 
636                 int  idx;
637                 public bool Used;
638                 public bool Assigned;
639                 public bool ReadOnly;
640                 
641                 public VariableInfo (string type, Location l)
642                 {
643                         Type = type;
644                         LocalBuilder = null;
645                         idx = -1;
646                         Location = l;
647                 }
648
649                 public int Idx {
650                         get {
651                                 if (idx == -1)
652                                         throw new Exception ("Unassigned idx for variable");
653                                 
654                                 return idx;
655                         }
656
657                         set {
658                                 idx = value;
659                         }
660                 }
661
662                 public void MakePinned ()
663                 {
664                         TypeManager.MakePinned (LocalBuilder);
665                 }                               
666         }
667                 
668         /// <summary>
669         ///   Block represents a C# block.
670         /// </summary>
671         ///
672         /// <remarks>
673         ///   This class is used in a number of places: either to represent
674         ///   explicit blocks that the programmer places or implicit blocks.
675         ///
676         ///   Implicit blocks are used as labels or to introduce variable
677         ///   declarations.
678         /// </remarks>
679         public class Block : Statement {
680                 public readonly Block  Parent;
681                 public readonly bool   Implicit;
682
683                 //
684                 // The statements in this block
685                 //
686                 StatementCollection statements;
687
688                 //
689                 // An array of Blocks.  We keep track of children just
690                 // to generate the local variable declarations.
691                 //
692                 // Statements and child statements are handled through the
693                 // statements.
694                 //
695                 ArrayList children;
696                 
697                 //
698                 // Labels.  (label, block) pairs.
699                 //
700                 Hashtable labels;
701
702                 //
703                 // Keeps track of (name, type) pairs
704                 //
705                 Hashtable variables;
706
707                 //
708                 // Keeps track of constants
709                 Hashtable constants;
710
711                 //
712                 // Maps variable names to ILGenerator.LocalBuilders
713                 //
714                 Hashtable local_builders;
715
716                 bool used = false;
717
718                 static int id;
719
720                 int this_id;
721                 
722                 public Block (Block parent)
723                 {
724                         if (parent != null)
725                                 parent.AddChild (this);
726                         
727                         this.Parent = parent;
728                         this.Implicit = false;
729
730                         this_id = id++;
731                 }
732
733                 public Block (Block parent, bool implicit_block)
734                 {
735                         if (parent != null)
736                                 parent.AddChild (this);
737                         
738                         this.Parent = parent;
739                         this.Implicit = true;
740                         this_id = id++;
741                 }
742
743                 public int ID {
744                         get {
745                                 return this_id;
746                         }
747                 }
748                 
749                 void AddChild (Block b)
750                 {
751                         if (children == null)
752                                 children = new ArrayList ();
753                         
754                         children.Add (b);
755                 }
756
757                 /// <summary>
758                 ///   Adds a label to the current block. 
759                 /// </summary>
760                 ///
761                 /// <returns>
762                 ///   false if the name already exists in this block. true
763                 ///   otherwise.
764                 /// </returns>
765                 ///
766                 public bool AddLabel (string name, LabeledStatement target)
767                 {
768                         if (labels == null)
769                                 labels = new Hashtable ();
770                         if (labels.Contains (name))
771                                 return false;
772                         
773                         labels.Add (name, target);
774                         return true;
775                 }
776
777                 public LabeledStatement LookupLabel (string name)
778                 {
779                         if (labels != null){
780                                 if (labels.Contains (name))
781                                         return ((LabeledStatement) labels [name]);
782                         }
783
784                         if (Parent != null)
785                                 return Parent.LookupLabel (name);
786
787                         return null;
788                 }
789
790                 public VariableInfo AddVariable (string type, string name, Parameters pars, Location l)
791                 {
792                         if (variables == null)
793                                 variables = new Hashtable ();
794
795                         if (GetVariableType (name) != null)
796                                 return null;
797
798                         if (pars != null) {
799                                 int idx = 0;
800                                 Parameter p = pars.GetParameterByName (name, out idx);
801                                 if (p != null) 
802                                         return null;
803                         }
804                         
805                         VariableInfo vi = new VariableInfo (type, l);
806
807                         variables.Add (name, vi);
808
809                         return vi;
810                 }
811
812                 public bool AddConstant (string type, string name, Expression value, Parameters pars, Location l)
813                 {
814                         if (AddVariable (type, name, pars, l) == null)
815                                 return false;
816                         
817                         if (constants == null)
818                                 constants = new Hashtable ();
819
820                         constants.Add (name, value);
821                         return true;
822                 }
823
824                 public Hashtable Variables {
825                         get {
826                                 return variables;
827                         }
828                 }
829
830                 public VariableInfo GetVariableInfo (string name)
831                 {
832                         if (variables != null) {
833                                 object temp;
834                                 temp = variables [name];
835
836                                 if (temp != null){
837                                         return (VariableInfo) temp;
838                                 }
839                         }
840
841                         if (Parent != null)
842                                 return Parent.GetVariableInfo (name);
843
844                         return null;
845                 }
846                 
847                 public string GetVariableType (string name)
848                 {
849                         VariableInfo vi = GetVariableInfo (name);
850
851                         if (vi != null)
852                                 return vi.Type;
853
854                         return null;
855                 }
856
857                 public Expression GetConstantExpression (string name)
858                 {
859                         if (constants != null) {
860                                 object temp;
861                                 temp = constants [name];
862                                 
863                                 if (temp != null)
864                                         return (Expression) temp;
865                         }
866                         
867                         if (Parent != null)
868                                 return Parent.GetConstantExpression (name);
869
870                         return null;
871                 }
872                 
873                 /// <summary>
874                 ///   True if the variable named @name has been defined
875                 ///   in this block
876                 /// </summary>
877                 public bool IsVariableDefined (string name)
878                 {
879                         if (variables != null) {
880                                 if (variables.Contains (name))
881                                         return true;
882                         }
883                         
884                         if (Parent != null)
885                                 return Parent.IsVariableDefined (name);
886
887                         return false;
888                 }
889
890                 /// <summary>
891                 ///   True if the variable named @name is a constant
892                 ///  </summary>
893                 public bool IsConstant (string name)
894                 {
895                         Expression e = null;
896                         
897                         e = GetConstantExpression (name);
898                         
899                         return e != null;
900                 }
901                 
902                 /// <summary>
903                 ///   Use to fetch the statement associated with this label
904                 /// </summary>
905                 public Statement this [string name] {
906                         get {
907                                 return (Statement) labels [name];
908                         }
909                 }
910
911                 /// <returns>
912                 ///   A list of labels that were not used within this block
913                 /// </returns>
914                 public string [] GetUnreferenced ()
915                 {
916                         // FIXME: Implement me
917                         return null;
918                 }
919
920                 public StatementCollection Statements {
921                         get {
922                                 if (statements == null)
923                                         statements = new StatementCollection ();
924
925                                 return statements;
926                         }
927                 }
928
929                 public void AddStatement (Statement s)
930                 {
931                         if (statements == null)
932                                 statements = new StatementCollection ();
933
934                         statements.Add (s);
935                         used = true;
936                 }
937
938                 public bool Used {
939                         get {
940                                 return used;
941                         }
942                 }
943
944                 public void Use ()
945                 {
946                         used = true;
947                 }
948                 
949                 /// <summary>
950                 ///   Emits the variable declarations and labels.
951                 /// </summary>
952                 /// <remarks>
953                 ///   tc: is our typecontainer (to resolve type references)
954                 ///   ig: is the code generator:
955                 ///   toplevel: the toplevel block.  This is used for checking 
956                 ///             that no two labels with the same name are used.
957                 /// </remarks>
958                 public int EmitMeta (EmitContext ec, Block toplevel, int count)
959                 {
960                         TypeContainer tc = ec.TypeContainer;
961                         ILGenerator ig = ec.ig;
962                                 
963                         //
964                         // Process this block variables
965                         //
966                         if (variables != null){
967                                 local_builders = new Hashtable ();
968                                 
969                                 foreach (DictionaryEntry de in variables){
970                                         string name = (string) de.Key;
971                                         VariableInfo vi = (VariableInfo) de.Value;
972                                         Type t;
973
974                                         t = RootContext.LookupType (tc, vi.Type, false, vi.Location);
975                                         if (t == null)
976                                                 continue;
977
978                                         vi.VariableType = t;
979                                         vi.LocalBuilder = ig.DeclareLocal (t);
980                                         vi.Idx = count++;
981
982                                         if (constants == null)
983                                                 continue;
984
985                                         Expression cv = (Expression) constants [name];
986                                         if (cv == null)
987                                                 continue;
988
989                                         Expression e = cv.Resolve (ec);
990                                         if (e == null)
991                                                 continue;
992
993                                         if (!(e is Constant)){
994                                                 Report.Error (133, vi.Location,
995                                                               "The expression being assigned to `" +
996                                                               name + "' must be constant");
997                                                 continue;
998                                         }
999
1000                                         constants.Remove (name);
1001                                         constants.Add (name, e);
1002                                 }
1003                         }
1004
1005                         //
1006                         // Now, handle the children
1007                         //
1008                         if (children != null){
1009                                 foreach (Block b in children)
1010                                         count = b.EmitMeta (ec, toplevel, count);
1011                         }
1012
1013                         return count;
1014                 }
1015
1016                 public void UsageWarning ()
1017                 {
1018                         string name;
1019                         
1020                         if (variables != null){
1021                                 foreach (DictionaryEntry de in variables){
1022                                         VariableInfo vi = (VariableInfo) de.Value;
1023                                         
1024                                         if (vi.Used)
1025                                                 continue;
1026                                         
1027                                         name = (string) de.Key;
1028                                                 
1029                                         if (vi.Assigned){
1030                                                 Report.Warning (
1031                                                         219, vi.Location, "The variable `" + name +
1032                                                         "' is assigned but its value is never used");
1033                                         } else {
1034                                                 Report.Warning (
1035                                                         168, vi.Location, "The variable `" +
1036                                                         name +
1037                                                         "' is declared but never used");
1038                                         } 
1039                                 }
1040                         }
1041
1042                         if (children != null)
1043                                 foreach (Block b in children)
1044                                         b.UsageWarning ();
1045                 }
1046
1047 //              static int count;
1048                 
1049                 public override bool Emit (EmitContext ec)
1050                 {
1051                         bool is_ret = false;
1052                         Block prev_block = ec.CurrentBlock;
1053
1054 //                      count++;
1055                         ec.CurrentBlock = this;
1056 //                      if (count == 40)
1057 //                              throw new Exception ();
1058                         foreach (Statement s in Statements)
1059                                 is_ret = s.Emit (ec);
1060 //                      count--;
1061                         
1062                         ec.CurrentBlock = prev_block;
1063                         return is_ret;
1064                 }
1065         }
1066
1067         public class SwitchLabel {
1068                 Expression label;
1069                 object converted;
1070                 public Location loc;
1071                 public Label ILLabel;
1072                 
1073                 //
1074                 // if expr == null, then it is the default case.
1075                 //
1076                 public SwitchLabel (Expression expr, Location l)
1077                 {
1078                         label = expr;
1079                         loc = l;
1080                 }
1081
1082                 public Expression Label {
1083                         get {
1084                                 return label;
1085                         }
1086                 }
1087
1088                 public object Converted {
1089                         get {
1090                                 return converted;
1091                         }
1092                 }
1093                 
1094                 //
1095                 // Resolves the expression, reduces it to a literal if possible
1096                 // and then converts it to the requested type.
1097                 //
1098                 public bool ResolveAndReduce (EmitContext ec, Type required_type)
1099                 {
1100                         ILLabel = ec.ig.DefineLabel ();
1101
1102                         if (label == null)
1103                                 return true;
1104                         
1105                         Expression e = label.Resolve (ec);
1106
1107                         if (e == null)
1108                                 return false;
1109
1110                         if (!(e is Constant)){
1111                                 Console.WriteLine ("Value is: " + label);
1112                                 Report.Error (150, loc, "A constant value is expected");
1113                                 return false;
1114                         }
1115
1116                         if (e is StringConstant || e is NullLiteral){
1117                                 if (required_type == TypeManager.string_type){
1118                                         converted = label;
1119                                         ILLabel = ec.ig.DefineLabel ();
1120                                         return true;
1121                                 }
1122                         }
1123
1124                         converted = Expression.ConvertIntLiteral ((Constant) e, required_type, loc);
1125                         if (converted == null)
1126                                 return false;
1127
1128                         return true;
1129                 }
1130         }
1131
1132         public class SwitchSection {
1133                 // An array of SwitchLabels.
1134                 public readonly ArrayList Labels;
1135                 public readonly Block Block;
1136                 
1137                 public SwitchSection (ArrayList labels, Block block)
1138                 {
1139                         Labels = labels;
1140                         Block = block;
1141                 }
1142         }
1143         
1144         public class Switch : Statement {
1145                 public readonly ArrayList Sections;
1146                 public Expression Expr;
1147
1148                 /// <summary>
1149                 ///   Maps constants whose type type SwitchType to their  SwitchLabels.
1150                 /// </summary>
1151                 public Hashtable Elements;
1152
1153                 /// <summary>
1154                 ///   The governing switch type
1155                 /// </summary>
1156                 public Type SwitchType;
1157
1158                 //
1159                 // Computed
1160                 //
1161                 bool got_default;
1162                 Label default_target;
1163                 Location loc;
1164                 
1165                 //
1166                 // The types allowed to be implicitly cast from
1167                 // on the governing type
1168                 //
1169                 static Type [] allowed_types;
1170                 
1171                 public Switch (Expression e, ArrayList sects, Location l)
1172                 {
1173                         Expr = e;
1174                         Sections = sects;
1175                         loc = l;
1176                 }
1177
1178                 public bool GotDefault {
1179                         get {
1180                                 return got_default;
1181                         }
1182                 }
1183
1184                 public Label DefaultTarget {
1185                         get {
1186                                 return default_target;
1187                         }
1188                 }
1189
1190                 //
1191                 // Determines the governing type for a switch.  The returned
1192                 // expression might be the expression from the switch, or an
1193                 // expression that includes any potential conversions to the
1194                 // integral types or to string.
1195                 //
1196                 Expression SwitchGoverningType (EmitContext ec, Type t)
1197                 {
1198                         if (t == TypeManager.int32_type ||
1199                             t == TypeManager.uint32_type ||
1200                             t == TypeManager.char_type ||
1201                             t == TypeManager.byte_type ||
1202                             t == TypeManager.sbyte_type ||
1203                             t == TypeManager.ushort_type ||
1204                             t == TypeManager.short_type ||
1205                             t == TypeManager.uint64_type ||
1206                             t == TypeManager.int64_type ||
1207                             t == TypeManager.string_type ||
1208                             t.IsSubclassOf (TypeManager.enum_type))
1209                                 return Expr;
1210
1211                         if (allowed_types == null){
1212                                 allowed_types = new Type [] {
1213                                         TypeManager.sbyte_type,
1214                                         TypeManager.byte_type,
1215                                         TypeManager.short_type,
1216                                         TypeManager.ushort_type,
1217                                         TypeManager.int32_type,
1218                                         TypeManager.uint32_type,
1219                                         TypeManager.int64_type,
1220                                         TypeManager.uint64_type,
1221                                         TypeManager.char_type,
1222                                         TypeManager.string_type
1223                                 };
1224                         }
1225
1226                         //
1227                         // Try to find a *user* defined implicit conversion.
1228                         //
1229                         // If there is no implicit conversion, or if there are multiple
1230                         // conversions, we have to report an error
1231                         //
1232                         Expression converted = null;
1233                         foreach (Type tt in allowed_types){
1234                                 Expression e;
1235                                 
1236                                 e = Expression.ImplicitUserConversion (ec, Expr, tt, loc);
1237                                 if (e == null)
1238                                         continue;
1239
1240                                 if (converted != null){
1241                                         Report.Error (-12, loc, "More than one conversion to an integral " +
1242                                                       " type exists for type `" +
1243                                                       TypeManager.CSharpName (Expr.Type)+"'");
1244                                         return null;
1245                                 } else
1246                                         converted = e;
1247                         }
1248                         return converted;
1249                 }
1250
1251                 void error152 (string n)
1252                 {
1253                         Report.Error (
1254                                 152, "The label `" + n + ":' " +
1255                                 "is already present on this switch statement");
1256                 }
1257                 
1258                 //
1259                 // Performs the basic sanity checks on the switch statement
1260                 // (looks for duplicate keys and non-constant expressions).
1261                 //
1262                 // It also returns a hashtable with the keys that we will later
1263                 // use to compute the switch tables
1264                 //
1265                 bool CheckSwitch (EmitContext ec)
1266                 {
1267                         Type compare_type;
1268                         bool error = false;
1269                         Elements = new Hashtable ();
1270                                 
1271                         got_default = false;
1272
1273                         if (TypeManager.IsEnumType (SwitchType)){
1274                                 compare_type = TypeManager.EnumToUnderlying (SwitchType);
1275                         } else
1276                                 compare_type = SwitchType;
1277                         
1278                         foreach (SwitchSection ss in Sections){
1279                                 foreach (SwitchLabel sl in ss.Labels){
1280                                         if (!sl.ResolveAndReduce (ec, SwitchType)){
1281                                                 error = true;
1282                                                 continue;
1283                                         }
1284
1285                                         if (sl.Label == null){
1286                                                 if (got_default){
1287                                                         error152 ("default");
1288                                                         error = true;
1289                                                 }
1290                                                 got_default = true;
1291                                                 continue;
1292                                         }
1293                                         
1294                                         object key = sl.Converted;
1295
1296                                         if (key is Constant)
1297                                                 key = ((Constant) key).GetValue ();
1298
1299                                         if (key == null)
1300                                                 key = NullLiteral.Null;
1301                                         
1302                                         string lname = null;
1303                                         if (compare_type == TypeManager.uint64_type){
1304                                                 ulong v = (ulong) key;
1305
1306                                                 if (Elements.Contains (v))
1307                                                         lname = v.ToString ();
1308                                                 else
1309                                                         Elements.Add (v, sl);
1310                                         } else if (compare_type == TypeManager.int64_type){
1311                                                 long v = (long) key;
1312
1313                                                 if (Elements.Contains (v))
1314                                                         lname = v.ToString ();
1315                                                 else
1316                                                         Elements.Add (v, sl);
1317                                         } else if (compare_type == TypeManager.uint32_type){
1318                                                 uint v = (uint) key;
1319
1320                                                 if (Elements.Contains (v))
1321                                                         lname = v.ToString ();
1322                                                 else
1323                                                         Elements.Add (v, sl);
1324                                         } else if (compare_type == TypeManager.char_type){
1325                                                 char v = (char) key;
1326                                                 
1327                                                 if (Elements.Contains (v))
1328                                                         lname = v.ToString ();
1329                                                 else
1330                                                         Elements.Add (v, sl);
1331                                         } else if (compare_type == TypeManager.byte_type){
1332                                                 byte v = (byte) key;
1333                                                 
1334                                                 if (Elements.Contains (v))
1335                                                         lname = v.ToString ();
1336                                                 else
1337                                                         Elements.Add (v, sl);
1338                                         } else if (compare_type == TypeManager.sbyte_type){
1339                                                 sbyte v = (sbyte) key;
1340                                                 
1341                                                 if (Elements.Contains (v))
1342                                                         lname = v.ToString ();
1343                                                 else
1344                                                         Elements.Add (v, sl);
1345                                         } else if (compare_type == TypeManager.short_type){
1346                                                 short v = (short) key;
1347                                                 
1348                                                 if (Elements.Contains (v))
1349                                                         lname = v.ToString ();
1350                                                 else
1351                                                         Elements.Add (v, sl);
1352                                         } else if (compare_type == TypeManager.ushort_type){
1353                                                 ushort v = (ushort) key;
1354                                                 
1355                                                 if (Elements.Contains (v))
1356                                                         lname = v.ToString ();
1357                                                 else
1358                                                         Elements.Add (v, sl);
1359                                         } else if (compare_type == TypeManager.string_type){
1360                                                 if (key is NullLiteral){
1361                                                         if (Elements.Contains (NullLiteral.Null))
1362                                                                 lname = "null";
1363                                                         else
1364                                                                 Elements.Add (NullLiteral.Null, null);
1365                                                 } else {
1366                                                         string s = (string) key;
1367
1368                                                         if (Elements.Contains (s))
1369                                                                 lname = s;
1370                                                         else
1371                                                                 Elements.Add (s, sl);
1372                                                 }
1373                                         } else if (compare_type == TypeManager.int32_type) {
1374                                                 int v = (int) key;
1375
1376                                                 if (Elements.Contains (v))
1377                                                         lname = v.ToString ();
1378                                                 else
1379                                                         Elements.Add (v, sl);
1380                                         } else {
1381                                                 throw new Exception ("Unknown switch type!" +
1382                                                                      SwitchType + " " + compare_type);
1383                                         }
1384
1385                                         if (lname != null){
1386                                                 error152 ("case + " + lname);
1387                                                 error = true;
1388                                         }
1389                                 }
1390                         }
1391                         if (error)
1392                                 return false;
1393                         
1394                         return true;
1395                 }
1396
1397                 void EmitObjectInteger (ILGenerator ig, object k)
1398                 {
1399                         if (k is int)
1400                                 IntConstant.EmitInt (ig, (int) k);
1401                         else if (k is Constant){
1402                                 EmitObjectInteger (ig, ((Constant) k).GetValue ());
1403                         } else if (k is uint)
1404                                 IntConstant.EmitInt (ig, unchecked ((int) (uint) k));
1405                         else if (k is long)
1406                                 LongConstant.EmitLong (ig, (long) k);
1407                         else if (k is ulong)
1408                                 LongConstant.EmitLong (ig, unchecked ((long) (ulong) k));
1409                         else if (k is char)
1410                                 IntConstant.EmitInt (ig, (int) ((char) k));
1411                         else if (k is sbyte)
1412                                 IntConstant.EmitInt (ig, (int) ((sbyte) k));
1413                         else if (k is byte)
1414                                 IntConstant.EmitInt (ig, (int) ((byte) k));
1415                         else 
1416                                 throw new Exception ("Unhandled case");
1417                 }
1418                 
1419                 //
1420                 // This simple emit switch works, but does not take advantage of the
1421                 // `switch' opcode.  The swithc opcode uses a jump table that we are not
1422                 // computing at this point
1423                 //
1424                 bool SimpleSwitchEmit (EmitContext ec, LocalBuilder val)
1425                 {
1426                         ILGenerator ig = ec.ig;
1427                         Label end_of_switch = ig.DefineLabel ();
1428                         Label next_test = ig.DefineLabel ();
1429                         Label null_target = ig.DefineLabel ();
1430                         bool default_found = false;
1431                         bool first_test = true;
1432                         bool pending_goto_end = false;
1433                         bool all_return = true;
1434                         bool is_string = false;
1435                         bool null_found;
1436                         
1437                         //
1438                         // Special processing for strings: we cant compare
1439                         // against null.
1440                         //
1441                         if (SwitchType == TypeManager.string_type){
1442                                 ig.Emit (OpCodes.Ldloc, val);
1443                                 is_string = true;
1444                                 
1445                                 if (Elements.Contains (NullLiteral.Null)){
1446                                         ig.Emit (OpCodes.Brfalse, null_target);
1447                                 } else
1448                                         ig.Emit (OpCodes.Brfalse, default_target);
1449
1450                                 ig.Emit (OpCodes.Ldloc, val);
1451                                 ig.Emit (OpCodes.Call, TypeManager.string_isinterneted_string);
1452                                 ig.Emit (OpCodes.Stloc, val);
1453                         }
1454                         
1455                         foreach (SwitchSection ss in Sections){
1456                                 Label sec_begin = ig.DefineLabel ();
1457
1458                                 if (pending_goto_end)
1459                                         ig.Emit (OpCodes.Br, end_of_switch);
1460
1461                                 int label_count = ss.Labels.Count;
1462                                 null_found = false;
1463                                 foreach (SwitchLabel sl in ss.Labels){
1464                                         ig.MarkLabel (sl.ILLabel);
1465                                         
1466                                         if (!first_test){
1467                                                 ig.MarkLabel (next_test);
1468                                                 next_test = ig.DefineLabel ();
1469                                         }
1470                                         //
1471                                         // If we are the default target
1472                                         //
1473                                         if (sl.Label == null){
1474                                                 ig.MarkLabel (default_target);
1475                                                 default_found = true;
1476                                         } else {
1477                                                 object lit = sl.Converted;
1478
1479                                                 if (lit is NullLiteral){
1480                                                         null_found = true;
1481                                                         if (label_count == 1)
1482                                                                 ig.Emit (OpCodes.Br, next_test);
1483                                                         continue;
1484                                                                               
1485                                                 }
1486                                                 if (is_string){
1487                                                         StringConstant str = (StringConstant) lit;
1488
1489                                                         ig.Emit (OpCodes.Ldloc, val);
1490                                                         ig.Emit (OpCodes.Ldstr, str.Value);
1491                                                         if (label_count == 1)
1492                                                                 ig.Emit (OpCodes.Bne_Un, next_test);
1493                                                         else
1494                                                                 ig.Emit (OpCodes.Beq, sec_begin);
1495                                                 } else {
1496                                                         ig.Emit (OpCodes.Ldloc, val);
1497                                                         EmitObjectInteger (ig, lit);
1498                                                         ig.Emit (OpCodes.Ceq);
1499                                                         if (label_count == 1)
1500                                                                 ig.Emit (OpCodes.Brfalse, next_test);
1501                                                         else
1502                                                                 ig.Emit (OpCodes.Brtrue, sec_begin);
1503                                                 }
1504                                         }
1505                                 }
1506                                 if (label_count != 1)
1507                                         ig.Emit (OpCodes.Br, next_test);
1508                                 
1509                                 if (null_found)
1510                                         ig.MarkLabel (null_target);
1511                                 ig.MarkLabel (sec_begin);
1512                                 if (ss.Block.Emit (ec))
1513                                         pending_goto_end = false;
1514                                 else {
1515                                         all_return = false;
1516                                         pending_goto_end = true;
1517                                 }
1518                                 first_test = false;
1519                         }
1520                         if (!default_found)
1521                                 ig.MarkLabel (default_target);
1522                         ig.MarkLabel (next_test);
1523                         ig.MarkLabel (end_of_switch);
1524                         
1525                         return all_return;
1526                 }
1527                 
1528                 public override bool Emit (EmitContext ec)
1529                 {
1530                         Expr = Expr.Resolve (ec);
1531                         if (Expr == null)
1532                                 return false;
1533
1534                         Expression new_expr = SwitchGoverningType (ec, Expr.Type);
1535                         if (new_expr == null){
1536                                 Report.Error (151, loc, "An integer type or string was expected for switch");
1537                                 return false;
1538                         }
1539
1540                         // Validate switch.
1541                         SwitchType = new_expr.Type;
1542
1543                         if (!CheckSwitch (ec))
1544                                 return false;
1545
1546                         // Store variable for comparission purposes
1547                         LocalBuilder value = ec.ig.DeclareLocal (SwitchType);
1548                         new_expr.Emit (ec);
1549                         ec.ig.Emit (OpCodes.Stloc, value);
1550
1551                         ILGenerator ig = ec.ig;
1552
1553                         default_target = ig.DefineLabel ();
1554
1555                         //
1556                         // Setup the codegen context
1557                         //
1558                         Label old_end = ec.LoopEnd;
1559                         Switch old_switch = ec.Switch;
1560                         
1561                         ec.LoopEnd = ig.DefineLabel ();
1562                         ec.Switch = this;
1563
1564                         // Emit Code.
1565                         bool all_return =  SimpleSwitchEmit (ec, value);
1566
1567                         // Restore context state. 
1568                         ig.MarkLabel (ec.LoopEnd);
1569
1570                         //
1571                         // FIXME: I am emitting a nop, because the switch performs
1572                         // no analysis on whether something ever reaches the end
1573                         //
1574                         // try: b (int a) { switch (a) { default: return 0; }  }
1575                         ig.Emit (OpCodes.Nop);
1576
1577                         //
1578                         // Restore the previous context
1579                         //
1580                         ec.LoopEnd = old_end;
1581                         ec.Switch = old_switch;
1582                         
1583                         //
1584                         // Because we have a nop at the end
1585                         //
1586                         return false;
1587                 }
1588         }
1589
1590         public class Lock : Statement {
1591                 public readonly Expression Expr;
1592                 public readonly Statement Statement;
1593                 Location loc;
1594                         
1595                 public Lock (Expression expr, Statement stmt, Location l)
1596                 {
1597                         Expr = expr;
1598                         Statement = stmt;
1599                         loc = l;
1600                 }
1601
1602                 public override bool Emit (EmitContext ec)
1603                 {
1604                         Expression e = Expr.Resolve (ec);
1605                         if (e == null)
1606                                 return false;
1607
1608                         Type type = e.Type;
1609                         
1610                         if (type.IsValueType){
1611                                 Report.Error (185, loc, "lock statement requires the expression to be " +
1612                                               " a reference type (type is: `" +
1613                                               TypeManager.CSharpName (type) + "'");
1614                                 return false;
1615                         }
1616
1617                         ILGenerator ig = ec.ig;
1618                         LocalBuilder temp = ig.DeclareLocal (type);
1619                                 
1620                         e.Emit (ec);
1621                         ig.Emit (OpCodes.Dup);
1622                         ig.Emit (OpCodes.Stloc, temp);
1623                         ig.Emit (OpCodes.Call, TypeManager.void_monitor_enter_object);
1624
1625                         // try
1626                         Label end = ig.BeginExceptionBlock ();
1627                         bool old_in_try = ec.InTry;
1628                         ec.InTry = true;
1629                         Label finish = ig.DefineLabel ();
1630                         Statement.Emit (ec);
1631                         ec.InTry = old_in_try;
1632                         // ig.Emit (OpCodes.Leave, finish);
1633
1634                         ig.MarkLabel (finish);
1635                         
1636                         // finally
1637                         ig.BeginFinallyBlock ();
1638                         ig.Emit (OpCodes.Ldloc, temp);
1639                         ig.Emit (OpCodes.Call, TypeManager.void_monitor_exit_object);
1640                         ig.EndExceptionBlock ();
1641                         
1642                         return false;
1643                 }
1644         }
1645
1646         public class Unchecked : Statement {
1647                 public readonly Block Block;
1648                 
1649                 public Unchecked (Block b)
1650                 {
1651                         Block = b;
1652                 }
1653
1654                 public override bool Emit (EmitContext ec)
1655                 {
1656                         bool previous_state = ec.CheckState;
1657                         bool val;
1658                         
1659                         ec.CheckState = false;
1660                         val = Block.Emit (ec);
1661                         ec.CheckState = previous_state;
1662
1663                         return val;
1664                 }
1665         }
1666
1667         public class Checked : Statement {
1668                 public readonly Block Block;
1669                 
1670                 public Checked (Block b)
1671                 {
1672                         Block = b;
1673                 }
1674
1675                 public override bool Emit (EmitContext ec)
1676                 {
1677                         bool previous_state = ec.CheckState;
1678                         bool val;
1679                         
1680                         ec.CheckState = true;
1681                         val = Block.Emit (ec);
1682                         ec.CheckState = previous_state;
1683
1684                         return val;
1685                 }
1686         }
1687
1688         public class Unsafe : Statement {
1689                 public readonly Block Block;
1690
1691                 public Unsafe (Block b)
1692                 {
1693                         Block = b;
1694                 }
1695
1696                 public override bool Emit (EmitContext ec)
1697                 {
1698                         bool previous_state = ec.InUnsafe;
1699                         bool val;
1700                         
1701                         ec.InUnsafe = true;
1702                         val = Block.Emit (ec);
1703                         ec.InUnsafe = previous_state;
1704
1705                         return val;
1706                 }
1707         }
1708
1709         // 
1710         // Fixed statement
1711         //
1712         public class Fixed : Statement {
1713                 string    type;
1714                 ArrayList declarators;
1715                 Statement statement;
1716                 Location  loc;
1717
1718                 public Fixed (string type, ArrayList decls, Statement stmt, Location l)
1719                 {
1720                         this.type = type;
1721                         declarators = decls;
1722                         statement = stmt;
1723                         loc = l;
1724                 }
1725
1726                 public override bool Emit (EmitContext ec)
1727                 {
1728                         ILGenerator ig = ec.ig;
1729                         Type t;
1730                         
1731                         t = RootContext.LookupType (ec.TypeContainer, type, false, loc);
1732                         if (t == null)
1733                                 return false;
1734
1735                         foreach (Pair p in declarators){
1736                                 VariableInfo vi = (VariableInfo) p.First;
1737                                 Expression e = (Expression) p.Second;
1738
1739                                 //
1740                                 // The rules for the possible declarators are pretty wise,
1741                                 // but the production on the grammar is more concise.
1742                                 //
1743                                 // So we have to enforce these rules here.
1744                                 //
1745                                 // We do not resolve before doing the case 1 test,
1746                                 // because the grammar is explicit in that the token &
1747                                 // is present, so we need to test for this particular case.
1748                                 //
1749
1750                                 //
1751                                 // Case 1: & object.
1752                                 //
1753                                 if (e is Unary && ((Unary) e).Oper == Unary.Operator.AddressOf){
1754                                         Expression child = ((Unary) e).Expr;
1755
1756                                         vi.MakePinned ();
1757                                         if (child is ParameterReference || child is LocalVariableReference){
1758                                                 Report.Error (
1759                                                         213, loc, 
1760                                                         "No need to use fixed statement for parameters or " +
1761                                                         "local variable declarations (address is already " +
1762                                                         "fixed)");
1763                                                 continue;
1764                                         }
1765                                         
1766                                         e = e.Resolve (ec);
1767                                         if (e == null)
1768                                                 continue;
1769
1770                                         child = ((Unary) e).Expr;
1771                                         
1772                                         if (!TypeManager.VerifyUnManaged (child.Type, loc))
1773                                                 continue;
1774
1775                                         //
1776                                         // Store pointer in pinned location
1777                                         //
1778                                         e.Emit (ec);
1779                                         ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
1780
1781                                         statement.Emit (ec);
1782
1783                                         // Clear the pinned variable.
1784                                         ig.Emit (OpCodes.Ldc_I4_0);
1785                                         ig.Emit (OpCodes.Conv_U);
1786                                         ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
1787
1788                                         continue;
1789                                 }
1790
1791                                 e = e.Resolve (ec);
1792                                 if (e == null)
1793                                         continue;
1794
1795                                 //
1796                                 // Case 2: Array
1797                                 //
1798                                 if (e.Type.IsArray){
1799                                         Type array_type = e.Type.GetElementType ();
1800                                         
1801                                         vi.MakePinned ();
1802                                         //
1803                                         // Provided that array_type is unmanaged,
1804                                         //
1805                                         if (!TypeManager.VerifyUnManaged (array_type, loc))
1806                                                 continue;
1807
1808                                         //
1809                                         // and T* is implicitly convertible to the
1810                                         // pointer type given in the fixed statement.
1811                                         //
1812                                         ArrayPtr array_ptr = new ArrayPtr (e);
1813                                         
1814                                         Expression converted = Expression.ConvertImplicitRequired (
1815                                                 ec, array_ptr, vi.VariableType, loc);
1816                                         if (converted == null)
1817                                                 continue;
1818
1819                                         //
1820                                         // Store pointer in pinned location
1821                                         //
1822                                         converted.Emit (ec);
1823                                         
1824                                         ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
1825
1826                                         statement.Emit (ec);
1827                                         
1828                                         // Clear the pinned variable.
1829                                         ig.Emit (OpCodes.Ldc_I4_0);
1830                                         ig.Emit (OpCodes.Conv_U);
1831                                         ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
1832
1833                                         continue;
1834                                 }
1835
1836                                 //
1837                                 // Case 3: string
1838                                 //
1839                                 if (e.Type == TypeManager.string_type){
1840                                         LocalBuilder pinned_string = ig.DeclareLocal (TypeManager.string_type);
1841                                         TypeManager.MakePinned (pinned_string);
1842                                         
1843                                         e.Emit (ec);
1844                                         ig.Emit (OpCodes.Stloc, pinned_string);
1845
1846                                         Expression sptr = new StringPtr (pinned_string);
1847                                         Expression converted = Expression.ConvertImplicitRequired (
1848                                                 ec, sptr, vi.VariableType, loc);
1849                                         
1850                                         if (converted == null)
1851                                                 continue;
1852
1853                                         converted.Emit (ec);
1854                                         ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
1855                                         
1856                                         statement.Emit (ec);
1857
1858                                         // Clear the pinned variable
1859                                         ig.Emit (OpCodes.Ldnull);
1860                                         ig.Emit (OpCodes.Stloc, pinned_string);
1861                                 }
1862                         }
1863
1864                         return false;
1865                 }
1866         }
1867         
1868         public class Catch {
1869                 public readonly string Type;
1870                 public readonly string Name;
1871                 public readonly Block  Block;
1872                 public readonly Location Location;
1873                 
1874                 public Catch (string type, string name, Block block, Location l)
1875                 {
1876                         Type = type;
1877                         Name = name;
1878                         Block = block;
1879                         Location = l;
1880                 }
1881         }
1882
1883         public class Try : Statement {
1884                 public readonly Block Fini, Block;
1885                 public readonly ArrayList Specific;
1886                 public readonly Catch General;
1887                 
1888                 //
1889                 // specific, general and fini might all be null.
1890                 //
1891                 public Try (Block block, ArrayList specific, Catch general, Block fini)
1892                 {
1893                         if (specific == null && general == null){
1894                                 Console.WriteLine ("CIR.Try: Either specific or general have to be non-null");
1895                         }
1896                         
1897                         this.Block = block;
1898                         this.Specific = specific;
1899                         this.General = general;
1900                         this.Fini = fini;
1901                 }
1902
1903                 public override bool Emit (EmitContext ec)
1904                 {
1905                         ILGenerator ig = ec.ig;
1906                         Label end;
1907                         Label finish = ig.DefineLabel ();;
1908                         bool returns;
1909                         
1910                         end = ig.BeginExceptionBlock ();
1911                         bool old_in_try = ec.InTry;
1912                         ec.InTry = true;
1913                         returns = Block.Emit (ec);
1914                         ec.InTry = old_in_try;
1915
1916                         //
1917                         // System.Reflection.Emit provides this automatically:
1918                         // ig.Emit (OpCodes.Leave, finish);
1919
1920                         bool old_in_catch = ec.InCatch;
1921                         ec.InCatch = true;
1922                         DeclSpace ds = ec.TypeContainer;
1923                         
1924                         foreach (Catch c in Specific){
1925                                 Type catch_type = RootContext.LookupType (ds, c.Type, false, c.Location);
1926                                 VariableInfo vi;
1927                                 
1928                                 if (catch_type == null)
1929                                         return false;
1930
1931                                 ig.BeginCatchBlock (catch_type);
1932
1933                                 if (c.Name != null){
1934                                         vi = c.Block.GetVariableInfo (c.Name);
1935                                         if (vi == null){
1936                                                 Console.WriteLine ("This should not happen! variable does not exist in this block");
1937                                                 Environment.Exit (0);
1938                                         }
1939                                 
1940                                         ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
1941                                 } else
1942                                         ig.Emit (OpCodes.Pop);
1943                                 
1944                                 c.Block.Emit (ec);
1945                         }
1946
1947                         if (General != null){
1948                                 ig.BeginCatchBlock (TypeManager.object_type);
1949                                 ig.Emit (OpCodes.Pop);
1950                                 General.Block.Emit (ec);
1951                         }
1952                         ec.InCatch = old_in_catch;
1953
1954                         ig.MarkLabel (finish);
1955                         if (Fini != null){
1956                                 ig.BeginFinallyBlock ();
1957                                 bool old_in_finally = ec.InFinally;
1958                                 ec.InFinally = true;
1959                                 Fini.Emit (ec);
1960                                 ec.InFinally = old_in_finally;
1961                         }
1962                         
1963                         ig.EndExceptionBlock ();
1964
1965                         //
1966                         // FIXME: Is this correct?
1967                         // Replace with `returns' and check test-18, maybe we can
1968                         // perform an optimization here.
1969                         //
1970                         return false;
1971                 }
1972         }
1973
1974         //
1975         // FIXME: We still do not support the expression variant of the using
1976         // statement.
1977         //
1978         public class Using : Statement {
1979                 object expression_or_block;
1980                 Statement Statement;
1981                 Location loc;
1982                 
1983                 public Using (object expression_or_block, Statement stmt, Location l)
1984                 {
1985                         this.expression_or_block = expression_or_block;
1986                         Statement = stmt;
1987                         loc = l;
1988                 }
1989
1990                 //
1991                 // Emits the code for the case of using using a local variable declaration.
1992                 //
1993                 bool EmitLocalVariableDecls (EmitContext ec, string type_name, ArrayList var_list)
1994                 {
1995                         ILGenerator ig = ec.ig;
1996                         Expression [] converted_vars;
1997                         bool need_conv = false;
1998                         Type type = RootContext.LookupType (ec.TypeContainer, type_name, false, loc);
1999                         int i = 0;
2000
2001                         if (type == null)
2002                                 return false;
2003                         
2004                         //
2005                         // The type must be an IDisposable or an implicit conversion
2006                         // must exist.
2007                         //
2008                         converted_vars = new Expression [var_list.Count];
2009                         if (!TypeManager.ImplementsInterface (type, TypeManager.idisposable_type)){
2010                                 foreach (DictionaryEntry e in var_list){
2011                                         Expression var = (Expression) e.Key;
2012
2013                                         var = var.Resolve (ec);
2014                                         if (var == null)
2015                                                 return false;
2016                                         
2017                                         converted_vars [i] = Expression.ConvertImplicit (
2018                                                 ec, var, TypeManager.idisposable_type, loc);
2019
2020                                         if (converted_vars [i] == null)
2021                                                 return false;
2022                                         i++;
2023                                 }
2024                                 need_conv = true;
2025                         }
2026                         
2027                         i = 0;
2028                         bool old_in_try = ec.InTry;
2029                         ec.InTry = true;
2030                         foreach (DictionaryEntry e in var_list){
2031                                 LocalVariableReference var = (LocalVariableReference) e.Key;
2032                                 Expression expr = (Expression) e.Value;
2033                                 Expression a;
2034
2035                                 a = new Assign (var, expr, loc);
2036                                 a.Resolve (ec);
2037                                 if (!need_conv)
2038                                         converted_vars [i] = var;
2039                                 i++;
2040                                 if (a == null)
2041                                         continue;
2042                                 ((ExpressionStatement) a).EmitStatement (ec);
2043                                 
2044                                 ig.BeginExceptionBlock ();
2045
2046                         }
2047                         Statement.Emit (ec);
2048                         ec.InTry = old_in_try;
2049
2050                         bool old_in_finally = ec.InFinally;
2051                         ec.InFinally = true;
2052                         var_list.Reverse ();
2053                         foreach (DictionaryEntry e in var_list){
2054                                 LocalVariableReference var = (LocalVariableReference) e.Key;
2055                                 Label skip = ig.DefineLabel ();
2056                                 i--;
2057                                 
2058                                 ig.BeginFinallyBlock ();
2059                                 
2060                                 var.Emit (ec);
2061                                 ig.Emit (OpCodes.Brfalse, skip);
2062                                 converted_vars [i].Emit (ec);
2063                                 ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
2064                                 ig.MarkLabel (skip);
2065                                 ig.EndExceptionBlock ();
2066                         }
2067                         ec.InFinally = old_in_finally;
2068
2069                         return false;
2070                 }
2071
2072                 bool EmitExpression (EmitContext ec, Expression expr)
2073                 {
2074                         Type expr_type = expr.Type;
2075                         Expression conv = null;
2076                         
2077                         if (!TypeManager.ImplementsInterface (expr_type, TypeManager.idisposable_type)){
2078                                 conv = Expression.ConvertImplicit (
2079                                         ec, expr, TypeManager.idisposable_type, loc);
2080
2081                                 if (conv == null)
2082                                         return false;
2083                         }
2084
2085                         //
2086                         // Make a copy of the expression and operate on that.
2087                         //
2088                         ILGenerator ig = ec.ig;
2089                         LocalBuilder local_copy = ig.DeclareLocal (expr_type);
2090                         if (conv != null)
2091                                 conv.Emit (ec);
2092                         else
2093                                 expr.Emit (ec);
2094                         ig.Emit (OpCodes.Stloc, local_copy);
2095
2096                         bool old_in_try = ec.InTry;
2097                         ec.InTry = true;
2098                         ig.BeginExceptionBlock ();
2099                         Statement.Emit (ec);
2100                         ec.InTry = old_in_try;
2101                         
2102                         Label skip = ig.DefineLabel ();
2103                         bool old_in_finally = ec.InFinally;
2104                         ig.BeginFinallyBlock ();
2105                         ig.Emit (OpCodes.Ldloc, local_copy);
2106                         ig.Emit (OpCodes.Brfalse, skip);
2107                         ig.Emit (OpCodes.Ldloc, local_copy);
2108                         ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
2109                         ig.MarkLabel (skip);
2110                         ec.InFinally = old_in_finally;
2111                         ig.EndExceptionBlock ();
2112
2113                         return false;
2114                 }
2115                 
2116                 public override bool Emit (EmitContext ec)
2117                 {
2118                         if (expression_or_block is DictionaryEntry){
2119                                 string t = (string) ((DictionaryEntry) expression_or_block).Key;
2120                                 ArrayList var_list = (ArrayList)((DictionaryEntry)expression_or_block).Value;
2121
2122                                 return EmitLocalVariableDecls (ec, t, var_list);
2123                         } if (expression_or_block is Expression){
2124                                 Expression e = (Expression) expression_or_block;
2125
2126                                 e = e.Resolve (ec);
2127                                 if (e == null)
2128                                         return false;
2129
2130                                 return EmitExpression (ec, e);
2131                         }
2132                         return false;
2133                 }
2134         }
2135
2136         /// <summary>
2137         ///   Implementation of the foreach C# statement
2138         /// </summary>
2139         public class Foreach : Statement {
2140                 string type;
2141                 LocalVariableReference variable;
2142                 Expression expr;
2143                 Statement statement;
2144                 Location loc;
2145                 
2146                 public Foreach (string type, LocalVariableReference var, Expression expr,
2147                                 Statement stmt, Location l)
2148                 {
2149                         this.type = type;
2150                         this.variable = var;
2151                         this.expr = expr;
2152                         statement = stmt;
2153                         loc = l;
2154                 }
2155
2156                 static bool GetEnumeratorFilter (MemberInfo m, object criteria)
2157                 {
2158                         if (m == null)
2159                                 return false;
2160                         
2161                         if (!(m is MethodInfo))
2162                                 return false;
2163                         
2164                         if (m.Name != "GetEnumerator")
2165                                 return false;
2166                         
2167                         MethodInfo mi = (MethodInfo) m;
2168
2169                         if (mi.ReturnType != TypeManager.ienumerator_type){
2170                                 if (!TypeManager.ienumerator_type.IsAssignableFrom (mi.ReturnType))
2171                                         return false;
2172                         }
2173                         
2174                         Type [] args = TypeManager.GetArgumentTypes (mi);
2175                         if (args == null)
2176                                 return true;
2177                         
2178                         if (args.Length == 0)
2179                                 return true;
2180                         
2181                         return false;
2182                 }
2183                 
2184                 /// <summary>
2185                 ///   This filter is used to find the GetEnumerator method
2186                 ///   on which IEnumerator operates
2187                 /// </summary>
2188                 static MemberFilter FilterEnumerator;
2189                 
2190                 static Foreach ()
2191                 {
2192                         FilterEnumerator = new MemberFilter (GetEnumeratorFilter);
2193                 }
2194
2195                 void error1579 (Type t)
2196                 {
2197                         Report.Error (1579, loc,
2198                                       "foreach statement cannot operate on variables of type `" +
2199                                       t.FullName + "' because that class does not provide a " +
2200                                       " GetEnumerator method or it is inaccessible");
2201                 }
2202
2203                 MethodInfo ProbeCollectionType (Type t)
2204                 {
2205                         MemberInfo [] mi;
2206
2207                         mi = TypeContainer.FindMembers (t, MemberTypes.Method,
2208                                                         BindingFlags.Public | BindingFlags.Instance,
2209                                                         FilterEnumerator, null);
2210
2211                         if (mi == null){
2212                                 error1579 (t);
2213                                 return null;
2214                         }
2215
2216                         if (mi.Length == 0){
2217                                 error1579 (t);
2218                                 return null;
2219                         }
2220
2221                         return (MethodInfo) mi [0];
2222                 }
2223
2224                 //
2225                 // FIXME: possible optimization.
2226                 // We might be able to avoid creating `empty' if the type is the sam
2227                 //
2228                 bool EmitCollectionForeach (EmitContext ec, Type var_type, MethodInfo get_enum)
2229                 {
2230                         ILGenerator ig = ec.ig;
2231                         LocalBuilder enumerator, disposable;
2232                         Expression empty = new EmptyExpression ();
2233                         Expression conv;
2234
2235                         //
2236                         // FIXME: maybe we can apply the same trick we do in the
2237                         // array handling to avoid creating empty and conv in some cases.
2238                         //
2239                         // Although it is not as important in this case, as the type
2240                         // will not likely be object (what the enumerator will return).
2241                         //
2242                         conv = Expression.ConvertExplicit (ec, empty, var_type, loc);
2243                         if (conv == null)
2244                                 return false;
2245                         
2246                         enumerator = ig.DeclareLocal (TypeManager.ienumerator_type);
2247                         disposable = ig.DeclareLocal (TypeManager.idisposable_type);
2248                         
2249                         //
2250                         // Instantiate the enumerator
2251
2252                         if (expr.Type.IsValueType){
2253                                 if (expr is IMemoryLocation){
2254                                         IMemoryLocation ml = (IMemoryLocation) expr;
2255
2256                                         ml.AddressOf (ec);
2257                                 } else
2258                                         throw new Exception ("Expr " + expr + " of type " + expr.Type +
2259                                                              " does not implement IMemoryLocation");
2260                                 ig.Emit (OpCodes.Call, get_enum);
2261                         } else {
2262                                 expr.Emit (ec);
2263                                 ig.Emit (OpCodes.Callvirt, get_enum);
2264                         }
2265                         ig.Emit (OpCodes.Stloc, enumerator);
2266
2267                         //
2268                         // Protect the code in a try/finalize block, so that
2269                         // if the beast implement IDisposable, we get rid of it
2270                         //
2271                         Label l = ig.BeginExceptionBlock ();
2272                         bool old_in_try = ec.InTry;
2273                         ec.InTry = true;
2274                         
2275                         Label end_try = ig.DefineLabel ();
2276                         
2277                         ig.MarkLabel (ec.LoopBegin);
2278                         ig.Emit (OpCodes.Ldloc, enumerator);
2279                         ig.Emit (OpCodes.Callvirt, TypeManager.bool_movenext_void);
2280                         ig.Emit (OpCodes.Brfalse, end_try);
2281                         ig.Emit (OpCodes.Ldloc, enumerator);
2282                         ig.Emit (OpCodes.Callvirt, TypeManager.object_getcurrent_void);
2283                         variable.EmitAssign (ec, conv);
2284                         statement.Emit (ec);
2285                         ig.Emit (OpCodes.Br, ec.LoopBegin);
2286                         ig.MarkLabel (end_try);
2287                         ec.InTry = old_in_try;
2288                         
2289                         // The runtime provides this for us.
2290                         // ig.Emit (OpCodes.Leave, end);
2291
2292                         //
2293                         // Now the finally block
2294                         //
2295                         Label end_finally = ig.DefineLabel ();
2296                         bool old_in_finally = ec.InFinally;
2297                         ec.InFinally = true;
2298                         ig.BeginFinallyBlock ();
2299                         
2300                         ig.Emit (OpCodes.Ldloc, enumerator);
2301                         ig.Emit (OpCodes.Isinst, TypeManager.idisposable_type);
2302                         ig.Emit (OpCodes.Stloc, disposable);
2303                         ig.Emit (OpCodes.Ldloc, disposable);
2304                         ig.Emit (OpCodes.Brfalse, end_finally);
2305                         ig.Emit (OpCodes.Ldloc, disposable);
2306                         ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
2307                         ig.MarkLabel (end_finally);
2308                         ec.InFinally = old_in_finally;
2309
2310                         // The runtime generates this anyways.
2311                         // ig.Emit (OpCodes.Endfinally);
2312
2313                         ig.EndExceptionBlock ();
2314
2315                         ig.MarkLabel (ec.LoopEnd);
2316                         return false;
2317                 }
2318
2319                 //
2320                 // FIXME: possible optimization.
2321                 // We might be able to avoid creating `empty' if the type is the sam
2322                 //
2323                 bool EmitArrayForeach (EmitContext ec, Type var_type)
2324                 {
2325                         Type array_type = expr.Type;
2326                         Type element_type = array_type.GetElementType ();
2327                         Expression conv = null;
2328                         Expression empty = new EmptyExpression (element_type);
2329                         
2330                         conv = Expression.ConvertExplicit (ec, empty, var_type, loc);
2331                         if (conv == null)
2332                                 return false;
2333
2334                         int rank = array_type.GetArrayRank ();
2335                         ILGenerator ig = ec.ig;
2336
2337                         LocalBuilder copy = ig.DeclareLocal (array_type);
2338                         
2339                         //
2340                         // Make our copy of the array
2341                         //
2342                         expr.Emit (ec);
2343                         ig.Emit (OpCodes.Stloc, copy);
2344                         
2345                         if (rank == 1){
2346                                 LocalBuilder counter = ig.DeclareLocal (TypeManager.int32_type);
2347
2348                                 Label loop, test;
2349                                 
2350                                 ig.Emit (OpCodes.Ldc_I4_0);
2351                                 ig.Emit (OpCodes.Stloc, counter);
2352                                 test = ig.DefineLabel ();
2353                                 ig.Emit (OpCodes.Br, test);
2354
2355                                 loop = ig.DefineLabel ();
2356                                 ig.MarkLabel (loop);
2357
2358                                 ig.Emit (OpCodes.Ldloc, copy);
2359                                 ig.Emit (OpCodes.Ldloc, counter);
2360                                 ArrayAccess.EmitLoadOpcode (ig, var_type);
2361
2362                                 variable.EmitAssign (ec, conv);
2363
2364                                 statement.Emit (ec);
2365
2366                                 ig.MarkLabel (ec.LoopBegin);
2367                                 ig.Emit (OpCodes.Ldloc, counter);
2368                                 ig.Emit (OpCodes.Ldc_I4_1);
2369                                 ig.Emit (OpCodes.Add);
2370                                 ig.Emit (OpCodes.Stloc, counter);
2371
2372                                 ig.MarkLabel (test);
2373                                 ig.Emit (OpCodes.Ldloc, counter);
2374                                 ig.Emit (OpCodes.Ldloc, copy);
2375                                 ig.Emit (OpCodes.Ldlen);
2376                                 ig.Emit (OpCodes.Conv_I4);
2377                                 ig.Emit (OpCodes.Blt, loop);
2378                         } else {
2379                                 LocalBuilder [] dim_len   = new LocalBuilder [rank];
2380                                 LocalBuilder [] dim_count = new LocalBuilder [rank];
2381                                 Label [] loop = new Label [rank];
2382                                 Label [] test = new Label [rank];
2383                                 int dim;
2384                                 
2385                                 for (dim = 0; dim < rank; dim++){
2386                                         dim_len [dim] = ig.DeclareLocal (TypeManager.int32_type);
2387                                         dim_count [dim] = ig.DeclareLocal (TypeManager.int32_type);
2388                                         test [dim] = ig.DefineLabel ();
2389                                         loop [dim] = ig.DefineLabel ();
2390                                 }
2391                                         
2392                                 for (dim = 0; dim < rank; dim++){
2393                                         ig.Emit (OpCodes.Ldloc, copy);
2394                                         IntLiteral.EmitInt (ig, dim);
2395                                         ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int);
2396                                         ig.Emit (OpCodes.Stloc, dim_len [dim]);
2397                                 }
2398
2399                                 for (dim = 0; dim < rank; dim++){
2400                                         ig.Emit (OpCodes.Ldc_I4_0);
2401                                         ig.Emit (OpCodes.Stloc, dim_count [dim]);
2402                                         ig.Emit (OpCodes.Br, test [dim]);
2403                                         ig.MarkLabel (loop [dim]);
2404                                 }
2405
2406                                 ig.Emit (OpCodes.Ldloc, copy);
2407                                 for (dim = 0; dim < rank; dim++)
2408                                         ig.Emit (OpCodes.Ldloc, dim_count [dim]);
2409
2410                                 //
2411                                 // FIXME: Maybe we can cache the computation of `get'?
2412                                 //
2413                                 Type [] args = new Type [rank];
2414                                 MethodInfo get;
2415
2416                                 for (int i = 0; i < rank; i++)
2417                                         args [i] = TypeManager.int32_type;
2418
2419                                 ModuleBuilder mb = RootContext.ModuleBuilder;
2420                                 get = mb.GetArrayMethod (
2421                                         array_type, "Get",
2422                                         CallingConventions.HasThis| CallingConventions.Standard,
2423                                         var_type, args);
2424                                 ig.Emit (OpCodes.Call, get);
2425                                 variable.EmitAssign (ec, conv);
2426                                 statement.Emit (ec);
2427                                 ig.MarkLabel (ec.LoopBegin);
2428                                 for (dim = rank - 1; dim >= 0; dim--){
2429                                         ig.Emit (OpCodes.Ldloc, dim_count [dim]);
2430                                         ig.Emit (OpCodes.Ldc_I4_1);
2431                                         ig.Emit (OpCodes.Add);
2432                                         ig.Emit (OpCodes.Stloc, dim_count [dim]);
2433
2434                                         ig.MarkLabel (test [dim]);
2435                                         ig.Emit (OpCodes.Ldloc, dim_count [dim]);
2436                                         ig.Emit (OpCodes.Ldloc, dim_len [dim]);
2437                                         ig.Emit (OpCodes.Blt, loop [dim]);
2438                                 }
2439                         }
2440                         ig.MarkLabel (ec.LoopEnd);
2441                         
2442                         return false;
2443                 }
2444                 
2445                 public override bool Emit (EmitContext ec)
2446                 {
2447                         Type var_type;
2448                         bool ret_val;
2449                         
2450                         expr = expr.Resolve (ec);
2451                         if (expr == null)
2452                                 return false;
2453
2454                         var_type = RootContext.LookupType (ec.TypeContainer, type, false, loc);
2455                         if (var_type == null)
2456                                 return false;
2457                         
2458                         //
2459                         // We need an instance variable.  Not sure this is the best
2460                         // way of doing this.
2461                         //
2462                         // FIXME: When we implement propertyaccess, will those turn
2463                         // out to return values in ExprClass?  I think they should.
2464                         //
2465                         if (!(expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.Value ||
2466                               expr.eclass == ExprClass.PropertyAccess)){
2467                                 error1579 (expr.Type);
2468                                 return false;
2469                         }
2470
2471                         ILGenerator ig = ec.ig;
2472                         
2473                         Label old_begin = ec.LoopBegin, old_end = ec.LoopEnd;
2474                         bool old_inloop = ec.InLoop;
2475                         ec.LoopBegin = ig.DefineLabel ();
2476                         ec.LoopEnd = ig.DefineLabel ();
2477                         ec.InLoop = true;
2478                         
2479                         if (expr.Type.IsArray)
2480                                 ret_val = EmitArrayForeach (ec, var_type);
2481                         else {
2482                                 MethodInfo get_enum;
2483                                 
2484                                 if ((get_enum = ProbeCollectionType (expr.Type)) == null)
2485                                         return false;
2486
2487                                 ret_val = EmitCollectionForeach (ec, var_type, get_enum);
2488                         }
2489                         
2490                         ec.LoopBegin = old_begin;
2491                         ec.LoopEnd = old_end;
2492                         ec.InLoop = old_inloop;
2493
2494                         return ret_val;
2495                 }
2496         }
2497 }
2498