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