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