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