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