2003-02-17 Gonzalo Paniagua Javier <gonzalo@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 //   Martin Baulig (martin@gnome.org)
7 //
8 // (C) 2001, 2002 Ximian, Inc.
9 //
10
11 using System;
12 using System.Text;
13 using System.Reflection;
14 using System.Reflection.Emit;
15 using System.Diagnostics;
16
17 namespace Mono.CSharp {
18
19         using System.Collections;
20         
21         public abstract class Statement {
22                 public Location loc;
23                 
24                 ///
25                 /// Resolves the statement, true means that all sub-statements
26                 /// did resolve ok.
27                 //
28                 public virtual bool Resolve (EmitContext ec)
29                 {
30                         return true;
31                 }
32                 
33                 /// <summary>
34                 ///   Return value indicates whether all code paths emitted return.
35                 /// </summary>
36                 protected abstract bool DoEmit (EmitContext ec);
37
38                 /// <summary>
39                 ///   Return value indicates whether all code paths emitted return.
40                 /// </summary>
41                 public virtual bool Emit (EmitContext ec)
42                 {
43                         ec.Mark (loc);
44                         Report.Debug (8, "MARK", this, loc);
45                         return DoEmit (ec);
46                 }
47                 
48                 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
49                 {
50                         e = e.Resolve (ec);
51                         if (e == null)
52                                 return null;
53                         
54                         if (e.Type != TypeManager.bool_type){
55                                 e = Expression.ConvertImplicit (ec, e, TypeManager.bool_type,
56                                                                 new Location (-1));
57                         }
58
59                         if (e == null){
60                                 Report.Error (
61                                         31, loc, "Can not convert the expression to a boolean");
62                         }
63
64                         ec.Mark (loc);
65
66                         return e;
67                 }
68                 
69                 /// <remarks>
70                 ///    Encapsulates the emission of a boolean test and jumping to a
71                 ///    destination.
72                 ///
73                 ///    This will emit the bool expression in `bool_expr' and if
74                 ///    `target_is_for_true' is true, then the code will generate a 
75                 ///    brtrue to the target.   Otherwise a brfalse. 
76                 /// </remarks>
77                 public static void EmitBoolExpression (EmitContext ec, Expression bool_expr,
78                                                        Label target, bool target_is_for_true)
79                 {
80                         ILGenerator ig = ec.ig;
81                         
82                         bool invert = false;
83                         if (bool_expr is Unary){
84                                 Unary u = (Unary) bool_expr;
85                                 
86                                 if (u.Oper == Unary.Operator.LogicalNot){
87                                         invert = true;
88
89                                         u.EmitLogicalNot (ec);
90                                 }
91                         } else if (bool_expr is Binary){
92                                 Binary b = (Binary) bool_expr;
93
94                                 if (b.EmitBranchable (ec, target, target_is_for_true))
95                                         return;
96                         }
97
98                         if (!invert)
99                                 bool_expr.Emit (ec);
100
101                         if (target_is_for_true){
102                                 if (invert)
103                                         ig.Emit (OpCodes.Brfalse, target);
104                                 else
105                                         ig.Emit (OpCodes.Brtrue, target);
106                         } else {
107                                 if (invert)
108                                         ig.Emit (OpCodes.Brtrue, target);
109                                 else
110                                         ig.Emit (OpCodes.Brfalse, target);
111                         }
112                 }
113
114                 public static void Warning_DeadCodeFound (Location loc)
115                 {
116                         Report.Warning (162, loc, "Unreachable code detected");
117                 }
118         }
119
120         public class EmptyStatement : Statement {
121                 public override bool Resolve (EmitContext ec)
122                 {
123                         return true;
124                 }
125                 
126                 protected override bool DoEmit (EmitContext ec)
127                 {
128                         return false;
129                 }
130         }
131         
132         public class If : Statement {
133                 Expression expr;
134                 public Statement TrueStatement;
135                 public Statement FalseStatement;
136                 
137                 public If (Expression expr, Statement trueStatement, Location l)
138                 {
139                         this.expr = expr;
140                         TrueStatement = trueStatement;
141                         loc = l;
142                 }
143
144                 public If (Expression expr,
145                            Statement trueStatement,
146                            Statement falseStatement,
147                            Location l)
148                 {
149                         this.expr = expr;
150                         TrueStatement = trueStatement;
151                         FalseStatement = falseStatement;
152                         loc = l;
153                 }
154
155                 public override bool Resolve (EmitContext ec)
156                 {
157                         Report.Debug (1, "START IF BLOCK", loc);
158
159                         expr = ResolveBoolean (ec, expr, loc);
160                         if (expr == null){
161                                 return false;
162                         }
163                         
164                         ec.StartFlowBranching (FlowBranchingType.BLOCK, loc);
165                         
166                         if (!TrueStatement.Resolve (ec)) {
167                                 ec.KillFlowBranching ();
168                                 return false;
169                         }
170
171                         ec.CurrentBranching.CreateSibling ();
172
173                         if ((FalseStatement != null) && !FalseStatement.Resolve (ec)) {
174                                 ec.KillFlowBranching ();
175                                 return false;
176                         }
177                                         
178                         ec.EndFlowBranching ();
179
180                         Report.Debug (1, "END IF BLOCK", loc);
181
182                         return true;
183                 }
184                 
185                 protected override bool DoEmit (EmitContext ec)
186                 {
187                         ILGenerator ig = ec.ig;
188                         Label false_target = ig.DefineLabel ();
189                         Label end;
190                         bool is_true_ret, is_false_ret;
191
192                         //
193                         // Dead code elimination
194                         //
195                         if (expr is BoolConstant){
196                                 bool take = ((BoolConstant) expr).Value;
197
198                                 if (take){
199                                         if (FalseStatement != null){
200                                                 Warning_DeadCodeFound (FalseStatement.loc);
201                                         }
202                                         return TrueStatement.Emit (ec);
203                                 } else {
204                                         Warning_DeadCodeFound (TrueStatement.loc);
205                                         if (FalseStatement != null)
206                                                 return FalseStatement.Emit (ec);
207                                 }
208                         }
209                         
210                         EmitBoolExpression (ec, expr, false_target, false);
211
212                         is_true_ret = TrueStatement.Emit (ec);
213                         is_false_ret = is_true_ret;
214
215                         if (FalseStatement != null){
216                                 bool branch_emitted = false;
217                                 
218                                 end = ig.DefineLabel ();
219                                 if (!is_true_ret){
220                                         ig.Emit (OpCodes.Br, end);
221                                         branch_emitted = true;
222                                 }
223
224                                 ig.MarkLabel (false_target);
225                                 is_false_ret = FalseStatement.Emit (ec);
226
227                                 if (branch_emitted)
228                                         ig.MarkLabel (end);
229                         } else {
230                                 ig.MarkLabel (false_target);
231                                 is_false_ret = false;
232                         }
233
234                         return is_true_ret && is_false_ret;
235                 }
236         }
237
238         public class Do : Statement {
239                 public Expression expr;
240                 public readonly Statement  EmbeddedStatement;
241                 bool infinite, may_return;
242                 
243                 public Do (Statement statement, Expression boolExpr, Location l)
244                 {
245                         expr = boolExpr;
246                         EmbeddedStatement = statement;
247                         loc = l;
248                 }
249
250                 public override bool Resolve (EmitContext ec)
251                 {
252                         bool ok = true;
253
254                         ec.StartFlowBranching (FlowBranchingType.LOOP_BLOCK, loc);
255
256                         if (!EmbeddedStatement.Resolve (ec))
257                                 ok = false;
258
259                         expr = ResolveBoolean (ec, expr, loc);
260                         if (expr == null)
261                                 ok = false;
262                         else if (expr is BoolConstant){
263                                 bool res = ((BoolConstant) expr).Value;
264
265                                 if (res)
266                                         infinite = true;
267                         }
268
269                         ec.CurrentBranching.Infinite = infinite;
270                         FlowReturns returns = ec.EndFlowBranching ();
271                         may_return = returns != FlowReturns.NEVER;
272
273                         return ok;
274                 }
275                 
276                 protected override bool DoEmit (EmitContext ec)
277                 {
278                         ILGenerator ig = ec.ig;
279                         Label loop = ig.DefineLabel ();
280                         Label old_begin = ec.LoopBegin;
281                         Label old_end = ec.LoopEnd;
282                         bool  old_inloop = ec.InLoop;
283                         int old_loop_begin_try_catch_level = ec.LoopBeginTryCatchLevel;
284                         
285                         ec.LoopBegin = ig.DefineLabel ();
286                         ec.LoopEnd = ig.DefineLabel ();
287                         ec.InLoop = true;
288                         ec.LoopBeginTryCatchLevel = ec.TryCatchLevel;
289                                 
290                         ig.MarkLabel (loop);
291                         EmbeddedStatement.Emit (ec);
292                         ig.MarkLabel (ec.LoopBegin);
293
294                         //
295                         // Dead code elimination
296                         //
297                         if (expr is BoolConstant){
298                                 bool res = ((BoolConstant) expr).Value;
299
300                                 if (res)
301                                         ec.ig.Emit (OpCodes.Br, loop); 
302                         } else
303                                 EmitBoolExpression (ec, expr, loop, true);
304                         
305                         ig.MarkLabel (ec.LoopEnd);
306
307                         ec.LoopBeginTryCatchLevel = old_loop_begin_try_catch_level;
308                         ec.LoopBegin = old_begin;
309                         ec.LoopEnd = old_end;
310                         ec.InLoop = old_inloop;
311
312                         if (infinite)
313                                 return may_return == false;
314                         else
315                                 return false;
316                 }
317         }
318
319         public class While : Statement {
320                 public Expression expr;
321                 public readonly Statement Statement;
322                 bool may_return, empty, infinite;
323                 
324                 public While (Expression boolExpr, Statement statement, Location l)
325                 {
326                         this.expr = boolExpr;
327                         Statement = statement;
328                         loc = l;
329                 }
330
331                 public override bool Resolve (EmitContext ec)
332                 {
333                         bool ok = true;
334
335                         expr = ResolveBoolean (ec, expr, loc);
336                         if (expr == null)
337                                 return false;
338
339                         ec.StartFlowBranching (FlowBranchingType.LOOP_BLOCK, loc);
340
341                         //
342                         // Inform whether we are infinite or not
343                         //
344                         if (expr is BoolConstant){
345                                 BoolConstant bc = (BoolConstant) expr;
346
347                                 if (bc.Value == false){
348                                         Warning_DeadCodeFound (Statement.loc);
349                                         empty = true;
350                                 } else
351                                         infinite = true;
352                         } else {
353                                 //
354                                 // We are not infinite, so the loop may or may not be executed.
355                                 //
356                                 ec.CurrentBranching.CreateSibling ();
357                         }
358
359                         if (!Statement.Resolve (ec))
360                                 ok = false;
361
362                         if (empty)
363                                 ec.KillFlowBranching ();
364                         else {
365                                 ec.CurrentBranching.Infinite = infinite;
366                                 FlowReturns returns = ec.EndFlowBranching ();
367                                 may_return = returns != FlowReturns.NEVER;
368                         }
369
370                         return ok;
371                 }
372                 
373                 protected override bool DoEmit (EmitContext ec)
374                 {
375                         if (empty)
376                                 return false;
377
378                         ILGenerator ig = ec.ig;
379                         Label old_begin = ec.LoopBegin;
380                         Label old_end = ec.LoopEnd;
381                         bool old_inloop = ec.InLoop;
382                         int old_loop_begin_try_catch_level = ec.LoopBeginTryCatchLevel;
383                         bool ret;
384                         
385                         ec.LoopBegin = ig.DefineLabel ();
386                         ec.LoopEnd = ig.DefineLabel ();
387                         ec.InLoop = true;
388                         ec.LoopBeginTryCatchLevel = ec.TryCatchLevel;
389
390                         //
391                         // Inform whether we are infinite or not
392                         //
393                         if (expr is BoolConstant){
394                                 BoolConstant bc = (BoolConstant) expr;
395
396                                 ig.MarkLabel (ec.LoopBegin);
397                                 Statement.Emit (ec);
398                                 ig.Emit (OpCodes.Br, ec.LoopBegin);
399                                         
400                                 //
401                                 // Inform that we are infinite (ie, `we return'), only
402                                 // if we do not `break' inside the code.
403                                 //
404                                 ret = may_return == false;
405                                 ig.MarkLabel (ec.LoopEnd);
406                         } else {
407                                 Label while_loop = ig.DefineLabel ();
408
409                                 ig.Emit (OpCodes.Br, ec.LoopBegin);
410                                 ig.MarkLabel (while_loop);
411
412                                 Statement.Emit (ec);
413                         
414                                 ig.MarkLabel (ec.LoopBegin);
415
416                                 EmitBoolExpression (ec, expr, while_loop, true);
417                                 ig.MarkLabel (ec.LoopEnd);
418
419                                 ret = false;
420                         }       
421
422                         ec.LoopBegin = old_begin;
423                         ec.LoopEnd = old_end;
424                         ec.InLoop = old_inloop;
425                         ec.LoopBeginTryCatchLevel = old_loop_begin_try_catch_level;
426
427                         return ret;
428                 }
429         }
430
431         public class For : Statement {
432                 Expression Test;
433                 readonly Statement InitStatement;
434                 readonly Statement Increment;
435                 readonly Statement Statement;
436                 bool may_return, infinite, empty;
437                 
438                 public For (Statement initStatement,
439                             Expression test,
440                             Statement increment,
441                             Statement statement,
442                             Location l)
443                 {
444                         InitStatement = initStatement;
445                         Test = test;
446                         Increment = increment;
447                         Statement = statement;
448                         loc = l;
449                 }
450
451                 public override bool Resolve (EmitContext ec)
452                 {
453                         bool ok = true;
454
455                         if (InitStatement != null){
456                                 if (!InitStatement.Resolve (ec))
457                                         ok = false;
458                         }
459
460                         if (Test != null){
461                                 Test = ResolveBoolean (ec, Test, loc);
462                                 if (Test == null)
463                                         ok = false;
464                                 else if (Test is BoolConstant){
465                                         BoolConstant bc = (BoolConstant) Test;
466
467                                         if (bc.Value == false){
468                                                 Warning_DeadCodeFound (Statement.loc);
469                                                 empty = true;
470                                         } else
471                                                 infinite = true;
472                                 }
473                         } else
474                                 infinite = true;
475
476                         if (Increment != null){
477                                 if (!Increment.Resolve (ec))
478                                         ok = false;
479                         }
480
481                         ec.StartFlowBranching (FlowBranchingType.LOOP_BLOCK, loc);
482                         if (!infinite)
483                                 ec.CurrentBranching.CreateSibling ();
484
485                         if (!Statement.Resolve (ec))
486                                 ok = false;
487
488                         if (empty)
489                                 ec.KillFlowBranching ();
490                         else {
491                                 ec.CurrentBranching.Infinite = infinite;
492                                 FlowReturns returns = ec.EndFlowBranching ();
493                                 may_return = returns != FlowReturns.NEVER;
494                         }
495
496                         return ok;
497                 }
498                 
499                 protected override bool DoEmit (EmitContext ec)
500                 {
501                         if (empty)
502                                 return false;
503
504                         ILGenerator ig = ec.ig;
505                         Label old_begin = ec.LoopBegin;
506                         Label old_end = ec.LoopEnd;
507                         bool old_inloop = ec.InLoop;
508                         int old_loop_begin_try_catch_level = ec.LoopBeginTryCatchLevel;
509                         Label loop = ig.DefineLabel ();
510                         Label test = ig.DefineLabel ();
511                         
512                         if (InitStatement != null)
513                                 if (! (InitStatement is EmptyStatement))
514                                         InitStatement.Emit (ec);
515
516                         ec.LoopBegin = ig.DefineLabel ();
517                         ec.LoopEnd = ig.DefineLabel ();
518                         ec.InLoop = true;
519                         ec.LoopBeginTryCatchLevel = ec.TryCatchLevel;
520
521                         ig.Emit (OpCodes.Br, test);
522                         ig.MarkLabel (loop);
523                         Statement.Emit (ec);
524
525                         ig.MarkLabel (ec.LoopBegin);
526                         if (!(Increment is EmptyStatement))
527                                 Increment.Emit (ec);
528
529                         ig.MarkLabel (test);
530                         //
531                         // If test is null, there is no test, and we are just
532                         // an infinite loop
533                         //
534                         if (Test != null){
535                                 //
536                                 // The Resolve code already catches the case for Test == BoolConstant (false)
537                                 // so we know that this is true
538                                 //
539                                 if (Test is BoolConstant)
540                                         ig.Emit (OpCodes.Br, loop);
541                                 else
542                                         EmitBoolExpression (ec, Test, loop, true);
543                         } else
544                                 ig.Emit (OpCodes.Br, loop);
545                         ig.MarkLabel (ec.LoopEnd);
546
547                         ec.LoopBegin = old_begin;
548                         ec.LoopEnd = old_end;
549                         ec.InLoop = old_inloop;
550                         ec.LoopBeginTryCatchLevel = old_loop_begin_try_catch_level;
551                         
552                         //
553                         // Inform whether we are infinite or not
554                         //
555                         if (Test != null){
556                                 if (Test is BoolConstant){
557                                         BoolConstant bc = (BoolConstant) Test;
558
559                                         if (bc.Value)
560                                                 return may_return == false;
561                                 }
562                                 return false;
563                         } else
564                                 return may_return == false;
565                 }
566         }
567         
568         public class StatementExpression : Statement {
569                 Expression expr;
570                 
571                 public StatementExpression (ExpressionStatement expr, Location l)
572                 {
573                         this.expr = expr;
574                         loc = l;
575                 }
576
577                 public override bool Resolve (EmitContext ec)
578                 {
579                         expr = (Expression) expr.Resolve (ec);
580                         return expr != null;
581                 }
582                 
583                 protected override bool DoEmit (EmitContext ec)
584                 {
585                         ILGenerator ig = ec.ig;
586                         
587                         if (expr is ExpressionStatement)
588                                 ((ExpressionStatement) expr).EmitStatement (ec);
589                         else {
590                                 expr.Emit (ec);
591                                 ig.Emit (OpCodes.Pop);
592                         }
593
594                         return false;
595                 }
596
597                 public override string ToString ()
598                 {
599                         return "StatementExpression (" + expr + ")";
600                 }
601         }
602
603         /// <summary>
604         ///   Implements the return statement
605         /// </summary>
606         public class Return : Statement {
607                 public Expression Expr;
608                 
609                 public Return (Expression expr, Location l)
610                 {
611                         Expr = expr;
612                         loc = l;
613                 }
614
615                 public override bool Resolve (EmitContext ec)
616                 {
617                         if (Expr != null){
618                                 Expr = Expr.Resolve (ec);
619                                 if (Expr == null)
620                                         return false;
621                         }
622
623                         FlowBranching.UsageVector vector = ec.CurrentBranching.CurrentUsageVector;
624
625                         if (ec.CurrentBranching.InTryBlock ())
626                                 ec.CurrentBranching.AddFinallyVector (vector);
627                         else
628                                 vector.CheckOutParameters (ec.CurrentBranching);
629
630                         vector.Returns = FlowReturns.ALWAYS;
631                         vector.Breaks = FlowReturns.ALWAYS;
632                         return true;
633                 }
634                 
635                 protected override bool DoEmit (EmitContext ec)
636                 {
637                         if (ec.InFinally){
638                                 Report.Error (157,loc,"Control can not leave the body of the finally block");
639                                 return false;
640                         }
641                         
642                         if (ec.ReturnType == null){
643                                 if (Expr != null){
644                                         Report.Error (127, loc, "Return with a value not allowed here");
645                                         return true;
646                                 }
647                         } else {
648                                 if (Expr == null){
649                                         Report.Error (126, loc, "An object of type `" +
650                                                       TypeManager.CSharpName (ec.ReturnType) + "' is " +
651                                                       "expected for the return statement");
652                                         return true;
653                                 }
654
655                                 if (Expr.Type != ec.ReturnType)
656                                         Expr = Expression.ConvertImplicitRequired (
657                                                 ec, Expr, ec.ReturnType, loc);
658
659                                 if (Expr == null)
660                                         return true;
661
662                                 Expr.Emit (ec);
663
664                                 if (ec.InTry || ec.InCatch)
665                                         ec.ig.Emit (OpCodes.Stloc, ec.TemporaryReturn ());
666                         }
667
668                         if (ec.InTry || ec.InCatch) {
669                                 if (!ec.HasReturnLabel) {
670                                         ec.ReturnLabel = ec.ig.DefineLabel ();
671                                         ec.HasReturnLabel = true;
672                                 }
673                                 ec.ig.Emit (OpCodes.Leave, ec.ReturnLabel);
674                         } else
675                                 ec.ig.Emit (OpCodes.Ret);
676
677                         return true; 
678                 }
679         }
680
681         public class Goto : Statement {
682                 string target;
683                 Block block;
684                 LabeledStatement label;
685                 
686                 public override bool Resolve (EmitContext ec)
687                 {
688                         label = block.LookupLabel (target);
689                         if (label == null){
690                                 Report.Error (
691                                         159, loc,
692                                         "No such label `" + target + "' in this scope");
693                                 return false;
694                         }
695
696                         // If this is a forward goto.
697                         if (!label.IsDefined)
698                                 label.AddUsageVector (ec.CurrentBranching.CurrentUsageVector);
699
700                         ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.ALWAYS;
701                         ec.CurrentBranching.CurrentUsageVector.Returns = FlowReturns.ALWAYS;
702
703                         return true;
704                 }
705                 
706                 public Goto (Block parent_block, string label, Location l)
707                 {
708                         block = parent_block;
709                         loc = l;
710                         target = label;
711                 }
712
713                 public string Target {
714                         get {
715                                 return target;
716                         }
717                 }
718
719                 protected override bool DoEmit (EmitContext ec)
720                 {
721                         Label l = label.LabelTarget (ec);
722                         ec.ig.Emit (OpCodes.Br, l);
723                         
724                         return false;
725                 }
726         }
727
728         public class LabeledStatement : Statement {
729                 public readonly Location Location;
730                 string label_name;
731                 bool defined;
732                 bool referenced;
733                 Label label;
734
735                 ArrayList vectors;
736                 
737                 public LabeledStatement (string label_name, Location l)
738                 {
739                         this.label_name = label_name;
740                         this.Location = l;
741                 }
742
743                 public Label LabelTarget (EmitContext ec)
744                 {
745                         if (defined)
746                                 return label;
747                         label = ec.ig.DefineLabel ();
748                         defined = true;
749
750                         return label;
751                 }
752
753                 public bool IsDefined {
754                         get {
755                                 return defined;
756                         }
757                 }
758
759                 public bool HasBeenReferenced {
760                         get {
761                                 return referenced;
762                         }
763                 }
764
765                 public void AddUsageVector (FlowBranching.UsageVector vector)
766                 {
767                         if (vectors == null)
768                                 vectors = new ArrayList ();
769
770                         vectors.Add (vector.Clone ());
771                 }
772
773                 public override bool Resolve (EmitContext ec)
774                 {
775                         if (vectors != null)
776                                 ec.CurrentBranching.CurrentUsageVector.MergeJumpOrigins (vectors);
777                         else {
778                                 ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.NEVER;
779                                 ec.CurrentBranching.CurrentUsageVector.Returns = FlowReturns.NEVER;
780                         }
781
782                         referenced = true;
783
784                         return true;
785                 }
786
787                 protected override bool DoEmit (EmitContext ec)
788                 {
789                         LabelTarget (ec);
790                         ec.ig.MarkLabel (label);
791
792                         return false;
793                 }
794         }
795         
796
797         /// <summary>
798         ///   `goto default' statement
799         /// </summary>
800         public class GotoDefault : Statement {
801                 
802                 public GotoDefault (Location l)
803                 {
804                         loc = l;
805                 }
806
807                 public override bool Resolve (EmitContext ec)
808                 {
809                         ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.ALWAYS;
810                         ec.CurrentBranching.CurrentUsageVector.Returns = FlowReturns.ALWAYS;
811                         return true;
812                 }
813
814                 protected override bool DoEmit (EmitContext ec)
815                 {
816                         if (ec.Switch == null){
817                                 Report.Error (153, loc, "goto default is only valid in a switch statement");
818                                 return false;
819                         }
820
821                         if (!ec.Switch.GotDefault){
822                                 Report.Error (159, loc, "No default target on switch statement");
823                                 return false;
824                         }
825                         ec.ig.Emit (OpCodes.Br, ec.Switch.DefaultTarget);
826                         return false;
827                 }
828         }
829
830         /// <summary>
831         ///   `goto case' statement
832         /// </summary>
833         public class GotoCase : Statement {
834                 Expression expr;
835                 Label label;
836                 
837                 public GotoCase (Expression e, Location l)
838                 {
839                         expr = e;
840                         loc = l;
841                 }
842
843                 public override bool Resolve (EmitContext ec)
844                 {
845                         if (ec.Switch == null){
846                                 Report.Error (153, loc, "goto case is only valid in a switch statement");
847                                 return false;
848                         }
849
850                         expr = expr.Resolve (ec);
851                         if (expr == null)
852                                 return false;
853
854                         if (!(expr is Constant)){
855                                 Report.Error (159, loc, "Target expression for goto case is not constant");
856                                 return false;
857                         }
858
859                         object val = Expression.ConvertIntLiteral (
860                                 (Constant) expr, ec.Switch.SwitchType, loc);
861
862                         if (val == null)
863                                 return false;
864                                         
865                         SwitchLabel sl = (SwitchLabel) ec.Switch.Elements [val];
866
867                         if (sl == null){
868                                 Report.Error (
869                                         159, loc,
870                                         "No such label 'case " + val + "': for the goto case");
871                         }
872
873                         label = sl.ILLabelCode;
874
875                         ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.UNREACHABLE;
876                         ec.CurrentBranching.CurrentUsageVector.Returns = FlowReturns.ALWAYS;
877                         return true;
878                 }
879
880                 protected override bool DoEmit (EmitContext ec)
881                 {
882                         ec.ig.Emit (OpCodes.Br, label);
883                         return true;
884                 }
885         }
886         
887         public class Throw : Statement {
888                 Expression expr;
889                 
890                 public Throw (Expression expr, Location l)
891                 {
892                         this.expr = expr;
893                         loc = l;
894                 }
895
896                 public override bool Resolve (EmitContext ec)
897                 {
898                         if (expr != null){
899                                 expr = expr.Resolve (ec);
900                                 if (expr == null)
901                                         return false;
902
903                                 ExprClass eclass = expr.eclass;
904
905                                 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
906                                       eclass == ExprClass.Value || eclass == ExprClass.IndexerAccess)) {
907                                         expr.Error118 ("value, variable, property or indexer access ");
908                                         return false;
909                                 }
910
911                                 Type t = expr.Type;
912                                 
913                                 if ((t != TypeManager.exception_type) &&
914                                     !t.IsSubclassOf (TypeManager.exception_type) &&
915                                     !(expr is NullLiteral)) {
916                                         Report.Error (155, loc,
917                                                       "The type caught or thrown must be derived " +
918                                                       "from System.Exception");
919                                         return false;
920                                 }
921                         }
922
923                         ec.CurrentBranching.CurrentUsageVector.Returns = FlowReturns.EXCEPTION;
924                         ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.EXCEPTION;
925                         return true;
926                 }
927                         
928                 protected override bool DoEmit (EmitContext ec)
929                 {
930                         if (expr == null){
931                                 if (ec.InCatch)
932                                         ec.ig.Emit (OpCodes.Rethrow);
933                                 else {
934                                         Report.Error (
935                                                 156, loc,
936                                                 "A throw statement with no argument is only " +
937                                                 "allowed in a catch clause");
938                                 }
939                                 return false;
940                         }
941
942                         expr.Emit (ec);
943
944                         ec.ig.Emit (OpCodes.Throw);
945
946                         return true;
947                 }
948         }
949
950         public class Break : Statement {
951                 
952                 public Break (Location l)
953                 {
954                         loc = l;
955                 }
956
957                 public override bool Resolve (EmitContext ec)
958                 {
959                         ec.CurrentBranching.MayLeaveLoop = true;
960                         ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.ALWAYS;
961                         return true;
962                 }
963
964                 protected override bool DoEmit (EmitContext ec)
965                 {
966                         ILGenerator ig = ec.ig;
967
968                         if (ec.InLoop == false && ec.Switch == null){
969                                 Report.Error (139, loc, "No enclosing loop or switch to continue to");
970                                 return false;
971                         }
972
973                         if (ec.InTry || ec.InCatch)
974                                 ig.Emit (OpCodes.Leave, ec.LoopEnd);
975                         else
976                                 ig.Emit (OpCodes.Br, ec.LoopEnd);
977
978                         return false;
979                 }
980         }
981
982         public class Continue : Statement {
983                 
984                 public Continue (Location l)
985                 {
986                         loc = l;
987                 }
988
989                 public override bool Resolve (EmitContext ec)
990                 {
991                         ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.ALWAYS;
992                         return true;
993                 }
994
995                 protected override bool DoEmit (EmitContext ec)
996                 {
997                         Label begin = ec.LoopBegin;
998                         
999                         if (!ec.InLoop){
1000                                 Report.Error (139, loc, "No enclosing loop to continue to");
1001                                 return false;
1002                         } 
1003
1004                         //
1005                         // UGH: Non trivial.  This Br might cross a try/catch boundary
1006                         // How can we tell?
1007                         //
1008                         // while () {
1009                         //   try { ... } catch { continue; }
1010                         // }
1011                         //
1012                         // From:
1013                         // try {} catch { while () { continue; }}
1014                         //
1015                         if (ec.TryCatchLevel > ec.LoopBeginTryCatchLevel)
1016                                 ec.ig.Emit (OpCodes.Leave, begin);
1017                         else if (ec.TryCatchLevel < ec.LoopBeginTryCatchLevel)
1018                                 throw new Exception ("Should never happen");
1019                         else
1020                                 ec.ig.Emit (OpCodes.Br, begin);
1021                         return false;
1022                 }
1023         }
1024
1025         // <summary>
1026         //   This is used in the control flow analysis code to specify whether the
1027         //   current code block may return to its enclosing block before reaching
1028         //   its end.
1029         // </summary>
1030         public enum FlowReturns {
1031                 // It can never return.
1032                 NEVER,
1033
1034                 // This means that the block contains a conditional return statement
1035                 // somewhere.
1036                 SOMETIMES,
1037
1038                 // The code always returns, ie. there's an unconditional return / break
1039                 // statement in it.
1040                 ALWAYS,
1041
1042                 // The code always throws an exception.
1043                 EXCEPTION,
1044
1045                 // The current code block is unreachable.  This happens if it's immediately
1046                 // following a FlowReturns.ALWAYS block.
1047                 UNREACHABLE
1048         }
1049
1050         // <summary>
1051         //   This is a special bit vector which can inherit from another bit vector doing a
1052         //   copy-on-write strategy.  The inherited vector may have a smaller size than the
1053         //   current one.
1054         // </summary>
1055         public class MyBitVector {
1056                 public readonly int Count;
1057                 public readonly MyBitVector InheritsFrom;
1058
1059                 bool is_dirty;
1060                 BitArray vector;
1061
1062                 public MyBitVector (int Count)
1063                         : this (null, Count)
1064                 { }
1065
1066                 public MyBitVector (MyBitVector InheritsFrom, int Count)
1067                 {
1068                         this.InheritsFrom = InheritsFrom;
1069                         this.Count = Count;
1070                 }
1071
1072                 // <summary>
1073                 //   Checks whether this bit vector has been modified.  After setting this to true,
1074                 //   we won't use the inherited vector anymore, but our own copy of it.
1075                 // </summary>
1076                 public bool IsDirty {
1077                         get {
1078                                 return is_dirty;
1079                         }
1080
1081                         set {
1082                                 if (!is_dirty)
1083                                         initialize_vector ();
1084                         }
1085                 }
1086
1087                 // <summary>
1088                 //   Get/set bit `index' in the bit vector.
1089                 // </summary>
1090                 public bool this [int index]
1091                 {
1092                         get {
1093                                 if (index > Count)
1094                                         throw new ArgumentOutOfRangeException ();
1095
1096                                 // We're doing a "copy-on-write" strategy here; as long
1097                                 // as nobody writes to the array, we can use our parent's
1098                                 // copy instead of duplicating the vector.
1099
1100                                 if (vector != null)
1101                                         return vector [index];
1102                                 else if (InheritsFrom != null) {
1103                                         BitArray inherited = InheritsFrom.Vector;
1104
1105                                         if (index < inherited.Count)
1106                                                 return inherited [index];
1107                                         else
1108                                                 return false;
1109                                 } else
1110                                         return false;
1111                         }
1112
1113                         set {
1114                                 if (index > Count)
1115                                         throw new ArgumentOutOfRangeException ();
1116
1117                                 // Only copy the vector if we're actually modifying it.
1118
1119                                 if (this [index] != value) {
1120                                         initialize_vector ();
1121
1122                                         vector [index] = value;
1123                                 }
1124                         }
1125                 }
1126
1127                 // <summary>
1128                 //   If you explicitly convert the MyBitVector to a BitArray, you will get a deep
1129                 //   copy of the bit vector.
1130                 // </summary>
1131                 public static explicit operator BitArray (MyBitVector vector)
1132                 {
1133                         vector.initialize_vector ();
1134                         return vector.Vector;
1135                 }
1136
1137                 // <summary>
1138                 //   Performs an `or' operation on the bit vector.  The `new_vector' may have a
1139                 //   different size than the current one.
1140                 // </summary>
1141                 public void Or (MyBitVector new_vector)
1142                 {
1143                         BitArray new_array = new_vector.Vector;
1144
1145                         initialize_vector ();
1146
1147                         int upper;
1148                         if (vector.Count < new_array.Count)
1149                                 upper = vector.Count;
1150                         else
1151                                 upper = new_array.Count;
1152
1153                         for (int i = 0; i < upper; i++)
1154                                 vector [i] = vector [i] | new_array [i];
1155                 }
1156
1157                 // <summary>
1158                 //   Perfonrms an `and' operation on the bit vector.  The `new_vector' may have
1159                 //   a different size than the current one.
1160                 // </summary>
1161                 public void And (MyBitVector new_vector)
1162                 {
1163                         BitArray new_array = new_vector.Vector;
1164
1165                         initialize_vector ();
1166
1167                         int lower, upper;
1168                         if (vector.Count < new_array.Count)
1169                                 lower = upper = vector.Count;
1170                         else {
1171                                 lower = new_array.Count;
1172                                 upper = vector.Count;
1173                         }
1174
1175                         for (int i = 0; i < lower; i++)
1176                                 vector [i] = vector [i] & new_array [i];
1177
1178                         for (int i = lower; i < upper; i++)
1179                                 vector [i] = false;
1180                 }
1181
1182                 // <summary>
1183                 //   This does a deep copy of the bit vector.
1184                 // </summary>
1185                 public MyBitVector Clone ()
1186                 {
1187                         MyBitVector retval = new MyBitVector (Count);
1188
1189                         retval.Vector = Vector;
1190
1191                         return retval;
1192                 }
1193
1194                 BitArray Vector {
1195                         get {
1196                                 if (vector != null)
1197                                         return vector;
1198                                 else if (!is_dirty && (InheritsFrom != null))
1199                                         return InheritsFrom.Vector;
1200
1201                                 initialize_vector ();
1202
1203                                 return vector;
1204                         }
1205
1206                         set {
1207                                 initialize_vector ();
1208
1209                                 for (int i = 0; i < Math.Min (vector.Count, value.Count); i++)
1210                                         vector [i] = value [i];
1211                         }
1212                 }
1213
1214                 void initialize_vector ()
1215                 {
1216                         if (vector != null)
1217                                 return;
1218
1219                         vector = new BitArray (Count, false);
1220                         if (InheritsFrom != null)
1221                                 Vector = InheritsFrom.Vector;
1222
1223                         is_dirty = true;
1224                 }
1225
1226                 public override string ToString ()
1227                 {
1228                         StringBuilder sb = new StringBuilder ("MyBitVector (");
1229
1230                         BitArray vector = Vector;
1231                         sb.Append (Count);
1232                         sb.Append (",");
1233                         if (!IsDirty)
1234                                 sb.Append ("INHERITED - ");
1235                         for (int i = 0; i < vector.Count; i++) {
1236                                 if (i > 0)
1237                                         sb.Append (",");
1238                                 sb.Append (vector [i]);
1239                         }
1240                         
1241                         sb.Append (")");
1242                         return sb.ToString ();
1243                 }
1244         }
1245
1246         // <summary>
1247         //   The type of a FlowBranching.
1248         // </summary>
1249         public enum FlowBranchingType {
1250                 // Normal (conditional or toplevel) block.
1251                 BLOCK,
1252
1253                 // A loop block.
1254                 LOOP_BLOCK,
1255
1256                 // Try/Catch block.
1257                 EXCEPTION,
1258
1259                 // Switch block.
1260                 SWITCH,
1261
1262                 // Switch section.
1263                 SWITCH_SECTION
1264         }
1265
1266         // <summary>
1267         //   A new instance of this class is created every time a new block is resolved
1268         //   and if there's branching in the block's control flow.
1269         // </summary>
1270         public class FlowBranching {
1271                 // <summary>
1272                 //   The type of this flow branching.
1273                 // </summary>
1274                 public readonly FlowBranchingType Type;
1275
1276                 // <summary>
1277                 //   The block this branching is contained in.  This may be null if it's not
1278                 //   a top-level block and it doesn't declare any local variables.
1279                 // </summary>
1280                 public readonly Block Block;
1281
1282                 // <summary>
1283                 //   The parent of this branching or null if this is the top-block.
1284                 // </summary>
1285                 public readonly FlowBranching Parent;
1286
1287                 // <summary>
1288                 //   Start-Location of this flow branching.
1289                 // </summary>
1290                 public readonly Location Location;
1291
1292                 // <summary>
1293                 //   A list of UsageVectors.  A new vector is added each time control flow may
1294                 //   take a different path.
1295                 // </summary>
1296                 public UsageVector[] Siblings;
1297
1298                 // <summary>
1299                 //   If this is an infinite loop.
1300                 // </summary>
1301                 public bool Infinite;
1302
1303                 // <summary>
1304                 //   If we may leave the current loop.
1305                 // </summary>
1306                 public bool MayLeaveLoop;
1307
1308                 //
1309                 // Private
1310                 //
1311                 InternalParameters param_info;
1312                 int[] param_map;
1313                 MyStructInfo[] struct_params;
1314                 int num_params;
1315                 ArrayList finally_vectors;
1316
1317                 static int next_id = 0;
1318                 int id;
1319
1320                 // <summary>
1321                 //   Performs an `And' operation on the FlowReturns status
1322                 //   (for instance, a block only returns ALWAYS if all its siblings
1323                 //   always return).
1324                 // </summary>
1325                 public static FlowReturns AndFlowReturns (FlowReturns a, FlowReturns b)
1326                 {
1327                         if (b == FlowReturns.UNREACHABLE)
1328                                 return a;
1329
1330                         switch (a) {
1331                         case FlowReturns.NEVER:
1332                                 if (b == FlowReturns.NEVER)
1333                                         return FlowReturns.NEVER;
1334                                 else
1335                                         return FlowReturns.SOMETIMES;
1336
1337                         case FlowReturns.SOMETIMES:
1338                                 return FlowReturns.SOMETIMES;
1339
1340                         case FlowReturns.ALWAYS:
1341                                 if ((b == FlowReturns.ALWAYS) || (b == FlowReturns.EXCEPTION))
1342                                         return FlowReturns.ALWAYS;
1343                                 else
1344                                         return FlowReturns.SOMETIMES;
1345
1346                         case FlowReturns.EXCEPTION:
1347                                 if (b == FlowReturns.EXCEPTION)
1348                                         return FlowReturns.EXCEPTION;
1349                                 else if (b == FlowReturns.ALWAYS)
1350                                         return FlowReturns.ALWAYS;
1351                                 else
1352                                         return FlowReturns.SOMETIMES;
1353                         }
1354
1355                         return b;
1356                 }
1357
1358                 // <summary>
1359                 //   The vector contains a BitArray with information about which local variables
1360                 //   and parameters are already initialized at the current code position.
1361                 // </summary>
1362                 public class UsageVector {
1363                         // <summary>
1364                         //   If this is true, then the usage vector has been modified and must be
1365                         //   merged when we're done with this branching.
1366                         // </summary>
1367                         public bool IsDirty;
1368
1369                         // <summary>
1370                         //   The number of parameters in this block.
1371                         // </summary>
1372                         public readonly int CountParameters;
1373
1374                         // <summary>
1375                         //   The number of locals in this block.
1376                         // </summary>
1377                         public readonly int CountLocals;
1378
1379                         // <summary>
1380                         //   If not null, then we inherit our state from this vector and do a
1381                         //   copy-on-write.  If null, then we're the first sibling in a top-level
1382                         //   block and inherit from the empty vector.
1383                         // </summary>
1384                         public readonly UsageVector InheritsFrom;
1385
1386                         //
1387                         // Private.
1388                         //
1389                         MyBitVector locals, parameters;
1390                         FlowReturns real_returns, real_breaks;
1391                         bool is_finally;
1392
1393                         static int next_id = 0;
1394                         int id;
1395
1396                         //
1397                         // Normally, you should not use any of these constructors.
1398                         //
1399                         public UsageVector (UsageVector parent, int num_params, int num_locals)
1400                         {
1401                                 this.InheritsFrom = parent;
1402                                 this.CountParameters = num_params;
1403                                 this.CountLocals = num_locals;
1404                                 this.real_returns = FlowReturns.NEVER;
1405                                 this.real_breaks = FlowReturns.NEVER;
1406
1407                                 if (parent != null) {
1408                                         locals = new MyBitVector (parent.locals, CountLocals);
1409                                         if (num_params > 0)
1410                                                 parameters = new MyBitVector (parent.parameters, num_params);
1411                                         real_returns = parent.Returns;
1412                                         real_breaks = parent.Breaks;
1413                                 } else {
1414                                         locals = new MyBitVector (null, CountLocals);
1415                                         if (num_params > 0)
1416                                                 parameters = new MyBitVector (null, num_params);
1417                                 }
1418
1419                                 id = ++next_id;
1420                         }
1421
1422                         public UsageVector (UsageVector parent)
1423                                 : this (parent, parent.CountParameters, parent.CountLocals)
1424                         { }
1425
1426                         // <summary>
1427                         //   This does a deep copy of the usage vector.
1428                         // </summary>
1429                         public UsageVector Clone ()
1430                         {
1431                                 UsageVector retval = new UsageVector (null, CountParameters, CountLocals);
1432
1433                                 retval.locals = locals.Clone ();
1434                                 if (parameters != null)
1435                                         retval.parameters = parameters.Clone ();
1436                                 retval.real_returns = real_returns;
1437                                 retval.real_breaks = real_breaks;
1438
1439                                 return retval;
1440                         }
1441
1442                         // 
1443                         // State of parameter `number'.
1444                         //
1445                         public bool this [int number]
1446                         {
1447                                 get {
1448                                         if (number == -1)
1449                                                 return true;
1450                                         else if (number == 0)
1451                                                 throw new ArgumentException ();
1452
1453                                         return parameters [number - 1];
1454                                 }
1455
1456                                 set {
1457                                         if (number == -1)
1458                                                 return;
1459                                         else if (number == 0)
1460                                                 throw new ArgumentException ();
1461
1462                                         parameters [number - 1] = value;
1463                                 }
1464                         }
1465
1466                         //
1467                         // State of the local variable `vi'.
1468                         // If the local variable is a struct, use a non-zero `field_idx'
1469                         // to check an individual field in it.
1470                         //
1471                         public bool this [VariableInfo vi, int field_idx]
1472                         {
1473                                 get {
1474                                         if (vi.Number == -1)
1475                                                 return true;
1476                                         else if (vi.Number == 0)
1477                                                 throw new ArgumentException ();
1478
1479                                         return locals [vi.Number + field_idx - 1];
1480                                 }
1481
1482                                 set {
1483                                         if (vi.Number == -1)
1484                                                 return;
1485                                         else if (vi.Number == 0)
1486                                                 throw new ArgumentException ();
1487
1488                                         locals [vi.Number + field_idx - 1] = value;
1489                                 }
1490                         }
1491
1492                         // <summary>
1493                         //   Specifies when the current block returns.
1494                         //   If this is FlowReturns.UNREACHABLE, then control can never reach the
1495                         //   end of the method (so that we don't need to emit a return statement).
1496                         //   The same applies for FlowReturns.EXCEPTION, but in this case the return
1497                         //   value will never be used.
1498                         // </summary>
1499                         public FlowReturns Returns {
1500                                 get {
1501                                         return real_returns;
1502                                 }
1503
1504                                 set {
1505                                         real_returns = value;
1506                                 }
1507                         }
1508
1509                         // <summary>
1510                         //   Specifies whether control may return to our containing block
1511                         //   before reaching the end of this block.  This happens if there
1512                         //   is a break/continue/goto/return in it.
1513                         //   This can also be used to find out whether the statement immediately
1514                         //   following the current block may be reached or not.
1515                         // </summary>
1516                         public FlowReturns Breaks {
1517                                 get {
1518                                         return real_breaks;
1519                                 }
1520
1521                                 set {
1522                                         real_breaks = value;
1523                                 }
1524                         }
1525
1526                         public bool AlwaysBreaks {
1527                                 get {
1528                                         return (Breaks == FlowReturns.ALWAYS) ||
1529                                                 (Breaks == FlowReturns.EXCEPTION) ||
1530                                                 (Breaks == FlowReturns.UNREACHABLE);
1531                                 }
1532                         }
1533
1534                         public bool MayBreak {
1535                                 get {
1536                                         return Breaks != FlowReturns.NEVER;
1537                                 }
1538                         }
1539
1540                         public bool AlwaysReturns {
1541                                 get {
1542                                         return (Returns == FlowReturns.ALWAYS) ||
1543                                                 (Returns == FlowReturns.EXCEPTION);
1544                                 }
1545                         }
1546
1547                         public bool MayReturn {
1548                                 get {
1549                                         return (Returns == FlowReturns.SOMETIMES) ||
1550                                                 (Returns == FlowReturns.ALWAYS);
1551                                 }
1552                         }
1553
1554                         // <summary>
1555                         //   Merge a child branching.
1556                         // </summary>
1557                         public FlowReturns MergeChildren (FlowBranching branching, UsageVector[] children)
1558                         {
1559                                 MyBitVector new_locals = null;
1560                                 MyBitVector new_params = null;
1561
1562                                 FlowReturns new_returns = FlowReturns.NEVER;
1563                                 FlowReturns new_breaks = FlowReturns.NEVER;
1564                                 bool new_returns_set = false, new_breaks_set = false;
1565
1566                                 Report.Debug (2, "MERGING CHILDREN", branching, branching.Type,
1567                                               this, children.Length);
1568
1569                                 foreach (UsageVector child in children) {
1570                                         Report.Debug (2, "  MERGING CHILD", child, child.is_finally);
1571                                         
1572                                         if (!child.is_finally) {
1573                                                 if (child.Breaks != FlowReturns.UNREACHABLE) {
1574                                                         // If Returns is already set, perform an
1575                                                         // `And' operation on it, otherwise just set just.
1576                                                         if (!new_returns_set) {
1577                                                                 new_returns = child.Returns;
1578                                                                 new_returns_set = true;
1579                                                         } else
1580                                                                 new_returns = AndFlowReturns (
1581                                                                         new_returns, child.Returns);
1582                                                 }
1583
1584                                                 // If Breaks is already set, perform an
1585                                                 // `And' operation on it, otherwise just set just.
1586                                                 if (!new_breaks_set) {
1587                                                         new_breaks = child.Breaks;
1588                                                         new_breaks_set = true;
1589                                                 } else
1590                                                         new_breaks = AndFlowReturns (
1591                                                                 new_breaks, child.Breaks);
1592                                         }
1593
1594                                         // Ignore unreachable children.
1595                                         if (child.Returns == FlowReturns.UNREACHABLE)
1596                                                 continue;
1597
1598                                         // A local variable is initialized after a flow branching if it
1599                                         // has been initialized in all its branches which do neither
1600                                         // always return or always throw an exception.
1601                                         //
1602                                         // If a branch may return, but does not always return, then we
1603                                         // can treat it like a never-returning branch here: control will
1604                                         // only reach the code position after the branching if we did not
1605                                         // return here.
1606                                         //
1607                                         // It's important to distinguish between always and sometimes
1608                                         // returning branches here:
1609                                         //
1610                                         //    1   int a;
1611                                         //    2   if (something) {
1612                                         //    3      return;
1613                                         //    4      a = 5;
1614                                         //    5   }
1615                                         //    6   Console.WriteLine (a);
1616                                         //
1617                                         // The if block in lines 3-4 always returns, so we must not look
1618                                         // at the initialization of `a' in line 4 - thus it'll still be
1619                                         // uninitialized in line 6.
1620                                         //
1621                                         // On the other hand, the following is allowed:
1622                                         //
1623                                         //    1   int a;
1624                                         //    2   if (something)
1625                                         //    3      a = 5;
1626                                         //    4   else
1627                                         //    5      return;
1628                                         //    6   Console.WriteLine (a);
1629                                         //
1630                                         // Here, `a' is initialized in line 3 and we must not look at
1631                                         // line 5 since it always returns.
1632                                         // 
1633                                         if (child.is_finally) {
1634                                                 if (new_locals == null)
1635                                                         new_locals = locals.Clone ();
1636                                                 new_locals.Or (child.locals);
1637
1638                                                 if (parameters != null) {
1639                                                         if (new_params == null)
1640                                                                 new_params = parameters.Clone ();
1641                                                         new_params.Or (child.parameters);
1642                                                 }
1643
1644                                         } else {
1645                                                 if (!child.AlwaysReturns && !child.AlwaysBreaks) {
1646                                                         if (new_locals != null)
1647                                                                 new_locals.And (child.locals);
1648                                                         else {
1649                                                                 new_locals = locals.Clone ();
1650                                                                 new_locals.Or (child.locals);
1651                                                         }
1652                                                 } else if (children.Length == 1) {
1653                                                         new_locals = locals.Clone ();
1654                                                         new_locals.Or (child.locals);
1655                                                 }
1656
1657                                                 // An `out' parameter must be assigned in all branches which do
1658                                                 // not always throw an exception.
1659                                                 if (parameters != null) {
1660                                                         if (child.Breaks != FlowReturns.EXCEPTION) {
1661                                                                 if (new_params != null)
1662                                                                         new_params.And (child.parameters);
1663                                                                 else {
1664                                                                         new_params = parameters.Clone ();
1665                                                                         new_params.Or (child.parameters);
1666                                                                 }
1667                                                         } else if (children.Length == 1) {
1668                                                                 new_params = parameters.Clone ();
1669                                                                 new_params.Or (child.parameters);
1670                                                         }
1671                                                 }
1672                                         }
1673                                 }
1674
1675                                 Returns = new_returns;
1676                                 if ((branching.Type == FlowBranchingType.BLOCK) ||
1677                                     (branching.Type == FlowBranchingType.EXCEPTION) ||
1678                                     (new_breaks == FlowReturns.UNREACHABLE) ||
1679                                     (new_breaks == FlowReturns.EXCEPTION))
1680                                         Breaks = new_breaks;
1681                                 else if (branching.Type == FlowBranchingType.SWITCH_SECTION)
1682                                         Breaks = new_returns;
1683                                 else if (branching.Type == FlowBranchingType.SWITCH){
1684                                         if (new_breaks == FlowReturns.ALWAYS)
1685                                                 Breaks = FlowReturns.ALWAYS;
1686                                 }
1687
1688                                 //
1689                                 // We've now either reached the point after the branching or we will
1690                                 // never get there since we always return or always throw an exception.
1691                                 //
1692                                 // If we can reach the point after the branching, mark all locals and
1693                                 // parameters as initialized which have been initialized in all branches
1694                                 // we need to look at (see above).
1695                                 //
1696
1697                                 if (((new_breaks != FlowReturns.ALWAYS) &&
1698                                      (new_breaks != FlowReturns.EXCEPTION) &&
1699                                      (new_breaks != FlowReturns.UNREACHABLE)) ||
1700                                     (children.Length == 1)) {
1701                                         if (new_locals != null)
1702                                                 locals.Or (new_locals);
1703
1704                                         if (new_params != null)
1705                                                 parameters.Or (new_params);
1706                                 }
1707
1708                                 Report.Debug (2, "MERGING CHILDREN DONE", branching.Type,
1709                                               new_params, new_locals, new_returns, new_breaks,
1710                                               branching.Infinite, branching.MayLeaveLoop, this);
1711
1712                                 if (branching.Type == FlowBranchingType.SWITCH_SECTION) {
1713                                         if ((new_breaks != FlowReturns.ALWAYS) &&
1714                                             (new_breaks != FlowReturns.EXCEPTION) &&
1715                                             (new_breaks != FlowReturns.UNREACHABLE))
1716                                                 Report.Error (163, branching.Location,
1717                                                               "Control cannot fall through from one " +
1718                                                               "case label to another");
1719                                 }
1720
1721                                 if (branching.Infinite && !branching.MayLeaveLoop) {
1722                                         Report.Debug (1, "INFINITE", new_returns, new_breaks,
1723                                                       Returns, Breaks, this);
1724
1725                                         // We're actually infinite.
1726                                         if (new_returns == FlowReturns.NEVER) {
1727                                                 Breaks = FlowReturns.UNREACHABLE;
1728                                                 return FlowReturns.UNREACHABLE;
1729                                         }
1730
1731                                         // If we're an infinite loop and do not break, the code after
1732                                         // the loop can never be reached.  However, if we may return
1733                                         // from the loop, then we do always return (or stay in the loop
1734                                         // forever).
1735                                         if ((new_returns == FlowReturns.SOMETIMES) ||
1736                                             (new_returns == FlowReturns.ALWAYS)) {
1737                                                 Returns = FlowReturns.ALWAYS;
1738                                                 return FlowReturns.ALWAYS;
1739                                         }
1740                                 }
1741
1742                                 return new_returns;
1743                         }
1744
1745                         // <summary>
1746                         //   Tells control flow analysis that the current code position may be reached with
1747                         //   a forward jump from any of the origins listed in `origin_vectors' which is a
1748                         //   list of UsageVectors.
1749                         //
1750                         //   This is used when resolving forward gotos - in the following example, the
1751                         //   variable `a' is uninitialized in line 8 becase this line may be reached via
1752                         //   the goto in line 4:
1753                         //
1754                         //      1     int a;
1755                         //
1756                         //      3     if (something)
1757                         //      4        goto World;
1758                         //
1759                         //      6     a = 5;
1760                         //
1761                         //      7  World:
1762                         //      8     Console.WriteLine (a);
1763                         //
1764                         // </summary>
1765                         public void MergeJumpOrigins (ICollection origin_vectors)
1766                         {
1767                                 Report.Debug (1, "MERGING JUMP ORIGIN", this);
1768
1769                                 real_breaks = FlowReturns.NEVER;
1770                                 real_returns = FlowReturns.NEVER;
1771
1772                                 foreach (UsageVector vector in origin_vectors) {
1773                                         Report.Debug (1, "  MERGING JUMP ORIGIN", vector);
1774
1775                                         locals.And (vector.locals);
1776                                         if (parameters != null)
1777                                                 parameters.And (vector.parameters);
1778                                         Breaks = AndFlowReturns (Breaks, vector.Breaks);
1779                                         Returns = AndFlowReturns (Returns, vector.Returns);
1780                                 }
1781
1782                                 Report.Debug (1, "MERGING JUMP ORIGIN DONE", this);
1783                         }
1784
1785                         // <summary>
1786                         //   This is used at the beginning of a finally block if there were
1787                         //   any return statements in the try block or one of the catch blocks.
1788                         // </summary>
1789                         public void MergeFinallyOrigins (ICollection finally_vectors)
1790                         {
1791                                 Report.Debug (1, "MERGING FINALLY ORIGIN", this);
1792
1793                                 real_breaks = FlowReturns.NEVER;
1794
1795                                 foreach (UsageVector vector in finally_vectors) {
1796                                         Report.Debug (1, "  MERGING FINALLY ORIGIN", vector);
1797
1798                                         if (parameters != null)
1799                                                 parameters.And (vector.parameters);
1800                                         Breaks = AndFlowReturns (Breaks, vector.Breaks);
1801                                 }
1802
1803                                 is_finally = true;
1804
1805                                 Report.Debug (1, "MERGING FINALLY ORIGIN DONE", this);
1806                         }
1807
1808                         public void CheckOutParameters (FlowBranching branching)
1809                         {
1810                                 if (parameters != null)
1811                                         branching.CheckOutParameters (parameters, branching.Location);
1812                         }
1813
1814                         // <summary>
1815                         //   Performs an `or' operation on the locals and the parameters.
1816                         // </summary>
1817                         public void Or (UsageVector new_vector)
1818                         {
1819                                 locals.Or (new_vector.locals);
1820                                 if (parameters != null)
1821                                         parameters.Or (new_vector.parameters);
1822                         }
1823
1824                         // <summary>
1825                         //   Performs an `and' operation on the locals.
1826                         // </summary>
1827                         public void AndLocals (UsageVector new_vector)
1828                         {
1829                                 locals.And (new_vector.locals);
1830                         }
1831
1832                         // <summary>
1833                         //   Returns a deep copy of the parameters.
1834                         // </summary>
1835                         public MyBitVector Parameters {
1836                                 get {
1837                                         if (parameters != null)
1838                                                 return parameters.Clone ();
1839                                         else
1840                                                 return null;
1841                                 }
1842                         }
1843
1844                         // <summary>
1845                         //   Returns a deep copy of the locals.
1846                         // </summary>
1847                         public MyBitVector Locals {
1848                                 get {
1849                                         return locals.Clone ();
1850                                 }
1851                         }
1852
1853                         //
1854                         // Debugging stuff.
1855                         //
1856
1857                         public override string ToString ()
1858                         {
1859                                 StringBuilder sb = new StringBuilder ();
1860
1861                                 sb.Append ("Vector (");
1862                                 sb.Append (id);
1863                                 sb.Append (",");
1864                                 sb.Append (Returns);
1865                                 sb.Append (",");
1866                                 sb.Append (Breaks);
1867                                 if (parameters != null) {
1868                                         sb.Append (" - ");
1869                                         sb.Append (parameters);
1870                                 }
1871                                 sb.Append (" - ");
1872                                 sb.Append (locals);
1873                                 sb.Append (")");
1874
1875                                 return sb.ToString ();
1876                         }
1877                 }
1878
1879                 FlowBranching (FlowBranchingType type, Location loc)
1880                 {
1881                         this.Block = null;
1882                         this.Location = loc;
1883                         this.Type = type;
1884                         id = ++next_id;
1885                 }
1886
1887                 // <summary>
1888                 //   Creates a new flow branching for `block'.
1889                 //   This is used from Block.Resolve to create the top-level branching of
1890                 //   the block.
1891                 // </summary>
1892                 public FlowBranching (Block block, InternalParameters ip, Location loc)
1893                         : this (FlowBranchingType.BLOCK, loc)
1894                 {
1895                         Block = block;
1896                         Parent = null;
1897
1898                         int count = (ip != null) ? ip.Count : 0;
1899
1900                         param_info = ip;
1901                         param_map = new int [count];
1902                         struct_params = new MyStructInfo [count];
1903                         num_params = 0;
1904
1905                         for (int i = 0; i < count; i++) {
1906                                 Parameter.Modifier mod = param_info.ParameterModifier (i);
1907
1908                                 if ((mod & Parameter.Modifier.OUT) == 0)
1909                                         continue;
1910
1911                                 param_map [i] = ++num_params;
1912
1913                                 Type param_type = param_info.ParameterType (i);
1914
1915                                 struct_params [i] = MyStructInfo.GetStructInfo (param_type);
1916                                 if (struct_params [i] != null)
1917                                         num_params += struct_params [i].Count;
1918                         }
1919
1920                         AddSibling (new UsageVector (null, num_params, block.CountVariables));
1921                 }
1922
1923                 // <summary>
1924                 //   Creates a new flow branching which is contained in `parent'.
1925                 //   You should only pass non-null for the `block' argument if this block
1926                 //   introduces any new variables - in this case, we need to create a new
1927                 //   usage vector with a different size than our parent's one.
1928                 // </summary>
1929                 public FlowBranching (FlowBranching parent, FlowBranchingType type,
1930                                       Block block, Location loc)
1931                         : this (type, loc)
1932                 {
1933                         Parent = parent;
1934                         Block = block;
1935
1936                         if (parent != null) {
1937                                 param_info = parent.param_info;
1938                                 param_map = parent.param_map;
1939                                 struct_params = parent.struct_params;
1940                                 num_params = parent.num_params;
1941                         }
1942
1943                         UsageVector vector;
1944                         if (Block != null)
1945                                 vector = new UsageVector (parent.CurrentUsageVector, num_params,
1946                                                           Block.CountVariables);
1947                         else
1948                                 vector = new UsageVector (Parent.CurrentUsageVector);
1949
1950                         AddSibling (vector);
1951
1952                         switch (Type) {
1953                         case FlowBranchingType.EXCEPTION:
1954                                 finally_vectors = new ArrayList ();
1955                                 break;
1956
1957                         default:
1958                                 break;
1959                         }
1960                 }
1961
1962                 void AddSibling (UsageVector uv)
1963                 {
1964                         if (Siblings != null) {
1965                                 UsageVector[] ns = new UsageVector [Siblings.Length + 1];
1966                                 for (int i = 0; i < Siblings.Length; ++i)
1967                                         ns [i] = Siblings [i];
1968                                 Siblings = ns;
1969                         } else {
1970                                 Siblings = new UsageVector [1];
1971                         }
1972                         Siblings [Siblings.Length - 1] = uv;
1973                 }
1974
1975                 // <summary>
1976                 //   Returns the branching's current usage vector.
1977                 // </summary>
1978                 public UsageVector CurrentUsageVector
1979                 {
1980                         get {
1981                                 return Siblings [Siblings.Length - 1];
1982                         }
1983                 }
1984
1985                 // <summary>
1986                 //   Creates a sibling of the current usage vector.
1987                 // </summary>
1988                 public void CreateSibling ()
1989                 {
1990                         AddSibling (new UsageVector (Parent.CurrentUsageVector));
1991
1992                         Report.Debug (1, "CREATED SIBLING", CurrentUsageVector);
1993                 }
1994
1995                 // <summary>
1996                 //   Creates a sibling for a `finally' block.
1997                 // </summary>
1998                 public void CreateSiblingForFinally ()
1999                 {
2000                         if (Type != FlowBranchingType.EXCEPTION)
2001                                 throw new NotSupportedException ();
2002
2003                         CreateSibling ();
2004
2005                         CurrentUsageVector.MergeFinallyOrigins (finally_vectors);
2006                 }
2007
2008                 // <summary>
2009                 //   Check whether all `out' parameters have been assigned.
2010                 // </summary>
2011                 public void CheckOutParameters (MyBitVector parameters, Location loc)
2012                 {
2013                         if (InTryBlock ())
2014                                 return;
2015
2016                         for (int i = 0; i < param_map.Length; i++) {
2017                                 int index = param_map [i];
2018
2019                                 if (index == 0)
2020                                         continue;
2021
2022                                 if (parameters [index - 1])
2023                                         continue;
2024
2025                                 // If it's a struct, we must ensure that all its fields have
2026                                 // been assigned.  If the struct has any non-public fields, this
2027                                 // can only be done by assigning the whole struct.
2028
2029                                 MyStructInfo struct_info = struct_params [i];
2030                                 if ((struct_info == null) || struct_info.HasNonPublicFields) {
2031                                         Report.Error (
2032                                                 177, loc, "The out parameter `" +
2033                                                 param_info.ParameterName (i) + "' must be " +
2034                                                 "assigned before control leave the current method.");
2035                                         param_map [i] = 0;
2036                                         continue;
2037                                 }
2038
2039
2040                                 for (int j = 0; j < struct_info.Count; j++) {
2041                                         if (!parameters [index + j]) {
2042                                                 Report.Error (
2043                                                         177, loc, "The out parameter `" +
2044                                                         param_info.ParameterName (i) + "' must be " +
2045                                                         "assigned before control leaves the current method.");
2046                                                 param_map [i] = 0;
2047                                                 break;
2048                                         }
2049                                 }
2050                         }
2051                 }
2052
2053                 // <summary>
2054                 //   Merge a child branching.
2055                 // </summary>
2056                 public FlowReturns MergeChild (FlowBranching child)
2057                 {
2058                         FlowReturns returns = CurrentUsageVector.MergeChildren (child, child.Siblings);
2059
2060                         if ((child.Type != FlowBranchingType.LOOP_BLOCK) &&
2061                             (child.Type != FlowBranchingType.SWITCH_SECTION))
2062                                 MayLeaveLoop |= child.MayLeaveLoop;
2063                         else
2064                                 MayLeaveLoop = false;
2065
2066                         return returns;
2067                 }
2068  
2069                 // <summary>
2070                 //   Does the toplevel merging.
2071                 // </summary>
2072                 public FlowReturns MergeTopBlock ()
2073                 {
2074                         if ((Type != FlowBranchingType.BLOCK) || (Block == null))
2075                                 throw new NotSupportedException ();
2076
2077                         UsageVector vector = new UsageVector (null, num_params, Block.CountVariables);
2078
2079                         Report.Debug (1, "MERGING TOP BLOCK", Location, vector);
2080
2081                         vector.MergeChildren (this, Siblings);
2082
2083                         if (Siblings.Length == 1)
2084                                 Siblings [0] = vector;
2085                         else {
2086                                 Siblings = null;
2087                                 AddSibling (vector);
2088                         }
2089
2090                         Report.Debug (1, "MERGING TOP BLOCK DONE", Location, vector);
2091
2092                         if (vector.Breaks != FlowReturns.EXCEPTION) {
2093                                 if (!vector.AlwaysBreaks)
2094                                         CheckOutParameters (CurrentUsageVector.Parameters, Location);
2095                                 return vector.AlwaysBreaks ? FlowReturns.ALWAYS : vector.Returns;
2096                         } else
2097                                 return FlowReturns.EXCEPTION;
2098                 }
2099
2100                 public bool InTryBlock ()
2101                 {
2102                         if (finally_vectors != null)
2103                                 return true;
2104                         else if (Parent != null)
2105                                 return Parent.InTryBlock ();
2106                         else
2107                                 return false;
2108                 }
2109
2110                 public void AddFinallyVector (UsageVector vector)
2111                 {
2112                         if (finally_vectors != null) {
2113                                 finally_vectors.Add (vector.Clone ());
2114                                 return;
2115                         }
2116
2117                         if (Parent != null)
2118                                 Parent.AddFinallyVector (vector);
2119                         else
2120                                 throw new NotSupportedException ();
2121                 }
2122
2123                 public bool IsVariableAssigned (VariableInfo vi)
2124                 {
2125                         if (CurrentUsageVector.AlwaysBreaks)
2126                                 return true;
2127                         else
2128                                 return CurrentUsageVector [vi, 0];
2129                 }
2130
2131                 public bool IsVariableAssigned (VariableInfo vi, int field_idx)
2132                 {
2133                         if (CurrentUsageVector.AlwaysBreaks)
2134                                 return true;
2135                         else
2136                                 return CurrentUsageVector [vi, field_idx];
2137                 }
2138
2139                 public void SetVariableAssigned (VariableInfo vi)
2140                 {
2141                         if (CurrentUsageVector.AlwaysBreaks)
2142                                 return;
2143
2144                         CurrentUsageVector [vi, 0] = true;
2145                 }
2146
2147                 public void SetVariableAssigned (VariableInfo vi, int field_idx)
2148                 {
2149                         if (CurrentUsageVector.AlwaysBreaks)
2150                                 return;
2151
2152                         CurrentUsageVector [vi, field_idx] = true;
2153                 }
2154
2155                 public bool IsParameterAssigned (int number)
2156                 {
2157                         int index = param_map [number];
2158
2159                         if (index == 0)
2160                                 return true;
2161
2162                         if (CurrentUsageVector [index])
2163                                 return true;
2164
2165                         // Parameter is not assigned, so check whether it's a struct.
2166                         // If it's either not a struct or a struct which non-public
2167                         // fields, return false.
2168                         MyStructInfo struct_info = struct_params [number];
2169                         if ((struct_info == null) || struct_info.HasNonPublicFields)
2170                                 return false;
2171
2172                         // Ok, so each field must be assigned.
2173                         for (int i = 0; i < struct_info.Count; i++)
2174                                 if (!CurrentUsageVector [index + i])
2175                                         return false;
2176
2177                         return true;
2178                 }
2179
2180                 public bool IsParameterAssigned (int number, string field_name)
2181                 {
2182                         int index = param_map [number];
2183
2184                         if (index == 0)
2185                                 return true;
2186
2187                         MyStructInfo info = (MyStructInfo) struct_params [number];
2188                         if (info == null)
2189                                 return true;
2190
2191                         int field_idx = info [field_name];
2192
2193                         return CurrentUsageVector [index + field_idx];
2194                 }
2195
2196                 public void SetParameterAssigned (int number)
2197                 {
2198                         if (param_map [number] == 0)
2199                                 return;
2200
2201                         if (!CurrentUsageVector.AlwaysBreaks)
2202                                 CurrentUsageVector [param_map [number]] = true;
2203                 }
2204
2205                 public void SetParameterAssigned (int number, string field_name)
2206                 {
2207                         int index = param_map [number];
2208
2209                         if (index == 0)
2210                                 return;
2211
2212                         MyStructInfo info = (MyStructInfo) struct_params [number];
2213                         if (info == null)
2214                                 return;
2215
2216                         int field_idx = info [field_name];
2217
2218                         if (!CurrentUsageVector.AlwaysBreaks)
2219                                 CurrentUsageVector [index + field_idx] = true;
2220                 }
2221
2222                 public bool IsReachable ()
2223                 {
2224                         bool reachable;
2225
2226                         switch (Type) {
2227                         case FlowBranchingType.SWITCH_SECTION:
2228                                 // The code following a switch block is reachable unless the switch
2229                                 // block always returns.
2230                                 reachable = !CurrentUsageVector.AlwaysReturns;
2231                                 break;
2232
2233                         case FlowBranchingType.LOOP_BLOCK:
2234                                 // The code following a loop is reachable unless the loop always
2235                                 // returns or it's an infinite loop without any `break's in it.
2236                                 reachable = !CurrentUsageVector.AlwaysReturns &&
2237                                         (CurrentUsageVector.Breaks != FlowReturns.UNREACHABLE);
2238                                 break;
2239
2240                         default:
2241                                 // The code following a block or exception is reachable unless the
2242                                 // block either always returns or always breaks.
2243                                 reachable = !CurrentUsageVector.AlwaysBreaks &&
2244                                         !CurrentUsageVector.AlwaysReturns;
2245                                 break;
2246                         }
2247
2248                         Report.Debug (1, "REACHABLE", Type, CurrentUsageVector.Returns,
2249                                       CurrentUsageVector.Breaks, CurrentUsageVector, reachable);
2250
2251                         return reachable;
2252                 }
2253
2254                 public override string ToString ()
2255                 {
2256                         StringBuilder sb = new StringBuilder ("FlowBranching (");
2257
2258                         sb.Append (id);
2259                         sb.Append (",");
2260                         sb.Append (Type);
2261                         if (Block != null) {
2262                                 sb.Append (" - ");
2263                                 sb.Append (Block.ID);
2264                                 sb.Append (" - ");
2265                                 sb.Append (Block.StartLocation);
2266                         }
2267                         sb.Append (" - ");
2268                         sb.Append (Siblings.Length);
2269                         sb.Append (" - ");
2270                         sb.Append (CurrentUsageVector);
2271                         sb.Append (")");
2272                         return sb.ToString ();
2273                 }
2274         }
2275
2276         public class MyStructInfo {
2277                 public readonly Type Type;
2278                 public readonly FieldInfo[] Fields;
2279                 public readonly FieldInfo[] NonPublicFields;
2280                 public readonly int Count;
2281                 public readonly int CountNonPublic;
2282                 public readonly bool HasNonPublicFields;
2283
2284                 private static Hashtable field_type_hash = new Hashtable ();
2285                 private Hashtable field_hash;
2286
2287                 // Private constructor.  To save memory usage, we only need to create one instance
2288                 // of this class per struct type.
2289                 private MyStructInfo (Type type)
2290                 {
2291                         this.Type = type;
2292
2293                         if (type is TypeBuilder) {
2294                                 TypeContainer tc = TypeManager.LookupTypeContainer (type);
2295
2296                                 ArrayList fields = tc.Fields;
2297                                 if (fields != null) {
2298                                         foreach (Field field in fields) {
2299                                                 if ((field.ModFlags & Modifiers.STATIC) != 0)
2300                                                         continue;
2301                                                 if ((field.ModFlags & Modifiers.PUBLIC) != 0)
2302                                                         ++Count;
2303                                                 else
2304                                                         ++CountNonPublic;
2305                                         }
2306                                 }
2307
2308                                 Fields = new FieldInfo [Count];
2309                                 NonPublicFields = new FieldInfo [CountNonPublic];
2310
2311                                 Count = CountNonPublic = 0;
2312                                 if (fields != null) {
2313                                         foreach (Field field in fields) {
2314                                                 if ((field.ModFlags & Modifiers.STATIC) != 0)
2315                                                         continue;
2316                                                 if ((field.ModFlags & Modifiers.PUBLIC) != 0)
2317                                                         Fields [Count++] = field.FieldBuilder;
2318                                                 else
2319                                                         NonPublicFields [CountNonPublic++] =
2320                                                                 field.FieldBuilder;
2321                                         }
2322                                 }
2323                                 
2324                         } else {
2325                                 Fields = type.GetFields (BindingFlags.Instance|BindingFlags.Public);
2326                                 Count = Fields.Length;
2327
2328                                 NonPublicFields = type.GetFields (BindingFlags.Instance|BindingFlags.NonPublic);
2329                                 CountNonPublic = NonPublicFields.Length;
2330                         }
2331
2332                         Count += NonPublicFields.Length;
2333
2334                         int number = 0;
2335                         field_hash = new Hashtable ();
2336                         foreach (FieldInfo field in Fields)
2337                                 field_hash.Add (field.Name, ++number);
2338
2339                         if (NonPublicFields.Length != 0)
2340                                 HasNonPublicFields = true;
2341
2342                         foreach (FieldInfo field in NonPublicFields)
2343                                 field_hash.Add (field.Name, ++number);
2344                 }
2345
2346                 public int this [string name] {
2347                         get {
2348                                 if (field_hash.Contains (name))
2349                                         return (int) field_hash [name];
2350                                 else
2351                                         return 0;
2352                         }
2353                 }
2354
2355                 public FieldInfo this [int index] {
2356                         get {
2357                                 if (index >= Fields.Length)
2358                                         return NonPublicFields [index - Fields.Length];
2359                                 else
2360                                         return Fields [index];
2361                         }
2362                 }                      
2363
2364                 public static MyStructInfo GetStructInfo (Type type)
2365                 {
2366                         if (!TypeManager.IsValueType (type) || TypeManager.IsEnumType (type))
2367                                 return null;
2368
2369                         if (!(type is TypeBuilder) && TypeManager.IsBuiltinType (type))
2370                                 return null;
2371
2372                         MyStructInfo info = (MyStructInfo) field_type_hash [type];
2373                         if (info != null)
2374                                 return info;
2375
2376                         info = new MyStructInfo (type);
2377                         field_type_hash.Add (type, info);
2378                         return info;
2379                 }
2380
2381                 public static MyStructInfo GetStructInfo (TypeContainer tc)
2382                 {
2383                         MyStructInfo info = (MyStructInfo) field_type_hash [tc.TypeBuilder];
2384                         if (info != null)
2385                                 return info;
2386
2387                         info = new MyStructInfo (tc.TypeBuilder);
2388                         field_type_hash.Add (tc.TypeBuilder, info);
2389                         return info;
2390                 }
2391         }
2392         
2393         public class VariableInfo : IVariable {
2394                 public Expression Type;
2395                 public LocalBuilder LocalBuilder;
2396                 public Type VariableType;
2397                 public readonly string Name;
2398                 public readonly Location Location;
2399                 public readonly int Block;
2400
2401                 public int Number;
2402                 
2403                 public bool Used;
2404                 public bool Assigned;
2405                 public bool ReadOnly;
2406                 
2407                 public VariableInfo (Expression type, string name, int block, Location l)
2408                 {
2409                         Type = type;
2410                         Name = name;
2411                         Block = block;
2412                         LocalBuilder = null;
2413                         Location = l;
2414                 }
2415
2416                 public VariableInfo (TypeContainer tc, int block, Location l)
2417                 {
2418                         VariableType = tc.TypeBuilder;
2419                         struct_info = MyStructInfo.GetStructInfo (tc);
2420                         Block = block;
2421                         LocalBuilder = null;
2422                         Location = l;
2423                 }
2424
2425                 MyStructInfo struct_info;
2426                 public MyStructInfo StructInfo {
2427                         get {
2428                                 return struct_info;
2429                         }
2430                 }
2431
2432                 public bool IsAssigned (EmitContext ec, Location loc)
2433                 {
2434                         if (!ec.DoFlowAnalysis || ec.CurrentBranching.IsVariableAssigned (this))
2435                                 return true;
2436
2437                         MyStructInfo struct_info = StructInfo;
2438                         if ((struct_info == null) || (struct_info.HasNonPublicFields && (Name != null))) {
2439                                 Report.Error (165, loc, "Use of unassigned local variable `" + Name + "'");
2440                                 ec.CurrentBranching.SetVariableAssigned (this);
2441                                 return false;
2442                         }
2443
2444                         int count = struct_info.Count;
2445
2446                         for (int i = 0; i < count; i++) {
2447                                 if (!ec.CurrentBranching.IsVariableAssigned (this, i+1)) {
2448                                         if (Name != null) {
2449                                                 Report.Error (165, loc,
2450                                                               "Use of unassigned local variable `" +
2451                                                               Name + "'");
2452                                                 ec.CurrentBranching.SetVariableAssigned (this);
2453                                                 return false;
2454                                         }
2455
2456                                         FieldInfo field = struct_info [i];
2457                                         Report.Error (171, loc,
2458                                                       "Field `" + TypeManager.CSharpName (VariableType) +
2459                                                       "." + field.Name + "' must be fully initialized " +
2460                                                       "before control leaves the constructor");
2461                                         return false;
2462                                 }
2463                         }
2464
2465                         return true;
2466                 }
2467
2468                 public bool IsFieldAssigned (EmitContext ec, string name, Location loc)
2469                 {
2470                         if (!ec.DoFlowAnalysis || ec.CurrentBranching.IsVariableAssigned (this) ||
2471                             (struct_info == null))
2472                                 return true;
2473
2474                         int field_idx = StructInfo [name];
2475                         if (field_idx == 0)
2476                                 return true;
2477
2478                         if (!ec.CurrentBranching.IsVariableAssigned (this, field_idx)) {
2479                                 Report.Error (170, loc,
2480                                               "Use of possibly unassigned field `" + name + "'");
2481                                 ec.CurrentBranching.SetVariableAssigned (this, field_idx);
2482                                 return false;
2483                         }
2484
2485                         return true;
2486                 }
2487
2488                 public void SetAssigned (EmitContext ec)
2489                 {
2490                         if (ec.DoFlowAnalysis)
2491                                 ec.CurrentBranching.SetVariableAssigned (this);
2492                 }
2493
2494                 public void SetFieldAssigned (EmitContext ec, string name)
2495                 {
2496                         if (ec.DoFlowAnalysis && (struct_info != null))
2497                                 ec.CurrentBranching.SetVariableAssigned (this, StructInfo [name]);
2498                 }
2499
2500                 public bool Resolve (DeclSpace decl)
2501                 {
2502                         if (struct_info != null)
2503                                 return true;
2504
2505                         if (VariableType == null)
2506                                 VariableType = decl.ResolveType (Type, false, Location);
2507
2508                         if (VariableType == null)
2509                                 return false;
2510
2511                         struct_info = MyStructInfo.GetStructInfo (VariableType);
2512
2513                         return true;
2514                 }
2515
2516                 public void MakePinned ()
2517                 {
2518                         TypeManager.MakePinned (LocalBuilder);
2519                 }
2520
2521                 public override string ToString ()
2522                 {
2523                         return "VariableInfo (" + Number + "," + Type + "," + Location + ")";
2524                 }
2525         }
2526                 
2527         /// <summary>
2528         ///   Block represents a C# block.
2529         /// </summary>
2530         ///
2531         /// <remarks>
2532         ///   This class is used in a number of places: either to represent
2533         ///   explicit blocks that the programmer places or implicit blocks.
2534         ///
2535         ///   Implicit blocks are used as labels or to introduce variable
2536         ///   declarations.
2537         /// </remarks>
2538         public class Block : Statement {
2539                 public readonly Block     Parent;
2540                 public readonly bool      Implicit;
2541                 public readonly Location  StartLocation;
2542                 public Location           EndLocation = Location.Null;
2543
2544                 //
2545                 // The statements in this block
2546                 //
2547                 ArrayList statements;
2548
2549                 //
2550                 // An array of Blocks.  We keep track of children just
2551                 // to generate the local variable declarations.
2552                 //
2553                 // Statements and child statements are handled through the
2554                 // statements.
2555                 //
2556                 ArrayList children;
2557                 
2558                 //
2559                 // Labels.  (label, block) pairs.
2560                 //
2561                 Hashtable labels;
2562
2563                 //
2564                 // Keeps track of (name, type) pairs
2565                 //
2566                 Hashtable variables;
2567
2568                 //
2569                 // Keeps track of constants
2570                 Hashtable constants;
2571
2572                 //
2573                 // Maps variable names to ILGenerator.LocalBuilders
2574                 //
2575                 Hashtable local_builders;
2576
2577                 bool used = false;
2578
2579                 static int id;
2580
2581                 int this_id;
2582                 
2583                 public Block (Block parent)
2584                         : this (parent, false, Location.Null, Location.Null)
2585                 { }
2586
2587                 public Block (Block parent, bool implicit_block)
2588                         : this (parent, implicit_block, Location.Null, Location.Null)
2589                 { }
2590
2591                 public Block (Block parent, bool implicit_block, Parameters parameters)
2592                         : this (parent, implicit_block, parameters, Location.Null, Location.Null)
2593                 { }
2594
2595                 public Block (Block parent, Location start, Location end)
2596                         : this (parent, false, start, end)
2597                 { }
2598
2599                 public Block (Block parent, Parameters parameters, Location start, Location end)
2600                         : this (parent, false, parameters, start, end)
2601                 { }
2602
2603                 public Block (Block parent, bool implicit_block, Location start, Location end)
2604                         : this (parent, implicit_block, Parameters.EmptyReadOnlyParameters,
2605                                 start, end)
2606                 { }
2607
2608                 public Block (Block parent, bool implicit_block, Parameters parameters,
2609                               Location start, Location end)
2610                 {
2611                         if (parent != null)
2612                                 parent.AddChild (this);
2613                         
2614                         this.Parent = parent;
2615                         this.Implicit = implicit_block;
2616                         this.parameters = parameters;
2617                         this.StartLocation = start;
2618                         this.EndLocation = end;
2619                         this.loc = start;
2620                         this_id = id++;
2621                         statements = new ArrayList ();
2622                 }
2623
2624                 public int ID {
2625                         get {
2626                                 return this_id;
2627                         }
2628                 }
2629
2630                 void AddChild (Block b)
2631                 {
2632                         if (children == null)
2633                                 children = new ArrayList ();
2634                         
2635                         children.Add (b);
2636                 }
2637
2638                 public void SetEndLocation (Location loc)
2639                 {
2640                         EndLocation = loc;
2641                 }
2642
2643                 /// <summary>
2644                 ///   Adds a label to the current block. 
2645                 /// </summary>
2646                 ///
2647                 /// <returns>
2648                 ///   false if the name already exists in this block. true
2649                 ///   otherwise.
2650                 /// </returns>
2651                 ///
2652                 public bool AddLabel (string name, LabeledStatement target)
2653                 {
2654                         if (labels == null)
2655                                 labels = new Hashtable ();
2656                         if (labels.Contains (name))
2657                                 return false;
2658                         
2659                         labels.Add (name, target);
2660                         return true;
2661                 }
2662
2663                 public LabeledStatement LookupLabel (string name)
2664                 {
2665                         if (labels != null){
2666                                 if (labels.Contains (name))
2667                                         return ((LabeledStatement) labels [name]);
2668                         }
2669
2670                         if (Parent != null)
2671                                 return Parent.LookupLabel (name);
2672
2673                         return null;
2674                 }
2675
2676                 VariableInfo this_variable = null;
2677
2678                 // <summary>
2679                 //   Returns the "this" instance variable of this block.
2680                 //   See AddThisVariable() for more information.
2681                 // </summary>
2682                 public VariableInfo ThisVariable {
2683                         get {
2684                                 if (this_variable != null)
2685                                         return this_variable;
2686                                 else if (Parent != null)
2687                                         return Parent.ThisVariable;
2688                                 else
2689                                         return null;
2690                         }
2691                 }
2692
2693                 Hashtable child_variable_names;
2694
2695                 // <summary>
2696                 //   Marks a variable with name @name as being used in a child block.
2697                 //   If a variable name has been used in a child block, it's illegal to
2698                 //   declare a variable with the same name in the current block.
2699                 // </summary>
2700                 public void AddChildVariableName (string name)
2701                 {
2702                         if (child_variable_names == null)
2703                                 child_variable_names = new Hashtable ();
2704
2705                         if (!child_variable_names.Contains (name))
2706                                 child_variable_names.Add (name, true);
2707                 }
2708
2709                 // <summary>
2710                 //   Marks all variables from block @block and all its children as being
2711                 //   used in a child block.
2712                 // </summary>
2713                 public void AddChildVariableNames (Block block)
2714                 {
2715                         if (block.Variables != null) {
2716                                 foreach (string name in block.Variables.Keys)
2717                                         AddChildVariableName (name);
2718                         }
2719
2720                         foreach (Block child in block.children) {
2721                                 if (child.Variables != null) {
2722                                         foreach (string name in child.Variables.Keys)
2723                                                 AddChildVariableName (name);
2724                                 }
2725                         }
2726                 }
2727
2728                 // <summary>
2729                 //   Checks whether a variable name has already been used in a child block.
2730                 // </summary>
2731                 public bool IsVariableNameUsedInChildBlock (string name)
2732                 {
2733                         if (child_variable_names == null)
2734                                 return false;
2735
2736                         return child_variable_names.Contains (name);
2737                 }
2738
2739                 // <summary>
2740                 //   This is used by non-static `struct' constructors which do not have an
2741                 //   initializer - in this case, the constructor must initialize all of the
2742                 //   struct's fields.  To do this, we add a "this" variable and use the flow
2743                 //   analysis code to ensure that it's been fully initialized before control
2744                 //   leaves the constructor.
2745                 // </summary>
2746                 public VariableInfo AddThisVariable (TypeContainer tc, Location l)
2747                 {
2748                         if (this_variable != null)
2749                                 return this_variable;
2750
2751                         this_variable = new VariableInfo (tc, ID, l);
2752
2753                         if (variables == null)
2754                                 variables = new Hashtable ();
2755                         variables.Add ("this", this_variable);
2756
2757                         return this_variable;
2758                 }
2759
2760                 public VariableInfo AddVariable (Expression type, string name, Parameters pars, Location l)
2761                 {
2762                         if (variables == null)
2763                                 variables = new Hashtable ();
2764
2765                         VariableInfo vi = GetVariableInfo (name);
2766                         if (vi != null) {
2767                                 if (vi.Block != ID)
2768                                         Report.Error (136, l, "A local variable named `" + name + "' " +
2769                                                       "cannot be declared in this scope since it would " +
2770                                                       "give a different meaning to `" + name + "', which " +
2771                                                       "is already used in a `parent or current' scope to " +
2772                                                       "denote something else");
2773                                 else
2774                                         Report.Error (128, l, "A local variable `" + name + "' is already " +
2775                                                       "defined in this scope");
2776                                 return null;
2777                         }
2778
2779                         if (IsVariableNameUsedInChildBlock (name)) {
2780                                 Report.Error (136, l, "A local variable named `" + name + "' " +
2781                                               "cannot be declared in this scope since it would " +
2782                                               "give a different meaning to `" + name + "', which " +
2783                                               "is already used in a `child' scope to denote something " +
2784                                               "else");
2785                                 return null;
2786                         }
2787
2788                         if (pars != null) {
2789                                 int idx = 0;
2790                                 Parameter p = pars.GetParameterByName (name, out idx);
2791                                 if (p != null) {
2792                                         Report.Error (136, l, "A local variable named `" + name + "' " +
2793                                                       "cannot be declared in this scope since it would " +
2794                                                       "give a different meaning to `" + name + "', which " +
2795                                                       "is already used in a `parent or current' scope to " +
2796                                                       "denote something else");
2797                                         return null;
2798                                 }
2799                         }
2800                         
2801                         vi = new VariableInfo (type, name, ID, l);
2802
2803                         variables.Add (name, vi);
2804
2805                         if (variables_initialized)
2806                                 throw new Exception ();
2807
2808                         // Console.WriteLine ("Adding {0} to {1}", name, ID);
2809                         return vi;
2810                 }
2811
2812                 public bool AddConstant (Expression type, string name, Expression value, Parameters pars, Location l)
2813                 {
2814                         if (AddVariable (type, name, pars, l) == null)
2815                                 return false;
2816                         
2817                         if (constants == null)
2818                                 constants = new Hashtable ();
2819
2820                         constants.Add (name, value);
2821                         return true;
2822                 }
2823
2824                 public Hashtable Variables {
2825                         get {
2826                                 return variables;
2827                         }
2828                 }
2829
2830                 public VariableInfo GetVariableInfo (string name)
2831                 {
2832                         if (variables != null) {
2833                                 object temp;
2834                                 temp = variables [name];
2835
2836                                 if (temp != null){
2837                                         return (VariableInfo) temp;
2838                                 }
2839                         }
2840
2841                         if (Parent != null)
2842                                 return Parent.GetVariableInfo (name);
2843
2844                         return null;
2845                 }
2846                 
2847                 public Expression GetVariableType (string name)
2848                 {
2849                         VariableInfo vi = GetVariableInfo (name);
2850
2851                         if (vi != null)
2852                                 return vi.Type;
2853
2854                         return null;
2855                 }
2856
2857                 public Expression GetConstantExpression (string name)
2858                 {
2859                         if (constants != null) {
2860                                 object temp;
2861                                 temp = constants [name];
2862                                 
2863                                 if (temp != null)
2864                                         return (Expression) temp;
2865                         }
2866                         
2867                         if (Parent != null)
2868                                 return Parent.GetConstantExpression (name);
2869
2870                         return null;
2871                 }
2872                 
2873                 /// <summary>
2874                 ///   True if the variable named @name is a constant
2875                 ///  </summary>
2876                 public bool IsConstant (string name)
2877                 {
2878                         Expression e = null;
2879                         
2880                         e = GetConstantExpression (name);
2881                         
2882                         return e != null;
2883                 }
2884                 
2885                 /// <summary>
2886                 ///   Use to fetch the statement associated with this label
2887                 /// </summary>
2888                 public Statement this [string name] {
2889                         get {
2890                                 return (Statement) labels [name];
2891                         }
2892                 }
2893
2894                 Parameters parameters = null;
2895                 public Parameters Parameters {
2896                         get {
2897                                 if (Parent != null)
2898                                         return Parent.Parameters;
2899
2900                                 return parameters;
2901                         }
2902                 }
2903
2904                 /// <returns>
2905                 ///   A list of labels that were not used within this block
2906                 /// </returns>
2907                 public string [] GetUnreferenced ()
2908                 {
2909                         // FIXME: Implement me
2910                         return null;
2911                 }
2912
2913                 public void AddStatement (Statement s)
2914                 {
2915                         statements.Add (s);
2916                         used = true;
2917                 }
2918
2919                 public bool Used {
2920                         get {
2921                                 return used;
2922                         }
2923                 }
2924
2925                 public void Use ()
2926                 {
2927                         used = true;
2928                 }
2929
2930                 bool variables_initialized = false;
2931                 int count_variables = 0, first_variable = 0;
2932
2933                 void UpdateVariableInfo (EmitContext ec)
2934                 {
2935                         DeclSpace ds = ec.DeclSpace;
2936
2937                         first_variable = 0;
2938
2939                         if (Parent != null)
2940                                 first_variable += Parent.CountVariables;
2941
2942                         count_variables = first_variable;
2943                         if (variables != null) {
2944                                 foreach (VariableInfo vi in variables.Values) {
2945                                         if (!vi.Resolve (ds)) {
2946                                                 vi.Number = -1;
2947                                                 continue;
2948                                         }
2949
2950                                         vi.Number = ++count_variables;
2951
2952                                         if (vi.StructInfo != null)
2953                                                 count_variables += vi.StructInfo.Count;
2954                                 }
2955                         }
2956
2957                         variables_initialized = true;
2958                 }
2959
2960                 //
2961                 // <returns>
2962                 //   The number of local variables in this block
2963                 // </returns>
2964                 public int CountVariables
2965                 {
2966                         get {
2967                                 if (!variables_initialized)
2968                                         throw new Exception ();
2969
2970                                 return count_variables;
2971                         }
2972                 }
2973
2974                 /// <summary>
2975                 ///   Emits the variable declarations and labels.
2976                 /// </summary>
2977                 /// <remarks>
2978                 ///   tc: is our typecontainer (to resolve type references)
2979                 ///   ig: is the code generator:
2980                 ///   toplevel: the toplevel block.  This is used for checking 
2981                 ///             that no two labels with the same name are used.
2982                 /// </remarks>
2983                 public void EmitMeta (EmitContext ec, Block toplevel)
2984                 {
2985                         DeclSpace ds = ec.DeclSpace;
2986                         ILGenerator ig = ec.ig;
2987
2988                         if (!variables_initialized)
2989                                 UpdateVariableInfo (ec);
2990
2991                         //
2992                         // Process this block variables
2993                         //
2994                         if (variables != null){
2995                                 local_builders = new Hashtable ();
2996                                 
2997                                 foreach (DictionaryEntry de in variables){
2998                                         string name = (string) de.Key;
2999                                         VariableInfo vi = (VariableInfo) de.Value;
3000
3001                                         if (vi.VariableType == null)
3002                                                 continue;
3003
3004                                         vi.LocalBuilder = ig.DeclareLocal (vi.VariableType);
3005
3006                                         if (CodeGen.SymbolWriter != null)
3007                                                 vi.LocalBuilder.SetLocalSymInfo (name);
3008
3009                                         if (constants == null)
3010                                                 continue;
3011
3012                                         Expression cv = (Expression) constants [name];
3013                                         if (cv == null)
3014                                                 continue;
3015
3016                                         Expression e = cv.Resolve (ec);
3017                                         if (e == null)
3018                                                 continue;
3019
3020                                         if (!(e is Constant)){
3021                                                 Report.Error (133, vi.Location,
3022                                                               "The expression being assigned to `" +
3023                                                               name + "' must be constant (" + e + ")");
3024                                                 continue;
3025                                         }
3026
3027                                         constants.Remove (name);
3028                                         constants.Add (name, e);
3029                                 }
3030                         }
3031
3032                         //
3033                         // Now, handle the children
3034                         //
3035                         if (children != null){
3036                                 foreach (Block b in children)
3037                                         b.EmitMeta (ec, toplevel);
3038                         }
3039                 }
3040
3041                 public void UsageWarning ()
3042                 {
3043                         string name;
3044                         
3045                         if (variables != null){
3046                                 foreach (DictionaryEntry de in variables){
3047                                         VariableInfo vi = (VariableInfo) de.Value;
3048                                         
3049                                         if (vi.Used)
3050                                                 continue;
3051                                         
3052                                         name = (string) de.Key;
3053                                                 
3054                                         if (vi.Assigned){
3055                                                 Report.Warning (
3056                                                         219, vi.Location, "The variable `" + name +
3057                                                         "' is assigned but its value is never used");
3058                                         } else {
3059                                                 Report.Warning (
3060                                                         168, vi.Location, "The variable `" +
3061                                                         name +
3062                                                         "' is declared but never used");
3063                                         } 
3064                                 }
3065                         }
3066
3067                         if (children != null)
3068                                 foreach (Block b in children)
3069                                         b.UsageWarning ();
3070                 }
3071
3072                 bool has_ret = false;
3073
3074                 public override bool Resolve (EmitContext ec)
3075                 {
3076                         Block prev_block = ec.CurrentBlock;
3077                         bool ok = true;
3078
3079                         ec.CurrentBlock = this;
3080                         ec.StartFlowBranching (this);
3081
3082                         Report.Debug (1, "RESOLVE BLOCK", StartLocation, ec.CurrentBranching);
3083
3084                         if (!variables_initialized)
3085                                 UpdateVariableInfo (ec);
3086
3087                         ArrayList new_statements = new ArrayList ();
3088                         bool unreachable = false, warning_shown = false;
3089
3090                         foreach (Statement s in statements){
3091                                 if (unreachable && !(s is LabeledStatement)) {
3092                                         if (!warning_shown && !(s is EmptyStatement)) {
3093                                                 warning_shown = true;
3094                                                 Warning_DeadCodeFound (s.loc);
3095                                         }
3096
3097                                         continue;
3098                                 }
3099
3100                                 if (s.Resolve (ec) == false) {
3101                                         ok = false;
3102                                         continue;
3103                                 }
3104
3105                                 if (s is LabeledStatement)
3106                                         unreachable = false;
3107                                 else
3108                                         unreachable = ! ec.CurrentBranching.IsReachable ();
3109
3110                                 new_statements.Add (s);
3111                         }
3112
3113                         statements = new_statements;
3114
3115                         Report.Debug (1, "RESOLVE BLOCK DONE", StartLocation, ec.CurrentBranching);
3116
3117                         FlowReturns returns = ec.EndFlowBranching ();
3118                         ec.CurrentBlock = prev_block;
3119
3120                         // If we're a non-static `struct' constructor which doesn't have an
3121                         // initializer, then we must initialize all of the struct's fields.
3122                         if ((this_variable != null) && (returns != FlowReturns.EXCEPTION) &&
3123                             !this_variable.IsAssigned (ec, loc))
3124                                 ok = false;
3125
3126                         if ((labels != null) && (RootContext.WarningLevel >= 2)) {
3127                                 foreach (LabeledStatement label in labels.Values)
3128                                         if (!label.HasBeenReferenced)
3129                                                 Report.Warning (164, label.Location,
3130                                                                 "This label has not been referenced");
3131                         }
3132
3133                         if ((returns == FlowReturns.ALWAYS) ||
3134                             (returns == FlowReturns.EXCEPTION) ||
3135                             (returns == FlowReturns.UNREACHABLE))
3136                                 has_ret = true;
3137
3138                         return ok;
3139                 }
3140                 
3141                 protected override bool DoEmit (EmitContext ec)
3142                 {
3143                         Block prev_block = ec.CurrentBlock;
3144
3145                         ec.CurrentBlock = this;
3146
3147                         ec.Mark (StartLocation);
3148                         foreach (Statement s in statements)
3149                                 s.Emit (ec);
3150                         ec.Mark (EndLocation); 
3151                         
3152                         ec.CurrentBlock = prev_block;
3153                         return has_ret;
3154                 }
3155         }
3156
3157         public class SwitchLabel {
3158                 Expression label;
3159                 object converted;
3160                 public Location loc;
3161                 public Label ILLabel;
3162                 public Label ILLabelCode;
3163
3164                 //
3165                 // if expr == null, then it is the default case.
3166                 //
3167                 public SwitchLabel (Expression expr, Location l)
3168                 {
3169                         label = expr;
3170                         loc = l;
3171                 }
3172
3173                 public Expression Label {
3174                         get {
3175                                 return label;
3176                         }
3177                 }
3178
3179                 public object Converted {
3180                         get {
3181                                 return converted;
3182                         }
3183                 }
3184
3185                 //
3186                 // Resolves the expression, reduces it to a literal if possible
3187                 // and then converts it to the requested type.
3188                 //
3189                 public bool ResolveAndReduce (EmitContext ec, Type required_type)
3190                 {
3191                         ILLabel = ec.ig.DefineLabel ();
3192                         ILLabelCode = ec.ig.DefineLabel ();
3193
3194                         if (label == null)
3195                                 return true;
3196                         
3197                         Expression e = label.Resolve (ec);
3198
3199                         if (e == null)
3200                                 return false;
3201
3202                         if (!(e is Constant)){
3203                                 Report.Error (150, loc, "A constant value is expected, got: " + e);
3204                                 return false;
3205                         }
3206
3207                         if (e is StringConstant || e is NullLiteral){
3208                                 if (required_type == TypeManager.string_type){
3209                                         converted = e;
3210                                         ILLabel = ec.ig.DefineLabel ();
3211                                         return true;
3212                                 }
3213                         }
3214
3215                         converted = Expression.ConvertIntLiteral ((Constant) e, required_type, loc);
3216                         if (converted == null)
3217                                 return false;
3218
3219                         return true;
3220                 }
3221         }
3222
3223         public class SwitchSection {
3224                 // An array of SwitchLabels.
3225                 public readonly ArrayList Labels;
3226                 public readonly Block Block;
3227                 
3228                 public SwitchSection (ArrayList labels, Block block)
3229                 {
3230                         Labels = labels;
3231                         Block = block;
3232                 }
3233         }
3234         
3235         public class Switch : Statement {
3236                 public readonly ArrayList Sections;
3237                 public Expression Expr;
3238
3239                 /// <summary>
3240                 ///   Maps constants whose type type SwitchType to their  SwitchLabels.
3241                 /// </summary>
3242                 public Hashtable Elements;
3243
3244                 /// <summary>
3245                 ///   The governing switch type
3246                 /// </summary>
3247                 public Type SwitchType;
3248
3249                 //
3250                 // Computed
3251                 //
3252                 bool got_default;
3253                 Label default_target;
3254                 Expression new_expr;
3255
3256                 //
3257                 // The types allowed to be implicitly cast from
3258                 // on the governing type
3259                 //
3260                 static Type [] allowed_types;
3261                 
3262                 public Switch (Expression e, ArrayList sects, Location l)
3263                 {
3264                         Expr = e;
3265                         Sections = sects;
3266                         loc = l;
3267                 }
3268
3269                 public bool GotDefault {
3270                         get {
3271                                 return got_default;
3272                         }
3273                 }
3274
3275                 public Label DefaultTarget {
3276                         get {
3277                                 return default_target;
3278                         }
3279                 }
3280
3281                 //
3282                 // Determines the governing type for a switch.  The returned
3283                 // expression might be the expression from the switch, or an
3284                 // expression that includes any potential conversions to the
3285                 // integral types or to string.
3286                 //
3287                 Expression SwitchGoverningType (EmitContext ec, Type t)
3288                 {
3289                         if (t == TypeManager.int32_type ||
3290                             t == TypeManager.uint32_type ||
3291                             t == TypeManager.char_type ||
3292                             t == TypeManager.byte_type ||
3293                             t == TypeManager.sbyte_type ||
3294                             t == TypeManager.ushort_type ||
3295                             t == TypeManager.short_type ||
3296                             t == TypeManager.uint64_type ||
3297                             t == TypeManager.int64_type ||
3298                             t == TypeManager.string_type ||
3299                                 t == TypeManager.bool_type ||
3300                                 t.IsSubclassOf (TypeManager.enum_type))
3301                                 return Expr;
3302
3303                         if (allowed_types == null){
3304                                 allowed_types = new Type [] {
3305                                         TypeManager.sbyte_type,
3306                                         TypeManager.byte_type,
3307                                         TypeManager.short_type,
3308                                         TypeManager.ushort_type,
3309                                         TypeManager.int32_type,
3310                                         TypeManager.uint32_type,
3311                                         TypeManager.int64_type,
3312                                         TypeManager.uint64_type,
3313                                         TypeManager.char_type,
3314                                         TypeManager.bool_type,
3315                                         TypeManager.string_type
3316                                 };
3317                         }
3318
3319                         //
3320                         // Try to find a *user* defined implicit conversion.
3321                         //
3322                         // If there is no implicit conversion, or if there are multiple
3323                         // conversions, we have to report an error
3324                         //
3325                         Expression converted = null;
3326                         foreach (Type tt in allowed_types){
3327                                 Expression e;
3328                                 
3329                                 e = Expression.ImplicitUserConversion (ec, Expr, tt, loc);
3330                                 if (e == null)
3331                                         continue;
3332
3333                                 if (converted != null){
3334                                         Report.Error (-12, loc, "More than one conversion to an integral " +
3335                                                       " type exists for type `" +
3336                                                       TypeManager.CSharpName (Expr.Type)+"'");
3337                                         return null;
3338                                 } else
3339                                         converted = e;
3340                         }
3341                         return converted;
3342                 }
3343
3344                 void error152 (string n)
3345                 {
3346                         Report.Error (
3347                                 152, "The label `" + n + ":' " +
3348                                 "is already present on this switch statement");
3349                 }
3350                 
3351                 //
3352                 // Performs the basic sanity checks on the switch statement
3353                 // (looks for duplicate keys and non-constant expressions).
3354                 //
3355                 // It also returns a hashtable with the keys that we will later
3356                 // use to compute the switch tables
3357                 //
3358                 bool CheckSwitch (EmitContext ec)
3359                 {
3360                         Type compare_type;
3361                         bool error = false;
3362                         Elements = new Hashtable ();
3363                                 
3364                         got_default = false;
3365
3366                         if (TypeManager.IsEnumType (SwitchType)){
3367                                 compare_type = TypeManager.EnumToUnderlying (SwitchType);
3368                         } else
3369                                 compare_type = SwitchType;
3370                         
3371                         foreach (SwitchSection ss in Sections){
3372                                 foreach (SwitchLabel sl in ss.Labels){
3373                                         if (!sl.ResolveAndReduce (ec, SwitchType)){
3374                                                 error = true;
3375                                                 continue;
3376                                         }
3377
3378                                         if (sl.Label == null){
3379                                                 if (got_default){
3380                                                         error152 ("default");
3381                                                         error = true;
3382                                                 }
3383                                                 got_default = true;
3384                                                 continue;
3385                                         }
3386                                         
3387                                         object key = sl.Converted;
3388
3389                                         if (key is Constant)
3390                                                 key = ((Constant) key).GetValue ();
3391
3392                                         if (key == null)
3393                                                 key = NullLiteral.Null;
3394                                         
3395                                         string lname = null;
3396                                         if (compare_type == TypeManager.uint64_type){
3397                                                 ulong v = (ulong) key;
3398
3399                                                 if (Elements.Contains (v))
3400                                                         lname = v.ToString ();
3401                                                 else
3402                                                         Elements.Add (v, sl);
3403                                         } else if (compare_type == TypeManager.int64_type){
3404                                                 long v = (long) key;
3405
3406                                                 if (Elements.Contains (v))
3407                                                         lname = v.ToString ();
3408                                                 else
3409                                                         Elements.Add (v, sl);
3410                                         } else if (compare_type == TypeManager.uint32_type){
3411                                                 uint v = (uint) key;
3412
3413                                                 if (Elements.Contains (v))
3414                                                         lname = v.ToString ();
3415                                                 else
3416                                                         Elements.Add (v, sl);
3417                                         } else if (compare_type == TypeManager.char_type){
3418                                                 char v = (char) key;
3419                                                 
3420                                                 if (Elements.Contains (v))
3421                                                         lname = v.ToString ();
3422                                                 else
3423                                                         Elements.Add (v, sl);
3424                                         } else if (compare_type == TypeManager.byte_type){
3425                                                 byte v = (byte) key;
3426                                                 
3427                                                 if (Elements.Contains (v))
3428                                                         lname = v.ToString ();
3429                                                 else
3430                                                         Elements.Add (v, sl);
3431                                         } else if (compare_type == TypeManager.sbyte_type){
3432                                                 sbyte v = (sbyte) key;
3433                                                 
3434                                                 if (Elements.Contains (v))
3435                                                         lname = v.ToString ();
3436                                                 else
3437                                                         Elements.Add (v, sl);
3438                                         } else if (compare_type == TypeManager.short_type){
3439                                                 short v = (short) key;
3440                                                 
3441                                                 if (Elements.Contains (v))
3442                                                         lname = v.ToString ();
3443                                                 else
3444                                                         Elements.Add (v, sl);
3445                                         } else if (compare_type == TypeManager.ushort_type){
3446                                                 ushort v = (ushort) key;
3447                                                 
3448                                                 if (Elements.Contains (v))
3449                                                         lname = v.ToString ();
3450                                                 else
3451                                                         Elements.Add (v, sl);
3452                                         } else if (compare_type == TypeManager.string_type){
3453                                                 if (key is NullLiteral){
3454                                                         if (Elements.Contains (NullLiteral.Null))
3455                                                                 lname = "null";
3456                                                         else
3457                                                                 Elements.Add (NullLiteral.Null, null);
3458                                                 } else {
3459                                                         string s = (string) key;
3460
3461                                                         if (Elements.Contains (s))
3462                                                                 lname = s;
3463                                                         else
3464                                                                 Elements.Add (s, sl);
3465                                                 }
3466                                         } else if (compare_type == TypeManager.int32_type) {
3467                                                 int v = (int) key;
3468
3469                                                 if (Elements.Contains (v))
3470                                                         lname = v.ToString ();
3471                                                 else
3472                                                         Elements.Add (v, sl);
3473                                         } else if (compare_type == TypeManager.bool_type) {
3474                                                 bool v = (bool) key;
3475
3476                                                 if (Elements.Contains (v))
3477                                                         lname = v.ToString ();
3478                                                 else
3479                                                         Elements.Add (v, sl);
3480                                         }
3481                                         else
3482                                         {
3483                                                 throw new Exception ("Unknown switch type!" +
3484                                                                      SwitchType + " " + compare_type);
3485                                         }
3486
3487                                         if (lname != null){
3488                                                 error152 ("case + " + lname);
3489                                                 error = true;
3490                                         }
3491                                 }
3492                         }
3493                         if (error)
3494                                 return false;
3495                         
3496                         return true;
3497                 }
3498
3499                 void EmitObjectInteger (ILGenerator ig, object k)
3500                 {
3501                         if (k is int)
3502                                 IntConstant.EmitInt (ig, (int) k);
3503                         else if (k is Constant) {
3504                                 EmitObjectInteger (ig, ((Constant) k).GetValue ());
3505                         } 
3506                         else if (k is uint)
3507                                 IntConstant.EmitInt (ig, unchecked ((int) (uint) k));
3508                         else if (k is long)
3509                         {
3510                                 if ((long) k >= int.MinValue && (long) k <= int.MaxValue)
3511                                 {
3512                                         IntConstant.EmitInt (ig, (int) (long) k);
3513                                         ig.Emit (OpCodes.Conv_I8);
3514                                 }
3515                                 else
3516                                         LongConstant.EmitLong (ig, (long) k);
3517                         }
3518                         else if (k is ulong)
3519                         {
3520                                 if ((ulong) k < (1L<<32))
3521                                 {
3522                                         IntConstant.EmitInt (ig, (int) (long) k);
3523                                         ig.Emit (OpCodes.Conv_U8);
3524                                 }
3525                                 else
3526                                 {
3527                                         LongConstant.EmitLong (ig, unchecked ((long) (ulong) k));
3528                                 }
3529                         }
3530                         else if (k is char)
3531                                 IntConstant.EmitInt (ig, (int) ((char) k));
3532                         else if (k is sbyte)
3533                                 IntConstant.EmitInt (ig, (int) ((sbyte) k));
3534                         else if (k is byte)
3535                                 IntConstant.EmitInt (ig, (int) ((byte) k));
3536                         else if (k is short)
3537                                 IntConstant.EmitInt (ig, (int) ((short) k));
3538                         else if (k is ushort)
3539                                 IntConstant.EmitInt (ig, (int) ((ushort) k));
3540                         else if (k is bool)
3541                                 IntConstant.EmitInt (ig, ((bool) k) ? 1 : 0);
3542                         else
3543                                 throw new Exception ("Unhandled case");
3544                 }
3545                 
3546                 // structure used to hold blocks of keys while calculating table switch
3547                 class KeyBlock : IComparable
3548                 {
3549                         public KeyBlock (long _nFirst)
3550                         {
3551                                 nFirst = nLast = _nFirst;
3552                         }
3553                         public long nFirst;
3554                         public long nLast;
3555                         public ArrayList rgKeys = null;
3556                         public int Length
3557                         {
3558                                 get { return (int) (nLast - nFirst + 1); }
3559                         }
3560                         public static long TotalLength (KeyBlock kbFirst, KeyBlock kbLast)
3561                         {
3562                                 return kbLast.nLast - kbFirst.nFirst + 1;
3563                         }
3564                         public int CompareTo (object obj)
3565                         {
3566                                 KeyBlock kb = (KeyBlock) obj;
3567                                 int nLength = Length;
3568                                 int nLengthOther = kb.Length;
3569                                 if (nLengthOther == nLength)
3570                                         return (int) (kb.nFirst - nFirst);
3571                                 return nLength - nLengthOther;
3572                         }
3573                 }
3574
3575                 /// <summary>
3576                 /// This method emits code for a lookup-based switch statement (non-string)
3577                 /// Basically it groups the cases into blocks that are at least half full,
3578                 /// and then spits out individual lookup opcodes for each block.
3579                 /// It emits the longest blocks first, and short blocks are just
3580                 /// handled with direct compares.
3581                 /// </summary>
3582                 /// <param name="ec"></param>
3583                 /// <param name="val"></param>
3584                 /// <returns></returns>
3585                 bool TableSwitchEmit (EmitContext ec, LocalBuilder val)
3586                 {
3587                         int cElements = Elements.Count;
3588                         object [] rgKeys = new object [cElements];
3589                         Elements.Keys.CopyTo (rgKeys, 0);
3590                         Array.Sort (rgKeys);
3591
3592                         // initialize the block list with one element per key
3593                         ArrayList rgKeyBlocks = new ArrayList ();
3594                         foreach (object key in rgKeys)
3595                                 rgKeyBlocks.Add (new KeyBlock (Convert.ToInt64 (key)));
3596
3597                         KeyBlock kbCurr;
3598                         // iteratively merge the blocks while they are at least half full
3599                         // there's probably a really cool way to do this with a tree...
3600                         while (rgKeyBlocks.Count > 1)
3601                         {
3602                                 ArrayList rgKeyBlocksNew = new ArrayList ();
3603                                 kbCurr = (KeyBlock) rgKeyBlocks [0];
3604                                 for (int ikb = 1; ikb < rgKeyBlocks.Count; ikb++)
3605                                 {
3606                                         KeyBlock kb = (KeyBlock) rgKeyBlocks [ikb];
3607                                         if ((kbCurr.Length + kb.Length) * 2 >=  KeyBlock.TotalLength (kbCurr, kb))
3608                                         {
3609                                                 // merge blocks
3610                                                 kbCurr.nLast = kb.nLast;
3611                                         }
3612                                         else
3613                                         {
3614                                                 // start a new block
3615                                                 rgKeyBlocksNew.Add (kbCurr);
3616                                                 kbCurr = kb;
3617                                         }
3618                                 }
3619                                 rgKeyBlocksNew.Add (kbCurr);
3620                                 if (rgKeyBlocks.Count == rgKeyBlocksNew.Count)
3621                                         break;
3622                                 rgKeyBlocks = rgKeyBlocksNew;
3623                         }
3624
3625                         // initialize the key lists
3626                         foreach (KeyBlock kb in rgKeyBlocks)
3627                                 kb.rgKeys = new ArrayList ();
3628
3629                         // fill the key lists
3630                         int iBlockCurr = 0;
3631                         if (rgKeyBlocks.Count > 0) {
3632                                 kbCurr = (KeyBlock) rgKeyBlocks [0];
3633                                 foreach (object key in rgKeys)
3634                                 {
3635                                         bool fNextBlock = (key is UInt64) ? (ulong) key > (ulong) kbCurr.nLast : Convert.ToInt64 (key) > kbCurr.nLast;
3636                                         if (fNextBlock)
3637                                                 kbCurr = (KeyBlock) rgKeyBlocks [++iBlockCurr];
3638                                         kbCurr.rgKeys.Add (key);
3639                                 }
3640                         }
3641
3642                         // sort the blocks so we can tackle the largest ones first
3643                         rgKeyBlocks.Sort ();
3644
3645                         // okay now we can start...
3646                         ILGenerator ig = ec.ig;
3647                         Label lblEnd = ig.DefineLabel ();       // at the end ;-)
3648                         Label lblDefault = ig.DefineLabel ();
3649
3650                         Type typeKeys = null;
3651                         if (rgKeys.Length > 0)
3652                                 typeKeys = rgKeys [0].GetType ();       // used for conversions
3653
3654                         for (int iBlock = rgKeyBlocks.Count - 1; iBlock >= 0; --iBlock)
3655                         {
3656                                 KeyBlock kb = ((KeyBlock) rgKeyBlocks [iBlock]);
3657                                 lblDefault = (iBlock == 0) ? DefaultTarget : ig.DefineLabel ();
3658                                 if (kb.Length <= 2)
3659                                 {
3660                                         foreach (object key in kb.rgKeys)
3661                                         {
3662                                                 ig.Emit (OpCodes.Ldloc, val);
3663                                                 EmitObjectInteger (ig, key);
3664                                                 SwitchLabel sl = (SwitchLabel) Elements [key];
3665                                                 ig.Emit (OpCodes.Beq, sl.ILLabel);
3666                                         }
3667                                 }
3668                                 else
3669                                 {
3670                                         // TODO: if all the keys in the block are the same and there are
3671                                         //       no gaps/defaults then just use a range-check.
3672                                         if (SwitchType == TypeManager.int64_type ||
3673                                                 SwitchType == TypeManager.uint64_type)
3674                                         {
3675                                                 // TODO: optimize constant/I4 cases
3676
3677                                                 // check block range (could be > 2^31)
3678                                                 ig.Emit (OpCodes.Ldloc, val);
3679                                                 EmitObjectInteger (ig, Convert.ChangeType (kb.nFirst, typeKeys));
3680                                                 ig.Emit (OpCodes.Blt, lblDefault);
3681                                                 ig.Emit (OpCodes.Ldloc, val);
3682                                                 EmitObjectInteger (ig, Convert.ChangeType (kb.nFirst, typeKeys));
3683                                                 ig.Emit (OpCodes.Bgt, lblDefault);
3684
3685                                                 // normalize range
3686                                                 ig.Emit (OpCodes.Ldloc, val);
3687                                                 if (kb.nFirst != 0)
3688                                                 {
3689                                                         EmitObjectInteger (ig, Convert.ChangeType (kb.nFirst, typeKeys));
3690                                                         ig.Emit (OpCodes.Sub);
3691                                                 }
3692                                                 ig.Emit (OpCodes.Conv_I4);      // assumes < 2^31 labels!
3693                                         }
3694                                         else
3695                                         {
3696                                                 // normalize range
3697                                                 ig.Emit (OpCodes.Ldloc, val);
3698                                                 int nFirst = (int) kb.nFirst;
3699                                                 if (nFirst > 0)
3700                                                 {
3701                                                         IntConstant.EmitInt (ig, nFirst);
3702                                                         ig.Emit (OpCodes.Sub);
3703                                                 }
3704                                                 else if (nFirst < 0)
3705                                                 {
3706                                                         IntConstant.EmitInt (ig, -nFirst);
3707                                                         ig.Emit (OpCodes.Add);
3708                                                 }
3709                                         }
3710
3711                                         // first, build the list of labels for the switch
3712                                         int iKey = 0;
3713                                         int cJumps = kb.Length;
3714                                         Label [] rgLabels = new Label [cJumps];
3715                                         for (int iJump = 0; iJump < cJumps; iJump++)
3716                                         {
3717                                                 object key = kb.rgKeys [iKey];
3718                                                 if (Convert.ToInt64 (key) == kb.nFirst + iJump)
3719                                                 {
3720                                                         SwitchLabel sl = (SwitchLabel) Elements [key];
3721                                                         rgLabels [iJump] = sl.ILLabel;
3722                                                         iKey++;
3723                                                 }
3724                                                 else
3725                                                         rgLabels [iJump] = lblDefault;
3726                                         }
3727                                         // emit the switch opcode
3728                                         ig.Emit (OpCodes.Switch, rgLabels);
3729                                 }
3730
3731                                 // mark the default for this block
3732                                 if (iBlock != 0)
3733                                         ig.MarkLabel (lblDefault);
3734                         }
3735
3736                         // TODO: find the default case and emit it here,
3737                         //       to prevent having to do the following jump.
3738                         //       make sure to mark other labels in the default section
3739
3740                         // the last default just goes to the end
3741                         ig.Emit (OpCodes.Br, lblDefault);
3742
3743                         // now emit the code for the sections
3744                         bool fFoundDefault = false;
3745                         bool fAllReturn = true;
3746                         foreach (SwitchSection ss in Sections)
3747                         {
3748                                 foreach (SwitchLabel sl in ss.Labels)
3749                                 {
3750                                         ig.MarkLabel (sl.ILLabel);
3751                                         ig.MarkLabel (sl.ILLabelCode);
3752                                         if (sl.Label == null)
3753                                         {
3754                                                 ig.MarkLabel (lblDefault);
3755                                                 fFoundDefault = true;
3756                                         }
3757                                 }
3758                                 bool returns = ss.Block.Emit (ec);
3759                                 fAllReturn &= returns;
3760                                 //ig.Emit (OpCodes.Br, lblEnd);
3761                         }
3762                         
3763                         if (!fFoundDefault) {
3764                                 ig.MarkLabel (lblDefault);
3765                                 fAllReturn = false;
3766                         }
3767                         ig.MarkLabel (lblEnd);
3768
3769                         return fAllReturn;
3770                 }
3771                 //
3772                 // This simple emit switch works, but does not take advantage of the
3773                 // `switch' opcode. 
3774                 // TODO: remove non-string logic from here
3775                 // TODO: binary search strings?
3776                 //
3777                 bool SimpleSwitchEmit (EmitContext ec, LocalBuilder val)
3778                 {
3779                         ILGenerator ig = ec.ig;
3780                         Label end_of_switch = ig.DefineLabel ();
3781                         Label next_test = ig.DefineLabel ();
3782                         Label null_target = ig.DefineLabel ();
3783                         bool default_found = false;
3784                         bool first_test = true;
3785                         bool pending_goto_end = false;
3786                         bool all_return = true;
3787                         bool is_string = false;
3788                         bool null_found;
3789                         
3790                         //
3791                         // Special processing for strings: we cant compare
3792                         // against null.
3793                         //
3794                         if (SwitchType == TypeManager.string_type){
3795                                 ig.Emit (OpCodes.Ldloc, val);
3796                                 is_string = true;
3797                                 
3798                                 if (Elements.Contains (NullLiteral.Null)){
3799                                         ig.Emit (OpCodes.Brfalse, null_target);
3800                                 } else
3801                                         ig.Emit (OpCodes.Brfalse, default_target);
3802
3803                                 ig.Emit (OpCodes.Ldloc, val);
3804                                 ig.Emit (OpCodes.Call, TypeManager.string_isinterneted_string);
3805                                 ig.Emit (OpCodes.Stloc, val);
3806                         }
3807                         
3808                         foreach (SwitchSection ss in Sections){
3809                                 Label sec_begin = ig.DefineLabel ();
3810
3811                                 if (pending_goto_end)
3812                                         ig.Emit (OpCodes.Br, end_of_switch);
3813
3814                                 int label_count = ss.Labels.Count;
3815                                 null_found = false;
3816                                 foreach (SwitchLabel sl in ss.Labels){
3817                                         ig.MarkLabel (sl.ILLabel);
3818                                         
3819                                         if (!first_test){
3820                                                 ig.MarkLabel (next_test);
3821                                                 next_test = ig.DefineLabel ();
3822                                         }
3823                                         //
3824                                         // If we are the default target
3825                                         //
3826                                         if (sl.Label == null){
3827                                                 ig.MarkLabel (default_target);
3828                                                 default_found = true;
3829                                         } else {
3830                                                 object lit = sl.Converted;
3831
3832                                                 if (lit is NullLiteral){
3833                                                         null_found = true;
3834                                                         if (label_count == 1)
3835                                                                 ig.Emit (OpCodes.Br, next_test);
3836                                                         continue;
3837                                                                               
3838                                                 }
3839                                                 if (is_string){
3840                                                         StringConstant str = (StringConstant) lit;
3841
3842                                                         ig.Emit (OpCodes.Ldloc, val);
3843                                                         ig.Emit (OpCodes.Ldstr, str.Value);
3844                                                         if (label_count == 1)
3845                                                                 ig.Emit (OpCodes.Bne_Un, next_test);
3846                                                         else
3847                                                                 ig.Emit (OpCodes.Beq, sec_begin);
3848                                                 } else {
3849                                                         ig.Emit (OpCodes.Ldloc, val);
3850                                                         EmitObjectInteger (ig, lit);
3851                                                         ig.Emit (OpCodes.Ceq);
3852                                                         if (label_count == 1)
3853                                                                 ig.Emit (OpCodes.Brfalse, next_test);
3854                                                         else
3855                                                                 ig.Emit (OpCodes.Brtrue, sec_begin);
3856                                                 }
3857                                         }
3858                                 }
3859                                 if (label_count != 1)
3860                                         ig.Emit (OpCodes.Br, next_test);
3861                                 
3862                                 if (null_found)
3863                                         ig.MarkLabel (null_target);
3864                                 ig.MarkLabel (sec_begin);
3865                                 foreach (SwitchLabel sl in ss.Labels)
3866                                         ig.MarkLabel (sl.ILLabelCode);
3867
3868                                 bool returns = ss.Block.Emit (ec);
3869                                 if (returns)
3870                                         pending_goto_end = false;
3871                                 else {
3872                                         all_return = false;
3873                                         pending_goto_end = true;
3874                                 }
3875                                 first_test = false;
3876                         }
3877                         if (!default_found){
3878                                 ig.MarkLabel (default_target);
3879                                 all_return = false;
3880                         }
3881                         ig.MarkLabel (next_test);
3882                         ig.MarkLabel (end_of_switch);
3883                         
3884                         return all_return;
3885                 }
3886
3887                 public override bool Resolve (EmitContext ec)
3888                 {
3889                         Expr = Expr.Resolve (ec);
3890                         if (Expr == null)
3891                                 return false;
3892
3893                         new_expr = SwitchGoverningType (ec, Expr.Type);
3894                         if (new_expr == null){
3895                                 Report.Error (151, loc, "An integer type or string was expected for switch");
3896                                 return false;
3897                         }
3898
3899                         // Validate switch.
3900                         SwitchType = new_expr.Type;
3901
3902                         if (!CheckSwitch (ec))
3903                                 return false;
3904
3905                         Switch old_switch = ec.Switch;
3906                         ec.Switch = this;
3907                         ec.Switch.SwitchType = SwitchType;
3908
3909                         ec.StartFlowBranching (FlowBranchingType.SWITCH, loc);
3910
3911                         bool first = true;
3912                         foreach (SwitchSection ss in Sections){
3913                                 if (!first)
3914                                         ec.CurrentBranching.CreateSibling ();
3915                                 else
3916                                         first = false;
3917
3918                                 if (ss.Block.Resolve (ec) != true)
3919                                         return false;
3920                         }
3921
3922
3923                         if (!got_default)
3924                                 ec.CurrentBranching.CreateSibling ();
3925
3926                         ec.EndFlowBranching ();
3927                         ec.Switch = old_switch;
3928
3929                         return true;
3930                 }
3931                 
3932                 protected override bool DoEmit (EmitContext ec)
3933                 {
3934                         // Store variable for comparission purposes
3935                         LocalBuilder value = ec.ig.DeclareLocal (SwitchType);
3936                         new_expr.Emit (ec);
3937                         ec.ig.Emit (OpCodes.Stloc, value);
3938
3939                         ILGenerator ig = ec.ig;
3940
3941                         default_target = ig.DefineLabel ();
3942
3943                         //
3944                         // Setup the codegen context
3945                         //
3946                         Label old_end = ec.LoopEnd;
3947                         Switch old_switch = ec.Switch;
3948                         
3949                         ec.LoopEnd = ig.DefineLabel ();
3950                         ec.Switch = this;
3951
3952                         // Emit Code.
3953                         bool all_return;
3954                         if (SwitchType == TypeManager.string_type)
3955                                 all_return = SimpleSwitchEmit (ec, value);
3956                         else
3957                                 all_return = TableSwitchEmit (ec, value);
3958
3959                         // Restore context state. 
3960                         ig.MarkLabel (ec.LoopEnd);
3961
3962                         //
3963                         // Restore the previous context
3964                         //
3965                         ec.LoopEnd = old_end;
3966                         ec.Switch = old_switch;
3967                         
3968                         return all_return;
3969                 }
3970         }
3971
3972         public class Lock : Statement {
3973                 Expression expr;
3974                 Statement Statement;
3975                         
3976                 public Lock (Expression expr, Statement stmt, Location l)
3977                 {
3978                         this.expr = expr;
3979                         Statement = stmt;
3980                         loc = l;
3981                 }
3982
3983                 public override bool Resolve (EmitContext ec)
3984                 {
3985                         expr = expr.Resolve (ec);
3986                         return Statement.Resolve (ec) && expr != null;
3987                 }
3988                 
3989                 protected override bool DoEmit (EmitContext ec)
3990                 {
3991                         Type type = expr.Type;
3992                         bool val;
3993                         
3994                         if (type.IsValueType){
3995                                 Report.Error (185, loc, "lock statement requires the expression to be " +
3996                                               " a reference type (type is: `" +
3997                                               TypeManager.CSharpName (type) + "'");
3998                                 return false;
3999                         }
4000
4001                         ILGenerator ig = ec.ig;
4002                         LocalBuilder temp = ig.DeclareLocal (type);
4003                                 
4004                         expr.Emit (ec);
4005                         ig.Emit (OpCodes.Dup);
4006                         ig.Emit (OpCodes.Stloc, temp);
4007                         ig.Emit (OpCodes.Call, TypeManager.void_monitor_enter_object);
4008
4009                         // try
4010                         Label end = ig.BeginExceptionBlock ();
4011                         bool old_in_try = ec.InTry;
4012                         ec.InTry = true;
4013                         Label finish = ig.DefineLabel ();
4014                         val = Statement.Emit (ec);
4015                         ec.InTry = old_in_try;
4016                         // ig.Emit (OpCodes.Leave, finish);
4017
4018                         ig.MarkLabel (finish);
4019                         
4020                         // finally
4021                         ig.BeginFinallyBlock ();
4022                         ig.Emit (OpCodes.Ldloc, temp);
4023                         ig.Emit (OpCodes.Call, TypeManager.void_monitor_exit_object);
4024                         ig.EndExceptionBlock ();
4025                         
4026                         return val;
4027                 }
4028         }
4029
4030         public class Unchecked : Statement {
4031                 public readonly Block Block;
4032                 
4033                 public Unchecked (Block b)
4034                 {
4035                         Block = b;
4036                 }
4037
4038                 public override bool Resolve (EmitContext ec)
4039                 {
4040                         return Block.Resolve (ec);
4041                 }
4042                 
4043                 protected override bool DoEmit (EmitContext ec)
4044                 {
4045                         bool previous_state = ec.CheckState;
4046                         bool previous_state_const = ec.ConstantCheckState;
4047                         bool val;
4048                         
4049                         ec.CheckState = false;
4050                         ec.ConstantCheckState = false;
4051                         val = Block.Emit (ec);
4052                         ec.CheckState = previous_state;
4053                         ec.ConstantCheckState = previous_state_const;
4054
4055                         return val;
4056                 }
4057         }
4058
4059         public class Checked : Statement {
4060                 public readonly Block Block;
4061                 
4062                 public Checked (Block b)
4063                 {
4064                         Block = b;
4065                 }
4066
4067                 public override bool Resolve (EmitContext ec)
4068                 {
4069                         bool previous_state = ec.CheckState;
4070                         bool previous_state_const = ec.ConstantCheckState;
4071                         
4072                         ec.CheckState = true;
4073                         ec.ConstantCheckState = true;
4074                         bool ret = Block.Resolve (ec);
4075                         ec.CheckState = previous_state;
4076                         ec.ConstantCheckState = previous_state_const;
4077
4078                         return ret;
4079                 }
4080
4081                 protected override bool DoEmit (EmitContext ec)
4082                 {
4083                         bool previous_state = ec.CheckState;
4084                         bool previous_state_const = ec.ConstantCheckState;
4085                         bool val;
4086                         
4087                         ec.CheckState = true;
4088                         ec.ConstantCheckState = true;
4089                         val = Block.Emit (ec);
4090                         ec.CheckState = previous_state;
4091                         ec.ConstantCheckState = previous_state_const;
4092
4093                         return val;
4094                 }
4095         }
4096
4097         public class Unsafe : Statement {
4098                 public readonly Block Block;
4099
4100                 public Unsafe (Block b)
4101                 {
4102                         Block = b;
4103                 }
4104
4105                 public override bool Resolve (EmitContext ec)
4106                 {
4107                         bool previous_state = ec.InUnsafe;
4108                         bool val;
4109                         
4110                         ec.InUnsafe = true;
4111                         val = Block.Resolve (ec);
4112                         ec.InUnsafe = previous_state;
4113
4114                         return val;
4115                 }
4116                 
4117                 protected override bool DoEmit (EmitContext ec)
4118                 {
4119                         bool previous_state = ec.InUnsafe;
4120                         bool val;
4121                         
4122                         ec.InUnsafe = true;
4123                         val = Block.Emit (ec);
4124                         ec.InUnsafe = previous_state;
4125
4126                         return val;
4127                 }
4128         }
4129
4130         // 
4131         // Fixed statement
4132         //
4133         public class Fixed : Statement {
4134                 Expression type;
4135                 ArrayList declarators;
4136                 Statement statement;
4137                 Type expr_type;
4138                 FixedData[] data;
4139
4140                 struct FixedData {
4141                         public bool is_object;
4142                         public VariableInfo vi;
4143                         public Expression expr;
4144                         public Expression converted;
4145                 }                       
4146
4147                 public Fixed (Expression type, ArrayList decls, Statement stmt, Location l)
4148                 {
4149                         this.type = type;
4150                         declarators = decls;
4151                         statement = stmt;
4152                         loc = l;
4153                 }
4154
4155                 public override bool Resolve (EmitContext ec)
4156                 {
4157                         expr_type = ec.DeclSpace.ResolveType (type, false, loc);
4158                         if (expr_type == null)
4159                                 return false;
4160
4161                         data = new FixedData [declarators.Count];
4162
4163                         if (!expr_type.IsPointer){
4164                                 Report.Error (209, loc, "Variables in a fixed statement must be pointers");
4165                                 return false;
4166                         }
4167                         
4168                         int i = 0;
4169                         foreach (Pair p in declarators){
4170                                 VariableInfo vi = (VariableInfo) p.First;
4171                                 Expression e = (Expression) p.Second;
4172
4173                                 vi.Number = -1;
4174
4175                                 //
4176                                 // The rules for the possible declarators are pretty wise,
4177                                 // but the production on the grammar is more concise.
4178                                 //
4179                                 // So we have to enforce these rules here.
4180                                 //
4181                                 // We do not resolve before doing the case 1 test,
4182                                 // because the grammar is explicit in that the token &
4183                                 // is present, so we need to test for this particular case.
4184                                 //
4185
4186                                 //
4187                                 // Case 1: & object.
4188                                 //
4189                                 if (e is Unary && ((Unary) e).Oper == Unary.Operator.AddressOf){
4190                                         Expression child = ((Unary) e).Expr;
4191
4192                                         vi.MakePinned ();
4193                                         if (child is ParameterReference || child is LocalVariableReference){
4194                                                 Report.Error (
4195                                                         213, loc, 
4196                                                         "No need to use fixed statement for parameters or " +
4197                                                         "local variable declarations (address is already " +
4198                                                         "fixed)");
4199                                                 return false;
4200                                         }
4201                                         
4202                                         e = e.Resolve (ec);
4203                                         if (e == null)
4204                                                 return false;
4205
4206                                         child = ((Unary) e).Expr;
4207                                         
4208                                         if (!TypeManager.VerifyUnManaged (child.Type, loc))
4209                                                 return false;
4210
4211                                         data [i].is_object = true;
4212                                         data [i].expr = e;
4213                                         data [i].converted = null;
4214                                         data [i].vi = vi;
4215                                         i++;
4216
4217                                         continue;
4218                                 }
4219
4220                                 e = e.Resolve (ec);
4221                                 if (e == null)
4222                                         return false;
4223
4224                                 //
4225                                 // Case 2: Array
4226                                 //
4227                                 if (e.Type.IsArray){
4228                                         Type array_type = e.Type.GetElementType ();
4229                                         
4230                                         vi.MakePinned ();
4231                                         //
4232                                         // Provided that array_type is unmanaged,
4233                                         //
4234                                         if (!TypeManager.VerifyUnManaged (array_type, loc))
4235                                                 return false;
4236
4237                                         //
4238                                         // and T* is implicitly convertible to the
4239                                         // pointer type given in the fixed statement.
4240                                         //
4241                                         ArrayPtr array_ptr = new ArrayPtr (e, loc);
4242                                         
4243                                         Expression converted = Expression.ConvertImplicitRequired (
4244                                                 ec, array_ptr, vi.VariableType, loc);
4245                                         if (converted == null)
4246                                                 return false;
4247
4248                                         data [i].is_object = false;
4249                                         data [i].expr = e;
4250                                         data [i].converted = converted;
4251                                         data [i].vi = vi;
4252                                         i++;
4253
4254                                         continue;
4255                                 }
4256
4257                                 //
4258                                 // Case 3: string
4259                                 //
4260                                 if (e.Type == TypeManager.string_type){
4261                                         data [i].is_object = false;
4262                                         data [i].expr = e;
4263                                         data [i].converted = null;
4264                                         data [i].vi = vi;
4265                                         i++;
4266                                 }
4267                         }
4268
4269                         return statement.Resolve (ec);
4270                 }
4271                 
4272                 protected override bool DoEmit (EmitContext ec)
4273                 {
4274                         ILGenerator ig = ec.ig;
4275
4276                         bool is_ret = false;
4277                         LocalBuilder [] clear_list = new LocalBuilder [data.Length];
4278                         
4279                         for (int i = 0; i < data.Length; i++) {
4280                                 VariableInfo vi = data [i].vi;
4281
4282                                 //
4283                                 // Case 1: & object.
4284                                 //
4285                                 if (data [i].is_object) {
4286                                         //
4287                                         // Store pointer in pinned location
4288                                         //
4289                                         data [i].expr.Emit (ec);
4290                                         ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
4291                                         clear_list [i] = vi.LocalBuilder;
4292                                         continue;
4293                                 }
4294
4295                                 //
4296                                 // Case 2: Array
4297                                 //
4298                                 if (data [i].expr.Type.IsArray){
4299                                         //
4300                                         // Store pointer in pinned location
4301                                         //
4302                                         data [i].converted.Emit (ec);
4303                                         
4304                                         ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
4305                                         clear_list [i] = vi.LocalBuilder;
4306                                         continue;
4307                                 }
4308
4309                                 //
4310                                 // Case 3: string
4311                                 //
4312                                 if (data [i].expr.Type == TypeManager.string_type){
4313                                         LocalBuilder pinned_string = ig.DeclareLocal (TypeManager.string_type);
4314                                         TypeManager.MakePinned (pinned_string);
4315                                         clear_list [i] = pinned_string;
4316                                         
4317                                         data [i].expr.Emit (ec);
4318                                         ig.Emit (OpCodes.Stloc, pinned_string);
4319
4320                                         Expression sptr = new StringPtr (pinned_string, loc);
4321                                         Expression converted = Expression.ConvertImplicitRequired (
4322                                                 ec, sptr, vi.VariableType, loc);
4323                                         
4324                                         if (converted == null)
4325                                                 continue;
4326
4327                                         converted.Emit (ec);
4328                                         ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
4329                                 }
4330                         }
4331
4332                         is_ret = statement.Emit (ec);
4333
4334                         if (is_ret)
4335                                 return is_ret;
4336                         //
4337                         // Clear the pinned variable
4338                         //
4339                         for (int i = 0; i < data.Length; i++) {
4340                                 VariableInfo vi = data [i].vi;
4341
4342                                 if (data [i].is_object || data [i].expr.Type.IsArray) {
4343                                         ig.Emit (OpCodes.Ldc_I4_0);
4344                                         ig.Emit (OpCodes.Conv_U);
4345                                         ig.Emit (OpCodes.Stloc, clear_list [i]);
4346                                 } else if (data [i].expr.Type == TypeManager.string_type){
4347                                         ig.Emit (OpCodes.Ldnull);
4348                                         ig.Emit (OpCodes.Stloc, clear_list [i]);
4349                                 }
4350                         }
4351
4352                         return is_ret;
4353                 }
4354         }
4355         
4356         public class Catch {
4357                 public readonly string Name;
4358                 public readonly Block  Block;
4359                 public readonly Location Location;
4360
4361                 Expression type_expr;
4362                 Type type;
4363                 
4364                 public Catch (Expression type, string name, Block block, Location l)
4365                 {
4366                         type_expr = type;
4367                         Name = name;
4368                         Block = block;
4369                         Location = l;
4370                 }
4371
4372                 public Type CatchType {
4373                         get {
4374                                 return type;
4375                         }
4376                 }
4377
4378                 public bool IsGeneral {
4379                         get {
4380                                 return type_expr == null;
4381                         }
4382                 }
4383
4384                 public bool Resolve (EmitContext ec)
4385                 {
4386                         if (type_expr != null) {
4387                                 type = ec.DeclSpace.ResolveType (type_expr, false, Location);
4388                                 if (type == null)
4389                                         return false;
4390
4391                                 if (type != TypeManager.exception_type && !type.IsSubclassOf (TypeManager.exception_type)){
4392                                         Report.Error (155, Location,
4393                                                       "The type caught or thrown must be derived " +
4394                                                       "from System.Exception");
4395                                         return false;
4396                                 }
4397                         } else
4398                                 type = null;
4399
4400                         if (!Block.Resolve (ec))
4401                                 return false;
4402
4403                         return true;
4404                 }
4405         }
4406
4407         public class Try : Statement {
4408                 public readonly Block Fini, Block;
4409                 public readonly ArrayList Specific;
4410                 public readonly Catch General;
4411                 
4412                 //
4413                 // specific, general and fini might all be null.
4414                 //
4415                 public Try (Block block, ArrayList specific, Catch general, Block fini, Location l)
4416                 {
4417                         if (specific == null && general == null){
4418                                 Console.WriteLine ("CIR.Try: Either specific or general have to be non-null");
4419                         }
4420                         
4421                         this.Block = block;
4422                         this.Specific = specific;
4423                         this.General = general;
4424                         this.Fini = fini;
4425                         loc = l;
4426                 }
4427
4428                 public override bool Resolve (EmitContext ec)
4429                 {
4430                         bool ok = true;
4431                         
4432                         ec.StartFlowBranching (FlowBranchingType.EXCEPTION, Block.StartLocation);
4433
4434                         Report.Debug (1, "START OF TRY BLOCK", Block.StartLocation);
4435
4436                         bool old_in_try = ec.InTry;
4437                         ec.InTry = true;
4438
4439                         if (!Block.Resolve (ec))
4440                                 ok = false;
4441
4442                         ec.InTry = old_in_try;
4443
4444                         FlowBranching.UsageVector vector = ec.CurrentBranching.CurrentUsageVector;
4445
4446                         Report.Debug (1, "START OF CATCH BLOCKS", vector);
4447
4448                         foreach (Catch c in Specific){
4449                                 ec.CurrentBranching.CreateSibling ();
4450                                 Report.Debug (1, "STARTED SIBLING FOR CATCH", ec.CurrentBranching);
4451
4452                                 if (c.Name != null) {
4453                                         VariableInfo vi = c.Block.GetVariableInfo (c.Name);
4454                                         if (vi == null)
4455                                                 throw new Exception ();
4456
4457                                         vi.Number = -1;
4458                                 }
4459
4460                                 bool old_in_catch = ec.InCatch;
4461                                 ec.InCatch = true;
4462
4463                                 if (!c.Resolve (ec))
4464                                         ok = false;
4465
4466                                 ec.InCatch = old_in_catch;
4467
4468                                 FlowBranching.UsageVector current = ec.CurrentBranching.CurrentUsageVector;
4469
4470                                 if (!current.AlwaysReturns && !current.AlwaysBreaks)
4471                                         vector.AndLocals (current);
4472                                 else
4473                                         vector.Or (current);
4474                         }
4475
4476                         Report.Debug (1, "END OF CATCH BLOCKS", ec.CurrentBranching);
4477
4478                         if (General != null){
4479                                 ec.CurrentBranching.CreateSibling ();
4480                                 Report.Debug (1, "STARTED SIBLING FOR GENERAL", ec.CurrentBranching);
4481
4482                                 bool old_in_catch = ec.InCatch;
4483                                 ec.InCatch = true;
4484
4485                                 if (!General.Resolve (ec))
4486                                         ok = false;
4487
4488                                 ec.InCatch = old_in_catch;
4489
4490                                 FlowBranching.UsageVector current = ec.CurrentBranching.CurrentUsageVector;
4491
4492                                 if (!current.AlwaysReturns && !current.AlwaysBreaks)
4493                                         vector.AndLocals (current);
4494                                 else    
4495                                         vector.Or (current);
4496                         }
4497
4498                         Report.Debug (1, "END OF GENERAL CATCH BLOCKS", ec.CurrentBranching);
4499
4500                         if (Fini != null) {
4501                                 ec.CurrentBranching.CreateSiblingForFinally ();
4502                                 Report.Debug (1, "STARTED SIBLING FOR FINALLY", ec.CurrentBranching, vector);
4503
4504                                 bool old_in_finally = ec.InFinally;
4505                                 ec.InFinally = true;
4506
4507                                 if (!Fini.Resolve (ec))
4508                                         ok = false;
4509
4510                                 ec.InFinally = old_in_finally;
4511                         }
4512
4513                         FlowReturns returns = ec.EndFlowBranching ();
4514
4515                         FlowBranching.UsageVector f_vector = ec.CurrentBranching.CurrentUsageVector;
4516
4517                         Report.Debug (1, "END OF FINALLY", ec.CurrentBranching, returns, vector, f_vector);
4518
4519                         if ((returns == FlowReturns.SOMETIMES) || (returns == FlowReturns.ALWAYS)) {
4520                                 ec.CurrentBranching.CheckOutParameters (f_vector.Parameters, loc);
4521                         }
4522
4523                         ec.CurrentBranching.CurrentUsageVector.Or (vector);
4524
4525                         Report.Debug (1, "END OF TRY", ec.CurrentBranching);
4526
4527                         return ok;
4528                 }
4529                 
4530                 protected override bool DoEmit (EmitContext ec)
4531                 {
4532                         ILGenerator ig = ec.ig;
4533                         Label end;
4534                         Label finish = ig.DefineLabel ();;
4535                         bool returns;
4536
4537                         ec.TryCatchLevel++;
4538                         end = ig.BeginExceptionBlock ();
4539                         bool old_in_try = ec.InTry;
4540                         ec.InTry = true;
4541                         returns = Block.Emit (ec);
4542                         ec.InTry = old_in_try;
4543
4544                         //
4545                         // System.Reflection.Emit provides this automatically:
4546                         // ig.Emit (OpCodes.Leave, finish);
4547
4548                         bool old_in_catch = ec.InCatch;
4549                         ec.InCatch = true;
4550                         DeclSpace ds = ec.DeclSpace;
4551
4552                         foreach (Catch c in Specific){
4553                                 VariableInfo vi;
4554                                 
4555                                 ig.BeginCatchBlock (c.CatchType);
4556
4557                                 if (c.Name != null){
4558                                         vi = c.Block.GetVariableInfo (c.Name);
4559                                         if (vi == null)
4560                                                 throw new Exception ("Variable does not exist in this block");
4561
4562                                         ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
4563                                 } else
4564                                         ig.Emit (OpCodes.Pop);
4565                                 
4566                                 if (!c.Block.Emit (ec))
4567                                         returns = false;
4568                         }
4569
4570                         if (General != null){
4571                                 ig.BeginCatchBlock (TypeManager.object_type);
4572                                 ig.Emit (OpCodes.Pop);
4573                                 if (!General.Block.Emit (ec))
4574                                         returns = false;
4575                         }
4576                         ec.InCatch = old_in_catch;
4577
4578                         ig.MarkLabel (finish);
4579                         if (Fini != null){
4580                                 ig.BeginFinallyBlock ();
4581                                 bool old_in_finally = ec.InFinally;
4582                                 ec.InFinally = true;
4583                                 Fini.Emit (ec);
4584                                 ec.InFinally = old_in_finally;
4585                         }
4586                         
4587                         ig.EndExceptionBlock ();
4588                         ec.TryCatchLevel--;
4589
4590                         if (!returns || ec.InTry || ec.InCatch)
4591                                 return returns;
4592
4593                         // Unfortunately, System.Reflection.Emit automatically emits a leave
4594                         // to the end of the finally block.  This is a problem if `returns'
4595                         // is true since we may jump to a point after the end of the method.
4596                         // As a workaround, emit an explicit ret here.
4597
4598                         if (ec.ReturnType != null)
4599                                 ec.ig.Emit (OpCodes.Ldloc, ec.TemporaryReturn ());
4600                         ec.ig.Emit (OpCodes.Ret);
4601
4602                         return true;
4603                 }
4604         }
4605
4606         public class Using : Statement {
4607                 object expression_or_block;
4608                 Statement Statement;
4609                 ArrayList var_list;
4610                 Expression expr;
4611                 Type expr_type;
4612                 Expression conv;
4613                 Expression [] converted_vars;
4614                 ExpressionStatement [] assign;
4615                 
4616                 public Using (object expression_or_block, Statement stmt, Location l)
4617                 {
4618                         this.expression_or_block = expression_or_block;
4619                         Statement = stmt;
4620                         loc = l;
4621                 }
4622
4623                 //
4624                 // Resolves for the case of using using a local variable declaration.
4625                 //
4626                 bool ResolveLocalVariableDecls (EmitContext ec)
4627                 {
4628                         bool need_conv = false;
4629                         expr_type = ec.DeclSpace.ResolveType (expr, false, loc);
4630                         int i = 0;
4631
4632                         if (expr_type == null)
4633                                 return false;
4634
4635                         //
4636                         // The type must be an IDisposable or an implicit conversion
4637                         // must exist.
4638                         //
4639                         converted_vars = new Expression [var_list.Count];
4640                         assign = new ExpressionStatement [var_list.Count];
4641                         if (!TypeManager.ImplementsInterface (expr_type, TypeManager.idisposable_type)){
4642                                 foreach (DictionaryEntry e in var_list){
4643                                         Expression var = (Expression) e.Key;
4644
4645                                         var = var.ResolveLValue (ec, new EmptyExpression ());
4646                                         if (var == null)
4647                                                 return false;
4648                                         
4649                                         converted_vars [i] = Expression.ConvertImplicitRequired (
4650                                                 ec, var, TypeManager.idisposable_type, loc);
4651
4652                                         if (converted_vars [i] == null)
4653                                                 return false;
4654                                         i++;
4655                                 }
4656                                 need_conv = true;
4657                         }
4658
4659                         i = 0;
4660                         foreach (DictionaryEntry e in var_list){
4661                                 LocalVariableReference var = (LocalVariableReference) e.Key;
4662                                 Expression new_expr = (Expression) e.Value;
4663                                 Expression a;
4664
4665                                 a = new Assign (var, new_expr, loc);
4666                                 a = a.Resolve (ec);
4667                                 if (a == null)
4668                                         return false;
4669
4670                                 if (!need_conv)
4671                                         converted_vars [i] = var;
4672                                 assign [i] = (ExpressionStatement) a;
4673                                 i++;
4674                         }
4675
4676                         return true;
4677                 }
4678
4679                 bool ResolveExpression (EmitContext ec)
4680                 {
4681                         if (!TypeManager.ImplementsInterface (expr_type, TypeManager.idisposable_type)){
4682                                 conv = Expression.ConvertImplicitRequired (
4683                                         ec, expr, TypeManager.idisposable_type, loc);
4684
4685                                 if (conv == null)
4686                                         return false;
4687                         }
4688
4689                         return true;
4690                 }
4691                 
4692                 //
4693                 // Emits the code for the case of using using a local variable declaration.
4694                 //
4695                 bool EmitLocalVariableDecls (EmitContext ec)
4696                 {
4697                         ILGenerator ig = ec.ig;
4698                         int i = 0;
4699
4700                         bool old_in_try = ec.InTry;
4701                         ec.InTry = true;
4702                         for (i = 0; i < assign.Length; i++) {
4703                                 assign [i].EmitStatement (ec);
4704                                 
4705                                 ig.BeginExceptionBlock ();
4706                         }
4707                         Statement.Emit (ec);
4708                         ec.InTry = old_in_try;
4709
4710                         bool old_in_finally = ec.InFinally;
4711                         ec.InFinally = true;
4712                         var_list.Reverse ();
4713                         foreach (DictionaryEntry e in var_list){
4714                                 LocalVariableReference var = (LocalVariableReference) e.Key;
4715                                 Label skip = ig.DefineLabel ();
4716                                 i--;
4717                                 
4718                                 ig.BeginFinallyBlock ();
4719                                 
4720                                 var.Emit (ec);
4721                                 ig.Emit (OpCodes.Brfalse, skip);
4722                                 converted_vars [i].Emit (ec);
4723                                 ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
4724                                 ig.MarkLabel (skip);
4725                                 ig.EndExceptionBlock ();
4726                         }
4727                         ec.InFinally = old_in_finally;
4728
4729                         return false;
4730                 }
4731
4732                 bool EmitExpression (EmitContext ec)
4733                 {
4734                         //
4735                         // Make a copy of the expression and operate on that.
4736                         //
4737                         ILGenerator ig = ec.ig;
4738                         LocalBuilder local_copy = ig.DeclareLocal (expr_type);
4739                         if (conv != null)
4740                                 conv.Emit (ec);
4741                         else
4742                                 expr.Emit (ec);
4743                         ig.Emit (OpCodes.Stloc, local_copy);
4744
4745                         bool old_in_try = ec.InTry;
4746                         ec.InTry = true;
4747                         ig.BeginExceptionBlock ();
4748                         Statement.Emit (ec);
4749                         ec.InTry = old_in_try;
4750                         
4751                         Label skip = ig.DefineLabel ();
4752                         bool old_in_finally = ec.InFinally;
4753                         ig.BeginFinallyBlock ();
4754                         ig.Emit (OpCodes.Ldloc, local_copy);
4755                         ig.Emit (OpCodes.Brfalse, skip);
4756                         ig.Emit (OpCodes.Ldloc, local_copy);
4757                         ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
4758                         ig.MarkLabel (skip);
4759                         ec.InFinally = old_in_finally;
4760                         ig.EndExceptionBlock ();
4761
4762                         return false;
4763                 }
4764                 
4765                 public override bool Resolve (EmitContext ec)
4766                 {
4767                         if (expression_or_block is DictionaryEntry){
4768                                 expr = (Expression) ((DictionaryEntry) expression_or_block).Key;
4769                                 var_list = (ArrayList)((DictionaryEntry)expression_or_block).Value;
4770
4771                                 if (!ResolveLocalVariableDecls (ec))
4772                                         return false;
4773
4774                         } else if (expression_or_block is Expression){
4775                                 expr = (Expression) expression_or_block;
4776
4777                                 expr = expr.Resolve (ec);
4778                                 if (expr == null)
4779                                         return false;
4780
4781                                 expr_type = expr.Type;
4782
4783                                 if (!ResolveExpression (ec))
4784                                         return false;
4785                         }                       
4786
4787                         return Statement.Resolve (ec);
4788                 }
4789                 
4790                 protected override bool DoEmit (EmitContext ec)
4791                 {
4792                         if (expression_or_block is DictionaryEntry)
4793                                 return EmitLocalVariableDecls (ec);
4794                         else if (expression_or_block is Expression)
4795                                 return EmitExpression (ec);
4796
4797                         return false;
4798                 }
4799         }
4800
4801         /// <summary>
4802         ///   Implementation of the foreach C# statement
4803         /// </summary>
4804         public class Foreach : Statement {
4805                 Expression type;
4806                 LocalVariableReference variable;
4807                 Expression expr;
4808                 Statement statement;
4809                 ForeachHelperMethods hm;
4810                 Expression empty, conv;
4811                 Type array_type, element_type;
4812                 Type var_type;
4813                 
4814                 public Foreach (Expression type, LocalVariableReference var, Expression expr,
4815                                 Statement stmt, Location l)
4816                 {
4817                         this.type = type;
4818                         this.variable = var;
4819                         this.expr = expr;
4820                         statement = stmt;
4821                         loc = l;
4822                 }
4823                 
4824                 public override bool Resolve (EmitContext ec)
4825                 {
4826                         expr = expr.Resolve (ec);
4827                         if (expr == null)
4828                                 return false;
4829
4830                         var_type = ec.DeclSpace.ResolveType (type, false, loc);
4831                         if (var_type == null)
4832                                 return false;
4833                         
4834                         //
4835                         // We need an instance variable.  Not sure this is the best
4836                         // way of doing this.
4837                         //
4838                         // FIXME: When we implement propertyaccess, will those turn
4839                         // out to return values in ExprClass?  I think they should.
4840                         //
4841                         if (!(expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.Value ||
4842                               expr.eclass == ExprClass.PropertyAccess || expr.eclass == ExprClass.IndexerAccess)){
4843                                 error1579 (expr.Type);
4844                                 return false;
4845                         }
4846
4847                         if (expr.Type.IsArray) {
4848                                 array_type = expr.Type;
4849                                 element_type = array_type.GetElementType ();
4850
4851                                 empty = new EmptyExpression (element_type);
4852                         } else {
4853                                 hm = ProbeCollectionType (ec, expr.Type);
4854                                 if (hm == null){
4855                                         error1579 (expr.Type);
4856                                         return false;
4857                                 }
4858
4859                                 array_type = expr.Type;
4860                                 element_type = hm.element_type;
4861
4862                                 empty = new EmptyExpression (hm.element_type);
4863                         }
4864
4865                         ec.StartFlowBranching (FlowBranchingType.LOOP_BLOCK, loc);
4866                         ec.CurrentBranching.CreateSibling ();
4867
4868                         //
4869                         //
4870                         // FIXME: maybe we can apply the same trick we do in the
4871                         // array handling to avoid creating empty and conv in some cases.
4872                         //
4873                         // Although it is not as important in this case, as the type
4874                         // will not likely be object (what the enumerator will return).
4875                         //
4876                         conv = Expression.ConvertExplicit (ec, empty, var_type, loc);
4877                         if (conv == null)
4878                                 return false;
4879
4880                         if (variable.ResolveLValue (ec, empty) == null)
4881                                 return false;
4882
4883                         if (!statement.Resolve (ec))
4884                                 return false;
4885
4886                         FlowReturns returns = ec.EndFlowBranching ();
4887
4888                         return true;
4889                 }
4890                 
4891                 //
4892                 // Retrieves a `public bool MoveNext ()' method from the Type `t'
4893                 //
4894                 static MethodInfo FetchMethodMoveNext (Type t)
4895                 {
4896                         MemberList move_next_list;
4897                         
4898                         move_next_list = TypeContainer.FindMembers (
4899                                 t, MemberTypes.Method,
4900                                 BindingFlags.Public | BindingFlags.Instance,
4901                                 Type.FilterName, "MoveNext");
4902                         if (move_next_list.Count == 0)
4903                                 return null;
4904
4905                         foreach (MemberInfo m in move_next_list){
4906                                 MethodInfo mi = (MethodInfo) m;
4907                                 Type [] args;
4908                                 
4909                                 args = TypeManager.GetArgumentTypes (mi);
4910                                 if (args != null && args.Length == 0){
4911                                         if (mi.ReturnType == TypeManager.bool_type)
4912                                                 return mi;
4913                                 }
4914                         }
4915                         return null;
4916                 }
4917                 
4918                 //
4919                 // Retrieves a `public T get_Current ()' method from the Type `t'
4920                 //
4921                 static MethodInfo FetchMethodGetCurrent (Type t)
4922                 {
4923                         MemberList move_next_list;
4924                         
4925                         move_next_list = TypeContainer.FindMembers (
4926                                 t, MemberTypes.Method,
4927                                 BindingFlags.Public | BindingFlags.Instance,
4928                                 Type.FilterName, "get_Current");
4929                         if (move_next_list.Count == 0)
4930                                 return null;
4931
4932                         foreach (MemberInfo m in move_next_list){
4933                                 MethodInfo mi = (MethodInfo) m;
4934                                 Type [] args;
4935
4936                                 args = TypeManager.GetArgumentTypes (mi);
4937                                 if (args != null && args.Length == 0)
4938                                         return mi;
4939                         }
4940                         return null;
4941                 }
4942
4943                 // 
4944                 // This struct records the helper methods used by the Foreach construct
4945                 //
4946                 class ForeachHelperMethods {
4947                         public EmitContext ec;
4948                         public MethodInfo get_enumerator;
4949                         public MethodInfo move_next;
4950                         public MethodInfo get_current;
4951                         public Type element_type;
4952                         public Type enumerator_type;
4953                         public bool is_disposable;
4954
4955                         public ForeachHelperMethods (EmitContext ec)
4956                         {
4957                                 this.ec = ec;
4958                                 this.element_type = TypeManager.object_type;
4959                                 this.enumerator_type = TypeManager.ienumerator_type;
4960                                 this.is_disposable = true;
4961                         }
4962                 }
4963                 
4964                 static bool GetEnumeratorFilter (MemberInfo m, object criteria)
4965                 {
4966                         if (m == null)
4967                                 return false;
4968                         
4969                         if (!(m is MethodInfo))
4970                                 return false;
4971                         
4972                         if (m.Name != "GetEnumerator")
4973                                 return false;
4974
4975                         MethodInfo mi = (MethodInfo) m;
4976                         Type [] args = TypeManager.GetArgumentTypes (mi);
4977                         if (args != null){
4978                                 if (args.Length != 0)
4979                                         return false;
4980                         }
4981                         ForeachHelperMethods hm = (ForeachHelperMethods) criteria;
4982                         EmitContext ec = hm.ec;
4983
4984                         //
4985                         // Check whether GetEnumerator is accessible to us
4986                         //
4987                         MethodAttributes prot = mi.Attributes & MethodAttributes.MemberAccessMask;
4988
4989                         Type declaring = mi.DeclaringType;
4990                         if (prot == MethodAttributes.Private){
4991                                 if (declaring != ec.ContainerType)
4992                                         return false;
4993                         } else if (prot == MethodAttributes.FamANDAssem){
4994                                 // If from a different assembly, false
4995                                 if (!(mi is MethodBuilder))
4996                                         return false;
4997                                 //
4998                                 // Are we being invoked from the same class, or from a derived method?
4999                                 //
5000                                 if (ec.ContainerType != declaring){
5001                                         if (!ec.ContainerType.IsSubclassOf (declaring))
5002                                                 return false;
5003                                 }
5004                         } else if (prot == MethodAttributes.FamORAssem){
5005                                 if (!(mi is MethodBuilder ||
5006                                       ec.ContainerType == declaring ||
5007                                       ec.ContainerType.IsSubclassOf (declaring)))
5008                                         return false;
5009                         } if (prot == MethodAttributes.Family){
5010                                 if (!(ec.ContainerType == declaring ||
5011                                       ec.ContainerType.IsSubclassOf (declaring)))
5012                                         return false;
5013                         }
5014
5015                         //
5016                         // Ok, we can access it, now make sure that we can do something
5017                         // with this `GetEnumerator'
5018                         //
5019
5020                         if (mi.ReturnType == TypeManager.ienumerator_type ||
5021                             TypeManager.ienumerator_type.IsAssignableFrom (mi.ReturnType) ||
5022                             (!RootContext.StdLib && TypeManager.ImplementsInterface (mi.ReturnType, TypeManager.ienumerator_type))) {
5023                                 hm.move_next = TypeManager.bool_movenext_void;
5024                                 hm.get_current = TypeManager.object_getcurrent_void;
5025                                 return true;
5026                         }
5027
5028                         //
5029                         // Ok, so they dont return an IEnumerable, we will have to
5030                         // find if they support the GetEnumerator pattern.
5031                         //
5032                         Type return_type = mi.ReturnType;
5033
5034                         hm.move_next = FetchMethodMoveNext (return_type);
5035                         if (hm.move_next == null)
5036                                 return false;
5037                         hm.get_current = FetchMethodGetCurrent (return_type);
5038                         if (hm.get_current == null)
5039                                 return false;
5040
5041                         hm.element_type = hm.get_current.ReturnType;
5042                         hm.enumerator_type = return_type;
5043                         hm.is_disposable = TypeManager.ImplementsInterface (
5044                                 hm.enumerator_type, TypeManager.idisposable_type);
5045
5046                         return true;
5047                 }
5048                 
5049                 /// <summary>
5050                 ///   This filter is used to find the GetEnumerator method
5051                 ///   on which IEnumerator operates
5052                 /// </summary>
5053                 static MemberFilter FilterEnumerator;
5054                 
5055                 static Foreach ()
5056                 {
5057                         FilterEnumerator = new MemberFilter (GetEnumeratorFilter);
5058                 }
5059
5060                 void error1579 (Type t)
5061                 {
5062                         Report.Error (1579, loc,
5063                                       "foreach statement cannot operate on variables of type `" +
5064                                       t.FullName + "' because that class does not provide a " +
5065                                       " GetEnumerator method or it is inaccessible");
5066                 }
5067
5068                 static bool TryType (Type t, ForeachHelperMethods hm)
5069                 {
5070                         MemberList mi;
5071                         
5072                         mi = TypeContainer.FindMembers (t, MemberTypes.Method,
5073                                                         BindingFlags.Public | BindingFlags.NonPublic |
5074                                                         BindingFlags.Instance,
5075                                                         FilterEnumerator, hm);
5076
5077                         if (mi.Count == 0)
5078                                 return false;
5079
5080                         hm.get_enumerator = (MethodInfo) mi [0];
5081                         return true;    
5082                 }
5083                 
5084                 //
5085                 // Looks for a usable GetEnumerator in the Type, and if found returns
5086                 // the three methods that participate: GetEnumerator, MoveNext and get_Current
5087                 //
5088                 ForeachHelperMethods ProbeCollectionType (EmitContext ec, Type t)
5089                 {
5090                         ForeachHelperMethods hm = new ForeachHelperMethods (ec);
5091
5092                         if (TryType (t, hm))
5093                                 return hm;
5094
5095                         //
5096                         // Now try to find the method in the interfaces
5097                         //
5098                         while (t != null){
5099                                 Type [] ifaces = t.GetInterfaces ();
5100
5101                                 foreach (Type i in ifaces){
5102                                         if (TryType (i, hm))
5103                                                 return hm;
5104                                 }
5105                                 
5106                                 //
5107                                 // Since TypeBuilder.GetInterfaces only returns the interface
5108                                 // types for this type, we have to keep looping, but once
5109                                 // we hit a non-TypeBuilder (ie, a Type), then we know we are
5110                                 // done, because it returns all the types
5111                                 //
5112                                 if ((t is TypeBuilder))
5113                                         t = t.BaseType;
5114                                 else
5115                                         break;
5116                         } 
5117
5118                         return null;
5119                 }
5120
5121                 //
5122                 // FIXME: possible optimization.
5123                 // We might be able to avoid creating `empty' if the type is the sam
5124                 //
5125                 bool EmitCollectionForeach (EmitContext ec)
5126                 {
5127                         ILGenerator ig = ec.ig;
5128                         LocalBuilder enumerator, disposable;
5129
5130                         enumerator = ig.DeclareLocal (hm.enumerator_type);
5131                         if (hm.is_disposable)
5132                                 disposable = ig.DeclareLocal (TypeManager.idisposable_type);
5133                         else
5134                                 disposable = null;
5135                         
5136                         //
5137                         // Instantiate the enumerator
5138                         //
5139                         if (expr.Type.IsValueType){
5140                                 if (expr is IMemoryLocation){
5141                                         IMemoryLocation ml = (IMemoryLocation) expr;
5142
5143                                         ml.AddressOf (ec, AddressOp.Load);
5144                                 } else
5145                                         throw new Exception ("Expr " + expr + " of type " + expr.Type +
5146                                                              " does not implement IMemoryLocation");
5147                                 ig.Emit (OpCodes.Call, hm.get_enumerator);
5148                         } else {
5149                                 expr.Emit (ec);
5150                                 ig.Emit (OpCodes.Callvirt, hm.get_enumerator);
5151                         }
5152                         ig.Emit (OpCodes.Stloc, enumerator);
5153
5154                         //
5155                         // Protect the code in a try/finalize block, so that
5156                         // if the beast implement IDisposable, we get rid of it
5157                         //
5158                         Label l;
5159                         bool old_in_try = ec.InTry;
5160
5161                         if (hm.is_disposable) {
5162                                 l = ig.BeginExceptionBlock ();
5163                                 ec.InTry = true;
5164                         }
5165                         
5166                         Label end_try = ig.DefineLabel ();
5167                         
5168                         ig.MarkLabel (ec.LoopBegin);
5169                         ig.Emit (OpCodes.Ldloc, enumerator);
5170                         ig.Emit (OpCodes.Callvirt, hm.move_next);
5171                         ig.Emit (OpCodes.Brfalse, end_try);
5172                         ig.Emit (OpCodes.Ldloc, enumerator);
5173                         ig.Emit (OpCodes.Callvirt, hm.get_current);
5174                         variable.EmitAssign (ec, conv);
5175                         statement.Emit (ec);
5176                         ig.Emit (OpCodes.Br, ec.LoopBegin);
5177                         ig.MarkLabel (end_try);
5178                         ec.InTry = old_in_try;
5179                         
5180                         // The runtime provides this for us.
5181                         // ig.Emit (OpCodes.Leave, end);
5182
5183                         //
5184                         // Now the finally block
5185                         //
5186                         if (hm.is_disposable) {
5187                                 Label end_finally = ig.DefineLabel ();
5188                                 bool old_in_finally = ec.InFinally;
5189                                 ec.InFinally = true;
5190                                 ig.BeginFinallyBlock ();
5191                         
5192                                 ig.Emit (OpCodes.Ldloc, enumerator);
5193                                 ig.Emit (OpCodes.Isinst, TypeManager.idisposable_type);
5194                                 ig.Emit (OpCodes.Stloc, disposable);
5195                                 ig.Emit (OpCodes.Ldloc, disposable);
5196                                 ig.Emit (OpCodes.Brfalse, end_finally);
5197                                 ig.Emit (OpCodes.Ldloc, disposable);
5198                                 ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
5199                                 ig.MarkLabel (end_finally);
5200                                 ec.InFinally = old_in_finally;
5201
5202                                 // The runtime generates this anyways.
5203                                 // ig.Emit (OpCodes.Endfinally);
5204
5205                                 ig.EndExceptionBlock ();
5206                         }
5207
5208                         ig.MarkLabel (ec.LoopEnd);
5209                         return false;
5210                 }
5211
5212                 //
5213                 // FIXME: possible optimization.
5214                 // We might be able to avoid creating `empty' if the type is the sam
5215                 //
5216                 bool EmitArrayForeach (EmitContext ec)
5217                 {
5218                         int rank = array_type.GetArrayRank ();
5219                         ILGenerator ig = ec.ig;
5220
5221                         LocalBuilder copy = ig.DeclareLocal (array_type);
5222                         
5223                         //
5224                         // Make our copy of the array
5225                         //
5226                         expr.Emit (ec);
5227                         ig.Emit (OpCodes.Stloc, copy);
5228                         
5229                         if (rank == 1){
5230                                 LocalBuilder counter = ig.DeclareLocal (TypeManager.int32_type);
5231
5232                                 Label loop, test;
5233                                 
5234                                 ig.Emit (OpCodes.Ldc_I4_0);
5235                                 ig.Emit (OpCodes.Stloc, counter);
5236                                 test = ig.DefineLabel ();
5237                                 ig.Emit (OpCodes.Br, test);
5238
5239                                 loop = ig.DefineLabel ();
5240                                 ig.MarkLabel (loop);
5241
5242                                 ig.Emit (OpCodes.Ldloc, copy);
5243                                 ig.Emit (OpCodes.Ldloc, counter);
5244                                 ArrayAccess.EmitLoadOpcode (ig, var_type);
5245
5246                                 variable.EmitAssign (ec, conv);
5247
5248                                 statement.Emit (ec);
5249
5250                                 ig.MarkLabel (ec.LoopBegin);
5251                                 ig.Emit (OpCodes.Ldloc, counter);
5252                                 ig.Emit (OpCodes.Ldc_I4_1);
5253                                 ig.Emit (OpCodes.Add);
5254                                 ig.Emit (OpCodes.Stloc, counter);
5255
5256                                 ig.MarkLabel (test);
5257                                 ig.Emit (OpCodes.Ldloc, counter);
5258                                 ig.Emit (OpCodes.Ldloc, copy);
5259                                 ig.Emit (OpCodes.Ldlen);
5260                                 ig.Emit (OpCodes.Conv_I4);
5261                                 ig.Emit (OpCodes.Blt, loop);
5262                         } else {
5263                                 LocalBuilder [] dim_len   = new LocalBuilder [rank];
5264                                 LocalBuilder [] dim_count = new LocalBuilder [rank];
5265                                 Label [] loop = new Label [rank];
5266                                 Label [] test = new Label [rank];
5267                                 int dim;
5268                                 
5269                                 for (dim = 0; dim < rank; dim++){
5270                                         dim_len [dim] = ig.DeclareLocal (TypeManager.int32_type);
5271                                         dim_count [dim] = ig.DeclareLocal (TypeManager.int32_type);
5272                                         test [dim] = ig.DefineLabel ();
5273                                         loop [dim] = ig.DefineLabel ();
5274                                 }
5275                                         
5276                                 for (dim = 0; dim < rank; dim++){
5277                                         ig.Emit (OpCodes.Ldloc, copy);
5278                                         IntLiteral.EmitInt (ig, dim);
5279                                         ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int);
5280                                         ig.Emit (OpCodes.Stloc, dim_len [dim]);
5281                                 }
5282
5283                                 for (dim = 0; dim < rank; dim++){
5284                                         ig.Emit (OpCodes.Ldc_I4_0);
5285                                         ig.Emit (OpCodes.Stloc, dim_count [dim]);
5286                                         ig.Emit (OpCodes.Br, test [dim]);
5287                                         ig.MarkLabel (loop [dim]);
5288                                 }
5289
5290                                 ig.Emit (OpCodes.Ldloc, copy);
5291                                 for (dim = 0; dim < rank; dim++)
5292                                         ig.Emit (OpCodes.Ldloc, dim_count [dim]);
5293
5294                                 //
5295                                 // FIXME: Maybe we can cache the computation of `get'?
5296                                 //
5297                                 Type [] args = new Type [rank];
5298                                 MethodInfo get;
5299
5300                                 for (int i = 0; i < rank; i++)
5301                                         args [i] = TypeManager.int32_type;
5302
5303                                 ModuleBuilder mb = CodeGen.ModuleBuilder;
5304                                 get = mb.GetArrayMethod (
5305                                         array_type, "Get",
5306                                         CallingConventions.HasThis| CallingConventions.Standard,
5307                                         var_type, args);
5308                                 ig.Emit (OpCodes.Call, get);
5309                                 variable.EmitAssign (ec, conv);
5310                                 statement.Emit (ec);
5311                                 ig.MarkLabel (ec.LoopBegin);
5312                                 for (dim = rank - 1; dim >= 0; dim--){
5313                                         ig.Emit (OpCodes.Ldloc, dim_count [dim]);
5314                                         ig.Emit (OpCodes.Ldc_I4_1);
5315                                         ig.Emit (OpCodes.Add);
5316                                         ig.Emit (OpCodes.Stloc, dim_count [dim]);
5317
5318                                         ig.MarkLabel (test [dim]);
5319                                         ig.Emit (OpCodes.Ldloc, dim_count [dim]);
5320                                         ig.Emit (OpCodes.Ldloc, dim_len [dim]);
5321                                         ig.Emit (OpCodes.Blt, loop [dim]);
5322                                 }
5323                         }
5324                         ig.MarkLabel (ec.LoopEnd);
5325                         
5326                         return false;
5327                 }
5328                 
5329                 protected override bool DoEmit (EmitContext ec)
5330                 {
5331                         bool ret_val;
5332                         
5333                         ILGenerator ig = ec.ig;
5334                         
5335                         Label old_begin = ec.LoopBegin, old_end = ec.LoopEnd;
5336                         bool old_inloop = ec.InLoop;
5337                         int old_loop_begin_try_catch_level = ec.LoopBeginTryCatchLevel;
5338                         ec.LoopBegin = ig.DefineLabel ();
5339                         ec.LoopEnd = ig.DefineLabel ();
5340                         ec.InLoop = true;
5341                         ec.LoopBeginTryCatchLevel = ec.TryCatchLevel;
5342                         
5343                         if (hm != null)
5344                                 ret_val = EmitCollectionForeach (ec);
5345                         else
5346                                 ret_val = EmitArrayForeach (ec);
5347                         
5348                         ec.LoopBegin = old_begin;
5349                         ec.LoopEnd = old_end;
5350                         ec.InLoop = old_inloop;
5351                         ec.LoopBeginTryCatchLevel = old_loop_begin_try_catch_level;
5352
5353                         return ret_val;
5354                 }
5355         }
5356 }