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