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