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