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