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