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