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