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