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