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