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