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