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