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