2001-10-14 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 Ximian, Inc.
8 //
9
10 using System;
11 using System.Reflection;
12 using System.Reflection.Emit;
13
14 namespace CIR {
15
16         using System.Collections;
17         
18         public abstract class Statement {
19
20                 //
21                 // Return value indicates whether the last instruction
22                 // was a return instruction
23                 //
24                 public abstract bool Emit (EmitContext ec);
25
26                 public static bool EmitBoolExpression (EmitContext ec, Expression e)
27                 {
28                         e = e.Resolve (ec);
29
30                         if (e == null)
31                                 return false;
32
33                         if (e.Type != TypeManager.bool_type)
34                                 e = Expression.ConvertImplicit (ec, e, TypeManager.bool_type,
35                                                                 new Location (-1));
36
37                         if (e == null){
38                                 Report.Error (
39                                         31, "Can not convert the expression to a boolean");
40                                 return false;
41                         }
42                         
43                         e.Emit (ec);
44
45                         return true;
46                 }
47
48         }
49
50         public class EmptyStatement : Statement {
51                 public override bool Emit (EmitContext ec)
52                 {
53                         return false;
54                 }
55         }
56         
57         public class If : Statement {
58                 public readonly Expression  Expr;
59                 public readonly Statement   TrueStatement;
60                 public readonly Statement   FalseStatement;
61                 
62                 public If (Expression expr, Statement trueStatement)
63                 {
64                         Expr = expr;
65                         TrueStatement = trueStatement;
66                 }
67
68                 public If (Expression expr,
69                            Statement trueStatement,
70                            Statement falseStatement)
71                 {
72                         Expr = expr;
73                         TrueStatement = trueStatement;
74                         FalseStatement = falseStatement;
75                 }
76
77                 public override bool Emit (EmitContext ec)
78                 {
79                         ILGenerator ig = ec.ig;
80                         Label false_target = ig.DefineLabel ();
81                         Label end;
82                         bool is_ret;
83                         
84                         if (!EmitBoolExpression (ec, Expr))
85                                 return false;
86                         
87                         ig.Emit (OpCodes.Brfalse, false_target);
88                         is_ret = TrueStatement.Emit (ec);
89
90                         if (FalseStatement != null){
91                                 bool branch_emitted = false;
92                                 
93                                 end = ig.DefineLabel ();
94                                 if (!is_ret){
95                                         ig.Emit (OpCodes.Br, end);
96                                         branch_emitted = true;
97                                 }
98                         
99                                 ig.MarkLabel (false_target);
100                                 is_ret = FalseStatement.Emit (ec);
101
102                                 if (branch_emitted)
103                                         ig.MarkLabel (end);
104                         } else
105                                 ig.MarkLabel (false_target);
106
107                         return is_ret;
108                 }
109         }
110
111         public class Do : Statement {
112                 public readonly Expression Expr;
113                 public readonly Statement  EmbeddedStatement;
114                 
115                 public Do (Statement statement, Expression boolExpr)
116                 {
117                         Expr = boolExpr;
118                         EmbeddedStatement = statement;
119                 }
120
121                 public override bool Emit (EmitContext ec)
122                 {
123                         ILGenerator ig = ec.ig;
124                         Label loop = ig.DefineLabel ();
125
126                         ig.MarkLabel (loop);
127                         EmbeddedStatement.Emit (ec);
128                         EmitBoolExpression (ec, Expr);
129                         ig.Emit (OpCodes.Brtrue, loop);
130
131                         return false;
132                 }
133         }
134
135         public class While : Statement {
136                 public readonly Expression Expr;
137                 public readonly Statement Statement;
138                 
139                 public While (Expression boolExpr, Statement statement)
140                 {
141                         Expr = boolExpr;
142                         Statement = statement;
143                 }
144
145                 public override bool Emit (EmitContext ec)
146                 {
147                         ILGenerator ig = ec.ig;
148                         Label while_eval = ig.DefineLabel ();
149                         Label exit = ig.DefineLabel ();
150                         
151                         ig.MarkLabel (while_eval);
152                         EmitBoolExpression (ec, Expr);
153                         ig.Emit (OpCodes.Brfalse, exit);
154                         Statement.Emit (ec);
155                         ig.Emit (OpCodes.Br, while_eval);
156                         ig.MarkLabel (exit);
157
158                         return false;
159                 }
160         }
161
162         public class For : Statement {
163                 public readonly Statement InitStatement;
164                 public readonly Expression Test;
165                 public readonly Statement Increment;
166                 public readonly Statement Statement;
167                 
168                 public For (Statement initStatement,
169                             Expression test,
170                             Statement increment,
171                             Statement statement)
172                 {
173                         InitStatement = initStatement;
174                         Test = test;
175                         Increment = increment;
176                         Statement = statement;
177                 }
178
179                 public override bool Emit (EmitContext ec)
180                 {
181                         ILGenerator ig = ec.ig;
182                         Label loop = ig.DefineLabel ();
183                         Label exit = ig.DefineLabel ();
184                         
185                         if (! (InitStatement is EmptyStatement))
186                                 InitStatement.Emit (ec);
187
188                         ig.MarkLabel (loop);
189                         EmitBoolExpression (ec, Test);
190                         ig.Emit (OpCodes.Brfalse, exit);
191                         Statement.Emit (ec);
192                         if (!(Increment is EmptyStatement))
193                                 Increment.Emit (ec);
194                         ig.Emit (OpCodes.Br, loop);
195                         ig.MarkLabel (exit);
196
197                         return false;
198                 }
199         }
200         
201         public class StatementExpression : Statement {
202                 public readonly ExpressionStatement Expr;
203                 
204                 public StatementExpression (ExpressionStatement expr)
205                 {
206                         Expr = expr;
207                 }
208
209                 public override bool Emit (EmitContext ec)
210                 {
211                         ILGenerator ig = ec.ig;
212                         Expression ne;
213                         
214                         ne = Expr.Resolve (ec);
215                         if (ne != null){
216                                 if (ne is ExpressionStatement)
217                                         ((ExpressionStatement) ne).EmitStatement (ec);
218                                 else {
219                                         ne.Emit (ec);
220                                         ig.Emit (OpCodes.Pop);
221                                 }
222                         }
223
224                         return false;
225                 }
226         }
227
228         public class Return : Statement {
229                 public Expression Expr;
230                 public readonly Location loc;
231                 
232                 public Return (Expression expr, Location l)
233                 {
234                         Expr = expr;
235                 }
236
237                 public override bool Emit (EmitContext ec)
238                 {
239                         if (ec.ReturnType == null){
240                                 if (Expr != null){
241                                         Report.Error (127, loc, "Return with a value not allowed here");
242                                         return false;
243                                 }
244                         } else {
245                                 if (Expr == null){
246                                         Report.Error (126, loc, "An object of type `" +
247                                                       TypeManager.CSharpName (ec.ReturnType) + "' is " +
248                                                       "expected for the return statement");
249                                         return false;
250                                 }
251
252                                 Expr = Expr.Resolve (ec);
253                                 if (Expr == null)
254                                         return false;
255
256                                 if (Expr.Type != ec.ReturnType)
257                                         Expr = Expression.ConvertImplicitRequired (
258                                                 ec, Expr, ec.ReturnType, loc);
259
260                                 if (Expr == null)
261                                         return false;
262
263                                 Expr.Emit (ec);
264                         }
265
266                         ec.ig.Emit (OpCodes.Ret);
267
268                         return true; 
269                 }
270         }
271
272         public class Goto : Statement {
273                 string target;
274                 
275                 public Goto (string label)
276                 {
277                         target = label;
278                 }
279
280                 public string Target {
281                         get {
282                                 return target;
283                         }
284                 }
285
286                 public override bool Emit (EmitContext ec)
287                 {
288                         throw new Exception ("Unimplemented");
289                 }
290         }
291
292         public class Throw : Statement {
293                 public readonly Expression Expr;
294                 
295                 public Throw (Expression expr)
296                 {
297                         Expr = expr;
298                 }
299
300                 public override bool Emit (EmitContext ec)
301                 {
302                         Expression e = Expr.Resolve (ec);
303
304                         if (e == null)
305                                 return false;
306
307                         e.Emit (ec);
308                         ec.ig.Emit (OpCodes.Throw);
309
310                         return false;
311                 }
312         }
313
314         public class Break : Statement {
315                 public Break ()
316                 {
317                 }
318
319                 public override bool Emit (EmitContext ec)
320                 {
321                         throw new Exception ("Unimplemented");
322                 }
323         }
324
325         public class Continue : Statement {
326                 public Continue ()
327                 {
328                 }
329
330                 public override bool Emit (EmitContext ec)
331                 {
332                         throw new Exception ("Unimplemented");
333                 }
334         }
335         
336         public class VariableInfo {
337                 public readonly string Type;
338                 public LocalBuilder LocalBuilder;
339                 public Type VariableType;
340                 public readonly Location Location;
341                 
342                 int  idx;
343                 public bool Used;
344                 public bool Assigned; 
345                 
346                 public VariableInfo (string type, Location l)
347                 {
348                         Type = type;
349                         LocalBuilder = null;
350                         idx = -1;
351                         Location = l;
352                 }
353
354                 public int Idx {
355                         get {
356                                 if (idx == -1)
357                                         throw new Exception ("Unassigned idx for variable");
358                                 
359                                 return idx;
360                         }
361
362                         set {
363                                 idx = value;
364                         }
365                 }
366
367         }
368                 
369         // <summary>
370         //   Used for Label management
371         // </summary>
372         //
373         public class Block : Statement {
374                 public readonly Block  Parent;
375                 public readonly bool   Implicit;
376                 public readonly string Label;
377
378                 //
379                 // The statements in this block
380                 //
381                 StatementCollection statements;
382
383                 //
384                 // An array of Blocks
385                 //
386                 ArrayList children;
387                 
388                 //
389                 // Labels.  (label, block) pairs.
390                 //
391                 Hashtable labels;
392
393                 //
394                 // Keeps track of (name, type) pairs
395                 //
396                 Hashtable variables;
397
398                 //
399                 // Maps variable names to ILGenerator.LocalBuilders
400                 //
401                 Hashtable local_builders;
402
403                 bool used = false;
404
405                 public Block (Block parent)
406                 {
407                         if (parent != null)
408                                 parent.AddChild (this);
409                         
410                         this.Parent = parent;
411                         this.Implicit = false;
412                 }
413
414                 public Block (Block parent, bool implicit_block)
415                 {
416                         if (parent != null)
417                                 parent.AddChild (this);
418                         
419                         this.Parent = parent;
420                         this.Implicit = true;
421                 }
422
423                 public Block (Block parent, string labeled)
424                 {
425                         if (parent != null)
426                                 parent.AddChild (this);
427                         
428                         this.Parent = parent;
429                         this.Implicit = true;
430                         Label = labeled;
431                 }
432
433                 public void AddChild (Block b)
434                 {
435                         if (children == null)
436                                 children = new ArrayList ();
437                         
438                         children.Add (b);
439                 }
440
441                 // <summary>
442                 //   Adds a label to the current block. 
443                 // </summary>
444                 //
445                 // <returns>
446                 //   false if the name already exists in this block. true
447                 //   otherwise.
448                 // </returns>
449                 //
450                 public bool AddLabel (string name, Block block)
451                 {
452                         if (labels == null)
453                                 labels = new Hashtable ();
454                         if (labels.Contains (name))
455                                 return false;
456                         
457                         labels.Add (name, block);
458                         return true;
459                 }
460
461                 public bool AddVariable (string type, string name, Location l)
462                 {
463                         if (variables == null)
464                                 variables = new Hashtable ();
465
466                         if (GetVariableType (name) != null)
467                                 return false;
468
469                         VariableInfo vi = new VariableInfo (type, l);
470                         
471                         variables.Add (name, vi);
472                         return true;
473                 }
474
475                 public Hashtable Variables {
476                         get {
477                                 return variables;
478                         }
479                 }
480
481                 public VariableInfo GetVariableInfo (string name)
482                 {
483                         if (variables != null) {
484                                 object temp;
485                                 temp = variables [name];
486
487                                 if (temp != null)
488                                         return (VariableInfo) temp;
489                         }
490
491                         if (Parent != null){
492                                 return Parent.GetVariableInfo (name);
493                         }
494
495                         return null;
496                 }
497                 
498                 public string GetVariableType (string name)
499                 {
500                         VariableInfo vi = GetVariableInfo (name);
501
502                         if (vi != null)
503                                 return vi.Type;
504
505                         return null;
506                 }
507
508                 // <summary>
509                 //   True if the variable named @name has been defined
510                 //   in this block
511                 // </summary>
512                 public bool IsVariableDefined (string name)
513                 {
514                         return GetVariableType (name) != null;
515                 }
516
517                 // <summary>
518                 //   Use to fetch the statement associated with this label
519                 // </summary>
520                 public Statement this [string name] {
521                         get {
522                                 return (Statement) labels [name];
523                         }
524                 }
525
526                 // <returns>
527                 //   A list of labels that were not used within this block
528                 // </returns>
529                 public string [] GetUnreferenced ()
530                 {
531                         // FIXME: Implement me
532                         return null;
533                 }
534
535                 public StatementCollection Statements {
536                         get {
537                                 if (statements == null)
538                                         statements = new StatementCollection ();
539
540                                 return statements;
541                         }
542                 }
543
544                 public void AddStatement (Statement s)
545                 {
546                         if (statements == null)
547                                 statements = new StatementCollection ();
548
549                         statements.Add (s);
550                         used = true;
551                 }
552
553                 public bool Used {
554                         get {
555                                 return used;
556                         }
557                 }
558
559                 public void Use ()
560                 {
561                         used = true;
562                 }
563                 
564                 // <summary>
565                 //   Creates a compiler-internal identifier, this is
566                 //   used to create temporary variables that should not
567                 //   be seen by the application
568                 // </summary
569                 int internal_id_serial;
570                 public string MakeInternalID () {
571                         string ret = internal_id_serial.ToString ();
572
573                         internal_id_serial++;
574                         return "0_" + ret;
575                 }
576
577                 // <summary>
578                 //   Emits the variable declarations and labels.
579                 // </summary>
580                 //
581                 // tc: is our typecontainer (to resolve type references)
582                 // ig: is the code generator:
583                 // toplevel: the toplevel block.  This is used for checking 
584                 //           that no two labels with the same name are used.
585                 //
586                 public void EmitMeta (TypeContainer tc, ILGenerator ig, Block toplevel, int count)
587                 {
588                         //
589                         // Process this block variables
590                         //
591                         if (variables != null){
592                                 local_builders = new Hashtable ();
593                                 
594                                 foreach (DictionaryEntry de in variables){
595                                         string name = (string) de.Key;
596                                         VariableInfo vi = (VariableInfo) de.Value;
597                                         Type t;
598                                         
599                                         t = tc.LookupType (vi.Type, false);
600                                         if (t == null)
601                                                 continue;
602
603                                         vi.VariableType = t;
604                                         vi.LocalBuilder = ig.DeclareLocal (t);
605                                         vi.Idx = count++;
606                                 }
607                         }
608
609                         //
610                         // Now, handle the children
611                         //
612                         if (children != null){
613                                 foreach (Block b in children)
614                                         b.EmitMeta (tc, ig, toplevel, count);
615                         }
616                 }
617
618                 public void UsageWarning ()
619                 {
620                         string name;
621                         
622                         if (variables != null){
623                                 foreach (DictionaryEntry de in variables){
624                                         VariableInfo vi = (VariableInfo) de.Value;
625                                         
626                                         if (vi.Used)
627                                                 continue;
628                                         
629                                         name = (string) de.Key;
630                                                 
631                                         if (vi.Assigned){
632                                                 Report.Warning (
633                                                         219, vi.Location, "The variable `" + name +
634                                                         "' is assigned but its value is never used");
635                                         } else {
636                                                 Report.Warning (
637                                                         168, vi.Location, "The variable `" +
638                                                         name +
639                                                         "' is declared but never used");
640                                         } 
641                                 }
642                         }
643
644                         if (children != null)
645                                 foreach (Block b in children)
646                                         b.UsageWarning ();
647                 }
648
649                 public override bool Emit (EmitContext ec)
650                 {
651                         bool is_ret = false;
652
653                         foreach (Statement s in Statements)
654                                 is_ret = s.Emit (ec);
655
656                         return is_ret;
657                 }
658         }
659
660         public class SwitchLabel {
661                 Expression label;
662
663                 //
664                 // if expr == null, then it is the default case.
665                 //
666                 public SwitchLabel (Expression expr)
667                 {
668                         label = expr;
669                 }
670                 
671                 public Expression Label {
672                         get {
673                                 return label;
674                         }
675                 }
676         }
677
678         public class SwitchSection {
679                 // An array of SwitchLabels.
680                 ArrayList labels;
681                 Block block;
682                 
683                 public SwitchSection (ArrayList labels, Block block)
684                 {
685                         this.labels = labels;
686                         this.block = block;
687                 }
688
689                 public Block Block {
690                         get {
691                                 return block;
692                         }
693                 }
694
695                 public ArrayList Labels {
696                         get {
697                                 return labels;
698                         }
699                 }
700         }
701         
702         public class Switch : Statement {
703                 ArrayList sections;
704                 Expression expr;
705                 
706                 public Switch (Expression expr, ArrayList sections)
707                 {
708                         this.expr = expr;
709                         this.sections = sections;
710                 }
711
712                 public Expression Expr {
713                         get {
714                                 return expr;
715                         }
716                 }
717
718                 public ArrayList Sections {
719                         get {
720                                 return sections;
721                         }
722                 }
723
724                 public override bool Emit (EmitContext ec)
725                 {
726                         throw new Exception ("Unimplemented");
727                 }
728         }
729
730         public class Lock : Statement {
731                 public readonly Expression Expr;
732                 public readonly Statement Statement;
733                 
734                 public Lock (Expression expr, Statement stmt)
735                 {
736                         Expr = expr;
737                         Statement = stmt;
738                 }
739
740                 public override bool Emit (EmitContext ec)
741                 {
742                         throw new Exception ("Unimplemented");
743                 }
744                 
745         }
746
747         public class Unchecked : Statement {
748                 public readonly Block Block;
749                 
750                 public Unchecked (Block b)
751                 {
752                         Block = b;
753                 }
754
755                 public override bool Emit (EmitContext ec)
756                 {
757                         bool previous_state = ec.CheckState;
758                         bool val;
759                         
760                         ec.CheckState = false;
761                         val = Block.Emit (ec);
762                         ec.CheckState = previous_state;
763
764                         return val;
765                 }
766         }
767
768         public class Checked : Statement {
769                 public readonly Block Block;
770                 
771                 public Checked (Block b)
772                 {
773                         Block = b;
774                 }
775
776                 public override bool Emit (EmitContext ec)
777                 {
778                         bool previous_state = ec.CheckState;
779                         bool val;
780                         
781                         ec.CheckState = true;
782                         val = Block.Emit (ec);
783                         ec.CheckState = previous_state;
784
785                         return val;
786                 }
787         }
788
789         public class Catch {
790                 public readonly string Type;
791                 public readonly string Name;
792                 public readonly Block  Block;
793                 
794                 public Catch (string type, string name, Block block)
795                 {
796                         Type = type;
797                         Name = name;
798                         Block = block;
799                 }
800         }
801
802         public class Try : Statement {
803                 public readonly Block Fini, Block;
804                 public readonly ArrayList Specific;
805                 public readonly Catch General;
806                 
807                 //
808                 // specific, general and fini might all be null.
809                 //
810                 public Try (Block block, ArrayList specific, Catch general, Block fini)
811                 {
812                         if (specific == null && general == null){
813                                 Console.WriteLine ("CIR.Try: Either specific or general have to be non-null");
814                         }
815                         
816                         this.Block = block;
817                         this.Specific = specific;
818                         this.General = general;
819                         this.Fini = fini;
820                 }
821
822                 public override bool Emit (EmitContext ec)
823                 {
824                         ILGenerator ig = ec.ig;
825                         Label end;
826                         Label finish = ig.DefineLabel ();;
827
828                         end = ig.BeginExceptionBlock ();
829                         Block.Emit (ec);
830                         ig.Emit (OpCodes.Leave, finish);
831                         
832                         foreach (Catch c in Specific){
833                                 Type catch_type = ec.TypeContainer.LookupType (c.Type, false);
834                                 VariableInfo vi;
835                                 
836                                 if (catch_type == null)
837                                         return false;
838
839                                 ig.BeginCatchBlock (catch_type);
840
841                                 if (c.Name != null){
842                                         vi = c.Block.GetVariableInfo (c.Name);
843                                         if (vi == null){
844                                                 Console.WriteLine ("This should not happen! variable does not exist in this block");
845                                                 Environment.Exit (0);
846                                         }
847                                 
848                                         ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
849                                 } else
850                                         ig.Emit (OpCodes.Pop);
851                                 
852                                 c.Block.Emit (ec);
853                         }
854
855                         if (General != null){
856                                 ig.BeginCatchBlock (TypeManager.object_type);
857                                 ig.Emit (OpCodes.Pop);
858                         }
859
860                         ig.MarkLabel (finish);
861                         if (Fini != null){
862                                 ig.BeginFinallyBlock ();
863                                 Fini.Emit (ec);
864                         }
865                         
866                         ig.EndExceptionBlock ();
867
868                         return false;
869                 }
870         }
871         
872         public class Foreach : Statement {
873                 public readonly string Type;
874                 public readonly LocalVariableReference Variable;
875                 public readonly Expression Expr;
876                 public readonly Statement Statement;
877                 public readonly Location Location;
878                 
879                 public Foreach (string type, LocalVariableReference var, Expression expr,
880                                 Statement stmt, Location l)
881                 {
882                         Type = type;
883                         Variable = var;
884                         Expr = expr;
885                         Statement = stmt;
886                         Location = l;
887                 }
888
889                 static bool GetEnumeratorFilter (MemberInfo m, object criteria)
890                 {
891                         if (m == null)
892                                 return false;
893                         
894                         if (!(m is MethodInfo))
895                                 return false;
896                         
897                         if (m.Name != "GetEnumerator")
898                                 return false;
899                         
900                         MethodInfo mi = (MethodInfo) m;
901                         
902                         if (mi.ReturnType != TypeManager.ienumerator_type)
903                                 return false;
904                         
905                         Type [] args = TypeManager.GetArgumentTypes (mi);
906                         if (args == null)
907                                 return true;
908                         
909                         if (args.Length == 0)
910                                 return true;
911                         
912                         return false;
913                 }
914                 
915                 // <summary>
916                 //   This filter is used to find the GetEnumerator method
917                 //   on which IEnumerator operates
918                 // </summary>
919                 static MemberFilter FilterEnumerator;
920                 
921                 static Foreach ()
922                 {
923                         FilterEnumerator = new MemberFilter (GetEnumeratorFilter);
924                 }
925
926                 void error1579 (Type t)
927                 {
928                         Report.Error (1579, Location,
929                                       "foreach statement cannot operate on variables of type `" +
930                                       t.FullName + "' because that class does not provide a " +
931                                       " GetEnumerator method or it is inaccessible");
932                 }
933
934                 MethodInfo ProbeCollectionType (Type t)
935                 {
936                         MemberInfo [] mi;
937
938                         mi = TypeContainer.FindMembers (t, MemberTypes.Method,
939                                                         BindingFlags.Public,
940                                                         FilterEnumerator, null);
941
942                         if (mi == null){
943                                 error1579 (t);
944                                 return null;
945                         }
946
947                         if (mi.Length == 0){
948                                 error1579 (t);
949                                 return null;
950                         }
951
952                         return (MethodInfo) mi [0];
953                 }
954                 
955                 public override bool Emit (EmitContext ec)
956                 {
957                         ILGenerator ig = ec.ig;
958                         Expression e = Expr;
959                         MethodInfo get_enum;
960                         LocalBuilder enumerator, disposable;
961                         Type var_type;
962                         
963                         e = e.Resolve (ec);
964                         if (e == null)
965                                 return false;
966
967                         var_type = ec.TypeContainer.LookupType (Type, false);
968                         if (var_type == null)
969                                 return false;
970                         
971                         //
972                         // We need an instance variable.  Not sure this is the best
973                         // way of doing this.
974                         //
975                         // FIXME: When we implement propertyaccess, will those turn
976                         // out to return values in ExprClass?  I think they should.
977                         //
978                         if (!(e.ExprClass == ExprClass.Variable || e.ExprClass == ExprClass.Value)){
979                                 error1579 (e.Type);
980                                 return false;
981                         }
982                         
983                         if ((get_enum = ProbeCollectionType (e.Type)) == null)
984                                 return false;
985
986                         Expression empty = new EmptyExpression ();
987                         Expression conv;
988
989                         conv = Expression.ConvertExplicit (ec, empty, var_type, Location);
990                         if (conv == null)
991                                 return false;
992                         
993                         enumerator = ig.DeclareLocal (TypeManager.ienumerator_type);
994                         disposable = ig.DeclareLocal (TypeManager.idisposable_type);
995                         
996                         //
997                         // Instantiate the enumerator
998
999                         Label end = ig.DefineLabel ();
1000                         Label end_try = ig.DefineLabel ();
1001                         Label loop = ig.DefineLabel ();
1002
1003                         //
1004                         // FIXME: This code does not work for cases like:
1005                         // foreach (int a in ValueTypeVariable){
1006                         // }
1007                         //
1008                         // The code should emit an ldarga instruction
1009                         // for the ValueTypeVariable rather than a ldarg
1010                         //
1011                         if (e.Type.IsValueType){
1012                                 ig.Emit (OpCodes.Call, get_enum);
1013                         } else {
1014                                 e.Emit (ec);
1015                                 ig.Emit (OpCodes.Callvirt, get_enum);
1016                         }
1017                         ig.Emit (OpCodes.Stloc, enumerator);
1018
1019                         //
1020                         // Protect the code in a try/finalize block, so that
1021                         // if the beast implement IDisposable, we get rid of it
1022                         //
1023                         Label l = ig.BeginExceptionBlock ();
1024                         ig.MarkLabel (loop);
1025                         ig.Emit (OpCodes.Ldloc, enumerator);
1026                         ig.Emit (OpCodes.Callvirt, TypeManager.bool_movenext_void);
1027                         ig.Emit (OpCodes.Brfalse, end_try);
1028                         ig.Emit (OpCodes.Ldloc, enumerator);
1029                         ig.Emit (OpCodes.Callvirt, TypeManager.object_getcurrent_void);
1030                         conv.Emit (ec);
1031                         Variable.Store (ec);
1032                         Statement.Emit (ec);
1033                         ig.Emit (OpCodes.Br, loop);
1034                         ig.MarkLabel (end_try);
1035
1036                         // The runtime provides this for us.
1037                         // ig.Emit (OpCodes.Leave, end);
1038
1039                         //
1040                         // Now the finally block
1041                         //
1042                         Label end_finally = ig.DefineLabel ();
1043                         
1044                         ig.BeginFinallyBlock ();
1045                         ig.Emit (OpCodes.Ldloc, enumerator);
1046                         ig.Emit (OpCodes.Isinst, TypeManager.idisposable_type);
1047                         ig.Emit (OpCodes.Stloc, disposable);
1048                         ig.Emit (OpCodes.Ldloc, disposable);
1049                         ig.Emit (OpCodes.Brfalse, end_finally);
1050                         ig.Emit (OpCodes.Ldloc, disposable);
1051                         ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
1052                         ig.MarkLabel (end_finally);
1053
1054                         // The runtime generates this anyways.
1055                         // ig.Emit (OpCodes.Endfinally);
1056
1057                         ig.EndExceptionBlock ();
1058                         ig.MarkLabel (end);
1059
1060                         return false;
1061                 }
1062
1063         }
1064 }
1065