0c02bf0562a271da6811188fd102ecf836f0986a
[mono.git] / mcs / mcs / statement.cs
1 //
2 // statement.cs: Statement representation for the IL tree.
3 //
4 // Authors:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //   Martin Baulig (martin@ximian.com)
7 //   Marek Safar (marek.safar@gmail.com)
8 //
9 // Copyright 2001, 2002, 2003 Ximian, Inc.
10 // Copyright 2003, 2004 Novell, Inc.
11 // Copyright 2011 Xamarin Inc.
12 //
13
14 using System;
15 using System.Collections.Generic;
16
17 #if STATIC
18 using IKVM.Reflection.Emit;
19 #else
20 using System.Reflection.Emit;
21 #endif
22
23 namespace Mono.CSharp {
24         
25         public abstract class Statement {
26                 public Location loc;
27                 protected bool reachable;
28
29                 public bool IsUnreachable {
30                         get {
31                                 return !reachable;
32                         }
33                 }
34                 
35                 /// <summary>
36                 ///   Resolves the statement, true means that all sub-statements
37                 ///   did resolve ok.
38                 ///  </summary>
39                 public virtual bool Resolve (BlockContext bc)
40                 {
41                         return true;
42                 }
43
44                 /// <summary>
45                 ///   Return value indicates whether all code paths emitted return.
46                 /// </summary>
47                 protected abstract void DoEmit (EmitContext ec);
48
49                 public virtual void Emit (EmitContext ec)
50                 {
51                         ec.Mark (loc);
52                         DoEmit (ec);
53
54                         if (ec.StatementEpilogue != null) {
55                                 ec.EmitEpilogue ();
56                         }
57                 }
58
59                 //
60                 // This routine must be overrided in derived classes and make copies
61                 // of all the data that might be modified if resolved
62                 // 
63                 protected abstract void CloneTo (CloneContext clonectx, Statement target);
64
65                 public Statement Clone (CloneContext clonectx)
66                 {
67                         Statement s = (Statement) this.MemberwiseClone ();
68                         CloneTo (clonectx, s);
69                         return s;
70                 }
71
72                 public virtual Expression CreateExpressionTree (ResolveContext ec)
73                 {
74                         ec.Report.Error (834, loc, "A lambda expression with statement body cannot be converted to an expresion tree");
75                         return null;
76                 }
77                 
78                 public virtual object Accept (StructuralVisitor visitor)
79                 {
80                         return visitor.Visit (this);
81                 }
82
83                 //
84                 // Return value indicates whether statement has unreachable end
85                 //
86                 protected abstract bool DoFlowAnalysis (FlowAnalysisContext fc);
87
88                 public bool FlowAnalysis (FlowAnalysisContext fc)
89                 {
90                         if (reachable) {
91                                 fc.UnreachableReported = false;
92                                 var res = DoFlowAnalysis (fc);
93                                 return res;
94                         }
95
96                         //
97                         // Special handling cases
98                         //
99                         if (this is Block) {
100                                 return DoFlowAnalysis (fc);
101                         }
102
103                         if (this is EmptyStatement || loc.IsNull)
104                                 return true;
105
106                         if (fc.UnreachableReported)
107                                 return true;
108
109                         fc.Report.Warning (162, 2, loc, "Unreachable code detected");
110                         fc.UnreachableReported = true;
111                         return true;
112                 }
113
114                 public virtual Reachability MarkReachable (Reachability rc)
115                 {
116                         if (!rc.IsUnreachable)
117                                 reachable = true;
118
119                         return rc;
120                 }
121
122                 protected void CheckExitBoundaries (BlockContext bc, Block scope)
123                 {
124                         if (bc.CurrentBlock.ParametersBlock.Original != scope.ParametersBlock.Original) {
125                                 bc.Report.Error (1632, loc, "Control cannot leave the body of an anonymous method");
126                                 return;
127                         }
128
129                         for (var b = bc.CurrentBlock; b != null && b != scope; b = b.Parent) {
130                                 if (b.IsFinallyBlock) {
131                                         Error_FinallyClauseExit (bc);
132                                         break;
133                                 }
134                         }
135                 }
136
137                 protected void Error_FinallyClauseExit (BlockContext bc)
138                 {
139                         bc.Report.Error (157, loc, "Control cannot leave the body of a finally clause");
140                 }
141         }
142
143         public sealed class EmptyStatement : Statement
144         {
145                 public EmptyStatement (Location loc)
146                 {
147                         this.loc = loc;
148                 }
149
150                 public override bool Resolve (BlockContext ec)
151                 {
152                         return true;
153                 }
154
155                 public override void Emit (EmitContext ec)
156                 {
157                 }
158
159                 protected override void DoEmit (EmitContext ec)
160                 {
161                         throw new NotSupportedException ();
162                 }
163
164                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
165                 {
166                         return false;
167                 }
168
169                 protected override void CloneTo (CloneContext clonectx, Statement target)
170                 {
171                         // nothing needed.
172                 }
173                 
174                 public override object Accept (StructuralVisitor visitor)
175                 {
176                         return visitor.Visit (this);
177                 }
178         }
179
180         public class If : Statement {
181                 Expression expr;
182                 public Statement TrueStatement;
183                 public Statement FalseStatement;
184
185                 bool true_returns, false_returns;
186
187                 public If (Expression bool_expr, Statement true_statement, Location l)
188                         : this (bool_expr, true_statement, null, l)
189                 {
190                 }
191
192                 public If (Expression bool_expr,
193                            Statement true_statement,
194                            Statement false_statement,
195                            Location l)
196                 {
197                         this.expr = bool_expr;
198                         TrueStatement = true_statement;
199                         FalseStatement = false_statement;
200                         loc = l;
201                 }
202
203                 public Expression Expr {
204                         get {
205                                 return this.expr;
206                         }
207                 }
208                 
209                 public override bool Resolve (BlockContext ec)
210                 {
211                         expr = expr.Resolve (ec);
212
213                         var ok = TrueStatement.Resolve (ec);
214
215                         if (FalseStatement != null) {
216                                 ok &= FalseStatement.Resolve (ec);
217                         }
218
219                         return ok;
220                 }
221                 
222                 protected override void DoEmit (EmitContext ec)
223                 {
224                         Label false_target = ec.DefineLabel ();
225                         Label end;
226
227                         //
228                         // If we're a boolean constant, Resolve() already
229                         // eliminated dead code for us.
230                         //
231                         Constant c = expr as Constant;
232                         if (c != null){
233                                 c.EmitSideEffect (ec);
234
235                                 if (!c.IsDefaultValue)
236                                         TrueStatement.Emit (ec);
237                                 else if (FalseStatement != null)
238                                         FalseStatement.Emit (ec);
239
240                                 return;
241                         }                       
242                         
243                         expr.EmitBranchable (ec, false_target, false);
244                         
245                         TrueStatement.Emit (ec);
246
247                         if (FalseStatement != null){
248                                 bool branch_emitted = false;
249                                 
250                                 end = ec.DefineLabel ();
251                                 if (!true_returns){
252                                         ec.Emit (OpCodes.Br, end);
253                                         branch_emitted = true;
254                                 }
255
256                                 ec.MarkLabel (false_target);
257                                 FalseStatement.Emit (ec);
258
259                                 if (branch_emitted)
260                                         ec.MarkLabel (end);
261                         } else {
262                                 ec.MarkLabel (false_target);
263                         }
264                 }
265
266                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
267                 {
268                         expr.FlowAnalysisConditional (fc);
269
270                         var da_false = new DefiniteAssignmentBitSet (fc.DefiniteAssignmentOnFalse);
271
272                         fc.BranchDefiniteAssignment (fc.DefiniteAssignmentOnTrue);
273                         var labels = fc.CopyLabelStack ();
274
275                         var res = TrueStatement.FlowAnalysis (fc);
276
277                         fc.SetLabelStack (labels);
278
279                         if (FalseStatement == null) {
280
281                                 var c = expr as Constant;
282                                 if (c != null && !c.IsDefaultValue)
283                                         return true_returns;
284
285                                 if (true_returns)
286                                         fc.DefiniteAssignment = da_false;
287                                 else
288                                         fc.DefiniteAssignment &= da_false;
289  
290                                 return false;
291                         }
292
293                         if (true_returns) {
294                                 fc.DefiniteAssignment = da_false;
295
296                                 res = FalseStatement.FlowAnalysis (fc);
297                                 fc.SetLabelStack (labels);
298                                 return res;
299                         }
300
301                         var da_true = fc.DefiniteAssignment;
302
303                         fc.DefiniteAssignment = da_false;
304
305                         res &= FalseStatement.FlowAnalysis (fc);
306
307                         fc.SetLabelStack (labels);
308
309                         if (!TrueStatement.IsUnreachable) {
310                                 if (false_returns || FalseStatement.IsUnreachable)
311                                         fc.DefiniteAssignment = da_true;
312                                 else
313                                         fc.DefiniteAssignment &= da_true;
314                         }
315
316                         return res;
317                 }
318
319                 public override Reachability MarkReachable (Reachability rc)
320                 {
321                         if (rc.IsUnreachable)
322                                 return rc;
323
324                         base.MarkReachable (rc);
325
326                         var c = expr as Constant;
327                         if (c != null) {
328                                 bool take = !c.IsDefaultValue;
329                                 if (take) {
330                                         rc = TrueStatement.MarkReachable (rc);
331                                 } else {
332                                         if (FalseStatement != null)
333                                                 rc = FalseStatement.MarkReachable (rc);
334                                 }
335
336                                 return rc;
337                         }
338
339                         var true_rc = TrueStatement.MarkReachable (rc);
340                         true_returns = true_rc.IsUnreachable;
341         
342                         if (FalseStatement == null)
343                                 return rc;
344
345                         var false_rc = FalseStatement.MarkReachable (rc);
346                         false_returns = false_rc.IsUnreachable;
347
348                         return true_rc & false_rc;
349                 }
350
351                 protected override void CloneTo (CloneContext clonectx, Statement t)
352                 {
353                         If target = (If) t;
354
355                         target.expr = expr.Clone (clonectx);
356                         target.TrueStatement = TrueStatement.Clone (clonectx);
357                         if (FalseStatement != null)
358                                 target.FalseStatement = FalseStatement.Clone (clonectx);
359                 }
360                 
361                 public override object Accept (StructuralVisitor visitor)
362                 {
363                         return visitor.Visit (this);
364                 }
365         }
366
367         public class Do : LoopStatement
368         {
369                 public Expression expr;
370                 bool iterator_reachable, end_reachable;
371
372                 public Do (Statement statement, BooleanExpression bool_expr, Location doLocation, Location whileLocation)
373                         : base (statement)
374                 {
375                         expr = bool_expr;
376                         loc = doLocation;
377                         WhileLocation = whileLocation;
378                 }
379
380                 public Location WhileLocation {
381                         get; private set;
382                 }
383
384                 public override bool Resolve (BlockContext bc)
385                 {
386                         var ok = base.Resolve (bc);
387
388                         expr = expr.Resolve (bc);
389
390                         return ok;
391                 }
392                 
393                 protected override void DoEmit (EmitContext ec)
394                 {
395                         Label loop = ec.DefineLabel ();
396                         Label old_begin = ec.LoopBegin;
397                         Label old_end = ec.LoopEnd;
398                         
399                         ec.LoopBegin = ec.DefineLabel ();
400                         ec.LoopEnd = ec.DefineLabel ();
401                                 
402                         ec.MarkLabel (loop);
403                         Statement.Emit (ec);
404                         ec.MarkLabel (ec.LoopBegin);
405
406                         // Mark start of while condition
407                         ec.Mark (WhileLocation);
408
409                         //
410                         // Dead code elimination
411                         //
412                         if (expr is Constant) {
413                                 bool res = !((Constant) expr).IsDefaultValue;
414
415                                 expr.EmitSideEffect (ec);
416                                 if (res)
417                                         ec.Emit (OpCodes.Br, loop);
418                         } else {
419                                 expr.EmitBranchable (ec, loop, true);
420                         }
421                         
422                         ec.MarkLabel (ec.LoopEnd);
423
424                         ec.LoopBegin = old_begin;
425                         ec.LoopEnd = old_end;
426                 }
427
428                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
429                 {
430                         var res = Statement.FlowAnalysis (fc);
431
432                         expr.FlowAnalysisConditional (fc);
433
434                         fc.DefiniteAssignment = fc.DefiniteAssignmentOnFalse;
435
436                         if (res && !iterator_reachable)
437                                 return !end_reachable;
438
439                         if (!end_reachable) {
440                                 var c = expr as Constant;
441                                 if (c != null && !c.IsDefaultValue)
442                                         return true;
443                         }
444
445                         return false;
446                 }
447                 
448                 public override Reachability MarkReachable (Reachability rc)
449                 {
450                         base.MarkReachable (rc);
451                         
452                         var body_rc = Statement.MarkReachable (rc);
453
454                         if (body_rc.IsUnreachable && !iterator_reachable) {
455                                 expr = new UnreachableExpression (expr);
456                                 return end_reachable ? rc : Reachability.CreateUnreachable ();
457                         }
458
459                         if (!end_reachable) {
460                                 var c = expr as Constant;
461                                 if (c != null && !c.IsDefaultValue)
462                                         return Reachability.CreateUnreachable ();
463                         }
464
465                         return rc;
466                 }
467
468                 protected override void CloneTo (CloneContext clonectx, Statement t)
469                 {
470                         Do target = (Do) t;
471
472                         target.Statement = Statement.Clone (clonectx);
473                         target.expr = expr.Clone (clonectx);
474                 }
475                 
476                 public override object Accept (StructuralVisitor visitor)
477                 {
478                         return visitor.Visit (this);
479                 }
480
481                 public override void SetEndReachable ()
482                 {
483                         end_reachable = true;
484                 }
485
486                 public override void SetIteratorReachable ()
487                 {
488                         iterator_reachable = true;
489                 }
490         }
491
492         public class While : LoopStatement
493         {
494                 public Expression expr;
495                 bool empty, infinite, end_reachable;
496                 List<DefiniteAssignmentBitSet> end_reachable_das;
497
498                 public While (BooleanExpression bool_expr, Statement statement, Location l)
499                         : base (statement)
500                 {
501                         this.expr = bool_expr;
502                         loc = l;
503                 }
504
505                 public override bool Resolve (BlockContext bc)
506                 {
507                         bool ok = true;
508
509                         expr = expr.Resolve (bc);
510                         if (expr == null)
511                                 ok = false;
512
513                         var c = expr as Constant;
514                         if (c != null) {
515                                 empty = c.IsDefaultValue;
516                                 infinite = !empty;
517                         }
518
519                         ok &= base.Resolve (bc);
520                         return ok;
521                 }
522                 
523                 protected override void DoEmit (EmitContext ec)
524                 {
525                         if (empty) {
526                                 expr.EmitSideEffect (ec);
527                                 return;
528                         }
529
530                         Label old_begin = ec.LoopBegin;
531                         Label old_end = ec.LoopEnd;
532                         
533                         ec.LoopBegin = ec.DefineLabel ();
534                         ec.LoopEnd = ec.DefineLabel ();
535
536                         //
537                         // Inform whether we are infinite or not
538                         //
539                         if (expr is Constant) {
540                                 // expr is 'true', since the 'empty' case above handles the 'false' case
541                                 ec.MarkLabel (ec.LoopBegin);
542
543                                 if (ec.EmitAccurateDebugInfo)
544                                         ec.Emit (OpCodes.Nop);
545
546                                 expr.EmitSideEffect (ec);
547                                 Statement.Emit (ec);
548                                 ec.Emit (OpCodes.Br, ec.LoopBegin);
549                                         
550                                 //
551                                 // Inform that we are infinite (ie, `we return'), only
552                                 // if we do not `break' inside the code.
553                                 //
554                                 ec.MarkLabel (ec.LoopEnd);
555                         } else {
556                                 Label while_loop = ec.DefineLabel ();
557
558                                 ec.Emit (OpCodes.Br, ec.LoopBegin);
559                                 ec.MarkLabel (while_loop);
560
561                                 expr.EmitPrepare (ec);
562
563                                 Statement.Emit (ec);
564                         
565                                 ec.MarkLabel (ec.LoopBegin);
566
567                                 ec.Mark (loc);
568                                 expr.EmitBranchable (ec, while_loop, true);
569                                 
570                                 ec.MarkLabel (ec.LoopEnd);
571                         }       
572
573                         ec.LoopBegin = old_begin;
574                         ec.LoopEnd = old_end;
575                 }
576
577                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
578                 {
579                         expr.FlowAnalysisConditional (fc);
580
581                         var da_false = new DefiniteAssignmentBitSet (fc.DefiniteAssignmentOnFalse);
582
583                         fc.BranchDefiniteAssignment (fc.DefiniteAssignmentOnTrue);
584
585                         Statement.FlowAnalysis (fc);
586
587                         //
588                         // Special case infinite while with breaks
589                         //
590                         if (end_reachable_das != null) {
591                                 da_false = DefiniteAssignmentBitSet.And (end_reachable_das);
592                                 end_reachable_das = null;
593                         }
594
595                         fc.DefiniteAssignment = da_false;
596
597                         if (infinite && !end_reachable)
598                                 return true;
599
600                         return false;
601                 }
602
603                 public override Reachability MarkReachable (Reachability rc)
604                 {
605                         if (rc.IsUnreachable)
606                                 return rc;
607
608                         base.MarkReachable (rc);
609
610                         //
611                         // Special case unreachable while body
612                         //
613                         if (empty) {
614                                 Statement.MarkReachable (Reachability.CreateUnreachable ());
615                                 return rc;
616                         }
617
618                         Statement.MarkReachable (rc);
619
620                         //
621                         // When infinite while end is unreachable via break anything what follows is unreachable too
622                         //
623                         if (infinite && !end_reachable)
624                                 return Reachability.CreateUnreachable ();
625
626                         return rc;
627                 }
628
629                 protected override void CloneTo (CloneContext clonectx, Statement t)
630                 {
631                         While target = (While) t;
632
633                         target.expr = expr.Clone (clonectx);
634                         target.Statement = Statement.Clone (clonectx);
635                 }
636                 
637                 public override object Accept (StructuralVisitor visitor)
638                 {
639                         return visitor.Visit (this);
640                 }
641
642                 public override void AddEndDefiniteAssignment (FlowAnalysisContext fc)
643                 {
644                         if (!infinite)
645                                 return;
646
647                         if (end_reachable_das == null)
648                                 end_reachable_das = new List<DefiniteAssignmentBitSet> ();
649
650                         end_reachable_das.Add (fc.DefiniteAssignment);
651                 }
652
653                 public override void SetEndReachable ()
654                 {
655                         end_reachable = true;
656                 }
657         }
658
659         public class For : LoopStatement
660         {
661                 bool infinite, empty, iterator_reachable, end_reachable;
662                 List<DefiniteAssignmentBitSet> end_reachable_das;
663                 
664                 public For (Location l)
665                         : base (null)
666                 {
667                         loc = l;
668                 }
669
670                 public Statement Initializer {
671                         get; set;
672                 }
673
674                 public Expression Condition {
675                         get; set;
676                 }
677
678                 public Statement Iterator {
679                         get; set;
680                 }
681
682                 public override bool Resolve (BlockContext bc)
683                 {
684                         Initializer.Resolve (bc);
685
686                         if (Condition != null) {
687                                 Condition = Condition.Resolve (bc);
688                                 var condition_constant = Condition as Constant;
689                                 if (condition_constant != null) {
690                                         if (condition_constant.IsDefaultValue) {
691                                                 empty = true;
692                                         } else {
693                                                 infinite = true;
694                                         }
695                                 }
696                         } else {
697                                 infinite = true;
698                         }
699
700                         return base.Resolve (bc) && Iterator.Resolve (bc);
701                 }
702
703                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
704                 {
705                         Initializer.FlowAnalysis (fc);
706
707                         DefiniteAssignmentBitSet da_false;
708                         if (Condition != null) {
709                                 Condition.FlowAnalysisConditional (fc);
710                                 fc.DefiniteAssignment = fc.DefiniteAssignmentOnTrue;
711                                 da_false = new DefiniteAssignmentBitSet (fc.DefiniteAssignmentOnFalse);
712                         } else {
713                                 da_false = fc.BranchDefiniteAssignment ();
714                         }
715
716                         Statement.FlowAnalysis (fc);
717
718                         Iterator.FlowAnalysis (fc);
719
720                         //
721                         // Special case infinite for with breaks
722                         //
723                         if (end_reachable_das != null) {
724                                 da_false = DefiniteAssignmentBitSet.And (end_reachable_das);
725                                 end_reachable_das = null;
726                         }
727
728                         fc.DefiniteAssignment = da_false;
729
730                         if (infinite && !end_reachable)
731                                 return true;
732
733                         return false;
734                 }
735
736                 public override Reachability MarkReachable (Reachability rc)
737                 {
738                         base.MarkReachable (rc);
739
740                         Initializer.MarkReachable (rc);
741
742                         var body_rc = Statement.MarkReachable (rc);
743                         if (!body_rc.IsUnreachable || iterator_reachable) {
744                                 Iterator.MarkReachable (rc);
745                         }
746
747                         //
748                         // When infinite for end is unreachable via break anything what follows is unreachable too
749                         //
750                         if (infinite && !end_reachable) {
751                                 return Reachability.CreateUnreachable ();
752                         }
753
754                         return rc;
755                 }
756
757                 protected override void DoEmit (EmitContext ec)
758                 {
759                         if (Initializer != null)
760                                 Initializer.Emit (ec);
761
762                         if (empty) {
763                                 Condition.EmitSideEffect (ec);
764                                 return;
765                         }
766
767                         Label old_begin = ec.LoopBegin;
768                         Label old_end = ec.LoopEnd;
769                         Label loop = ec.DefineLabel ();
770                         Label test = ec.DefineLabel ();
771
772                         ec.LoopBegin = ec.DefineLabel ();
773                         ec.LoopEnd = ec.DefineLabel ();
774
775                         ec.Emit (OpCodes.Br, test);
776                         ec.MarkLabel (loop);
777                         Statement.Emit (ec);
778
779                         ec.MarkLabel (ec.LoopBegin);
780                         Iterator.Emit (ec);
781
782                         ec.MarkLabel (test);
783                         //
784                         // If test is null, there is no test, and we are just
785                         // an infinite loop
786                         //
787                         if (Condition != null) {
788                                 ec.Mark (Condition.Location);
789
790                                 //
791                                 // The Resolve code already catches the case for
792                                 // Test == Constant (false) so we know that
793                                 // this is true
794                                 //
795                                 if (Condition is Constant) {
796                                         Condition.EmitSideEffect (ec);
797                                         ec.Emit (OpCodes.Br, loop);
798                                 } else {
799                                         Condition.EmitBranchable (ec, loop, true);
800                                 }
801                                 
802                         } else
803                                 ec.Emit (OpCodes.Br, loop);
804                         ec.MarkLabel (ec.LoopEnd);
805
806                         ec.LoopBegin = old_begin;
807                         ec.LoopEnd = old_end;
808                 }
809
810                 protected override void CloneTo (CloneContext clonectx, Statement t)
811                 {
812                         For target = (For) t;
813
814                         if (Initializer != null)
815                                 target.Initializer = Initializer.Clone (clonectx);
816                         if (Condition != null)
817                                 target.Condition = Condition.Clone (clonectx);
818                         if (Iterator != null)
819                                 target.Iterator = Iterator.Clone (clonectx);
820                         target.Statement = Statement.Clone (clonectx);
821                 }
822
823                 public override object Accept (StructuralVisitor visitor)
824                 {
825                         return visitor.Visit (this);
826                 }
827
828                 public override void AddEndDefiniteAssignment (FlowAnalysisContext fc)
829                 {
830                         if (!infinite)
831                                 return;
832
833                         if (end_reachable_das == null)
834                                 end_reachable_das = new List<DefiniteAssignmentBitSet> ();
835
836                         end_reachable_das.Add (fc.DefiniteAssignment);
837                 }
838
839                 public override void SetEndReachable ()
840                 {
841                         end_reachable = true;
842                 }
843
844                 public override void SetIteratorReachable ()
845                 {
846                         iterator_reachable = true;
847                 }
848         }
849
850         public abstract class LoopStatement : Statement
851         {
852                 protected LoopStatement (Statement statement)
853                 {
854                         Statement = statement;
855                 }
856
857                 public Statement Statement { get; set; }
858
859                 public override bool Resolve (BlockContext bc)
860                 {
861                         var prev_loop = bc.EnclosingLoop;
862                         var prev_los = bc.EnclosingLoopOrSwitch;
863                         bc.EnclosingLoopOrSwitch = bc.EnclosingLoop = this;
864                         var ok = Statement.Resolve (bc);
865                         bc.EnclosingLoopOrSwitch = prev_los;
866                         bc.EnclosingLoop = prev_loop;
867
868                         return ok;
869                 }
870
871                 //
872                 // Needed by possibly infinite loops statements (for, while) and switch statment
873                 //
874                 public virtual void AddEndDefiniteAssignment (FlowAnalysisContext fc)
875                 {
876                 }
877
878                 public virtual void SetEndReachable ()
879                 {
880                 }
881
882                 public virtual void SetIteratorReachable ()
883                 {
884                 }
885         }
886         
887         public class StatementExpression : Statement
888         {
889                 ExpressionStatement expr;
890                 
891                 public StatementExpression (ExpressionStatement expr)
892                 {
893                         this.expr = expr;
894                         loc = expr.StartLocation;
895                 }
896
897                 public StatementExpression (ExpressionStatement expr, Location loc)
898                 {
899                         this.expr = expr;
900                         this.loc = loc;
901                 }
902
903                 public ExpressionStatement Expr {
904                         get {
905                                 return this.expr;
906                         }
907                 }
908                 
909                 protected override void CloneTo (CloneContext clonectx, Statement t)
910                 {
911                         StatementExpression target = (StatementExpression) t;
912                         target.expr = (ExpressionStatement) expr.Clone (clonectx);
913                 }
914                 
915                 protected override void DoEmit (EmitContext ec)
916                 {
917                         expr.EmitStatement (ec);
918                 }
919
920                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
921                 {
922                         expr.FlowAnalysis (fc);
923                         return false;
924                 }
925
926                 public override Reachability MarkReachable (Reachability rc)
927                 {
928                         base.MarkReachable (rc);
929                         expr.MarkReachable (rc);
930                         return rc;
931                 }
932
933                 public override bool Resolve (BlockContext ec)
934                 {
935                         expr = expr.ResolveStatement (ec);
936                         return expr != null;
937                 }
938                 
939                 public override object Accept (StructuralVisitor visitor)
940                 {
941                         return visitor.Visit (this);
942                 }
943         }
944
945         public class StatementErrorExpression : Statement
946         {
947                 Expression expr;
948
949                 public StatementErrorExpression (Expression expr)
950                 {
951                         this.expr = expr;
952                         this.loc = expr.StartLocation;
953                 }
954
955                 public Expression Expr {
956                         get {
957                                 return expr;
958                         }
959                 }
960
961                 public override bool Resolve (BlockContext bc)
962                 {
963                         expr.Error_InvalidExpressionStatement (bc);
964                         return true;
965                 }
966
967                 protected override void DoEmit (EmitContext ec)
968                 {
969                         throw new NotSupportedException ();
970                 }
971
972                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
973                 {
974                         return false;
975                 }
976
977                 protected override void CloneTo (CloneContext clonectx, Statement target)
978                 {
979                         var t = (StatementErrorExpression) target;
980
981                         t.expr = expr.Clone (clonectx);
982                 }
983                 
984                 public override object Accept (StructuralVisitor visitor)
985                 {
986                         return visitor.Visit (this);
987                 }
988         }
989
990         //
991         // Simple version of statement list not requiring a block
992         //
993         public class StatementList : Statement
994         {
995                 List<Statement> statements;
996
997                 public StatementList (Statement first, Statement second)
998                 {
999                         statements = new List<Statement> { first, second };
1000                 }
1001
1002                 #region Properties
1003                 public IList<Statement> Statements {
1004                         get {
1005                                 return statements;
1006                         }
1007                 }
1008                 #endregion
1009
1010                 public void Add (Statement statement)
1011                 {
1012                         statements.Add (statement);
1013                 }
1014
1015                 public override bool Resolve (BlockContext ec)
1016                 {
1017                         foreach (var s in statements)
1018                                 s.Resolve (ec);
1019
1020                         return true;
1021                 }
1022
1023                 protected override void DoEmit (EmitContext ec)
1024                 {
1025                         foreach (var s in statements)
1026                                 s.Emit (ec);
1027                 }
1028
1029                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
1030                 {
1031                         foreach (var s in statements)
1032                                 s.FlowAnalysis (fc);
1033
1034                         return false;
1035                 }
1036
1037                 public override Reachability MarkReachable (Reachability rc)
1038                 {
1039                         base.MarkReachable (rc);
1040
1041                         Reachability res = rc;
1042                         foreach (var s in statements)
1043                                 res = s.MarkReachable (rc);
1044
1045                         return res;
1046                 }
1047
1048                 protected override void CloneTo (CloneContext clonectx, Statement target)
1049                 {
1050                         StatementList t = (StatementList) target;
1051
1052                         t.statements = new List<Statement> (statements.Count);
1053                         foreach (Statement s in statements)
1054                                 t.statements.Add (s.Clone (clonectx));
1055                 }
1056                 
1057                 public override object Accept (StructuralVisitor visitor)
1058                 {
1059                         return visitor.Visit (this);
1060                 }
1061         }
1062
1063         //
1064         // For statements which require special handling when inside try or catch block
1065         //
1066         public abstract class ExitStatement : Statement
1067         {
1068                 protected bool unwind_protect;
1069
1070                 protected abstract bool DoResolve (BlockContext bc);
1071                 protected abstract bool IsLocalExit { get; }
1072
1073                 public override bool Resolve (BlockContext bc)
1074                 {
1075                         var res = DoResolve (bc);
1076
1077                         if (!IsLocalExit) {
1078                                 //
1079                                 // We are inside finally scope but is it the scope we are exiting
1080                                 //
1081                                 if (bc.HasSet (ResolveContext.Options.FinallyScope)) {
1082
1083                                         for (var b = bc.CurrentBlock; b != null; b = b.Parent) {
1084                                                 if (b.IsFinallyBlock) {
1085                                                         Error_FinallyClauseExit (bc);
1086                                                         break;
1087                                                 }
1088
1089                                                 if (b is ParametersBlock)
1090                                                         break;
1091                                         }
1092                                 }
1093                         }
1094
1095                         unwind_protect = bc.HasAny (ResolveContext.Options.TryScope | ResolveContext.Options.CatchScope);
1096                         return res;
1097                 }
1098
1099                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
1100                 {
1101                         if (IsLocalExit)
1102                                 return true;
1103
1104                         if (fc.TryFinally != null) {
1105                             fc.TryFinally.RegisterForControlExitCheck (new DefiniteAssignmentBitSet (fc.DefiniteAssignment));
1106                         } else {
1107                             fc.ParametersBlock.CheckControlExit (fc);
1108                         }
1109
1110                         return true;
1111                 }
1112         }
1113
1114         /// <summary>
1115         ///   Implements the return statement
1116         /// </summary>
1117         public class Return : ExitStatement
1118         {
1119                 Expression expr;
1120                 bool expr_returns;
1121
1122                 public Return (Expression expr, Location l)
1123                 {
1124                         this.expr = expr;
1125                         loc = l;
1126                 }
1127
1128                 #region Properties
1129
1130                 public Expression Expr {
1131                         get {
1132                                 return expr;
1133                         }
1134                         protected set {
1135                                 expr = value;
1136                         }
1137                 }
1138
1139                 protected override bool IsLocalExit {
1140                         get {
1141                                 return false;
1142                         }
1143                 }
1144
1145                 #endregion
1146
1147                 protected override bool DoResolve (BlockContext ec)
1148                 {
1149                         var block_return_type = ec.ReturnType;
1150
1151                         if (expr == null) {
1152                                 if (block_return_type.Kind == MemberKind.Void || block_return_type == InternalType.ErrorType)
1153                                         return true;
1154
1155                                 //
1156                                 // Return must not be followed by an expression when
1157                                 // the method return type is Task
1158                                 //
1159                                 if (ec.CurrentAnonymousMethod is AsyncInitializer) {
1160                                         var storey = (AsyncTaskStorey) ec.CurrentAnonymousMethod.Storey;
1161                                         if (storey.ReturnType == ec.Module.PredefinedTypes.Task.TypeSpec) {
1162                                                 //
1163                                                 // Extra trick not to emit ret/leave inside awaiter body
1164                                                 //
1165                                                 expr = EmptyExpression.Null;
1166                                                 return true;
1167                                         }
1168
1169                                         if (storey.ReturnType.IsGenericTask)
1170                                                 block_return_type = storey.ReturnType.TypeArguments[0];
1171                                 }
1172
1173                                 if (ec.CurrentIterator != null) {
1174                                         Error_ReturnFromIterator (ec);
1175                                 } else if (block_return_type != InternalType.ErrorType) {
1176                                         ec.Report.Error (126, loc,
1177                                                 "An object of a type convertible to `{0}' is required for the return statement",
1178                                                 block_return_type.GetSignatureForError ());
1179                                 }
1180
1181                                 return false;
1182                         }
1183
1184                         expr = expr.Resolve (ec);
1185
1186                         AnonymousExpression am = ec.CurrentAnonymousMethod;
1187                         if (am == null) {
1188                                 if (block_return_type.Kind == MemberKind.Void) {
1189                                         ec.Report.Error (127, loc,
1190                                                 "`{0}': A return keyword must not be followed by any expression when method returns void",
1191                                                 ec.GetSignatureForError ());
1192
1193                                         return false;
1194                                 }
1195                         } else {
1196                                 if (am.IsIterator) {
1197                                         Error_ReturnFromIterator (ec);
1198                                         return false;
1199                                 }
1200
1201                                 var async_block = am as AsyncInitializer;
1202                                 if (async_block != null) {
1203                                         if (expr != null) {
1204                                                 var storey = (AsyncTaskStorey) am.Storey;
1205                                                 var async_type = storey.ReturnType;
1206
1207                                                 if (async_type == null && async_block.ReturnTypeInference != null) {
1208                                                         if (expr.Type.Kind == MemberKind.Void && !(this is ContextualReturn))
1209                                                                 ec.Report.Error (4029, loc, "Cannot return an expression of type `void'");
1210                                                         else
1211                                                                 async_block.ReturnTypeInference.AddCommonTypeBoundAsync (expr.Type);
1212                                                         return true;
1213                                                 }
1214
1215                                                 if (async_type.Kind == MemberKind.Void) {
1216                                                         ec.Report.Error (8030, loc,
1217                                                                 "Anonymous function or lambda expression converted to a void returning delegate cannot return a value");
1218                                                         return false;
1219                                                 }
1220
1221                                                 if (!async_type.IsGenericTask) {
1222                                                         if (this is ContextualReturn)
1223                                                                 return true;
1224
1225                                                         if (async_block.DelegateType != null) {
1226                                                                 ec.Report.Error (8031, loc,
1227                                                                         "Async lambda expression or anonymous method converted to a `Task' cannot return a value. Consider returning `Task<T>'");
1228                                                         } else {
1229                                                                 ec.Report.Error (1997, loc,
1230                                                                         "`{0}': A return keyword must not be followed by an expression when async method returns `Task'. Consider using `Task<T>' return type",
1231                                                                         ec.GetSignatureForError ());
1232                                                         }
1233                                                         return false;
1234                                                 }
1235
1236                                                 //
1237                                                 // The return type is actually Task<T> type argument
1238                                                 //
1239                                                 if (expr.Type == async_type && async_type.TypeArguments [0] != ec.Module.PredefinedTypes.Task.TypeSpec) {
1240                                                         ec.Report.Error (4016, loc,
1241                                                                 "`{0}': The return expression type of async method must be `{1}' rather than `Task<{1}>'",
1242                                                                 ec.GetSignatureForError (), async_type.TypeArguments[0].GetSignatureForError ());
1243                                                 } else {
1244                                                         block_return_type = async_type.TypeArguments[0];
1245                                                 }
1246                                         }
1247                                 } else {
1248                                         if (block_return_type.Kind == MemberKind.Void) {
1249                                                 ec.Report.Error (8030, loc,
1250                                                         "Anonymous function or lambda expression converted to a void returning delegate cannot return a value");
1251                                                 return false;
1252                                         }
1253
1254                                         var l = am as AnonymousMethodBody;
1255                                         if (l != null && expr != null) {
1256                                                 if (l.ReturnTypeInference != null) {
1257                                                         l.ReturnTypeInference.AddCommonTypeBound (expr.Type);
1258                                                         return true;
1259                                                 }
1260
1261                                                 //
1262                                                 // Try to optimize simple lambda. Only when optimizations are enabled not to cause
1263                                                 // unexpected debugging experience
1264                                                 //
1265                                                 if (this is ContextualReturn && !ec.IsInProbingMode && ec.Module.Compiler.Settings.Optimize) {
1266                                                         l.DirectMethodGroupConversion = expr.CanReduceLambda (l);
1267                                                 }
1268                                         }
1269                                 }
1270                         }
1271
1272                         if (expr == null)
1273                                 return false;
1274
1275                         if (expr is ReferenceExpression && block_return_type.Kind != MemberKind.ByRef) {
1276                                 ec.Report.Error (8149, loc, "By-reference returns can only be used in methods that return by reference");
1277                                 return false;
1278                         }
1279
1280                         if (expr.Type != block_return_type && expr.Type != InternalType.ErrorType) {
1281                                 if (block_return_type.Kind == MemberKind.ByRef) {
1282                                         var ref_expr = Expr as ReferenceExpression;
1283                                         if (ref_expr == null) {
1284                                                 ec.Report.Error (8150, loc, "By-reference return is required when method returns by reference");
1285                                                 return false;
1286                                         }
1287
1288                                         var byref_return = (ReferenceContainer)block_return_type;
1289
1290                                         if (expr.Type != byref_return.Element) {
1291                                                 ec.Report.Error (8151, loc, "The return by reference expression must be of type `{0}' because this method returns by reference",
1292                                                                                  byref_return.GetSignatureForError ());
1293                                                 return false;
1294                                         }
1295                                 } else {
1296
1297                                         expr = Convert.ImplicitConversionRequired (ec, expr, block_return_type, loc);
1298
1299                                         if (expr == null) {
1300                                                 if (am != null && block_return_type == ec.ReturnType) {
1301                                                         ec.Report.Error (1662, loc,
1302                                                                 "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",
1303                                                                 am.ContainerType, am.GetSignatureForError ());
1304                                                 }
1305                                                 return false;
1306                                         }
1307                                 }
1308                         }
1309
1310                         return true;                    
1311                 }
1312                 
1313                 protected override void DoEmit (EmitContext ec)
1314                 {
1315                         if (expr != null) {
1316
1317                                 var async_body = ec.CurrentAnonymousMethod as AsyncInitializer;
1318                                 if (async_body != null) {
1319                                         var storey = (AsyncTaskStorey)async_body.Storey;
1320                                         Label exit_label = async_body.BodyEnd;
1321
1322                                         //
1323                                         // It's null for await without async
1324                                         //
1325                                         if (storey.HoistedReturnValue != null) {
1326                                                 //
1327                                                 // Special case hoisted return value (happens in try/finally scenario)
1328                                                 //
1329                                                 if (ec.TryFinallyUnwind != null) {
1330                                                         exit_label = TryFinally.EmitRedirectedReturn (ec, async_body, unwind_protect);
1331                                                 }
1332
1333                                                 var async_return = (IAssignMethod)storey.HoistedReturnValue;
1334                                                 async_return.EmitAssign (ec, expr, false, false);
1335                                                 ec.EmitEpilogue ();
1336                                         } else {
1337                                                 expr.Emit (ec);
1338
1339                                                 if (ec.TryFinallyUnwind != null)
1340                                                         exit_label = TryFinally.EmitRedirectedReturn (ec, async_body, unwind_protect);
1341                                         }
1342
1343                                         ec.Emit (OpCodes.Leave, exit_label);
1344                                         return;
1345                                 }
1346
1347                                 expr.Emit (ec);
1348                                 ec.EmitEpilogue ();
1349
1350                                 if (unwind_protect || ec.EmitAccurateDebugInfo)
1351                                         ec.Emit (OpCodes.Stloc, ec.TemporaryReturn ());
1352                         }
1353
1354                         if (unwind_protect) {
1355                                 ec.Emit (OpCodes.Leave, ec.CreateReturnLabel ());
1356                         } else if (ec.EmitAccurateDebugInfo) {
1357                                 ec.Emit (OpCodes.Br, ec.CreateReturnLabel ());
1358                         } else {
1359                                 ec.Emit (OpCodes.Ret);
1360                         }
1361                 }
1362
1363                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
1364                 {
1365                         if (expr != null)
1366                                 expr.FlowAnalysis (fc);
1367
1368                         if (!expr_returns)
1369                                 base.DoFlowAnalysis (fc);
1370                         
1371                         return true;
1372                 }
1373
1374                 void Error_ReturnFromIterator (ResolveContext rc)
1375                 {
1376                         rc.Report.Error (1622, loc,
1377                                 "Cannot return a value from iterators. Use the yield return statement to return a value, or yield break to end the iteration");
1378                 }
1379
1380                 public override Reachability MarkReachable (Reachability rc)
1381                 {
1382                         base.MarkReachable (rc);
1383
1384                         if (Expr != null) {
1385                                 rc = Expr.MarkReachable (rc);
1386                                 expr_returns = rc.IsUnreachable;
1387                         }
1388
1389                         return Reachability.CreateUnreachable ();
1390                 }
1391
1392                 protected override void CloneTo (CloneContext clonectx, Statement t)
1393                 {
1394                         Return target = (Return) t;
1395                         // It's null for simple return;
1396                         if (expr != null)
1397                                 target.expr = expr.Clone (clonectx);
1398                 }
1399
1400                 public override object Accept (StructuralVisitor visitor)
1401                 {
1402                         return visitor.Visit (this);
1403                 }
1404         }
1405
1406         public class Goto : ExitStatement
1407         {
1408                 string target;
1409                 LabeledStatement label;
1410                 TryFinally try_finally;
1411
1412                 public Goto (string label, Location l)
1413                 {
1414                         loc = l;
1415                         target = label;
1416                 }
1417
1418                 public string Target {
1419                         get { return target; }
1420                 }
1421
1422                 protected override bool IsLocalExit {
1423                         get {
1424                                 return true;
1425                         }
1426                 }
1427
1428                 protected override bool DoResolve (BlockContext bc)
1429                 {
1430                         label = bc.CurrentBlock.LookupLabel (target);
1431                         if (label == null) {
1432                                 Error_UnknownLabel (bc, target, loc);
1433                                 return false;
1434                         }
1435
1436                         try_finally = bc.CurrentTryBlock as TryFinally;
1437
1438                         CheckExitBoundaries (bc, label.Block);
1439
1440                         return true;
1441                 }
1442
1443                 public static void Error_UnknownLabel (BlockContext bc, string label, Location loc)
1444                 {
1445                         bc.Report.Error (159, loc, "The label `{0}:' could not be found within the scope of the goto statement",
1446                                 label);
1447                 }
1448
1449                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
1450                 {
1451                         // Goto to unreachable label
1452                         if (label == null)
1453                                 return true;
1454
1455                         if (fc.AddReachedLabel (label))
1456                                 return true;
1457
1458                         label.Block.ScanGotoJump (label, fc);
1459                         return true;
1460                 }
1461
1462                 public override Reachability MarkReachable (Reachability rc)
1463                 {
1464                         if (rc.IsUnreachable)
1465                                 return rc;
1466
1467                         base.MarkReachable (rc);
1468
1469                         if (try_finally != null) {
1470                                 if (try_finally.FinallyBlock.HasReachableClosingBrace) {
1471                                         label.AddGotoReference (rc);
1472                                 } else {
1473                                         label = null;
1474                                 }
1475                         } else {
1476                                 label.AddGotoReference (rc);
1477                         }
1478
1479                         return Reachability.CreateUnreachable ();
1480                 }
1481
1482                 protected override void CloneTo (CloneContext clonectx, Statement target)
1483                 {
1484                         // Nothing to clone
1485                 }
1486
1487                 protected override void DoEmit (EmitContext ec)
1488                 {
1489                         // This should only happen for goto from try block to unrechable label
1490                         if (label == null)
1491                                 return;
1492
1493                         Label l = label.LabelTarget (ec);
1494
1495                         if (ec.TryFinallyUnwind != null && IsLeavingFinally (label.Block)) {
1496                                 var async_body = (AsyncInitializer) ec.CurrentAnonymousMethod;
1497                                 l = TryFinally.EmitRedirectedJump (ec, async_body, l, label.Block, unwind_protect);
1498                         }
1499
1500                         ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, l);
1501                 }
1502
1503                 bool IsLeavingFinally (Block labelBlock)
1504                 {
1505                         var b = try_finally.Statement as Block;
1506                         while (b != null) {
1507                                 if (b == labelBlock)
1508                                         return true;
1509
1510                                 b = b.Parent;
1511                         }
1512
1513                         return false;
1514                 }
1515                 
1516                 public override object Accept (StructuralVisitor visitor)
1517                 {
1518                         return visitor.Visit (this);
1519                 }
1520         }
1521
1522         public class LabeledStatement : Statement {
1523                 string name;
1524                 bool defined;
1525                 bool referenced;
1526                 Label label;
1527                 Block block;
1528                 
1529                 public LabeledStatement (string name, Block block, Location l)
1530                 {
1531                         this.name = name;
1532                         this.block = block;
1533                         this.loc = l;
1534                 }
1535
1536                 public Label LabelTarget (EmitContext ec)
1537                 {
1538                         if (defined)
1539                                 return label;
1540
1541                         label = ec.DefineLabel ();
1542                         defined = true;
1543                         return label;
1544                 }
1545
1546                 public Block Block {
1547                         get {
1548                                 return block;
1549                         }
1550                 }
1551
1552                 public string Name {
1553                         get { return name; }
1554                 }
1555
1556                 protected override void CloneTo (CloneContext clonectx, Statement target)
1557                 {
1558                         var t = (LabeledStatement) target;
1559
1560                         t.block = clonectx.RemapBlockCopy (block);
1561                 }
1562
1563                 public override bool Resolve (BlockContext bc)
1564                 {
1565                         return true;
1566                 }
1567
1568                 protected override void DoEmit (EmitContext ec)
1569                 {
1570                         LabelTarget (ec);
1571                         ec.MarkLabel (label);
1572                 }
1573
1574                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
1575                 {
1576                         if (!referenced) {
1577                                 fc.Report.Warning (164, 2, loc, "This label has not been referenced");
1578                         }
1579
1580                         return false;
1581                 }
1582
1583                 public override Reachability MarkReachable (Reachability rc)
1584                 {
1585                         base.MarkReachable (rc);
1586
1587                         if (referenced)
1588                                 rc = new Reachability ();
1589
1590                         return rc;
1591                 }
1592
1593                 public void AddGotoReference (Reachability rc)
1594                 {
1595                         if (referenced)
1596                                 return;
1597
1598                         referenced = true;
1599                         MarkReachable (rc);
1600
1601                         block.ScanGotoJump (this);
1602                 }
1603
1604                 public override object Accept (StructuralVisitor visitor)
1605                 {
1606                         return visitor.Visit (this);
1607                 }
1608         }
1609         
1610
1611         /// <summary>
1612         ///   `goto default' statement
1613         /// </summary>
1614         public class GotoDefault : SwitchGoto
1615         {               
1616                 public GotoDefault (Location l)
1617                         : base (l)
1618                 {
1619                 }
1620
1621                 public override bool Resolve (BlockContext bc)
1622                 {
1623                         if (bc.Switch == null) {
1624                                 Error_GotoCaseRequiresSwitchBlock (bc);
1625                                 return false;
1626                         }
1627
1628                         bc.Switch.RegisterGotoCase (null, null);
1629                         base.Resolve (bc);
1630
1631                         return true;
1632                 }
1633
1634                 protected override void DoEmit (EmitContext ec)
1635                 {
1636                         ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.Switch.DefaultLabel.GetILLabel (ec));
1637                 }
1638
1639                 public override Reachability MarkReachable (Reachability rc)
1640                 {
1641                         if (!rc.IsUnreachable) {
1642                                 var label = switch_statement.DefaultLabel;
1643                                 if (label.IsUnreachable) {
1644                                         label.MarkReachable (rc);
1645                                         switch_statement.Block.ScanGotoJump (label);
1646                                 }
1647                         }
1648
1649                         return base.MarkReachable (rc);
1650                 }
1651
1652                 public override object Accept (StructuralVisitor visitor)
1653                 {
1654                         return visitor.Visit (this);
1655                 }
1656         }
1657
1658         /// <summary>
1659         ///   `goto case' statement
1660         /// </summary>
1661         public class GotoCase : SwitchGoto
1662         {
1663                 Expression expr;
1664                 
1665                 public GotoCase (Expression e, Location l)
1666                         : base (l)
1667                 {
1668                         expr = e;
1669                 }
1670
1671                 public Expression Expr {
1672                         get {
1673                                 return expr;
1674                         }
1675                 }
1676
1677                 public SwitchLabel Label { get; set; }
1678
1679                 public override bool Resolve (BlockContext ec)
1680                 {
1681                         if (ec.Switch == null) {
1682                                 Error_GotoCaseRequiresSwitchBlock (ec);
1683                                 return false;
1684                         }
1685
1686                         Constant c = expr.ResolveLabelConstant (ec);
1687                         if (c == null) {
1688                                 return false;
1689                         }
1690
1691                         Constant res;
1692                         if (ec.Switch.IsNullable && c is NullLiteral) {
1693                                 res = c;
1694                         } else {
1695                                 TypeSpec type = ec.Switch.SwitchType;
1696                                 res = c.Reduce (ec, type);
1697                                 if (res == null) {
1698                                         c.Error_ValueCannotBeConverted (ec, type, true);
1699                                         return false;
1700                                 }
1701
1702                                 if (!Convert.ImplicitStandardConversionExists (c, type))
1703                                         ec.Report.Warning (469, 2, loc,
1704                                                 "The `goto case' value is not implicitly convertible to type `{0}'",
1705                                                 type.GetSignatureForError ());
1706
1707                         }
1708
1709                         ec.Switch.RegisterGotoCase (this, res);
1710                         base.Resolve (ec);
1711                         expr = res;
1712
1713                         return true;
1714                 }
1715
1716                 protected override void DoEmit (EmitContext ec)
1717                 {
1718                         ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, Label.GetILLabel (ec));
1719                 }
1720
1721                 protected override void CloneTo (CloneContext clonectx, Statement t)
1722                 {
1723                         GotoCase target = (GotoCase) t;
1724
1725                         target.expr = expr.Clone (clonectx);
1726                 }
1727
1728                 public override Reachability MarkReachable (Reachability rc)
1729                 {
1730                         if (!rc.IsUnreachable) {
1731                                 var label = switch_statement.FindLabel ((Constant) expr);
1732                                 if (label.IsUnreachable) {
1733                                         label.MarkReachable (rc);
1734                                         switch_statement.Block.ScanGotoJump (label);
1735                                 }
1736                         }
1737
1738                         return base.MarkReachable (rc);
1739                 }
1740                 
1741                 public override object Accept (StructuralVisitor visitor)
1742                 {
1743                         return visitor.Visit (this);
1744                 }
1745         }
1746
1747         public abstract class SwitchGoto : Statement
1748         {
1749                 protected bool unwind_protect;
1750                 protected Switch switch_statement;
1751
1752                 protected SwitchGoto (Location loc)
1753                 {
1754                         this.loc = loc;
1755                 }
1756
1757                 protected override void CloneTo (CloneContext clonectx, Statement target)
1758                 {
1759                         // Nothing to clone
1760                 }
1761
1762                 public override bool Resolve (BlockContext bc)
1763                 {
1764                         CheckExitBoundaries (bc, bc.Switch.Block);
1765
1766                         unwind_protect = bc.HasAny (ResolveContext.Options.TryScope | ResolveContext.Options.CatchScope);
1767                         switch_statement = bc.Switch;
1768
1769                         return true;
1770                 }
1771
1772                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
1773                 {
1774                         return true;
1775                 }
1776
1777                 public override Reachability MarkReachable (Reachability rc)
1778                 {
1779                         base.MarkReachable (rc);
1780                         return Reachability.CreateUnreachable ();
1781                 }
1782
1783                 protected void Error_GotoCaseRequiresSwitchBlock (BlockContext bc)
1784                 {
1785                         bc.Report.Error (153, loc, "A goto case is only valid inside a switch statement");
1786                 }
1787         }
1788         
1789         public class Throw : Statement {
1790                 Expression expr;
1791                 
1792                 public Throw (Expression expr, Location l)
1793                 {
1794                         this.expr = expr;
1795                         loc = l;
1796                 }
1797
1798                 public Expression Expr {
1799                         get {
1800                                 return this.expr;
1801                         }
1802                 }
1803
1804                 public static Expression ConvertType (ResolveContext rc, Expression expr)
1805                 {
1806                         var et = rc.BuiltinTypes.Exception;
1807                         if (Convert.ImplicitConversionExists (rc, expr, et))
1808                                 expr = Convert.ImplicitConversion (rc, expr, et, expr.Location);
1809                         else {
1810                                 rc.Report.Error (155, expr.Location, "The type caught or thrown must be derived from System.Exception");
1811                                 expr = EmptyCast.Create (expr, et);
1812                         }
1813
1814                         return expr;
1815                 }
1816
1817                 public override bool Resolve (BlockContext ec)
1818                 {
1819                         if (expr == null) {
1820                                 if (!ec.HasSet (ResolveContext.Options.CatchScope)) {
1821                                         ec.Report.Error (156, loc, "A throw statement with no arguments is not allowed outside of a catch clause");
1822                                 } else if (ec.HasSet (ResolveContext.Options.FinallyScope)) {
1823                                         for (var b = ec.CurrentBlock; b != null && !b.IsCatchBlock; b = b.Parent) {
1824                                                 if (b.IsFinallyBlock) {
1825                                                         ec.Report.Error (724, loc,
1826                                                                 "A throw statement with no arguments is not allowed inside of a finally clause nested inside of the innermost catch clause");
1827                                                         break;
1828                                                 }
1829                                         }
1830                                 }
1831
1832                                 return true;
1833                         }
1834
1835                         expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
1836
1837                         if (expr == null)
1838                                 return false;
1839
1840                         expr = ConvertType (ec, expr);
1841
1842                         return true;
1843                 }
1844                         
1845                 protected override void DoEmit (EmitContext ec)
1846                 {
1847                         if (expr == null) {
1848                                 var atv = ec.AsyncThrowVariable;
1849                                 if (atv != null) {
1850                                         if (atv.HoistedVariant != null) {
1851                                                 atv.HoistedVariant.Emit (ec);
1852                                         } else {
1853                                                 atv.Emit (ec);
1854                                         }
1855
1856                                         ec.Emit (OpCodes.Throw);
1857                                 } else {
1858                                         ec.Emit (OpCodes.Rethrow);
1859                                 }
1860                         } else {
1861                                 expr.Emit (ec);
1862
1863                                 ec.Emit (OpCodes.Throw);
1864                         }
1865                 }
1866
1867                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
1868                 {
1869                         if (expr != null)
1870                                 expr.FlowAnalysis (fc);
1871
1872                         return true;
1873                 }
1874
1875                 public override Reachability MarkReachable (Reachability rc)
1876                 {
1877                         base.MarkReachable (rc);
1878                         return Reachability.CreateUnreachable ();
1879                 }
1880
1881                 protected override void CloneTo (CloneContext clonectx, Statement t)
1882                 {
1883                         Throw target = (Throw) t;
1884
1885                         if (expr != null)
1886                                 target.expr = expr.Clone (clonectx);
1887                 }
1888                 
1889                 public override object Accept (StructuralVisitor visitor)
1890                 {
1891                         return visitor.Visit (this);
1892                 }
1893         }
1894
1895         public class Break : LocalExitStatement
1896         {               
1897                 public Break (Location l)
1898                         : base (l)
1899                 {
1900                 }
1901                 
1902                 public override object Accept (StructuralVisitor visitor)
1903                 {
1904                         return visitor.Visit (this);
1905                 }
1906
1907                 protected override void DoEmit (EmitContext ec)
1908                 {
1909                         var l = ec.LoopEnd;
1910
1911                         if (ec.TryFinallyUnwind != null) {
1912                                 var async_body = (AsyncInitializer) ec.CurrentAnonymousMethod;
1913                                 l = TryFinally.EmitRedirectedJump (ec, async_body, l, enclosing_loop.Statement as Block, unwind_protect);
1914                         }
1915
1916                         ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, l);
1917                 }
1918
1919                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
1920                 {
1921                         enclosing_loop.AddEndDefiniteAssignment (fc);
1922                         return true;
1923                 }
1924
1925                 protected override bool DoResolve (BlockContext bc)
1926                 {
1927                         enclosing_loop = bc.EnclosingLoopOrSwitch;
1928                         return base.DoResolve (bc);
1929                 }
1930
1931                 public override Reachability MarkReachable (Reachability rc)
1932                 {
1933                         base.MarkReachable (rc);
1934
1935                         if (!rc.IsUnreachable)
1936                                 enclosing_loop.SetEndReachable ();
1937
1938                         return Reachability.CreateUnreachable ();
1939                 }
1940         }
1941
1942         public class Continue : LocalExitStatement
1943         {               
1944                 public Continue (Location l)
1945                         : base (l)
1946                 {
1947                 }
1948
1949                 public override object Accept (StructuralVisitor visitor)
1950                 {
1951                         return visitor.Visit (this);
1952                 }
1953
1954
1955                 protected override void DoEmit (EmitContext ec)
1956                 {
1957                         var l = ec.LoopBegin;
1958
1959                         if (ec.TryFinallyUnwind != null) {
1960                                 var async_body = (AsyncInitializer) ec.CurrentAnonymousMethod;
1961                                 l = TryFinally.EmitRedirectedJump (ec, async_body, l, enclosing_loop.Statement as Block, unwind_protect);
1962                         }
1963
1964                         ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, l);
1965                 }
1966
1967                 protected override bool DoResolve (BlockContext bc)
1968                 {
1969                         enclosing_loop = bc.EnclosingLoop;
1970                         return base.DoResolve (bc);
1971                 }
1972
1973                 public override Reachability MarkReachable (Reachability rc)
1974                 {
1975                         base.MarkReachable (rc);
1976
1977                         if (!rc.IsUnreachable)
1978                                 enclosing_loop.SetIteratorReachable ();
1979
1980                         return Reachability.CreateUnreachable ();
1981                 }
1982         }
1983
1984         public abstract class LocalExitStatement : ExitStatement
1985         {
1986                 protected LoopStatement enclosing_loop;
1987
1988                 protected LocalExitStatement (Location loc)
1989                 {
1990                         this.loc = loc;
1991                 }
1992
1993                 protected override bool IsLocalExit {
1994                         get {
1995                                 return true;
1996                         }
1997                 }
1998
1999                 protected override void CloneTo (CloneContext clonectx, Statement t)
2000                 {
2001                         // nothing needed.
2002                 }
2003
2004                 protected override bool DoResolve (BlockContext bc)
2005                 {
2006                         if (enclosing_loop == null) {
2007                                 bc.Report.Error (139, loc, "No enclosing loop out of which to break or continue");
2008                                 return false;
2009                         }
2010
2011                         var block = enclosing_loop.Statement as Block;
2012
2013                         // Don't need to do extra checks for simple statements loops
2014                         if (block != null) {
2015                                 CheckExitBoundaries (bc, block);
2016                         }
2017
2018                         return true;
2019                 }
2020         }
2021
2022         public interface ILocalVariable
2023         {
2024                 void Emit (EmitContext ec);
2025                 void EmitAssign (EmitContext ec);
2026                 void EmitAddressOf (EmitContext ec);
2027         }
2028
2029         public interface INamedBlockVariable
2030         {
2031                 Block Block { get; }
2032                 Expression CreateReferenceExpression (ResolveContext rc, Location loc);
2033                 bool IsDeclared { get; }
2034                 bool IsParameter { get; }
2035                 Location Location { get; }
2036         }
2037
2038         public class BlockVariableDeclarator
2039         {
2040                 LocalVariable li;
2041                 Expression initializer;
2042
2043                 public BlockVariableDeclarator (LocalVariable li, Expression initializer)
2044                 {
2045                         if (li.Type != null)
2046                                 throw new ArgumentException ("Expected null variable type");
2047
2048                         this.li = li;
2049                         this.initializer = initializer;
2050                 }
2051
2052                 #region Properties
2053
2054                 public LocalVariable Variable {
2055                         get {
2056                                 return li;
2057                         }
2058                 }
2059
2060                 public Expression Initializer {
2061                         get {
2062                                 return initializer;
2063                         }
2064                         set {
2065                                 initializer = value;
2066                         }
2067                 }
2068
2069                 #endregion
2070
2071                 public virtual BlockVariableDeclarator Clone (CloneContext cloneCtx)
2072                 {
2073                         var t = (BlockVariableDeclarator) MemberwiseClone ();
2074                         if (initializer != null)
2075                                 t.initializer = initializer.Clone (cloneCtx);
2076
2077                         return t;
2078                 }
2079         }
2080
2081         public class BlockVariable : Statement
2082         {
2083                 Expression initializer;
2084                 protected FullNamedExpression type_expr;
2085                 protected LocalVariable li;
2086                 protected List<BlockVariableDeclarator> declarators;
2087                 TypeSpec type;
2088
2089                 public BlockVariable (FullNamedExpression type, LocalVariable li)
2090                 {
2091                         this.type_expr = type;
2092                         this.li = li;
2093                         this.loc = type_expr.Location;
2094                 }
2095
2096                 protected BlockVariable (LocalVariable li)
2097                 {
2098                         this.li = li;
2099                 }
2100
2101                 #region Properties
2102
2103                 public List<BlockVariableDeclarator> Declarators {
2104                         get {
2105                                 return declarators;
2106                         }
2107                 }
2108
2109                 public Expression Initializer {
2110                         get {
2111                                 return initializer;
2112                         }
2113                         set {
2114                                 initializer = value;
2115                         }
2116                 }
2117
2118                 public FullNamedExpression TypeExpression {
2119                         get {
2120                                 return type_expr;
2121                         }
2122                 }
2123
2124                 public LocalVariable Variable {
2125                         get {
2126                                 return li;
2127                         }
2128                 }
2129
2130                 #endregion
2131
2132                 public void AddDeclarator (BlockVariableDeclarator decl)
2133                 {
2134                         if (declarators == null)
2135                                 declarators = new List<BlockVariableDeclarator> ();
2136
2137                         declarators.Add (decl);
2138                 }
2139
2140                 static void CreateEvaluatorVariable (BlockContext bc, LocalVariable li)
2141                 {
2142                         if (bc.Report.Errors != 0)
2143                                 return;
2144
2145                         var container = bc.CurrentMemberDefinition.Parent.PartialContainer;
2146
2147                         Field f = new Field (container, new TypeExpression (li.Type, li.Location), Modifiers.PUBLIC | Modifiers.STATIC,
2148                                 new MemberName (li.Name, li.Location), null);
2149
2150                         container.AddField (f);
2151                         f.Define ();
2152
2153                         li.HoistedVariant = new HoistedEvaluatorVariable (f);
2154                         li.SetIsUsed ();
2155                 }
2156
2157                 public override bool Resolve (BlockContext bc)
2158                 {
2159                         return Resolve (bc, true);
2160                 }
2161
2162                 public bool Resolve (BlockContext bc, bool resolveDeclaratorInitializers)
2163                 {
2164                         if (type == null && !li.IsCompilerGenerated) {
2165                                 var vexpr = type_expr as VarExpr;
2166
2167                                 //
2168                                 // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
2169                                 // same name exists or as a keyword when no type was found
2170                                 //
2171                                 if (vexpr != null && !vexpr.IsPossibleType (bc)) {
2172                                         if (bc.Module.Compiler.Settings.Version < LanguageVersion.V_3)
2173                                                 bc.Report.FeatureIsNotAvailable (bc.Module.Compiler, loc, "implicitly typed local variable");
2174
2175                                         if (li.IsFixed) {
2176                                                 bc.Report.Error (821, loc, "A fixed statement cannot use an implicitly typed local variable");
2177                                                 return false;
2178                                         }
2179
2180                                         if (li.IsConstant) {
2181                                                 bc.Report.Error (822, loc, "An implicitly typed local variable cannot be a constant");
2182                                                 return false;
2183                                         }
2184
2185                                         if (Initializer == null) {
2186                                                 bc.Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");
2187                                                 return false;
2188                                         }
2189
2190                                         if (declarators != null) {
2191                                                 bc.Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
2192                                                 declarators = null;
2193                                         }
2194
2195                                         Initializer = Initializer.Resolve (bc);
2196                                         if (Initializer != null) {
2197                                                 ((VarExpr) type_expr).InferType (bc, Initializer);
2198                                                 type = type_expr.Type;
2199                                         } else {
2200                                                 // Set error type to indicate the var was placed correctly but could
2201                                                 // not be infered
2202                                                 //
2203                                                 // var a = missing ();
2204                                                 //
2205                                                 type = InternalType.ErrorType;
2206                                         }
2207                                 }
2208
2209                                 if (type == null) {
2210                                         type = ResolveTypeExpression (bc);
2211                                         if (type == null)
2212                                                 return false;
2213
2214                                         if (li.IsConstant && !type.IsConstantCompatible) {
2215                                                 Const.Error_InvalidConstantType (type, loc, bc.Report);
2216                                         }
2217                                 }
2218
2219                                 if (type.IsStatic)
2220                                         FieldBase.Error_VariableOfStaticClass (loc, li.Name, type, bc.Report);
2221
2222                                 li.Type = type;
2223                         }
2224
2225                         bool eval_global = bc.Module.Compiler.Settings.StatementMode && bc.CurrentBlock is ToplevelBlock;
2226                         if (eval_global) {
2227                                 CreateEvaluatorVariable (bc, li);
2228                         } else if (type != InternalType.ErrorType) {
2229                                 li.PrepareAssignmentAnalysis (bc);
2230                         }
2231
2232                         if (initializer != null) {
2233                                 if (li.IsByRef) {
2234                                         if (!(initializer is ReferenceExpression)) {
2235                                                 bc.Report.Error (8172, loc, "Cannot initialize a by-reference variable `{0}' with a value", li.Name);
2236                                                 return false;
2237                                         }
2238
2239                                         if (bc.CurrentAnonymousMethod is AsyncInitializer) {
2240                                                 bc.Report.Error (8177, loc, "Async methods cannot use by-reference variables");
2241                                         } else if (bc.CurrentIterator != null) {
2242                                                 bc.Report.Error (8176, loc, "Iterators cannot use by-reference variables");
2243                                         }
2244
2245                                 } else {
2246                                         if (initializer is ReferenceExpression) {
2247                                                 bc.Report.Error (8171, loc, "Cannot initialize a by-value variable `{0}' with a reference expression", li.Name);
2248                                                 return false;
2249                                         }
2250                                 }
2251
2252                                 initializer = ResolveInitializer (bc, li, initializer);
2253                                 // li.Variable.DefinitelyAssigned 
2254                         }
2255
2256                         if (declarators != null) {
2257                                 foreach (var d in declarators) {
2258                                         d.Variable.Type = li.Type;
2259                                         if (eval_global) {
2260                                                 CreateEvaluatorVariable (bc, d.Variable);
2261                                         } else if (type != InternalType.ErrorType) {
2262                                                 d.Variable.PrepareAssignmentAnalysis (bc);
2263                                         }
2264
2265                                         if (d.Initializer != null && resolveDeclaratorInitializers) {
2266                                                 d.Initializer = ResolveInitializer (bc, d.Variable, d.Initializer);
2267                                                 // d.Variable.DefinitelyAssigned 
2268                                         } 
2269                                 }
2270                         }
2271
2272                         return true;
2273                 }
2274
2275                 protected virtual Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
2276                 {
2277                         var a = new SimpleAssign (li.CreateReferenceExpression (bc, li.Location), initializer, li.Location);
2278                         return a.ResolveStatement (bc);
2279                 }
2280
2281                 protected virtual TypeSpec ResolveTypeExpression (BlockContext bc)
2282                 {
2283                         return type_expr.ResolveAsType (bc);
2284                 }
2285
2286                 protected override void DoEmit (EmitContext ec)
2287                 {
2288                         li.CreateBuilder (ec);
2289
2290                         if (Initializer != null && !IsUnreachable)
2291                                 ((ExpressionStatement) Initializer).EmitStatement (ec);
2292
2293                         if (declarators != null) {
2294                                 foreach (var d in declarators) {
2295                                         d.Variable.CreateBuilder (ec);
2296                                         if (d.Initializer != null && !IsUnreachable) {
2297                                                 ec.Mark (d.Variable.Location);
2298                                                 ((ExpressionStatement) d.Initializer).EmitStatement (ec);
2299                                         }
2300                                 }
2301                         }
2302                 }
2303
2304                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
2305                 {
2306                         if (Initializer != null)
2307                                 Initializer.FlowAnalysis (fc);
2308
2309                         if (declarators != null) {
2310                                 foreach (var d in declarators) {
2311                                         if (d.Initializer != null)
2312                                                 d.Initializer.FlowAnalysis (fc);
2313                                 }
2314                         }
2315
2316                         return false;
2317                 }
2318
2319                 public override Reachability MarkReachable (Reachability rc)
2320                 {
2321                         base.MarkReachable (rc);
2322                         return initializer == null ? rc : initializer.MarkReachable (rc);
2323                 }
2324
2325                 protected override void CloneTo (CloneContext clonectx, Statement target)
2326                 {
2327                         BlockVariable t = (BlockVariable) target;
2328
2329                         if (type_expr != null)
2330                                 t.type_expr = (FullNamedExpression) type_expr.Clone (clonectx);
2331
2332                         if (initializer != null)
2333                                 t.initializer = initializer.Clone (clonectx);
2334
2335                         if (declarators != null) {
2336                                 t.declarators = null;
2337                                 foreach (var d in declarators)
2338                                         t.AddDeclarator (d.Clone (clonectx));
2339                         }
2340                 }
2341
2342                 public override object Accept (StructuralVisitor visitor)
2343                 {
2344                         return visitor.Visit (this);
2345                 }
2346         }
2347
2348         public class BlockConstant : BlockVariable
2349         {
2350                 public BlockConstant (FullNamedExpression type, LocalVariable li)
2351                         : base (type, li)
2352                 {
2353                 }
2354
2355                 public override void Emit (EmitContext ec)
2356                 {
2357                         if (!Variable.IsUsed)
2358                                 ec.Report.Warning (219, 3, loc, "The constant `{0}' is never used", Variable.Name);
2359                         
2360                         // Nothing to emit, not even sequence point
2361                 }
2362
2363                 protected override Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
2364                 {
2365                         initializer = initializer.Resolve (bc);
2366                         if (initializer == null)
2367                                 return null;
2368
2369                         var c = initializer as Constant;
2370                         if (c == null) {
2371                                 initializer.Error_ExpressionMustBeConstant (bc, initializer.Location, li.Name);
2372                                 return null;
2373                         }
2374
2375                         c = c.ConvertImplicitly (li.Type);
2376                         if (c == null) {
2377                                 if (TypeSpec.IsReferenceType (li.Type))
2378                                         initializer.Error_ConstantCanBeInitializedWithNullOnly (bc, li.Type, initializer.Location, li.Name);
2379                                 else
2380                                         initializer.Error_ValueCannotBeConverted (bc, li.Type, false);
2381
2382                                 return null;
2383                         }
2384
2385                         li.ConstantValue = c;
2386                         return initializer;
2387                 }
2388                 
2389                 public override object Accept (StructuralVisitor visitor)
2390                 {
2391                         return visitor.Visit (this);
2392                 }
2393         }
2394
2395         //
2396         // The information about a user-perceived local variable
2397         //
2398         public sealed class LocalVariable : INamedBlockVariable, ILocalVariable
2399         {
2400                 [Flags]
2401                 public enum Flags
2402                 {
2403                         Used = 1,
2404                         IsThis = 1 << 1,
2405                         AddressTaken = 1 << 2,
2406                         CompilerGenerated = 1 << 3,
2407                         Constant = 1 << 4,
2408                         ForeachVariable = 1 << 5,
2409                         FixedVariable = 1 << 6,
2410                         UsingVariable = 1 << 7,
2411                         IsLocked = 1 << 8,
2412                         SymbolFileHidden = 1 << 9,
2413                         ByRef = 1 << 10,
2414
2415                         ReadonlyMask = ForeachVariable | FixedVariable | UsingVariable
2416                 }
2417
2418                 TypeSpec type;
2419                 readonly string name;
2420                 readonly Location loc;
2421                 readonly Block block;
2422                 Flags flags;
2423                 Constant const_value;
2424
2425                 public VariableInfo VariableInfo;
2426                 HoistedVariable hoisted_variant;
2427
2428                 LocalBuilder builder;
2429
2430                 public LocalVariable (Block block, string name, Location loc)
2431                 {
2432                         this.block = block;
2433                         this.name = name;
2434                         this.loc = loc;
2435                 }
2436
2437                 public LocalVariable (Block block, string name, Flags flags, Location loc)
2438                         : this (block, name, loc)
2439                 {
2440                         this.flags = flags;
2441                 }
2442
2443                 //
2444                 // Used by variable declarators
2445                 //
2446                 public LocalVariable (LocalVariable li, string name, Location loc)
2447                         : this (li.block, name, li.flags, loc)
2448                 {
2449                 }
2450
2451                 #region Properties
2452
2453                 public bool AddressTaken {
2454                         get {
2455                                 return (flags & Flags.AddressTaken) != 0;
2456                         }
2457                 }
2458
2459                 public Block Block {
2460                         get {
2461                                 return block;
2462                         }
2463                 }
2464
2465                 public Constant ConstantValue {
2466                         get {
2467                                 return const_value;
2468                         }
2469                         set {
2470                                 const_value = value;
2471                         }
2472                 }
2473
2474                 //
2475                 // Hoisted local variable variant
2476                 //
2477                 public HoistedVariable HoistedVariant {
2478                         get {
2479                                 return hoisted_variant;
2480                         }
2481                         set {
2482                                 hoisted_variant = value;
2483                         }
2484                 }
2485
2486                 public bool Created {
2487                         get {
2488                                 return builder != null;
2489                         }
2490                 }
2491
2492                 public bool IsDeclared {
2493                         get {
2494                                 return type != null;
2495                         }
2496                 }
2497
2498                 public bool IsByRef => (flags & Flags.ByRef) != 0;
2499
2500                 public bool IsCompilerGenerated {
2501                         get {
2502                                 return (flags & Flags.CompilerGenerated) != 0;
2503                         }
2504                 }
2505
2506                 public bool IsConstant {
2507                         get {
2508                                 return (flags & Flags.Constant) != 0;
2509                         }
2510                 }
2511
2512                 public bool IsLocked {
2513                         get {
2514                                 return (flags & Flags.IsLocked) != 0;
2515                         }
2516                         set {
2517                                 flags = value ? flags | Flags.IsLocked : flags & ~Flags.IsLocked;
2518                         }
2519                 }
2520
2521                 public bool IsThis {
2522                         get {
2523                                 return (flags & Flags.IsThis) != 0;
2524                         }
2525                 }
2526
2527                 public bool IsUsed {
2528                         get {
2529                                 return (flags & Flags.Used) != 0;
2530                         }
2531                 }
2532
2533                 public bool IsFixed {
2534                         get {
2535                                 return (flags & Flags.FixedVariable) != 0;
2536                         }
2537                         set {
2538                                 flags = value ? flags | Flags.FixedVariable : flags & ~Flags.FixedVariable;
2539                         }
2540                 }
2541
2542                 bool INamedBlockVariable.IsParameter {
2543                         get {
2544                                 return false;
2545                         }
2546                 }
2547
2548                 public bool IsReadonly {
2549                         get {
2550                                 return (flags & Flags.ReadonlyMask) != 0;
2551                         }
2552                 }
2553
2554                 public Location Location {
2555                         get {
2556                                 return loc;
2557                         }
2558                 }
2559
2560                 public string Name {
2561                         get {
2562                                 return name;
2563                         }
2564                 }
2565
2566                 public TypeSpec Type {
2567                     get {
2568                                 return type;
2569                         }
2570                     set {
2571                                 type = value;
2572                         }
2573                 }
2574
2575                 #endregion
2576
2577                 public void CreateBuilder (EmitContext ec)
2578                 {
2579                         if ((flags & Flags.Used) == 0) {
2580                                 if (VariableInfo == null) {
2581                                         // Missing flow analysis or wrong variable flags
2582                                         throw new InternalErrorException ("VariableInfo is null and the variable `{0}' is not used", name);
2583                                 }
2584
2585                                 if (VariableInfo.IsEverAssigned)
2586                                         ec.Report.Warning (219, 3, Location, "The variable `{0}' is assigned but its value is never used", Name);
2587                                 else
2588                                         ec.Report.Warning (168, 3, Location, "The variable `{0}' is declared but never used", Name);
2589                         }
2590
2591                         if (HoistedVariant != null)
2592                                 return;
2593
2594                         if (builder != null) {
2595                                 if ((flags & Flags.CompilerGenerated) != 0)
2596                                         return;
2597
2598                                 // To avoid Used warning duplicates
2599                                 throw new InternalErrorException ("Already created variable `{0}'", name);
2600                         }
2601
2602                         if (IsByRef) {
2603                                 builder = ec.DeclareLocal (ReferenceContainer.MakeType (ec.Module, Type), IsFixed);
2604                         } else {
2605                                 //
2606                                 // All fixed variabled are pinned, a slot has to be alocated
2607                                 //
2608                                 builder = ec.DeclareLocal(Type, IsFixed);
2609                         }
2610
2611                         if ((flags & Flags.SymbolFileHidden) == 0)
2612                                 ec.DefineLocalVariable (name, builder);
2613                 }
2614
2615                 public static LocalVariable CreateCompilerGenerated (TypeSpec type, Block block, Location loc, bool writeToSymbolFile = false)
2616                 {
2617                         LocalVariable li = new LocalVariable (block, GetCompilerGeneratedName (block), Flags.CompilerGenerated | Flags.Used, loc);
2618                         if (!writeToSymbolFile)
2619                                 li.flags |= Flags.SymbolFileHidden;
2620                         
2621                         li.Type = type;
2622                         return li;
2623                 }
2624
2625                 public Expression CreateReferenceExpression (ResolveContext rc, Location loc)
2626                 {
2627                         if (IsConstant && const_value != null) {
2628                                 SetIsUsed ();
2629                                 return Constant.CreateConstantFromValue (Type, const_value.GetValue (), loc);
2630                         }
2631
2632                         return new LocalVariableReference (this, loc);
2633                 }
2634
2635                 public void Emit (EmitContext ec)
2636                 {
2637                         // TODO: Need something better for temporary variables
2638                         if ((flags & Flags.CompilerGenerated) != 0)
2639                                 CreateBuilder (ec);
2640
2641                         ec.Emit (OpCodes.Ldloc, builder);
2642                 }
2643
2644                 public void EmitAssign (EmitContext ec)
2645                 {
2646                         // TODO: Need something better for temporary variables
2647                         if ((flags & Flags.CompilerGenerated) != 0)
2648                                 CreateBuilder (ec);
2649
2650                         ec.Emit (OpCodes.Stloc, builder);
2651                 }
2652
2653                 public void EmitAddressOf (EmitContext ec)
2654                 {
2655                         // TODO: Need something better for temporary variables
2656                         if ((flags & Flags.CompilerGenerated) != 0)
2657                                 CreateBuilder (ec);
2658
2659                         if (IsByRef)
2660                                 ec.Emit (OpCodes.Ldloc, builder);
2661                         else
2662                                 ec.Emit (OpCodes.Ldloca, builder);
2663                 }
2664
2665                 public static string GetCompilerGeneratedName (Block block)
2666                 {
2667                         // HACK: Debugger depends on the name semantics
2668                         return "$locvar" + block.ParametersBlock.TemporaryLocalsCount++.ToString ("X");
2669                 }
2670
2671                 public string GetReadOnlyContext ()
2672                 {
2673                         switch (flags & Flags.ReadonlyMask) {
2674                         case Flags.FixedVariable:
2675                                 return "fixed variable";
2676                         case Flags.ForeachVariable:
2677                                 return "foreach iteration variable";
2678                         case Flags.UsingVariable:
2679                                 return "using variable";
2680                         }
2681
2682                         throw new InternalErrorException ("Variable is not readonly");
2683                 }
2684
2685                 public bool IsThisAssigned (FlowAnalysisContext fc, Block block)
2686                 {
2687                         if (VariableInfo == null)
2688                                 throw new Exception ();
2689
2690                         if (IsAssigned (fc))
2691                                 return true;
2692
2693                         return VariableInfo.IsFullyInitialized (fc, block.StartLocation);
2694                 }
2695
2696                 public bool IsAssigned (FlowAnalysisContext fc)
2697                 {
2698                         return fc.IsDefinitelyAssigned (VariableInfo);
2699                 }
2700
2701                 public void PrepareAssignmentAnalysis (BlockContext bc)
2702                 {
2703                         //
2704                         // No need to run assignment analysis for these guys
2705                         //
2706                         if ((flags & (Flags.Constant | Flags.ReadonlyMask | Flags.CompilerGenerated)) != 0)
2707                                 return;
2708
2709                         VariableInfo = VariableInfo.Create (bc, this);
2710                 }
2711
2712                 //
2713                 // Mark the variables as referenced in the user code
2714                 //
2715                 public void SetIsUsed ()
2716                 {
2717                         flags |= Flags.Used;
2718                 }
2719
2720                 public void SetHasAddressTaken ()
2721                 {
2722                         flags |= (Flags.AddressTaken | Flags.Used);
2723                 }
2724
2725                 public override string ToString ()
2726                 {
2727                         return string.Format ("LocalInfo ({0},{1},{2},{3})", name, type, VariableInfo, Location);
2728                 }
2729         }
2730
2731         /// <summary>
2732         ///   Block represents a C# block.
2733         /// </summary>
2734         ///
2735         /// <remarks>
2736         ///   This class is used in a number of places: either to represent
2737         ///   explicit blocks that the programmer places or implicit blocks.
2738         ///
2739         ///   Implicit blocks are used as labels or to introduce variable
2740         ///   declarations.
2741         ///
2742         ///   Top-level blocks derive from Block, and they are called ToplevelBlock
2743         ///   they contain extra information that is not necessary on normal blocks.
2744         /// </remarks>
2745         public class Block : Statement {
2746                 [Flags]
2747                 public enum Flags
2748                 {
2749                         Unchecked = 1,
2750                         ReachableEnd = 8,
2751                         Unsafe = 16,
2752                         HasCapturedVariable = 64,
2753                         HasCapturedThis = 1 << 7,
2754                         IsExpressionTree = 1 << 8,
2755                         CompilerGenerated = 1 << 9,
2756                         HasAsyncModifier = 1 << 10,
2757                         Resolved = 1 << 11,
2758                         YieldBlock = 1 << 12,
2759                         AwaitBlock = 1 << 13,
2760                         FinallyBlock = 1 << 14,
2761                         CatchBlock = 1 << 15,
2762                         HasReferenceToStoreyForInstanceLambdas = 1 << 16,
2763                         Iterator = 1 << 20,
2764                         NoFlowAnalysis = 1 << 21,
2765                         InitializationEmitted = 1 << 22
2766                 }
2767
2768                 public Block Parent;
2769                 public Location StartLocation;
2770                 public Location EndLocation;
2771
2772                 public ExplicitBlock Explicit;
2773                 public ParametersBlock ParametersBlock;
2774
2775                 protected Flags flags;
2776
2777                 //
2778                 // The statements in this block
2779                 //
2780                 protected List<Statement> statements;
2781
2782                 protected List<Statement> scope_initializers;
2783
2784                 int? resolving_init_idx;
2785
2786                 Block original;
2787
2788 #if DEBUG
2789                 static int id;
2790                 public int ID = id++;
2791
2792                 static int clone_id_counter;
2793                 int clone_id;
2794 #endif
2795
2796 //              int assignable_slots;
2797
2798                 public Block (Block parent, Location start, Location end)
2799                         : this (parent, 0, start, end)
2800                 {
2801                 }
2802
2803                 public Block (Block parent, Flags flags, Location start, Location end)
2804                 {
2805                         if (parent != null) {
2806                                 // the appropriate constructors will fixup these fields
2807                                 ParametersBlock = parent.ParametersBlock;
2808                                 Explicit = parent.Explicit;
2809                         }
2810                         
2811                         this.Parent = parent;
2812                         this.flags = flags;
2813                         this.StartLocation = start;
2814                         this.EndLocation = end;
2815                         this.loc = start;
2816                         statements = new List<Statement> (4);
2817
2818                         this.original = this;
2819                 }
2820
2821                 #region Properties
2822
2823                 public Block Original {
2824                         get {
2825                                 return original;
2826                         }
2827                         protected set {
2828                                 original = value;
2829                         }
2830                 }
2831
2832                 public bool IsCompilerGenerated {
2833                         get { return (flags & Flags.CompilerGenerated) != 0; }
2834                         set { flags = value ? flags | Flags.CompilerGenerated : flags & ~Flags.CompilerGenerated; }
2835                 }
2836
2837
2838                 public bool IsCatchBlock {
2839                         get {
2840                                 return (flags & Flags.CatchBlock) != 0;
2841                         }
2842                 }
2843
2844                 public bool IsFinallyBlock {
2845                         get {
2846                                 return (flags & Flags.FinallyBlock) != 0;
2847                         }
2848                 }
2849
2850                 public bool Unchecked {
2851                         get { return (flags & Flags.Unchecked) != 0; }
2852                         set { flags = value ? flags | Flags.Unchecked : flags & ~Flags.Unchecked; }
2853                 }
2854
2855                 public bool Unsafe {
2856                         get { return (flags & Flags.Unsafe) != 0; }
2857                         set { flags |= Flags.Unsafe; }
2858                 }
2859
2860                 public List<Statement> Statements {
2861                         get { return statements; }
2862                 }
2863
2864                 #endregion
2865
2866                 public void SetEndLocation (Location loc)
2867                 {
2868                         EndLocation = loc;
2869                 }
2870
2871                 public void AddLabel (LabeledStatement target)
2872                 {
2873                         ParametersBlock.TopBlock.AddLabel (target.Name, target);
2874                 }
2875
2876                 public void AddLocalName (LocalVariable li)
2877                 {
2878                         AddLocalName (li.Name, li);
2879                 }
2880
2881                 public void AddLocalName (string name, INamedBlockVariable li)
2882                 {
2883                         ParametersBlock.TopBlock.AddLocalName (name, li, false);
2884                 }
2885
2886                 public virtual void Error_AlreadyDeclared (string name, INamedBlockVariable variable, string reason)
2887                 {
2888                         if (reason == null) {
2889                                 Error_AlreadyDeclared (name, variable);
2890                                 return;
2891                         }
2892
2893                         ParametersBlock.TopBlock.Report.Error (136, variable.Location,
2894                                 "A local variable named `{0}' cannot be declared in this scope because it would give a different meaning " +
2895                                 "to `{0}', which is already used in a `{1}' scope to denote something else",
2896                                 name, reason);
2897                 }
2898
2899                 public virtual void Error_AlreadyDeclared (string name, INamedBlockVariable variable)
2900                 {
2901                         var pi = variable as ParametersBlock.ParameterInfo;
2902                         if (pi != null) {
2903                                 pi.Parameter.Error_DuplicateName (ParametersBlock.TopBlock.Report);
2904                         } else {
2905                                 ParametersBlock.TopBlock.Report.Error (128, variable.Location,
2906                                         "A local variable named `{0}' is already defined in this scope", name);
2907                         }
2908                 }
2909                                         
2910                 public virtual void Error_AlreadyDeclaredTypeParameter (string name, Location loc)
2911                 {
2912                         ParametersBlock.TopBlock.Report.Error (412, loc,
2913                                 "The type parameter name `{0}' is the same as local variable or parameter name",
2914                                 name);
2915                 }
2916
2917                 //
2918                 // It should be used by expressions which require to
2919                 // register a statement during resolve process.
2920                 //
2921                 public void AddScopeStatement (Statement s)
2922                 {
2923                         if (scope_initializers == null)
2924                                 scope_initializers = new List<Statement> ();
2925
2926                         //
2927                         // Simple recursive helper, when resolve scope initializer another
2928                         // new scope initializer can be added, this ensures it's initialized
2929                         // before existing one. For now this can happen with expression trees
2930                         // in base ctor initializer only
2931                         //
2932                         if (resolving_init_idx.HasValue) {
2933                                 scope_initializers.Insert (resolving_init_idx.Value, s);
2934                                 ++resolving_init_idx;
2935                         } else {
2936                                 scope_initializers.Add (s);
2937                         }
2938                 }
2939
2940                 public void InsertStatement (int index, Statement s)
2941                 {
2942                         statements.Insert (index, s);
2943                 }
2944                 
2945                 public void AddStatement (Statement s)
2946                 {
2947                         statements.Add (s);
2948                 }
2949
2950                 public LabeledStatement LookupLabel (string name)
2951                 {
2952                         return ParametersBlock.GetLabel (name, this);
2953                 }
2954
2955                 public override Reachability MarkReachable (Reachability rc)
2956                 {
2957                         if (rc.IsUnreachable)
2958                                 return rc;
2959
2960                         MarkReachableScope (rc);
2961
2962                         foreach (var s in statements) {
2963                                 rc = s.MarkReachable (rc);
2964                                 if (rc.IsUnreachable) {
2965                                         if ((flags & Flags.ReachableEnd) != 0)
2966                                                 return new Reachability ();
2967
2968                                         return rc;
2969                                 }
2970                         }
2971
2972                         flags |= Flags.ReachableEnd;
2973
2974                         return rc;
2975                 }
2976
2977                 public void MarkReachableScope (Reachability rc)
2978                 {
2979                         base.MarkReachable (rc);
2980
2981                         if (scope_initializers != null) {
2982                                 foreach (var si in scope_initializers)
2983                                         si.MarkReachable (rc);
2984                         }
2985                 }
2986
2987                 public override bool Resolve (BlockContext bc)
2988                 {
2989                         if ((flags & Flags.Resolved) != 0)
2990                                 return true;
2991
2992                         Block prev_block = bc.CurrentBlock;
2993                         bc.CurrentBlock = this;
2994
2995                         //
2996                         // Compiler generated scope statements
2997                         //
2998                         if (scope_initializers != null) {
2999                                 for (resolving_init_idx = 0; resolving_init_idx < scope_initializers.Count; ++resolving_init_idx) {
3000                                         scope_initializers[resolving_init_idx.Value].Resolve (bc);
3001                                 }
3002
3003                                 resolving_init_idx = null;
3004                         }
3005
3006                         bool ok = true;
3007                         int statement_count = statements.Count;
3008                         for (int ix = 0; ix < statement_count; ix++){
3009                                 Statement s = statements [ix];
3010
3011                                 if (!s.Resolve (bc)) {
3012                                         ok = false;
3013                                         statements [ix] = new EmptyStatement (s.loc);
3014                                         continue;
3015                                 }
3016                         }
3017
3018                         bc.CurrentBlock = prev_block;
3019
3020                         flags |= Flags.Resolved;
3021                         return ok;
3022                 }
3023
3024                 protected override void DoEmit (EmitContext ec)
3025                 {
3026                         for (int ix = 0; ix < statements.Count; ix++){
3027                                 statements [ix].Emit (ec);
3028                         }
3029                 }
3030
3031                 public override void Emit (EmitContext ec)
3032                 {
3033                         if (scope_initializers != null)
3034                                 EmitScopeInitializers (ec);
3035
3036                         DoEmit (ec);
3037                 }
3038
3039                 protected void EmitScopeInitializers (EmitContext ec)
3040                 {
3041                         foreach (Statement s in scope_initializers)
3042                                 s.Emit (ec);
3043                 }
3044
3045                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
3046                 {
3047                         if (scope_initializers != null) {
3048                                 foreach (var si in scope_initializers)
3049                                         si.FlowAnalysis (fc);
3050                         }
3051
3052                         return DoFlowAnalysis (fc, 0);  
3053                 }
3054
3055                 bool DoFlowAnalysis (FlowAnalysisContext fc, int startIndex)
3056                 {
3057                         bool end_unreachable = !reachable;
3058                         bool goto_flow_analysis = startIndex != 0;
3059                         for (; startIndex < statements.Count; ++startIndex) {
3060                                 var s = statements[startIndex];
3061
3062                                 end_unreachable = s.FlowAnalysis (fc);
3063                                 if (s.IsUnreachable) {
3064                                         statements [startIndex] = RewriteUnreachableStatement (s);
3065                                         continue;
3066                                 }
3067
3068                                 //
3069                                 // Statement end reachability is needed mostly due to goto support. Consider
3070                                 //
3071                                 // if (cond) {
3072                                 //    goto X;
3073                                 // } else {
3074                                 //    goto Y;
3075                                 // }
3076                                 // X:
3077                                 //
3078                                 // X label is reachable only via goto not as another statement after if. We need
3079                                 // this for flow-analysis only to carry variable info correctly.
3080                                 //
3081                                 if (end_unreachable) {
3082                                         bool after_goto_case = goto_flow_analysis && s is GotoCase;
3083
3084                                         var f = s as TryFinally;
3085                                         if (f != null && !f.FinallyBlock.HasReachableClosingBrace) {
3086                                                 //
3087                                                 // Special case for try-finally with unreachable code after
3088                                                 // finally block. Try block has to include leave opcode but there is
3089                                                 // no label to leave to after unreachable finally block closing
3090                                                 // brace. This sentinel ensures there is always IL instruction to
3091                                                 // leave to even if we know it'll never be reached.
3092                                                 //
3093                                                 statements.Insert (startIndex + 1, new SentinelStatement ());
3094                                         } else {
3095                                                 for (++startIndex; startIndex < statements.Count; ++startIndex) {
3096                                                         s = statements [startIndex];
3097                                                         if (s is SwitchLabel) {
3098                                                                 if (!after_goto_case)
3099                                                                         s.FlowAnalysis (fc);
3100
3101                                                                 break;
3102                                                         }
3103
3104                                                         if (s.IsUnreachable) {
3105                                                                 s.FlowAnalysis (fc);
3106                                                                 statements [startIndex] = RewriteUnreachableStatement (s);
3107                                                         }
3108                                                 }
3109                                         }
3110
3111                                         //
3112                                         // Idea is to stop after goto case because goto case will always have at least same
3113                                         // variable assigned as switch case label. This saves a lot for complex goto case tests
3114                                         //
3115                                         if (after_goto_case)
3116                                                 break;
3117
3118                                         continue;
3119                                 }
3120
3121                                 var lb = s as LabeledStatement;
3122                                 if (lb != null && fc.AddReachedLabel (lb))
3123                                         break;
3124                         }
3125
3126                         //
3127                         // The condition should be true unless there is forward jumping goto
3128                         // 
3129                         // if (this is ExplicitBlock && end_unreachable != Explicit.HasReachableClosingBrace)
3130                         //      Debug.Fail ();
3131
3132                         return !Explicit.HasReachableClosingBrace;
3133                 }
3134
3135                 static Statement RewriteUnreachableStatement (Statement s)
3136                 {
3137                         // LAMESPEC: It's not clear whether declararion statement should be part of reachability
3138                         // analysis. Even csc report unreachable warning for it but it's actually used hence
3139                         // we try to emulate this behaviour
3140                         //
3141                         // Consider:
3142                         //      goto L;
3143                         //      int v;
3144                         // L:
3145                         //      v = 1;
3146
3147                         if (s is BlockVariable || s is EmptyStatement || s is SentinelStatement)
3148                                 return s;
3149
3150                         return new EmptyStatement (s.loc);
3151                 }
3152
3153                 public void ScanGotoJump (Statement label)
3154                 {
3155                         int i;
3156                         for (i = 0; i < statements.Count; ++i) {
3157                                 if (statements[i] == label)
3158                                         break;
3159                         }
3160
3161                         var rc = new Reachability ();
3162                         for (++i; i < statements.Count; ++i) {
3163                                 var s = statements[i];
3164                                 rc = s.MarkReachable (rc);
3165                                 if (rc.IsUnreachable)
3166                                         return;
3167                         }
3168
3169                         flags |= Flags.ReachableEnd;
3170                 }
3171
3172                 public void ScanGotoJump (Statement label, FlowAnalysisContext fc)
3173                 {
3174                         int i;
3175                         for (i = 0; i < statements.Count; ++i) {
3176                                 if (statements[i] == label)
3177                                         break;
3178                         }
3179
3180                         DoFlowAnalysis (fc, ++i);
3181                 }
3182
3183 #if DEBUG
3184                 public override string ToString ()
3185                 {
3186                         return String.Format ("{0}: ID={1} Clone={2} Location={3}", GetType (), ID, clone_id != 0, StartLocation);
3187                 }
3188 #endif
3189
3190                 protected override void CloneTo (CloneContext clonectx, Statement t)
3191                 {
3192                         Block target = (Block) t;
3193 #if DEBUG
3194                         target.clone_id = ++clone_id_counter;
3195 #endif
3196
3197                         clonectx.AddBlockMap (this, target);
3198                         if (original != this)
3199                                 clonectx.AddBlockMap (original, target);
3200
3201                         target.ParametersBlock = (ParametersBlock) (ParametersBlock == this ? target : clonectx.RemapBlockCopy (ParametersBlock));
3202                         target.Explicit = (ExplicitBlock) (Explicit == this ? target : clonectx.LookupBlock (Explicit));
3203
3204                         if (Parent != null)
3205                                 target.Parent = clonectx.RemapBlockCopy (Parent);
3206
3207                         target.statements = new List<Statement> (statements.Count);
3208                         foreach (Statement s in statements)
3209                                 target.statements.Add (s.Clone (clonectx));
3210                 }
3211
3212                 public override object Accept (StructuralVisitor visitor)
3213                 {
3214                         return visitor.Visit (this);
3215                 }
3216         }
3217
3218         public class ExplicitBlock : Block
3219         {
3220                 protected AnonymousMethodStorey am_storey;
3221                 int debug_scope_index;
3222
3223                 public ExplicitBlock (Block parent, Location start, Location end)
3224                         : this (parent, (Flags) 0, start, end)
3225                 {
3226                 }
3227
3228                 public ExplicitBlock (Block parent, Flags flags, Location start, Location end)
3229                         : base (parent, flags, start, end)
3230                 {
3231                         this.Explicit = this;
3232                 }
3233
3234                 #region Properties
3235
3236                 public AnonymousMethodStorey AnonymousMethodStorey {
3237                         get {
3238                                 return am_storey;
3239                         }
3240                 }
3241
3242                 public bool HasAwait {
3243                         get {
3244                                 return (flags & Flags.AwaitBlock) != 0;
3245                         }
3246                 }
3247
3248                 public bool HasCapturedThis {
3249                         set {
3250                                 flags = value ? flags | Flags.HasCapturedThis : flags & ~Flags.HasCapturedThis;
3251                         }
3252                         get {
3253                                 return (flags & Flags.HasCapturedThis) != 0;
3254                         }
3255                 }
3256
3257                 //
3258                 // Used to indicate that the block has reference to parent
3259                 // block and cannot be made static when defining anonymous method
3260                 //
3261                 public bool HasCapturedVariable {
3262                         set {
3263                                 flags = value ? flags | Flags.HasCapturedVariable : flags & ~Flags.HasCapturedVariable;
3264                         }
3265                         get {
3266                                 return (flags & Flags.HasCapturedVariable) != 0;
3267                         }
3268                 }
3269
3270                 public bool HasReachableClosingBrace {
3271                     get {
3272                         return (flags & Flags.ReachableEnd) != 0;
3273                     }
3274                         set {
3275                                 flags = value ? flags | Flags.ReachableEnd : flags & ~Flags.ReachableEnd;
3276                         }
3277                 }
3278
3279                 public bool HasYield {
3280                         get {
3281                                 return (flags & Flags.YieldBlock) != 0;
3282                         }
3283                 }
3284
3285                 #endregion
3286
3287                 //
3288                 // Creates anonymous method storey in current block
3289                 //
3290                 public AnonymousMethodStorey CreateAnonymousMethodStorey (ResolveContext ec)
3291                 {
3292                         //
3293                         // Return same story for iterator and async blocks unless we are
3294                         // in nested anonymous method
3295                         //
3296                         if (ec.CurrentAnonymousMethod is StateMachineInitializer && ParametersBlock.Original == ec.CurrentAnonymousMethod.Block.Original)
3297                                 return ec.CurrentAnonymousMethod.Storey;
3298
3299                         if (am_storey == null) {
3300                                 MemberBase mc = ec.MemberContext as MemberBase;
3301
3302                                 //
3303                                 // Creates anonymous method storey for this block
3304                                 //
3305                                 am_storey = new AnonymousMethodStorey (this, ec.CurrentMemberDefinition.Parent.PartialContainer, mc, ec.CurrentTypeParameters, "AnonStorey", MemberKind.Class);
3306                         }
3307
3308                         return am_storey;
3309                 }
3310
3311                 public void EmitScopeInitialization (EmitContext ec)
3312                 {
3313                         if ((flags & Flags.InitializationEmitted) != 0)
3314                                 return;
3315
3316                         if (am_storey != null) {
3317                                 DefineStoreyContainer (ec, am_storey);
3318                                 am_storey.EmitStoreyInstantiation (ec, this);
3319                         }
3320
3321                         if (scope_initializers != null)
3322                                 EmitScopeInitializers (ec);
3323
3324                         flags |= Flags.InitializationEmitted;
3325                 }
3326
3327                 public override void Emit (EmitContext ec)
3328                 {
3329                         // TODO: It's needed only when scope has variable (normal or lifted)
3330                         var scopeIndex = GetDebugSymbolScopeIndex ();
3331                         if (scopeIndex > 0) {
3332                                 ec.BeginScope (scopeIndex);
3333                         }
3334
3335                         EmitScopeInitialization (ec);
3336
3337                         if (ec.EmitAccurateDebugInfo && !IsCompilerGenerated && ec.Mark (StartLocation)) {
3338                                 ec.Emit (OpCodes.Nop);
3339                         }
3340
3341                         DoEmit (ec);
3342
3343                         if (scopeIndex > 0)
3344                                 ec.EndScope ();
3345
3346                         if (ec.EmitAccurateDebugInfo && HasReachableClosingBrace && !(this is ParametersBlock) &&
3347                                 !IsCompilerGenerated && ec.Mark (EndLocation)) {
3348                                 ec.Emit (OpCodes.Nop);
3349                         }
3350                 }
3351
3352                 protected void DefineStoreyContainer (EmitContext ec, AnonymousMethodStorey storey)
3353                 {
3354                         if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.Storey != null) {
3355                                 storey.SetNestedStoryParent (ec.CurrentAnonymousMethod.Storey);
3356                                 storey.Mutator = ec.CurrentAnonymousMethod.Storey.Mutator;
3357                         }
3358
3359                         //
3360                         // Creates anonymous method storey
3361                         //
3362                         storey.CreateContainer ();
3363                         storey.DefineContainer ();
3364                         storey.ExpandBaseInterfaces ();
3365
3366                         if (Original.Explicit.HasCapturedThis && Original.ParametersBlock.TopBlock.ThisReferencesFromChildrenBlock != null) {
3367
3368                                 //
3369                                 // Only first storey in path will hold this reference. All children blocks will
3370                                 // reference it indirectly using $ref field
3371                                 //
3372                                 for (Block b = Original.Explicit; b != null; b = b.Parent) {
3373                                         if (b.Parent != null) {
3374                                                 var s = b.Parent.Explicit.AnonymousMethodStorey;
3375                                                 if (s != null) {
3376                                                         storey.HoistedThis = s.HoistedThis;
3377                                                         break;
3378                                                 }
3379                                         }
3380
3381                                         if (b.Explicit == b.Explicit.ParametersBlock && b.Explicit.ParametersBlock.StateMachine != null) {
3382                                                 if (storey.HoistedThis == null)
3383                                                         storey.HoistedThis = b.Explicit.ParametersBlock.StateMachine.HoistedThis;
3384
3385                                                 if (storey.HoistedThis != null)
3386                                                         break;
3387                                         }
3388                                 }
3389
3390                                 //
3391                                 // We are the first storey on path and 'this' has to be hoisted
3392                                 //
3393                                 if (storey.HoistedThis == null || !(storey.Parent is HoistedStoreyClass)) {
3394                                         foreach (ExplicitBlock ref_block in Original.ParametersBlock.TopBlock.ThisReferencesFromChildrenBlock) {
3395                                                 //
3396                                                 // ThisReferencesFromChildrenBlock holds all reference even if they
3397                                                 // are not on this path. It saves some memory otherwise it'd have to
3398                                                 // be in every explicit block. We run this check to see if the reference
3399                                                 // is valid for this storey
3400                                                 //
3401                                                 Block block_on_path = ref_block;
3402                                                 for (; block_on_path != null && block_on_path != Original; block_on_path = block_on_path.Parent);
3403
3404                                                 if (block_on_path == null)
3405                                                         continue;
3406
3407                                                 if (storey.HoistedThis == null) {
3408                                                         storey.AddCapturedThisField (ec, null);
3409                                                 }
3410
3411                                                 for (ExplicitBlock b = ref_block; b.AnonymousMethodStorey != storey; b = b.Parent.Explicit) {
3412                                                         ParametersBlock pb;
3413                                                         AnonymousMethodStorey b_storey = b.AnonymousMethodStorey;
3414
3415                                                         if (b_storey != null) {
3416                                                                 //
3417                                                                 // Don't add storey cross reference for `this' when the storey ends up not
3418                                                                 // beeing attached to any parent
3419                                                                 //
3420                                                                 if (b.ParametersBlock.StateMachine == null) {
3421                                                                         AnonymousMethodStorey s = null;
3422                                                                         for (Block ab = b.AnonymousMethodStorey.OriginalSourceBlock.Parent; ab != null; ab = ab.Parent) {
3423                                                                                 s = ab.Explicit.AnonymousMethodStorey;
3424                                                                                 if (s != null)
3425                                                                                         break;
3426                                                                         }
3427
3428                                                                         // Needs to be in sync with AnonymousMethodBody::DoCreateMethodHost
3429                                                                         if (s == null) {
3430                                                                                 var parent = storey == null || storey.Kind == MemberKind.Struct ? null : storey;
3431                                                                                 b.AnonymousMethodStorey.AddCapturedThisField (ec, parent);
3432                                                                                 break;
3433                                                                         }
3434
3435                                                                 }
3436
3437                                                                 //
3438                                                                 // Stop propagation inside same top block
3439                                                                 //
3440                                                                 if (b.ParametersBlock == ParametersBlock.Original) {
3441                                                                         b_storey.AddParentStoreyReference (ec, storey);
3442 //                                                                      b_storey.HoistedThis = storey.HoistedThis;
3443                                                                         break;
3444                                                                 }
3445
3446                                                                 b = pb = b.ParametersBlock;
3447                                                         } else {
3448                                                                 pb = b as ParametersBlock;
3449                                                         }
3450
3451                                                         if (pb != null && pb.StateMachine != null) {
3452                                                                 if (pb.StateMachine == storey)
3453                                                                         break;
3454
3455                                                                 //
3456                                                                 // If we are state machine with no parent. We can hook into parent without additional
3457                                                                 // reference and capture this directly
3458                                                                 //
3459                                                                 ExplicitBlock parent_storey_block = pb;
3460                                                                 while (parent_storey_block.Parent != null) {
3461                                                                         parent_storey_block = parent_storey_block.Parent.Explicit;
3462                                                                         if (parent_storey_block.AnonymousMethodStorey != null) {
3463                                                                                 break;
3464                                                                         }
3465                                                                 }
3466
3467                                                                 if (parent_storey_block.AnonymousMethodStorey == null) {
3468                                                                         if (pb.StateMachine.HoistedThis == null) {
3469                                                                                 pb.StateMachine.AddCapturedThisField (ec, null);
3470                                                                                 b.HasCapturedThis = true;
3471                                                                         }
3472
3473                                                                         continue;
3474                                                                 }
3475
3476                                                                 var parent_this_block = pb;
3477                                                                 while (parent_this_block.Parent != null) {
3478                                                                         parent_this_block = parent_this_block.Parent.ParametersBlock;
3479                                                                         if (parent_this_block.StateMachine != null && parent_this_block.StateMachine.HoistedThis != null) {
3480                                                                                 break;
3481                                                                         }
3482                                                                 }
3483
3484                                                                 //
3485                                                                 // Add reference to closest storey which holds captured this
3486                                                                 //
3487                                                                 pb.StateMachine.AddParentStoreyReference (ec, parent_this_block.StateMachine ?? storey);
3488                                                         }
3489
3490                                                         //
3491                                                         // Add parent storey reference only when this is not captured directly
3492                                                         //
3493                                                         if (b_storey != null) {
3494                                                                 b_storey.AddParentStoreyReference (ec, storey);
3495                                                                 b_storey.HoistedThis = storey.HoistedThis;
3496                                                         }
3497                                                 }
3498                                         }
3499                                 }
3500                         }
3501
3502                         var ref_blocks = storey.ReferencesFromChildrenBlock;
3503                         if (ref_blocks != null) {
3504                                 foreach (ExplicitBlock ref_block in ref_blocks) {
3505                                         for (ExplicitBlock b = ref_block; b.AnonymousMethodStorey != storey; b = b.Parent.Explicit) {
3506                                                 if (b.AnonymousMethodStorey != null) {
3507                                                         b.AnonymousMethodStorey.AddParentStoreyReference (ec, storey);
3508
3509                                                         //
3510                                                         // Stop propagation inside same top block
3511                                                         //
3512                                                         if (b.ParametersBlock == ParametersBlock.Original)
3513                                                                 break;
3514
3515                                                         b = b.ParametersBlock;
3516                                                 }
3517
3518                                                 var pb = b as ParametersBlock;
3519                                                 if (pb != null && pb.StateMachine != null) {
3520                                                         if (pb.StateMachine == storey)
3521                                                                 break;
3522
3523                                                         pb.StateMachine.AddParentStoreyReference (ec, storey);
3524                                                 }
3525
3526                                                 b.HasCapturedVariable = true;
3527                                         }
3528                                 }
3529                         }
3530
3531                         storey.Define ();
3532                         storey.PrepareEmit ();
3533                         storey.Parent.PartialContainer.AddCompilerGeneratedClass (storey);
3534                 }
3535
3536                 public void DisableDebugScopeIndex ()
3537                 {
3538                         debug_scope_index = -1;
3539                 }
3540
3541                 public virtual int GetDebugSymbolScopeIndex ()
3542                 {
3543                         if (debug_scope_index == 0)
3544                                 debug_scope_index = ++ParametersBlock.debug_scope_index;
3545
3546                         return debug_scope_index;
3547                 }
3548
3549                 public void RegisterAsyncAwait ()
3550                 {
3551                         var block = this;
3552                         while ((block.flags & Flags.AwaitBlock) == 0) {
3553                                 block.flags |= Flags.AwaitBlock;
3554
3555                                 if (block is ParametersBlock)
3556                                         return;
3557
3558                                 block = block.Parent.Explicit;
3559                         }
3560                 }
3561
3562                 public void RegisterIteratorYield ()
3563                 {
3564                         ParametersBlock.TopBlock.IsIterator = true;
3565
3566                         var block = this;
3567                         while ((block.flags & Flags.YieldBlock) == 0) {
3568                                 block.flags |= Flags.YieldBlock;
3569
3570                                 if (block.Parent == null)
3571                                         return;
3572
3573                                 block = block.Parent.Explicit;
3574                         }
3575                 }
3576
3577                 public void SetCatchBlock ()
3578                 {
3579                         flags |= Flags.CatchBlock;
3580                 }
3581
3582                 public void SetFinallyBlock ()
3583                 {
3584                         flags |= Flags.FinallyBlock;
3585                 }
3586
3587                 public void WrapIntoDestructor (TryFinally tf, ExplicitBlock tryBlock)
3588                 {
3589                         tryBlock.statements = statements;
3590                         statements = new List<Statement> (1);
3591                         statements.Add (tf);
3592                 }
3593         }
3594
3595         //
3596         // ParametersBlock was introduced to support anonymous methods
3597         // and lambda expressions
3598         // 
3599         public class ParametersBlock : ExplicitBlock
3600         {
3601                 public class ParameterInfo : INamedBlockVariable
3602                 {
3603                         readonly ParametersBlock block;
3604                         readonly int index;
3605                         public VariableInfo VariableInfo;
3606                         bool is_locked;
3607
3608                         public ParameterInfo (ParametersBlock block, int index)
3609                         {
3610                                 this.block = block;
3611                                 this.index = index;
3612                         }
3613
3614                         #region Properties
3615
3616                         public ParametersBlock Block {
3617                                 get {
3618                                         return block;
3619                                 }
3620                         }
3621
3622                         Block INamedBlockVariable.Block {
3623                                 get {
3624                                         return block;
3625                                 }
3626                         }
3627
3628                         public bool IsDeclared {
3629                                 get {
3630                                         return true;
3631                                 }
3632                         }
3633
3634                         public bool IsParameter {
3635                                 get {
3636                                         return true;
3637                                 }
3638                         }
3639
3640                         public bool IsLocked {
3641                                 get {
3642                                         return is_locked;
3643                                 }
3644                                 set {
3645                                         is_locked = value;
3646                                 }
3647                         }
3648
3649                         public Location Location {
3650                                 get {
3651                                         return Parameter.Location;
3652                                 }
3653                         }
3654
3655                         public Parameter Parameter {
3656                                 get {
3657                                         return block.Parameters [index];
3658                                 }
3659                         }
3660
3661                         public TypeSpec ParameterType {
3662                                 get {
3663                                         return Parameter.Type;
3664                                 }
3665                         }
3666
3667                         #endregion
3668
3669                         public Expression CreateReferenceExpression (ResolveContext rc, Location loc)
3670                         {
3671                                 return new ParameterReference (this, loc);
3672                         }
3673                 }
3674
3675                 // 
3676                 // Block is converted into an expression
3677                 //
3678                 sealed class BlockScopeExpression : Expression
3679                 {
3680                         Expression child;
3681                         readonly ParametersBlock block;
3682
3683                         public BlockScopeExpression (Expression child, ParametersBlock block)
3684                         {
3685                                 this.child = child;
3686                                 this.block = block;
3687                         }
3688
3689                         public override bool ContainsEmitWithAwait ()
3690                         {
3691                                 return child.ContainsEmitWithAwait ();
3692                         }
3693
3694                         public override Expression CreateExpressionTree (ResolveContext ec)
3695                         {
3696                                 throw new NotSupportedException ();
3697                         }
3698
3699                         protected override Expression DoResolve (ResolveContext ec)
3700                         {
3701                                 if (child == null)
3702                                         return null;
3703
3704                                 child = child.Resolve (ec);
3705                                 if (child == null)
3706                                         return null;
3707
3708                                 eclass = child.eclass;
3709                                 type = child.Type;
3710                                 return this;
3711                         }
3712
3713                         public override void Emit (EmitContext ec)
3714                         {
3715                                 block.EmitScopeInitializers (ec);
3716                                 child.Emit (ec);
3717                         }
3718                 }
3719
3720                 protected ParametersCompiled parameters;
3721                 protected ParameterInfo[] parameter_info;
3722                 protected bool resolved;
3723                 protected ToplevelBlock top_block;
3724                 protected StateMachine state_machine;
3725                 protected Dictionary<string, object> labels;
3726
3727                 public ParametersBlock (Block parent, ParametersCompiled parameters, Location start, Flags flags = 0)
3728                         : base (parent, 0, start, start)
3729                 {
3730                         if (parameters == null)
3731                                 throw new ArgumentNullException ("parameters");
3732
3733                         this.parameters = parameters;
3734                         ParametersBlock = this;
3735
3736                         this.flags |= flags | (parent.ParametersBlock.flags & (Flags.YieldBlock | Flags.AwaitBlock));
3737
3738                         this.top_block = parent.ParametersBlock.top_block;
3739                         ProcessParameters ();
3740                 }
3741
3742                 protected ParametersBlock (ParametersCompiled parameters, Location start)
3743                         : base (null, 0, start, start)
3744                 {
3745                         if (parameters == null)
3746                                 throw new ArgumentNullException ("parameters");
3747
3748                         this.parameters = parameters;
3749                         ParametersBlock = this;
3750                 }
3751
3752                 //
3753                 // It's supposed to be used by method body implementation of anonymous methods
3754                 //
3755                 protected ParametersBlock (ParametersBlock source, ParametersCompiled parameters)
3756                         : base (null, 0, source.StartLocation, source.EndLocation)
3757                 {
3758                         this.parameters = parameters;
3759                         this.statements = source.statements;
3760                         this.scope_initializers = source.scope_initializers;
3761
3762                         this.resolved = true;
3763                         this.reachable = source.reachable;
3764                         this.am_storey = source.am_storey;
3765                         this.state_machine = source.state_machine;
3766                         this.flags = source.flags & Flags.ReachableEnd;
3767
3768                         ParametersBlock = this;
3769
3770                         //
3771                         // Overwrite original for comparison purposes when linking cross references
3772                         // between anonymous methods
3773                         //
3774                         Original = source.Original;
3775                 }
3776
3777                 #region Properties
3778
3779                 public bool HasReferenceToStoreyForInstanceLambdas {
3780                         get {
3781                                 return (flags & Flags.HasReferenceToStoreyForInstanceLambdas) != 0;
3782                         }
3783                         set {
3784                                 flags = value ? flags | Flags.HasReferenceToStoreyForInstanceLambdas : flags & ~Flags.HasReferenceToStoreyForInstanceLambdas;
3785                         }
3786                 }
3787
3788                 public bool IsAsync {
3789                         get {
3790                                 return (flags & Flags.HasAsyncModifier) != 0;
3791                         }
3792                         set {
3793                                 flags = value ? flags | Flags.HasAsyncModifier : flags & ~Flags.HasAsyncModifier;
3794                         }
3795                 }
3796
3797                 //
3798                 // Block has been converted to expression tree
3799                 //
3800                 public bool IsExpressionTree {
3801                         get {
3802                                 return (flags & Flags.IsExpressionTree) != 0;
3803                         }
3804                 }
3805
3806                 //
3807                 // The parameters for the block.
3808                 //
3809                 public ParametersCompiled Parameters {
3810                         get {
3811                                 return parameters;
3812                         }
3813                 }
3814
3815                 public StateMachine StateMachine {
3816                         get {
3817                                 return state_machine;
3818                         }
3819                 }
3820
3821                 public ToplevelBlock TopBlock {
3822                         get {
3823                                 return top_block;
3824                         }
3825                         set {
3826                                 top_block = value;
3827                         }
3828                 }
3829
3830                 public bool Resolved {
3831                         get {
3832                                 return (flags & Flags.Resolved) != 0;
3833                         }
3834                 }
3835
3836                 public int TemporaryLocalsCount { get; set; }
3837
3838                 #endregion
3839
3840                 //
3841                 // Checks whether all `out' parameters have been assigned.
3842                 //
3843                 public void CheckControlExit (FlowAnalysisContext fc)
3844                 {
3845                         CheckControlExit (fc, fc.DefiniteAssignment);
3846                 }
3847
3848                 public virtual void CheckControlExit (FlowAnalysisContext fc, DefiniteAssignmentBitSet dat)
3849                 {
3850                         if (parameter_info == null)
3851                                 return;
3852
3853                         foreach (var p in parameter_info) {
3854                                 if (p.VariableInfo == null)
3855                                         continue;
3856
3857                                 if (p.VariableInfo.IsAssigned (dat))
3858                                         continue;
3859
3860                                 fc.Report.Error (177, p.Location,
3861                                         "The out parameter `{0}' must be assigned to before control leaves the current method",
3862                                         p.Parameter.Name);
3863                         }                                       
3864                 }
3865
3866                 protected override void CloneTo (CloneContext clonectx, Statement t)
3867                 {
3868                         base.CloneTo (clonectx, t);
3869
3870                         var target = (ParametersBlock) t;
3871
3872                         //
3873                         // Clone label statements as well as they contain block reference
3874                         //
3875                         var pb = this;
3876                         while (true) {
3877                                 if (pb.labels != null) {
3878                                         target.labels = new Dictionary<string, object> ();
3879
3880                                         foreach (var entry in pb.labels) {
3881                                                 var list = entry.Value as List<LabeledStatement>;
3882
3883                                                 if (list != null) {
3884                                                         var list_clone = new List<LabeledStatement> ();
3885                                                         foreach (var lentry in list) {
3886                                                                 list_clone.Add (RemapLabeledStatement (lentry, clonectx.RemapBlockCopy (lentry.Block)));
3887                                                         }
3888
3889                                                         target.labels.Add (entry.Key, list_clone);
3890                                                 } else {
3891                                                         var labeled = (LabeledStatement) entry.Value;
3892                                                         target.labels.Add (entry.Key, RemapLabeledStatement (labeled, clonectx.RemapBlockCopy (labeled.Block)));
3893                                                 }
3894                                         }
3895
3896                                         break;
3897                                 }
3898
3899                                 if (pb.Parent == null)
3900                                         break;
3901
3902                                 pb = pb.Parent.ParametersBlock;
3903                         }
3904                 }
3905
3906                 public override Expression CreateExpressionTree (ResolveContext ec)
3907                 {
3908                         if (statements.Count == 1) {
3909                                 Expression expr = statements[0].CreateExpressionTree (ec);
3910                                 if (scope_initializers != null)
3911                                         expr = new BlockScopeExpression (expr, this);
3912
3913                                 return expr;
3914                         }
3915
3916                         return base.CreateExpressionTree (ec);
3917                 }
3918
3919                 public override void Emit (EmitContext ec)
3920                 {
3921                         if (state_machine != null && state_machine.OriginalSourceBlock != this) {
3922                                 DefineStoreyContainer (ec, state_machine);
3923                                 state_machine.EmitStoreyInstantiation (ec, this);
3924                         }
3925
3926                         base.Emit (ec);
3927                 }
3928
3929                 public void EmitEmbedded (EmitContext ec)
3930                 {
3931                         if (state_machine != null && state_machine.OriginalSourceBlock != this) {
3932                                 DefineStoreyContainer (ec, state_machine);
3933                                 state_machine.EmitStoreyInstantiation (ec, this);
3934                         }
3935
3936                         base.Emit (ec);
3937                 }
3938
3939                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
3940                 {
3941                         var res = base.DoFlowAnalysis (fc);
3942
3943                         if (HasReachableClosingBrace)
3944                                 CheckControlExit (fc);
3945
3946                         return res;
3947                 }
3948
3949                 public override int GetDebugSymbolScopeIndex ()
3950                 {
3951                         return 0;
3952                 }
3953
3954                 public LabeledStatement GetLabel (string name, Block block)
3955                 {
3956                         //
3957                         // Cloned parameters blocks can have their own cloned version of top-level labels
3958                         //
3959                         if (labels == null) {
3960                                 if (Parent != null)
3961                                         return Parent.ParametersBlock.GetLabel (name, block);
3962
3963                                 return null;
3964                         }
3965
3966                         object value;
3967                         if (!labels.TryGetValue (name, out value)) {
3968                                 return null;
3969                         }
3970
3971                         var label = value as LabeledStatement;
3972                         Block b = block;
3973                         if (label != null) {
3974                                 if (IsLabelVisible (label, b))
3975                                         return label;
3976
3977                         } else {
3978                                 List<LabeledStatement> list = (List<LabeledStatement>) value;
3979                                 for (int i = 0; i < list.Count; ++i) {
3980                                         label = list[i];
3981                                         if (IsLabelVisible (label, b))
3982                                                 return label;
3983                                 }
3984                         }
3985
3986                         return null;
3987                 }
3988
3989                 static bool IsLabelVisible (LabeledStatement label, Block b)
3990                 {
3991                         do {
3992                                 if (label.Block == b)
3993                                         return true;
3994                                 b = b.Parent;
3995                         } while (b != null);
3996
3997                         return false;
3998                 }
3999
4000                 public ParameterInfo GetParameterInfo (Parameter p)
4001                 {
4002                         for (int i = 0; i < parameters.Count; ++i) {
4003                                 if (parameters[i] == p)
4004                                         return parameter_info[i];
4005                         }
4006
4007                         throw new ArgumentException ("Invalid parameter");
4008                 }
4009
4010                 public ParameterReference GetParameterReference (int index, Location loc)
4011                 {
4012                         return new ParameterReference (parameter_info[index], loc);
4013                 }
4014
4015                 public Statement PerformClone (ref HashSet<LocalVariable> undeclaredVariables)
4016                 {
4017                         undeclaredVariables = TopBlock.GetUndeclaredVariables ();
4018
4019                         CloneContext clonectx = new CloneContext ();
4020                         return Clone (clonectx);
4021                 }
4022
4023                 protected void ProcessParameters ()
4024                 {
4025                         if (parameters.Count == 0)
4026                                 return;
4027
4028                         parameter_info = new ParameterInfo[parameters.Count];
4029                         for (int i = 0; i < parameter_info.Length; ++i) {
4030                                 var p = parameters.FixedParameters[i];
4031                                 if (p == null)
4032                                         continue;
4033
4034                                 // TODO: Should use Parameter only and more block there
4035                                 parameter_info[i] = new ParameterInfo (this, i);
4036                                 if (p.Name != null)
4037                                         AddLocalName (p.Name, parameter_info[i]);
4038                         }
4039                 }
4040
4041                 LabeledStatement RemapLabeledStatement (LabeledStatement stmt, Block dst)
4042                 {
4043                         var src = stmt.Block;
4044
4045                         //
4046                         // Cannot remap label block if the label was not yet cloned which
4047                         // can happen in case of anonymous method inside anoynymous method
4048                         // with a label. But in this case we don't care because goto cannot
4049                         // jump of out anonymous method
4050                         //
4051                         if (src.ParametersBlock != this)
4052                                 return stmt;
4053
4054                         var src_stmts = src.Statements;
4055                         for (int i = 0; i < src_stmts.Count; ++i) {
4056                                 if (src_stmts[i] == stmt)
4057                                         return (LabeledStatement) dst.Statements[i];
4058                         }
4059
4060                         throw new InternalErrorException ("Should never be reached");
4061                 }
4062
4063                 public override bool Resolve (BlockContext bc)
4064                 {
4065                         // TODO: if ((flags & Flags.Resolved) != 0)
4066
4067                         if (resolved)
4068                                 return true;
4069
4070                         resolved = true;
4071
4072                         if (bc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4073                                 flags |= Flags.IsExpressionTree;
4074
4075                         try {
4076                                 PrepareAssignmentAnalysis (bc);
4077
4078                                 if (!base.Resolve (bc))
4079                                         return false;
4080
4081                         } catch (Exception e) {
4082                                 if (e is CompletionResult || bc.Report.IsDisabled || e is FatalException || bc.Report.Printer is NullReportPrinter || bc.Module.Compiler.Settings.BreakOnInternalError)
4083                                         throw;
4084
4085                                 if (bc.CurrentBlock != null) {
4086                                         bc.Report.Error (584, bc.CurrentBlock.StartLocation, "Internal compiler error: {0}", e.Message);
4087                                 } else {
4088                                         bc.Report.Error (587, "Internal compiler error: {0}", e.Message);
4089                                 }
4090                         }
4091
4092                         //
4093                         // If an asynchronous body of F is either an expression classified as nothing, or a 
4094                         // statement block where no return statements have expressions, the inferred return type is Task
4095                         //
4096                         if (IsAsync) {
4097                                 var am = bc.CurrentAnonymousMethod as AnonymousMethodBody;
4098                                 if (am != null && am.ReturnTypeInference != null && !am.ReturnTypeInference.HasBounds (0)) {
4099                                         am.ReturnTypeInference = null;
4100                                         am.ReturnType = bc.Module.PredefinedTypes.Task.TypeSpec;
4101                                         return true;
4102                                 }
4103                         }
4104
4105                         return true;
4106                 }
4107
4108                 void PrepareAssignmentAnalysis (BlockContext bc)
4109                 {
4110                         for (int i = 0; i < parameters.Count; ++i) {
4111                                 var par = parameters.FixedParameters[i];
4112
4113                                 if ((par.ModFlags & Parameter.Modifier.OUT) == 0)
4114                                         continue;
4115
4116                                 parameter_info [i].VariableInfo = VariableInfo.Create (bc, (Parameter) par);
4117                         }
4118                 }
4119
4120                 public ToplevelBlock ConvertToIterator (IMethodData method, TypeDefinition host, TypeSpec iterator_type, bool is_enumerable)
4121                 {
4122                         var iterator = new Iterator (this, method, host, iterator_type, is_enumerable);
4123                         var stateMachine = new IteratorStorey (iterator);
4124
4125                         state_machine = stateMachine;
4126                         iterator.SetStateMachine (stateMachine);
4127
4128                         var tlb = new ToplevelBlock (host.Compiler, Parameters, Location.Null, Flags.CompilerGenerated);
4129                         tlb.Original = this;
4130                         tlb.state_machine = stateMachine;
4131                         tlb.AddStatement (new Return (iterator, iterator.Location));
4132                         return tlb;
4133                 }
4134
4135                 public ParametersBlock ConvertToAsyncTask (IMemberContext context, TypeDefinition host, ParametersCompiled parameters, TypeSpec returnType, TypeSpec delegateType, Location loc)
4136                 {
4137                         for (int i = 0; i < parameters.Count; i++) {
4138                                 Parameter p = parameters[i];
4139                                 Parameter.Modifier mod = p.ModFlags;
4140                                 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
4141                                         host.Compiler.Report.Error (1988, p.Location,
4142                                                 "Async methods cannot have ref or out parameters");
4143                                         return this;
4144                                 }
4145
4146                                 if (p is ArglistParameter) {
4147                                         host.Compiler.Report.Error (4006, p.Location,
4148                                                 "__arglist is not allowed in parameter list of async methods");
4149                                         return this;
4150                                 }
4151
4152                                 if (parameters.Types[i].IsPointer) {
4153                                         host.Compiler.Report.Error (4005, p.Location,
4154                                                 "Async methods cannot have unsafe parameters");
4155                                         return this;
4156                                 }
4157                         }
4158
4159                         if (!HasAwait) {
4160                                 host.Compiler.Report.Warning (1998, 1, loc,
4161                                         "Async block lacks `await' operator and will run synchronously");
4162                         }
4163
4164                         var block_type = host.Module.Compiler.BuiltinTypes.Void;
4165                         var initializer = new AsyncInitializer (this, host, block_type);
4166                         initializer.Type = block_type;
4167                         initializer.DelegateType = delegateType;
4168
4169                         var stateMachine = new AsyncTaskStorey (this, context, initializer, returnType);
4170
4171                         state_machine = stateMachine;
4172                         initializer.SetStateMachine (stateMachine);
4173
4174                         const Flags flags = Flags.CompilerGenerated;
4175
4176                         var b = this is ToplevelBlock ?
4177                                 new ToplevelBlock (host.Compiler, Parameters, Location.Null, flags) :
4178                                 new ParametersBlock (Parent, parameters, Location.Null, flags | Flags.HasAsyncModifier);
4179
4180                         b.Original = this;
4181                         b.state_machine = stateMachine;
4182                         b.AddStatement (new AsyncInitializerStatement (initializer));
4183                         return b;
4184                 }
4185         }
4186
4187         //
4188         //
4189         //
4190         public class ToplevelBlock : ParametersBlock
4191         {
4192                 LocalVariable this_variable;
4193                 CompilerContext compiler;
4194                 Dictionary<string, object> names;
4195
4196                 List<ExplicitBlock> this_references;
4197
4198                 public ToplevelBlock (CompilerContext ctx, Location loc)
4199                         : this (ctx, ParametersCompiled.EmptyReadOnlyParameters, loc)
4200                 {
4201                 }
4202
4203                 public ToplevelBlock (CompilerContext ctx, ParametersCompiled parameters, Location start, Flags flags = 0)
4204                         : base (parameters, start)
4205                 {
4206                         this.compiler = ctx;
4207                         this.flags = flags;
4208                         top_block = this;
4209
4210                         ProcessParameters ();
4211                 }
4212
4213                 //
4214                 // Recreates a top level block from parameters block. Used for
4215                 // compiler generated methods where the original block comes from
4216                 // explicit child block. This works for already resolved blocks
4217                 // only to ensure we resolve them in the correct flow order
4218                 //
4219                 public ToplevelBlock (ParametersBlock source, ParametersCompiled parameters)
4220                         : base (source, parameters)
4221                 {
4222                         this.compiler = source.TopBlock.compiler;
4223                         top_block = this;
4224                 }
4225
4226                 public bool IsIterator {
4227                         get {
4228                                 return (flags & Flags.Iterator) != 0;
4229                         }
4230                         set {
4231                                 flags = value ? flags | Flags.Iterator : flags & ~Flags.Iterator;
4232                         }
4233                 }
4234
4235                 public Report Report {
4236                         get {
4237                                 return compiler.Report;
4238                         }
4239                 }
4240
4241                 //
4242                 // Used by anonymous blocks to track references of `this' variable
4243                 //
4244                 public List<ExplicitBlock> ThisReferencesFromChildrenBlock {
4245                         get {
4246                                 return this_references;
4247                         }
4248                 }
4249
4250                 //
4251                 // Returns the "this" instance variable of this block.
4252                 // See AddThisVariable() for more information.
4253                 //
4254                 public LocalVariable ThisVariable {
4255                         get {
4256                                 return this_variable;
4257                         }
4258                 }
4259
4260                 public void AddLocalName (string name, INamedBlockVariable li, bool ignoreChildrenBlocks)
4261                 {
4262                         if (names == null)
4263                                 names = new Dictionary<string, object> ();
4264
4265                         object value;
4266                         if (!names.TryGetValue (name, out value)) {
4267                                 names.Add (name, li);
4268                                 return;
4269                         }
4270
4271                         INamedBlockVariable existing = value as INamedBlockVariable;
4272                         List<INamedBlockVariable> existing_list;
4273                         if (existing != null) {
4274                                 existing_list = new List<INamedBlockVariable> ();
4275                                 existing_list.Add (existing);
4276                                 names[name] = existing_list;
4277                         } else {
4278                                 existing_list = (List<INamedBlockVariable>) value;
4279                         }
4280
4281                         //
4282                         // A collision checking between local names
4283                         //
4284                         var variable_block = li.Block.Explicit;
4285                         for (int i = 0; i < existing_list.Count; ++i) {
4286                                 existing = existing_list[i];
4287                                 Block b = existing.Block.Explicit;
4288
4289                                 // Collision at same level
4290                                 if (variable_block == b) {
4291                                         li.Block.Error_AlreadyDeclared (name, li);
4292                                         break;
4293                                 }
4294
4295                                 // Collision with parent
4296                                 Block parent = variable_block;
4297                                 while ((parent = parent.Parent) != null) {
4298                                         if (parent == b) {
4299                                                 li.Block.Error_AlreadyDeclared (name, li, "parent or current");
4300                                                 i = existing_list.Count;
4301                                                 break;
4302                                         }
4303                                 }
4304
4305                                 if (!ignoreChildrenBlocks && variable_block.Parent != b.Parent) {
4306                                         // Collision with children
4307                                         while ((b = b.Parent) != null) {
4308                                                 if (variable_block == b) {
4309                                                         li.Block.Error_AlreadyDeclared (name, li, "child");
4310                                                         i = existing_list.Count;
4311                                                         break;
4312                                                 }
4313                                         }
4314                                 }
4315                         }
4316
4317                         existing_list.Add (li);
4318                 }
4319
4320                 public void AddLabel (string name, LabeledStatement label)
4321                 {
4322                         if (labels == null)
4323                                 labels = new Dictionary<string, object> ();
4324
4325                         object value;
4326                         if (!labels.TryGetValue (name, out value)) {
4327                                 labels.Add (name, label);
4328                                 return;
4329                         }
4330
4331                         LabeledStatement existing = value as LabeledStatement;
4332                         List<LabeledStatement> existing_list;
4333                         if (existing != null) {
4334                                 existing_list = new List<LabeledStatement> ();
4335                                 existing_list.Add (existing);
4336                                 labels[name] = existing_list;
4337                         } else {
4338                                 existing_list = (List<LabeledStatement>) value;
4339                         }
4340
4341                         //
4342                         // A collision checking between labels
4343                         //
4344                         for (int i = 0; i < existing_list.Count; ++i) {
4345                                 existing = existing_list[i];
4346                                 Block b = existing.Block;
4347
4348                                 // Collision at same level
4349                                 if (label.Block == b) {
4350                                         Report.SymbolRelatedToPreviousError (existing.loc, name);
4351                                         Report.Error (140, label.loc, "The label `{0}' is a duplicate", name);
4352                                         break;
4353                                 }
4354
4355                                 // Collision with parent
4356                                 b = label.Block;
4357                                 while ((b = b.Parent) != null) {
4358                                         if (existing.Block == b) {
4359                                                 Report.Error (158, label.loc,
4360                                                         "The label `{0}' shadows another label by the same name in a contained scope", name);
4361                                                 i = existing_list.Count;
4362                                                 break;
4363                                         }
4364                                 }
4365
4366                                 // Collision with with children
4367                                 b = existing.Block;
4368                                 while ((b = b.Parent) != null) {
4369                                         if (label.Block == b) {
4370                                                 Report.Error (158, label.loc,
4371                                                         "The label `{0}' shadows another label by the same name in a contained scope", name);
4372                                                 i = existing_list.Count;
4373                                                 break;
4374                                         }
4375                                 }
4376                         }
4377
4378                         existing_list.Add (label);
4379                 }
4380
4381                 public void AddThisReferenceFromChildrenBlock (ExplicitBlock block)
4382                 {
4383                         if (this_references == null)
4384                                 this_references = new List<ExplicitBlock> ();
4385
4386                         if (!this_references.Contains (block))
4387                                 this_references.Add (block);
4388                 }
4389
4390                 public void RemoveThisReferenceFromChildrenBlock (ExplicitBlock block)
4391                 {
4392                         this_references.Remove (block);
4393                 }
4394
4395                 //
4396                 // Creates an arguments set from all parameters, useful for method proxy calls
4397                 //
4398                 public Arguments GetAllParametersArguments ()
4399                 {
4400                         int count = parameters.Count;
4401                         Arguments args = new Arguments (count);
4402                         for (int i = 0; i < count; ++i) {
4403                                 var pi = parameter_info[i];
4404                                 var arg_expr = GetParameterReference (i, pi.Location);
4405
4406                                 Argument.AType atype_modifier;
4407                                 switch (pi.Parameter.ParameterModifier & Parameter.Modifier.RefOutMask) {
4408                                 case Parameter.Modifier.REF:
4409                                         atype_modifier = Argument.AType.Ref;
4410                                         break;
4411                                 case Parameter.Modifier.OUT:
4412                                         atype_modifier = Argument.AType.Out;
4413                                         break;
4414                                 default:
4415                                         atype_modifier = 0;
4416                                         break;
4417                                 }
4418
4419                                 args.Add (new Argument (arg_expr, atype_modifier));
4420                         }
4421
4422                         return args;
4423                 }
4424
4425                 //
4426                 // Lookup inside a block, the returned value can represent 3 states
4427                 //
4428                 // true+variable: A local name was found and it's valid
4429                 // false+variable: A local name was found in a child block only
4430                 // false+null: No local name was found
4431                 //
4432                 public bool GetLocalName (string name, Block block, ref INamedBlockVariable variable)
4433                 {
4434                         if (names == null)
4435                                 return false;
4436
4437                         object value;
4438                         if (!names.TryGetValue (name, out value))
4439                                 return false;
4440
4441                         variable = value as INamedBlockVariable;
4442                         Block b = block;
4443                         if (variable != null) {
4444                                 do {
4445                                         if (variable.Block == b.Original)
4446                                                 return true;
4447
4448                                         b = b.Parent;
4449                                 } while (b != null);
4450
4451                                 b = variable.Block;
4452                                 do {
4453                                         if (block == b)
4454                                                 return false;
4455
4456                                         b = b.Parent;
4457                                 } while (b != null);
4458                         } else {
4459                                 List<INamedBlockVariable> list = (List<INamedBlockVariable>) value;
4460                                 for (int i = 0; i < list.Count; ++i) {
4461                                         variable = list[i];
4462                                         do {
4463                                                 if (variable.Block == b.Original)
4464                                                         return true;
4465
4466                                                 b = b.Parent;
4467                                         } while (b != null);
4468
4469                                         b = variable.Block;
4470                                         do {
4471                                                 if (block == b)
4472                                                         return false;
4473
4474                                                 b = b.Parent;
4475                                         } while (b != null);
4476
4477                                         b = block;
4478                                 }
4479                         }
4480
4481                         variable = null;
4482                         return false;
4483                 }
4484
4485                 public void IncludeBlock (ParametersBlock pb, ToplevelBlock block)
4486                 {
4487                         if (block.names != null) {
4488                                 foreach (var n in block.names) {
4489                                         var variable = n.Value as INamedBlockVariable;
4490                                         if (variable != null) {
4491                                                 if (variable.Block.ParametersBlock == pb)
4492                                                         AddLocalName (n.Key, variable, false);
4493                                                 continue;
4494                                         }
4495
4496                                         foreach (var v in (List<INamedBlockVariable>) n.Value)
4497                                                 if (v.Block.ParametersBlock == pb)
4498                                                         AddLocalName (n.Key, v, false);
4499                                 }
4500                         }
4501                 }
4502
4503                 // <summary>
4504                 //   This is used by non-static `struct' constructors which do not have an
4505                 //   initializer - in this case, the constructor must initialize all of the
4506                 //   struct's fields.  To do this, we add a "this" variable and use the flow
4507                 //   analysis code to ensure that it's been fully initialized before control
4508                 //   leaves the constructor.
4509                 // </summary>
4510                 public void AddThisVariable (BlockContext bc)
4511                 {
4512                         if (this_variable != null)
4513                                 throw new InternalErrorException (StartLocation.ToString ());
4514
4515                         this_variable = new LocalVariable (this, "this", LocalVariable.Flags.IsThis | LocalVariable.Flags.Used, StartLocation);
4516                         this_variable.Type = bc.CurrentType;
4517                         this_variable.PrepareAssignmentAnalysis (bc);
4518                 }
4519
4520                 public override void CheckControlExit (FlowAnalysisContext fc, DefiniteAssignmentBitSet dat)
4521                 {
4522                         //
4523                         // If we're a non-static struct constructor which doesn't have an
4524                         // initializer, then we must initialize all of the struct's fields.
4525                         //
4526                         if (this_variable != null)
4527                                 this_variable.IsThisAssigned (fc, this);
4528
4529                         base.CheckControlExit (fc, dat);
4530                 }
4531
4532                 public HashSet<LocalVariable> GetUndeclaredVariables ()
4533                 {
4534                         if (names == null)
4535                                 return null;
4536
4537                         HashSet<LocalVariable> variables = null;
4538
4539                         foreach (var entry in names) {
4540                                 var complex = entry.Value as List<INamedBlockVariable>;
4541                                 if (complex != null) {
4542                                         foreach (var centry in complex) {
4543                                                 if (IsUndeclaredVariable (centry)) {
4544                                                         if (variables == null)
4545                                                                 variables = new HashSet<LocalVariable> ();
4546
4547                                                         variables.Add ((LocalVariable) centry);
4548                                                 }
4549                                         }
4550                                 } else if (IsUndeclaredVariable ((INamedBlockVariable)entry.Value)) {
4551                                         if (variables == null)
4552                                                 variables = new HashSet<LocalVariable> ();
4553
4554                                         variables.Add ((LocalVariable)entry.Value);                                     
4555                                 }
4556                         }
4557
4558                         return variables;
4559                 }
4560
4561                 static bool IsUndeclaredVariable (INamedBlockVariable namedBlockVariable)
4562                 {
4563                         var lv = namedBlockVariable as LocalVariable;
4564                         return lv != null && !lv.IsDeclared;
4565                 }
4566
4567                 public void SetUndeclaredVariables (HashSet<LocalVariable> undeclaredVariables)
4568                 {
4569                         if (names == null)
4570                                 return;
4571                         
4572                         foreach (var entry in names) {
4573                                 var complex = entry.Value as List<INamedBlockVariable>;
4574                                 if (complex != null) {
4575                                         foreach (var centry in complex) {
4576                                                 var lv = centry as LocalVariable;
4577                                                 if (lv != null && undeclaredVariables.Contains (lv)) {
4578                                                         lv.Type = null;
4579                                                 }
4580                                         }
4581                                 } else {
4582                                         var lv = entry.Value as LocalVariable;
4583                                         if (lv != null && undeclaredVariables.Contains (lv))
4584                                                 lv.Type = null;
4585                                 }
4586                         }
4587                 }
4588
4589                 public override void Emit (EmitContext ec)
4590                 {
4591                         if (Report.Errors > 0)
4592                                 return;
4593
4594                         try {
4595                         if (IsCompilerGenerated) {
4596                                 using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
4597                                         base.Emit (ec);
4598                                 }
4599                         } else {
4600                                 base.Emit (ec);
4601                         }
4602
4603                         //
4604                         // If `HasReturnLabel' is set, then we already emitted a
4605                         // jump to the end of the method, so we must emit a `ret'
4606                         // there.
4607                         //
4608                         // Unfortunately, System.Reflection.Emit automatically emits
4609                         // a leave to the end of a finally block.  This is a problem
4610                         // if no code is following the try/finally block since we may
4611                         // jump to a point after the end of the method.
4612                         // As a workaround, we're always creating a return label in
4613                         // this case.
4614                         //
4615                         if (ec.HasReturnLabel || HasReachableClosingBrace) {
4616                                 if (ec.HasReturnLabel)
4617                                         ec.MarkLabel (ec.ReturnLabel);
4618
4619                                 if (ec.EmitAccurateDebugInfo && !IsCompilerGenerated)
4620                                         ec.Mark (EndLocation);
4621
4622                                 if (ec.ReturnType.Kind != MemberKind.Void)
4623                                         ec.Emit (OpCodes.Ldloc, ec.TemporaryReturn ());
4624
4625                                 ec.Emit (OpCodes.Ret);
4626                         }
4627
4628                         } catch (Exception e) {
4629                                 throw new InternalErrorException (e, StartLocation);
4630                         }
4631                 }
4632
4633                 public bool Resolve (BlockContext bc, IMethodData md)
4634                 {
4635                         if (resolved)
4636                                 return true;
4637
4638                         var errors = bc.Report.Errors;
4639
4640                         base.Resolve (bc);
4641
4642                         if (bc.Report.Errors > errors)
4643                                 return false;
4644
4645                         MarkReachable (new Reachability ());
4646
4647                         if (HasReachableClosingBrace && bc.ReturnType.Kind != MemberKind.Void) {
4648                                 // TODO: var md = bc.CurrentMemberDefinition;
4649                                 bc.Report.Error (161, md.Location, "`{0}': not all code paths return a value", md.GetSignatureForError ());
4650                         }
4651
4652                         if ((flags & Flags.NoFlowAnalysis) != 0)
4653                                 return true;
4654
4655                         var fc = new FlowAnalysisContext (bc.Module.Compiler, this, bc.AssignmentInfoOffset);
4656                         try {
4657                                 FlowAnalysis (fc);
4658                         } catch (Exception e) {
4659                                 throw new InternalErrorException (e, StartLocation);
4660                         }
4661
4662                         return true;
4663                 }
4664         }
4665         
4666         public class SwitchLabel : Statement
4667         {
4668                 Constant converted;
4669                 Expression label;
4670
4671                 Label? il_label;
4672
4673                 //
4674                 // if expr == null, then it is the default case.
4675                 //
4676                 public SwitchLabel (Expression expr, Location l)
4677                 {
4678                         label = expr;
4679                         loc = l;
4680                 }
4681
4682                 public bool IsDefault {
4683                         get {
4684                                 return label == null;
4685                         }
4686                 }
4687
4688                 public Expression Label {
4689                         get {
4690                                 return label;
4691                         }
4692                 }
4693
4694                 public Location Location {
4695                         get {
4696                                 return loc;
4697                         }
4698                 }
4699
4700                 public Constant Converted {
4701                         get {
4702                                 return converted;
4703                         }
4704                         set {
4705                                 converted = value; 
4706                         }
4707                 }
4708
4709                 public bool PatternMatching { get; set; }
4710
4711                 public bool SectionStart { get; set; }
4712
4713                 public Label GetILLabel (EmitContext ec)
4714                 {
4715                         if (il_label == null){
4716                                 il_label = ec.DefineLabel ();
4717                         }
4718
4719                         return il_label.Value;
4720                 }
4721
4722                 protected override void DoEmit (EmitContext ec)
4723                 {
4724                         ec.MarkLabel (GetILLabel (ec));
4725                 }
4726
4727                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
4728                 {
4729                         if (!SectionStart)
4730                                 return false;
4731
4732                         fc.BranchDefiniteAssignment (fc.SwitchInitialDefinitiveAssignment);
4733                         return false;
4734                 }
4735
4736                 public override bool Resolve (BlockContext bc)
4737                 {
4738                         if (ResolveAndReduce (bc))
4739                                 bc.Switch.RegisterLabel (bc, this);
4740
4741                         return true;
4742                 }
4743
4744                 //
4745                 // Resolves the expression, reduces it to a literal if possible
4746                 // and then converts it to the requested type.
4747                 //
4748                 bool ResolveAndReduce (BlockContext bc)
4749                 {
4750                         if (IsDefault)
4751                                 return true;
4752
4753                         var switch_statement = bc.Switch;
4754
4755                         if (PatternMatching) {
4756                                 label = new Is (switch_statement.ExpressionValue, label, loc).Resolve (bc);
4757                                 return label != null;
4758                         }
4759
4760                         var c = label.ResolveLabelConstant (bc);
4761                         if (c == null)
4762                                 return false;
4763
4764                         if (switch_statement.IsNullable && c is NullLiteral) {
4765                                 converted = c;
4766                                 return true;
4767                         }
4768
4769                         if (switch_statement.IsPatternMatching) {
4770                                 label = new Is (switch_statement.ExpressionValue, label, loc).Resolve (bc);
4771                                 return true;
4772                         }
4773
4774                         converted = c.ImplicitConversionRequired (bc, switch_statement.SwitchType);
4775                         return converted != null;
4776                 }
4777
4778                 public void Error_AlreadyOccurs (ResolveContext ec, SwitchLabel collision_with)
4779                 {
4780                         ec.Report.SymbolRelatedToPreviousError (collision_with.loc, null);
4781                         ec.Report.Error (152, loc, "The label `{0}' already occurs in this switch statement", GetSignatureForError ());
4782                 }
4783
4784                 protected override void CloneTo (CloneContext clonectx, Statement target)
4785                 {
4786                         var t = (SwitchLabel) target;
4787                         if (label != null)
4788                                 t.label = label.Clone (clonectx);
4789                 }
4790
4791                 public override object Accept (StructuralVisitor visitor)
4792                 {
4793                         return visitor.Visit (this);
4794                 }
4795
4796                 public string GetSignatureForError ()
4797                 {
4798                         string label;
4799                         if (converted == null)
4800                                 label = "default";
4801                         else
4802                                 label = converted.GetValueAsLiteral ();
4803
4804                         return string.Format ("case {0}:", label);
4805                 }
4806         }
4807
4808         public class Switch : LoopStatement
4809         {
4810                 // structure used to hold blocks of keys while calculating table switch
4811                 sealed class LabelsRange : IComparable<LabelsRange>
4812                 {
4813                         public readonly long min;
4814                         public long max;
4815                         public readonly List<long> label_values;
4816
4817                         public LabelsRange (long value)
4818                         {
4819                                 min = max = value;
4820                                 label_values = new List<long> ();
4821                                 label_values.Add (value);
4822                         }
4823
4824                         public LabelsRange (long min, long max, ICollection<long> values)
4825                         {
4826                                 this.min = min;
4827                                 this.max = max;
4828                                 this.label_values = new List<long> (values);
4829                         }
4830
4831                         public long Range {
4832                                 get {
4833                                         return max - min + 1;
4834                                 }
4835                         }
4836
4837                         public bool AddValue (long value)
4838                         {
4839                                 var gap = value - min + 1;
4840                                 // Ensure the range has > 50% occupancy
4841                                 if (gap > 2 * (label_values.Count + 1) || gap <= 0)
4842                                         return false;
4843
4844                                 max = value;
4845                                 label_values.Add (value);
4846                                 return true;
4847                         }
4848
4849                         public int CompareTo (LabelsRange other)
4850                         {
4851                                 int nLength = label_values.Count;
4852                                 int nLengthOther = other.label_values.Count;
4853                                 if (nLengthOther == nLength)
4854                                         return (int) (other.min - min);
4855
4856                                 return nLength - nLengthOther;
4857                         }
4858                 }
4859
4860                 sealed class DispatchStatement : Statement
4861                 {
4862                         readonly Switch body;
4863
4864                         public DispatchStatement (Switch body)
4865                         {
4866                                 this.body = body;
4867                         }
4868
4869                         protected override void CloneTo (CloneContext clonectx, Statement target)
4870                         {
4871                                 throw new NotImplementedException ();
4872                         }
4873
4874                         protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
4875                         {
4876                                 return false;
4877                         }
4878
4879                         protected override void DoEmit (EmitContext ec)
4880                         {
4881                                 body.EmitDispatch (ec);
4882                         }
4883                 }
4884
4885                 class MissingBreak : Statement
4886                 {
4887                         readonly SwitchLabel label;
4888
4889                         public MissingBreak (SwitchLabel sl)
4890                         {
4891                                 this.label = sl;
4892                                 this.loc = sl.loc;
4893                         }
4894
4895                         public bool FallOut { get; set; }
4896
4897                         protected override void DoEmit (EmitContext ec)
4898                         {
4899                         }
4900
4901                         protected override void CloneTo (CloneContext clonectx, Statement target)
4902                         {
4903                         }
4904
4905                         protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
4906                         {
4907                                 if (FallOut) {
4908                                         fc.Report.Error (8070, loc, "Control cannot fall out of switch statement through final case label `{0}'",
4909                                                 label.GetSignatureForError ());
4910                                 } else {
4911                                         fc.Report.Error (163, loc, "Control cannot fall through from one case label `{0}' to another",
4912                                                 label.GetSignatureForError ());
4913                                 }
4914                                 return true;
4915                         }
4916                 }
4917
4918                 public Expression Expr;
4919
4920                 //
4921                 // Mapping of all labels to their SwitchLabels
4922                 //
4923                 Dictionary<long, SwitchLabel> labels;
4924                 Dictionary<string, SwitchLabel> string_labels;
4925                 List<SwitchLabel> case_labels;
4926
4927                 List<Tuple<GotoCase, Constant>> goto_cases;
4928                 List<DefiniteAssignmentBitSet> end_reachable_das;
4929
4930                 /// <summary>
4931                 ///   The governing switch type
4932                 /// </summary>
4933                 public TypeSpec SwitchType;
4934
4935                 Expression new_expr;
4936
4937                 SwitchLabel case_null;
4938                 SwitchLabel case_default;
4939
4940                 Label defaultLabel, nullLabel;
4941                 VariableReference value;
4942                 ExpressionStatement string_dictionary;
4943                 FieldExpr switch_cache_field;
4944                 ExplicitBlock block;
4945                 bool end_reachable;
4946
4947                 //
4948                 // Nullable Types support
4949                 //
4950                 Nullable.Unwrap unwrap;
4951
4952                 public Switch (Expression e, ExplicitBlock block, Location l)
4953                         : base (block)
4954                 {
4955                         Expr = e;
4956                         this.block = block;
4957                         loc = l;
4958                 }
4959
4960                 public SwitchLabel ActiveLabel { get; set; }
4961
4962                 public ExplicitBlock Block {
4963                         get {
4964                                 return block;
4965                         }
4966                 }
4967
4968                 public SwitchLabel DefaultLabel {
4969                         get {
4970                                 return case_default;
4971                         }
4972                 }
4973
4974                 public bool IsNullable {
4975                         get {
4976                                 return unwrap != null;
4977                         }
4978                 }
4979
4980                 public bool IsPatternMatching {
4981                         get {
4982                                 return new_expr == null && SwitchType != null;
4983                         }
4984                 }
4985
4986                 public List<SwitchLabel> RegisteredLabels {
4987                         get {
4988                                 return case_labels;
4989                         }
4990                 }
4991
4992                 public VariableReference ExpressionValue {
4993                         get {
4994                                 return value;
4995                         }
4996                 }
4997
4998                 //
4999                 // Determines the governing type for a switch.  The returned
5000                 // expression might be the expression from the switch, or an
5001                 // expression that includes any potential conversions to
5002                 //
5003                 static Expression SwitchGoverningType (ResolveContext rc, Expression expr, bool unwrapExpr)
5004                 {
5005                         switch (expr.Type.BuiltinType) {
5006                         case BuiltinTypeSpec.Type.Byte:
5007                         case BuiltinTypeSpec.Type.SByte:
5008                         case BuiltinTypeSpec.Type.UShort:
5009                         case BuiltinTypeSpec.Type.Short:
5010                         case BuiltinTypeSpec.Type.UInt:
5011                         case BuiltinTypeSpec.Type.Int:
5012                         case BuiltinTypeSpec.Type.ULong:
5013                         case BuiltinTypeSpec.Type.Long:
5014                         case BuiltinTypeSpec.Type.Char:
5015                         case BuiltinTypeSpec.Type.String:
5016                         case BuiltinTypeSpec.Type.Bool:
5017                                 return expr;
5018                         }
5019
5020                         if (expr.Type.IsEnum)
5021                                 return expr;
5022
5023                         //
5024                         // Try to find a *user* defined implicit conversion.
5025                         //
5026                         // If there is no implicit conversion, or if there are multiple
5027                         // conversions, we have to report an error
5028                         //
5029                         Expression converted = null;
5030                         foreach (TypeSpec tt in rc.Module.PredefinedTypes.SwitchUserTypes) {
5031
5032                                 if (!unwrapExpr && tt.IsNullableType && expr.Type.IsNullableType)
5033                                         break;
5034
5035                                 var restr = Convert.UserConversionRestriction.ImplicitOnly |
5036                                         Convert.UserConversionRestriction.ProbingOnly;
5037
5038                                 if (unwrapExpr)
5039                                         restr |= Convert.UserConversionRestriction.NullableSourceOnly;
5040
5041                                 var e = Convert.UserDefinedConversion (rc, expr, tt, restr, Location.Null);
5042                                 if (e == null)
5043                                         continue;
5044
5045                                 //
5046                                 // Ignore over-worked ImplicitUserConversions that do
5047                                 // an implicit conversion in addition to the user conversion.
5048                                 // 
5049                                 var uc = e as UserCast;
5050                                 if (uc == null)
5051                                         continue;
5052
5053                                 if (converted != null){
5054 //                                      rc.Report.ExtraInformation (loc, "(Ambiguous implicit user defined conversion in previous ");
5055                                         return null;
5056                                 }
5057
5058                                 converted = e;
5059                         }
5060                         return converted;
5061                 }
5062
5063                 public static TypeSpec[] CreateSwitchUserTypes (ModuleContainer module, TypeSpec nullable)
5064                 {
5065                         var types = module.Compiler.BuiltinTypes;
5066
5067                         // LAMESPEC: For some reason it does not contain bool which looks like csc bug
5068                         TypeSpec[] stypes = new[] {
5069                                 types.SByte,
5070                                 types.Byte,
5071                                 types.Short,
5072                                 types.UShort,
5073                                 types.Int,
5074                                 types.UInt,
5075                                 types.Long,
5076                                 types.ULong,
5077                                 types.Char,
5078                                 types.String
5079                         };
5080
5081                         if (nullable != null) {
5082
5083                                 Array.Resize (ref stypes, stypes.Length + 9);
5084
5085                                 for (int i = 0; i < 9; ++i) {
5086                                         stypes [10 + i] = nullable.MakeGenericType (module, new [] { stypes [i] });
5087                                 }
5088                         }
5089
5090                         return stypes;
5091                 }
5092
5093                 public void RegisterLabel (BlockContext rc, SwitchLabel sl)
5094                 {
5095                         case_labels.Add (sl);
5096
5097                         if (sl.IsDefault) {
5098                                 if (case_default != null) {
5099                                         sl.Error_AlreadyOccurs (rc, case_default);
5100                                 } else {
5101                                         case_default = sl;
5102                                 }
5103
5104                                 return;
5105                         }
5106
5107                         if (sl.Converted == null)
5108                                 return;
5109
5110                         try {
5111                                 if (string_labels != null) {
5112                                         string string_value = sl.Converted.GetValue () as string;
5113                                         if (string_value == null)
5114                                                 case_null = sl;
5115                                         else
5116                                                 string_labels.Add (string_value, sl);
5117                                 } else {
5118                                         if (sl.Converted.IsNull) {
5119                                                 case_null = sl;
5120                                         } else {
5121                                                 labels.Add (sl.Converted.GetValueAsLong (), sl);
5122                                         }
5123                                 }
5124                         } catch (ArgumentException) {
5125                                 if (string_labels != null)
5126                                         sl.Error_AlreadyOccurs (rc, string_labels[(string) sl.Converted.GetValue ()]);
5127                                 else
5128                                         sl.Error_AlreadyOccurs (rc, labels[sl.Converted.GetValueAsLong ()]);
5129                         }
5130                 }
5131                 
5132                 //
5133                 // This method emits code for a lookup-based switch statement (non-string)
5134                 // Basically it groups the cases into blocks that are at least half full,
5135                 // and then spits out individual lookup opcodes for each block.
5136                 // It emits the longest blocks first, and short blocks are just
5137                 // handled with direct compares.
5138                 //
5139                 void EmitTableSwitch (EmitContext ec, Expression val)
5140                 {
5141                         if (labels != null && labels.Count > 0) {
5142                                 List<LabelsRange> ranges;
5143                                 if (string_labels != null) {
5144                                         // We have done all hard work for string already
5145                                         // setup single range only
5146                                         ranges = new List<LabelsRange> (1);
5147                                         ranges.Add (new LabelsRange (0, labels.Count - 1, labels.Keys));
5148                                 } else {
5149                                         var element_keys = new long[labels.Count];
5150                                         labels.Keys.CopyTo (element_keys, 0);
5151                                         Array.Sort (element_keys);
5152
5153                                         //
5154                                         // Build possible ranges of switch labes to reduce number
5155                                         // of comparisons
5156                                         //
5157                                         ranges = new List<LabelsRange> (element_keys.Length);
5158                                         var range = new LabelsRange (element_keys[0]);
5159                                         ranges.Add (range);
5160                                         for (int i = 1; i < element_keys.Length; ++i) {
5161                                                 var l = element_keys[i];
5162                                                 if (range.AddValue (l))
5163                                                         continue;
5164
5165                                                 range = new LabelsRange (l);
5166                                                 ranges.Add (range);
5167                                         }
5168
5169                                         // sort the blocks so we can tackle the largest ones first
5170                                         ranges.Sort ();
5171                                 }
5172
5173                                 Label lbl_default = defaultLabel;
5174                                 TypeSpec compare_type = SwitchType.IsEnum ? EnumSpec.GetUnderlyingType (SwitchType) : SwitchType;
5175
5176                                 for (int range_index = ranges.Count - 1; range_index >= 0; --range_index) {
5177                                         LabelsRange kb = ranges[range_index];
5178                                         lbl_default = (range_index == 0) ? defaultLabel : ec.DefineLabel ();
5179
5180                                         // Optimize small ranges using simple equality check
5181                                         if (kb.Range <= 2) {
5182                                                 foreach (var key in kb.label_values) {
5183                                                         SwitchLabel sl = labels[key];
5184                                                         if (sl == case_default || sl == case_null)
5185                                                                 continue;
5186
5187                                                         if (sl.Converted.IsZeroInteger) {
5188                                                                 val.EmitBranchable (ec, sl.GetILLabel (ec), false);
5189                                                         } else {
5190                                                                 val.Emit (ec);
5191                                                                 sl.Converted.Emit (ec);
5192                                                                 ec.Emit (OpCodes.Beq, sl.GetILLabel (ec));
5193                                                         }
5194                                                 }
5195                                         } else {
5196                                                 // TODO: if all the keys in the block are the same and there are
5197                                                 //       no gaps/defaults then just use a range-check.
5198                                                 if (compare_type.BuiltinType == BuiltinTypeSpec.Type.Long || compare_type.BuiltinType == BuiltinTypeSpec.Type.ULong) {
5199                                                         // TODO: optimize constant/I4 cases
5200
5201                                                         // check block range (could be > 2^31)
5202                                                         val.Emit (ec);
5203                                                         ec.EmitLong (kb.min);
5204                                                         ec.Emit (OpCodes.Blt, lbl_default);
5205
5206                                                         val.Emit (ec);
5207                                                         ec.EmitLong (kb.max);
5208                                                         ec.Emit (OpCodes.Bgt, lbl_default);
5209
5210                                                         // normalize range
5211                                                         val.Emit (ec);
5212                                                         if (kb.min != 0) {
5213                                                                 ec.EmitLong (kb.min);
5214                                                                 ec.Emit (OpCodes.Sub);
5215                                                         }
5216
5217                                                         ec.Emit (OpCodes.Conv_I4);      // assumes < 2^31 labels!
5218                                                 } else {
5219                                                         // normalize range
5220                                                         val.Emit (ec);
5221                                                         int first = (int) kb.min;
5222                                                         if (first > 0) {
5223                                                                 ec.EmitInt (first);
5224                                                                 ec.Emit (OpCodes.Sub);
5225                                                         } else if (first < 0) {
5226                                                                 ec.EmitInt (-first);
5227                                                                 ec.Emit (OpCodes.Add);
5228                                                         }
5229                                                 }
5230
5231                                                 // first, build the list of labels for the switch
5232                                                 int iKey = 0;
5233                                                 long cJumps = kb.Range;
5234                                                 Label[] switch_labels = new Label[cJumps];
5235                                                 for (int iJump = 0; iJump < cJumps; iJump++) {
5236                                                         var key = kb.label_values[iKey];
5237                                                         if (key == kb.min + iJump) {
5238                                                                 switch_labels[iJump] = labels[key].GetILLabel (ec);
5239                                                                 iKey++;
5240                                                         } else {
5241                                                                 switch_labels[iJump] = lbl_default;
5242                                                         }
5243                                                 }
5244
5245                                                 // emit the switch opcode
5246                                                 ec.Emit (OpCodes.Switch, switch_labels);
5247                                         }
5248
5249                                         // mark the default for this block
5250                                         if (range_index != 0)
5251                                                 ec.MarkLabel (lbl_default);
5252                                 }
5253
5254                                 // the last default just goes to the end
5255                                 if (ranges.Count > 0)
5256                                         ec.Emit (OpCodes.Br, lbl_default);
5257                         }
5258                 }
5259                 
5260                 public SwitchLabel FindLabel (Constant value)
5261                 {
5262                         SwitchLabel sl = null;
5263
5264                         if (string_labels != null) {
5265                                 string s = value.GetValue () as string;
5266                                 if (s == null) {
5267                                         if (case_null != null)
5268                                                 sl = case_null;
5269                                         else if (case_default != null)
5270                                                 sl = case_default;
5271                                 } else {
5272                                         string_labels.TryGetValue (s, out sl);
5273                                 }
5274                         } else {
5275                                 if (value is NullLiteral) {
5276                                         sl = case_null;
5277                                 } else {
5278                                         labels.TryGetValue (value.GetValueAsLong (), out sl);
5279                                 }
5280                         }
5281
5282                         if (sl == null || sl.SectionStart)
5283                                 return sl;
5284
5285                         //
5286                         // Always return section start, it simplifies handling of switch labels
5287                         //
5288                         for (int idx = case_labels.IndexOf (sl); ; --idx) {
5289                                 var cs = case_labels [idx];
5290                                 if (cs.SectionStart)
5291                                         return cs;
5292                         }
5293                 }
5294
5295                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
5296                 {
5297                         Expr.FlowAnalysis (fc);
5298
5299                         var prev_switch = fc.SwitchInitialDefinitiveAssignment;
5300                         var InitialDefinitiveAssignment = fc.DefiniteAssignment;
5301                         fc.SwitchInitialDefinitiveAssignment = InitialDefinitiveAssignment;
5302
5303                         block.FlowAnalysis (fc);
5304
5305                         fc.SwitchInitialDefinitiveAssignment = prev_switch;
5306
5307                         if (end_reachable_das != null) {
5308                                 var sections_das = DefiniteAssignmentBitSet.And (end_reachable_das);
5309                                 InitialDefinitiveAssignment |= sections_das;
5310                                 end_reachable_das = null;
5311                         }
5312
5313                         fc.DefiniteAssignment = InitialDefinitiveAssignment;
5314
5315                         return case_default != null && !end_reachable;
5316                 }
5317
5318                 public override bool Resolve (BlockContext ec)
5319                 {
5320                         Expr = Expr.Resolve (ec);
5321                         if (Expr == null)
5322                                 return false;
5323
5324                         //
5325                         // LAMESPEC: User conversion from non-nullable governing type has a priority
5326                         //
5327                         new_expr = SwitchGoverningType (ec, Expr, false);
5328
5329                         if (new_expr == null) {
5330                                 if (Expr.Type.IsNullableType) {
5331                                         unwrap = Nullable.Unwrap.Create (Expr, false);
5332                                         if (unwrap == null)
5333                                                 return false;
5334
5335                                         //
5336                                         // Unwrap + user conversion using non-nullable type is not allowed but user operator
5337                                         // involving nullable Expr and nullable governing type is
5338                                         //
5339                                         new_expr = SwitchGoverningType (ec, unwrap, true);
5340                                 }
5341                         }
5342
5343                         Expression switch_expr;
5344                         if (new_expr == null) {
5345                                 if (ec.Module.Compiler.Settings.Version != LanguageVersion.Experimental) {
5346                                         if (Expr.Type != InternalType.ErrorType) {
5347                                                 ec.Report.Error (151, loc,
5348                                                         "A switch expression of type `{0}' cannot be converted to an integral type, bool, char, string, enum or nullable type",
5349                                                         Expr.Type.GetSignatureForError ());
5350                                         }
5351
5352                                         return false;
5353                                 }
5354
5355                                 switch_expr = Expr;
5356                                 SwitchType = Expr.Type;
5357                         } else {
5358                                 switch_expr = new_expr;
5359                                 SwitchType = new_expr.Type;
5360                                 if (SwitchType.IsNullableType) {
5361                                         new_expr = unwrap = Nullable.Unwrap.Create (new_expr, true);
5362                                         SwitchType = Nullable.NullableInfo.GetUnderlyingType (SwitchType);
5363                                 }
5364
5365                                 if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.Bool && ec.Module.Compiler.Settings.Version == LanguageVersion.ISO_1) {
5366                                         ec.Report.FeatureIsNotAvailable (ec.Module.Compiler, loc, "switch expression of boolean type");
5367                                         return false;
5368                                 }
5369
5370                                 if (block.Statements.Count == 0)
5371                                         return true;
5372
5373                                 if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String) {
5374                                         string_labels = new Dictionary<string, SwitchLabel> ();
5375                                 } else {
5376                                         labels = new Dictionary<long, SwitchLabel> ();
5377                                 }
5378                         }
5379
5380                         var constant = switch_expr as Constant;
5381
5382                         //
5383                         // Don't need extra variable for constant switch or switch with
5384                         // only default case
5385                         //
5386                         if (constant == null) {
5387                                 //
5388                                 // Store switch expression for comparison purposes
5389                                 //
5390                                 value = switch_expr as VariableReference;
5391                                 if (value == null && !HasOnlyDefaultSection ()) {
5392                                         var current_block = ec.CurrentBlock;
5393                                         ec.CurrentBlock = Block;
5394                                         // Create temporary variable inside switch scope
5395                                         value = TemporaryVariableReference.Create (SwitchType, ec.CurrentBlock, loc);
5396                                         value.Resolve (ec);
5397                                         ec.CurrentBlock = current_block;
5398                                 }
5399                         }
5400
5401                         case_labels = new List<SwitchLabel> ();
5402
5403                         Switch old_switch = ec.Switch;
5404                         ec.Switch = this;
5405                         var parent_los = ec.EnclosingLoopOrSwitch;
5406                         ec.EnclosingLoopOrSwitch = this;
5407
5408                         var ok = Statement.Resolve (ec);
5409
5410                         ec.EnclosingLoopOrSwitch = parent_los;
5411                         ec.Switch = old_switch;
5412
5413                         //
5414                         // Check if all goto cases are valid. Needs to be done after switch
5415                         // is resolved because goto can jump forward in the scope.
5416                         //
5417                         if (goto_cases != null) {
5418                                 foreach (var gc in goto_cases) {
5419                                         if (gc.Item1 == null) {
5420                                                 if (DefaultLabel == null) {
5421                                                         Goto.Error_UnknownLabel (ec, "default", loc);
5422                                                 }
5423
5424                                                 continue;
5425                                         }
5426
5427                                         var sl = FindLabel (gc.Item2);
5428                                         if (sl == null) {
5429                                                 Goto.Error_UnknownLabel (ec, "case " + gc.Item2.GetValueAsLiteral (), loc);
5430                                         } else {
5431                                                 gc.Item1.Label = sl;
5432                                         }
5433                                 }
5434                         }
5435
5436                         if (!ok)
5437                                 return false;
5438
5439                         if (constant == null && SwitchType.BuiltinType == BuiltinTypeSpec.Type.String && string_labels.Count > 6) {
5440                                 ResolveStringSwitchMap (ec);
5441                         }
5442
5443                         //
5444                         // Anonymous storey initialization has to happen before
5445                         // any generated switch dispatch
5446                         //
5447                         block.InsertStatement (0, new DispatchStatement (this));
5448
5449                         return true;
5450                 }
5451
5452                 bool HasOnlyDefaultSection ()
5453                 {
5454                         for (int i = 0; i < block.Statements.Count; ++i) {
5455                                 var s = block.Statements[i] as SwitchLabel;
5456
5457                                 if (s == null || s.IsDefault)
5458                                         continue;
5459
5460                                 return false;
5461                         }
5462
5463                         return true;
5464                 }
5465
5466                 public override Reachability MarkReachable (Reachability rc)
5467                 {
5468                         if (rc.IsUnreachable)
5469                                 return rc;
5470
5471                         base.MarkReachable (rc);
5472
5473                         block.MarkReachableScope (rc);
5474
5475                         if (block.Statements.Count == 0)
5476                                 return rc;
5477
5478                         SwitchLabel constant_label = null;
5479                         var constant = new_expr as Constant;
5480
5481                         if (constant != null) {
5482                                 constant_label = FindLabel (constant) ?? case_default;
5483                                 if (constant_label == null) {
5484                                         block.Statements.RemoveAt (0);
5485                                         return rc;
5486                                 }
5487                         }
5488
5489                         var section_rc = new Reachability ();
5490                         SwitchLabel prev_label = null;
5491
5492                         for (int i = 0; i < block.Statements.Count; ++i) {
5493                                 var s = block.Statements[i];
5494                                 var sl = s as SwitchLabel;
5495
5496                                 if (sl != null && sl.SectionStart) {
5497                                         //
5498                                         // Section is marked already via goto case
5499                                         //
5500                                         if (!sl.IsUnreachable) {
5501                                                 section_rc = new Reachability ();
5502                                                 continue;
5503                                         }
5504
5505                                         if (section_rc.IsUnreachable) {
5506                                                 //
5507                                                 // Common case. Previous label section end is unreachable as
5508                                                 // it ends with break, return, etc. For next section revert
5509                                                 // to reachable again unless we have constant switch block
5510                                                 //
5511                                                 section_rc = constant_label != null && constant_label != sl ?
5512                                                         Reachability.CreateUnreachable () :
5513                                                         new Reachability ();
5514                                         } else if (prev_label != null) {
5515                                                 //
5516                                                 // Error case as control cannot fall through from one case label
5517                                                 //
5518                                                 sl.SectionStart = false;
5519                                                 s = new MissingBreak (prev_label);
5520                                                 s.MarkReachable (rc);
5521                                                 block.Statements.Insert (i - 1, s);
5522                                                 ++i;
5523                                         } else if (constant_label != null && constant_label != sl) {
5524                                                 //
5525                                                 // Special case for the first unreachable label in constant
5526                                                 // switch block
5527                                                 //
5528                                                 section_rc = Reachability.CreateUnreachable ();
5529                                         }
5530
5531                                         prev_label = sl;
5532                                 }
5533
5534                                 section_rc = s.MarkReachable (section_rc);
5535                         }
5536
5537                         if (!section_rc.IsUnreachable && prev_label != null) {
5538                                 prev_label.SectionStart = false;
5539                                 var s = new MissingBreak (prev_label) {
5540                                         FallOut = true
5541                                 };
5542
5543                                 s.MarkReachable (rc);
5544                                 block.Statements.Add (s);
5545                         }
5546
5547                         //
5548                         // Reachability can affect parent only when all possible paths are handled but
5549                         // we still need to run reachability check on switch body to check for fall-through
5550                         //
5551                         if (case_default == null && constant_label == null)
5552                                 return rc;
5553
5554                         //
5555                         // We have at least one local exit from the switch
5556                         //
5557                         if (end_reachable)
5558                                 return rc;
5559
5560                         return Reachability.CreateUnreachable ();
5561                 }
5562
5563                 public void RegisterGotoCase (GotoCase gotoCase, Constant value)
5564                 {
5565                         if (goto_cases == null)
5566                                 goto_cases = new List<Tuple<GotoCase, Constant>> ();
5567
5568                         goto_cases.Add (Tuple.Create (gotoCase, value));
5569                 }
5570
5571                 //
5572                 // Converts string switch into string hashtable
5573                 //
5574                 void ResolveStringSwitchMap (ResolveContext ec)
5575                 {
5576                         FullNamedExpression string_dictionary_type;
5577                         if (ec.Module.PredefinedTypes.Dictionary.Define ()) {
5578                                 string_dictionary_type = new TypeExpression (
5579                                         ec.Module.PredefinedTypes.Dictionary.TypeSpec.MakeGenericType (ec,
5580                                                 new [] { ec.BuiltinTypes.String, ec.BuiltinTypes.Int }),
5581                                         loc);
5582                         } else if (ec.Module.PredefinedTypes.Hashtable.Define ()) {
5583                                 string_dictionary_type = new TypeExpression (ec.Module.PredefinedTypes.Hashtable.TypeSpec, loc);
5584                         } else {
5585                                 ec.Module.PredefinedTypes.Dictionary.Resolve ();
5586                                 return;
5587                         }
5588
5589                         var ctype = ec.CurrentMemberDefinition.Parent.PartialContainer;
5590                         Field field = new Field (ctype, string_dictionary_type,
5591                                 Modifiers.STATIC | Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED,
5592                                 new MemberName (CompilerGeneratedContainer.MakeName (null, "f", "switch$map", ec.Module.CounterSwitchTypes++), loc), null);
5593                         if (!field.Define ())
5594                                 return;
5595                         ctype.AddField (field);
5596
5597                         var init = new List<Expression> ();
5598                         int counter = -1;
5599                         labels = new Dictionary<long, SwitchLabel> (string_labels.Count);
5600                         string value = null;
5601
5602                         foreach (SwitchLabel sl in case_labels) {
5603
5604                                 if (sl.SectionStart)
5605                                         labels.Add (++counter, sl);
5606
5607                                 if (sl == case_default || sl == case_null)
5608                                         continue;
5609
5610                                 value = (string) sl.Converted.GetValue ();
5611                                 var init_args = new List<Expression> (2);
5612                                 init_args.Add (new StringLiteral (ec.BuiltinTypes, value, sl.Location));
5613
5614                                 sl.Converted = new IntConstant (ec.BuiltinTypes, counter, loc);
5615                                 init_args.Add (sl.Converted);
5616
5617                                 init.Add (new CollectionElementInitializer (init_args, loc));
5618                         }
5619         
5620                         Arguments args = new Arguments (1);
5621                         args.Add (new Argument (new IntConstant (ec.BuiltinTypes, init.Count, loc)));
5622                         Expression initializer = new NewInitialize (string_dictionary_type, args,
5623                                 new CollectionOrObjectInitializers (init, loc), loc);
5624
5625                         switch_cache_field = new FieldExpr (field, loc);
5626                         string_dictionary = new SimpleAssign (switch_cache_field, initializer.Resolve (ec));
5627                 }
5628
5629                 void DoEmitStringSwitch (EmitContext ec)
5630                 {
5631                         Label l_initialized = ec.DefineLabel ();
5632
5633                         //
5634                         // Skip initialization when value is null
5635                         //
5636                         value.EmitBranchable (ec, nullLabel, false);
5637
5638                         //
5639                         // Check if string dictionary is initialized and initialize
5640                         //
5641                         switch_cache_field.EmitBranchable (ec, l_initialized, true);
5642                         using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
5643                                 string_dictionary.EmitStatement (ec);
5644                         }
5645                         ec.MarkLabel (l_initialized);
5646
5647                         LocalTemporary string_switch_variable = new LocalTemporary (ec.BuiltinTypes.Int);
5648
5649                         ResolveContext rc = new ResolveContext (ec.MemberContext);
5650
5651                         if (switch_cache_field.Type.IsGeneric) {
5652                                 Arguments get_value_args = new Arguments (2);
5653                                 get_value_args.Add (new Argument (value));
5654                                 get_value_args.Add (new Argument (string_switch_variable, Argument.AType.Out));
5655                                 Expression get_item = new Invocation (new MemberAccess (switch_cache_field, "TryGetValue", loc), get_value_args).Resolve (rc);
5656                                 if (get_item == null)
5657                                         return;
5658
5659                                 //
5660                                 // A value was not found, go to default case
5661                                 //
5662                                 get_item.EmitBranchable (ec, defaultLabel, false);
5663                         } else {
5664                                 Arguments get_value_args = new Arguments (1);
5665                                 get_value_args.Add (new Argument (value));
5666
5667                                 Expression get_item = new ElementAccess (switch_cache_field, get_value_args, loc).Resolve (rc);
5668                                 if (get_item == null)
5669                                         return;
5670
5671                                 LocalTemporary get_item_object = new LocalTemporary (ec.BuiltinTypes.Object);
5672                                 get_item_object.EmitAssign (ec, get_item, true, false);
5673                                 ec.Emit (OpCodes.Brfalse, defaultLabel);
5674
5675                                 ExpressionStatement get_item_int = (ExpressionStatement) new SimpleAssign (string_switch_variable,
5676                                         new Cast (new TypeExpression (ec.BuiltinTypes.Int, loc), get_item_object, loc)).Resolve (rc);
5677
5678                                 get_item_int.EmitStatement (ec);
5679                                 get_item_object.Release (ec);
5680                         }
5681
5682                         EmitTableSwitch (ec, string_switch_variable);
5683                         string_switch_variable.Release (ec);
5684                 }
5685
5686                 //
5687                 // Emits switch using simple if/else comparison for small label count (4 + optional default)
5688                 //
5689                 void EmitShortSwitch (EmitContext ec)
5690                 {
5691                         MethodSpec equal_method = null;
5692                         if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String) {
5693                                 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (loc);
5694                         }
5695
5696                         if (equal_method != null) {
5697                                 value.EmitBranchable (ec, nullLabel, false);
5698                         }
5699
5700                         for (int i = 0; i < case_labels.Count; ++i) {
5701                                 var label = case_labels [i];
5702                                 if (label == case_default || label == case_null)
5703                                         continue;
5704
5705                                 var constant = label.Converted;
5706
5707                                 if (constant == null) {
5708                                         label.Label.EmitBranchable (ec, label.GetILLabel (ec), true);
5709                                         continue;
5710                                 }
5711
5712                                 if (equal_method != null) {
5713                                         value.Emit (ec);
5714                                         constant.Emit (ec);
5715
5716                                         var call = new CallEmitter ();
5717                                         call.EmitPredefined (ec, equal_method, new Arguments (0));
5718                                         ec.Emit (OpCodes.Brtrue, label.GetILLabel (ec));
5719                                         continue;
5720                                 }
5721
5722                                 if (constant.IsZeroInteger && constant.Type.BuiltinType != BuiltinTypeSpec.Type.Long && constant.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
5723                                         value.EmitBranchable (ec, label.GetILLabel (ec), false);
5724                                         continue;
5725                                 }
5726
5727                                 value.Emit (ec);
5728                                 constant.Emit (ec);
5729                                 ec.Emit (OpCodes.Beq, label.GetILLabel (ec));
5730                         }
5731
5732                         ec.Emit (OpCodes.Br, defaultLabel);
5733                 }
5734
5735                 void EmitDispatch (EmitContext ec)
5736                 {
5737                         if (IsPatternMatching) {
5738                                 EmitShortSwitch (ec);
5739                                 return;
5740                         }
5741
5742                         if (value == null) {
5743                                 //
5744                                 // Constant switch, we've already done the work if there is only 1 label
5745                                 // referenced
5746                                 //
5747                                 int reachable = 0;
5748                                 foreach (var sl in case_labels) {
5749                                         if (sl.IsUnreachable)
5750                                                 continue;
5751
5752                                         if (reachable++ > 0) {
5753                                                 var constant = (Constant) new_expr;
5754                                                 var constant_label = FindLabel (constant) ?? case_default;
5755
5756                                                 ec.Emit (OpCodes.Br, constant_label.GetILLabel (ec));
5757                                                 break;
5758                                         }
5759                                 }
5760
5761                                 return;
5762                         }
5763
5764                         if (string_dictionary != null) {
5765                                 DoEmitStringSwitch (ec);
5766                         } else if (case_labels.Count < 4 || string_labels != null) {
5767                                 EmitShortSwitch (ec);
5768                         } else {
5769                                 EmitTableSwitch (ec, value);
5770                         }
5771                 }
5772
5773                 protected override void DoEmit (EmitContext ec)
5774                 {
5775                         //
5776                         // Setup the codegen context
5777                         //
5778                         Label old_end = ec.LoopEnd;
5779                         Switch old_switch = ec.Switch;
5780
5781                         ec.LoopEnd = ec.DefineLabel ();
5782                         ec.Switch = this;
5783
5784                         defaultLabel = case_default == null ? ec.LoopEnd : case_default.GetILLabel (ec);
5785                         nullLabel = case_null == null ? defaultLabel : case_null.GetILLabel (ec);
5786
5787                         if (value != null) {
5788                                 ec.Mark (loc);
5789
5790                                 var switch_expr = new_expr ?? Expr;
5791                                 if (IsNullable) {
5792                                         unwrap.EmitCheck (ec);
5793                                         ec.Emit (OpCodes.Brfalse, nullLabel);
5794                                         value.EmitAssign (ec, switch_expr, false, false);
5795                                 } else if (switch_expr != value) {
5796                                         value.EmitAssign (ec, switch_expr, false, false);
5797                                 }
5798
5799
5800                                 //
5801                                 // Next statement is compiler generated we don't need extra
5802                                 // nop when we can use the statement for sequence point
5803                                 //
5804                                 ec.Mark (block.StartLocation);
5805                                 block.IsCompilerGenerated = true;
5806                         } else {
5807                                 new_expr.EmitSideEffect (ec);
5808                         }
5809
5810                         block.Emit (ec);
5811
5812                         // Restore context state. 
5813                         ec.MarkLabel (ec.LoopEnd);
5814
5815                         //
5816                         // Restore the previous context
5817                         //
5818                         ec.LoopEnd = old_end;
5819                         ec.Switch = old_switch;
5820                 }
5821
5822                 protected override void CloneTo (CloneContext clonectx, Statement t)
5823                 {
5824                         Switch target = (Switch) t;
5825
5826                         target.Expr = Expr.Clone (clonectx);
5827                         target.Statement = target.block = (ExplicitBlock) block.Clone (clonectx);
5828                 }
5829                 
5830                 public override object Accept (StructuralVisitor visitor)
5831                 {
5832                         return visitor.Visit (this);
5833                 }
5834
5835                 public override void AddEndDefiniteAssignment (FlowAnalysisContext fc)
5836                 {
5837                         if (case_default == null && !(new_expr is Constant))
5838                                 return;
5839
5840                         if (end_reachable_das == null)
5841                                 end_reachable_das = new List<DefiniteAssignmentBitSet> ();
5842
5843                         end_reachable_das.Add (fc.DefiniteAssignment);
5844                 }
5845
5846                 public override void SetEndReachable ()
5847                 {
5848                         end_reachable = true;
5849                 }
5850         }
5851
5852         // A place where execution can restart in a state machine
5853         public abstract class ResumableStatement : Statement
5854         {
5855                 bool prepared;
5856                 protected Label resume_point;
5857
5858                 public Label PrepareForEmit (EmitContext ec)
5859                 {
5860                         if (!prepared) {
5861                                 prepared = true;
5862                                 resume_point = ec.DefineLabel ();
5863                         }
5864                         return resume_point;
5865                 }
5866
5867                 public virtual Label PrepareForDispose (EmitContext ec, Label end)
5868                 {
5869                         return end;
5870                 }
5871
5872                 public virtual void EmitForDispose (EmitContext ec, LocalBuilder pc, Label end, bool have_dispatcher)
5873                 {
5874                 }
5875         }
5876
5877         public abstract class TryFinallyBlock : ExceptionStatement
5878         {
5879                 protected Statement stmt;
5880                 Label dispose_try_block;
5881                 bool prepared_for_dispose, emitted_dispose;
5882                 Method finally_host;
5883
5884                 protected TryFinallyBlock (Statement stmt, Location loc)
5885                         : base (loc)
5886                 {
5887                         this.stmt = stmt;
5888                 }
5889
5890                 #region Properties
5891
5892                 public Statement Statement {
5893                         get {
5894                                 return stmt;
5895                         }
5896                 }
5897
5898                 #endregion
5899
5900                 protected abstract void EmitTryBody (EmitContext ec);
5901                 public abstract void EmitFinallyBody (EmitContext ec);
5902
5903                 public override Label PrepareForDispose (EmitContext ec, Label end)
5904                 {
5905                         if (!prepared_for_dispose) {
5906                                 prepared_for_dispose = true;
5907                                 dispose_try_block = ec.DefineLabel ();
5908                         }
5909                         return dispose_try_block;
5910                 }
5911
5912                 protected sealed override void DoEmit (EmitContext ec)
5913                 {
5914                         EmitTryBodyPrepare (ec);
5915                         EmitTryBody (ec);
5916
5917                         bool beginFinally = EmitBeginFinallyBlock (ec);
5918
5919                         Label start_finally = ec.DefineLabel ();
5920                         if (resume_points != null && beginFinally) {
5921                                 var state_machine = (StateMachineInitializer) ec.CurrentAnonymousMethod;
5922
5923                                 ec.Emit (OpCodes.Ldloc, state_machine.SkipFinally);
5924                                 ec.Emit (OpCodes.Brfalse_S, start_finally);
5925                                 ec.Emit (OpCodes.Endfinally);
5926                         }
5927
5928                         ec.MarkLabel (start_finally);
5929
5930                         if (finally_host != null) {
5931                                 finally_host.Define ();
5932                                 finally_host.PrepareEmit ();
5933                                 finally_host.Emit ();
5934
5935                                 // Now it's safe to add, to close it properly and emit sequence points
5936                                 finally_host.Parent.AddMember (finally_host);
5937
5938                                 var ce = new CallEmitter ();
5939                                 ce.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, loc);
5940                                 ce.EmitPredefined (ec, finally_host.Spec, new Arguments (0), true);
5941                         } else {
5942                                 EmitFinallyBody (ec);
5943                         }
5944
5945                         if (beginFinally)
5946                                 ec.EndExceptionBlock ();
5947                 }
5948
5949                 public override void EmitForDispose (EmitContext ec, LocalBuilder pc, Label end, bool have_dispatcher)
5950                 {
5951                         if (emitted_dispose)
5952                                 return;
5953
5954                         emitted_dispose = true;
5955
5956                         Label end_of_try = ec.DefineLabel ();
5957
5958                         // Ensure that the only way we can get into this code is through a dispatcher
5959                         if (have_dispatcher)
5960                                 ec.Emit (OpCodes.Br, end);
5961
5962                         ec.BeginExceptionBlock ();
5963
5964                         ec.MarkLabel (dispose_try_block);
5965
5966                         Label[] labels = null;
5967                         for (int i = 0; i < resume_points.Count; ++i) {
5968                                 ResumableStatement s = resume_points[i];
5969                                 Label ret = s.PrepareForDispose (ec, end_of_try);
5970                                 if (ret.Equals (end_of_try) && labels == null)
5971                                         continue;
5972                                 if (labels == null) {
5973                                         labels = new Label[resume_points.Count];
5974                                         for (int j = 0; j < i; ++j)
5975                                                 labels[j] = end_of_try;
5976                                 }
5977                                 labels[i] = ret;
5978                         }
5979
5980                         if (labels != null) {
5981                                 int j;
5982                                 for (j = 1; j < labels.Length; ++j)
5983                                         if (!labels[0].Equals (labels[j]))
5984                                                 break;
5985                                 bool emit_dispatcher = j < labels.Length;
5986
5987                                 if (emit_dispatcher) {
5988                                         ec.Emit (OpCodes.Ldloc, pc);
5989                                         ec.EmitInt (first_resume_pc);
5990                                         ec.Emit (OpCodes.Sub);
5991                                         ec.Emit (OpCodes.Switch, labels);
5992                                 }
5993
5994                                 foreach (ResumableStatement s in resume_points)
5995                                         s.EmitForDispose (ec, pc, end_of_try, emit_dispatcher);
5996                         }
5997
5998                         ec.MarkLabel (end_of_try);
5999
6000                         ec.BeginFinallyBlock ();
6001
6002                         if (finally_host != null) {
6003                                 var ce = new CallEmitter ();
6004                                 ce.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, loc);
6005                                 ce.EmitPredefined (ec, finally_host.Spec, new Arguments (0), true);
6006                         } else {
6007                                 EmitFinallyBody (ec);
6008                         }
6009
6010                         ec.EndExceptionBlock ();
6011                 }
6012
6013                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6014                 {
6015                         var res = stmt.FlowAnalysis (fc);
6016                         parent_try_block = null;
6017                         return res;
6018                 }
6019
6020                 protected virtual bool EmitBeginFinallyBlock (EmitContext ec)
6021                 {
6022                         ec.BeginFinallyBlock ();
6023                         return true;
6024                 }
6025
6026                 public override Reachability MarkReachable (Reachability rc)
6027                 {
6028                         base.MarkReachable (rc);
6029                         return Statement.MarkReachable (rc);
6030                 }
6031
6032                 public override bool Resolve (BlockContext bc)
6033                 {
6034                         bool ok;
6035
6036                         parent_try_block = bc.CurrentTryBlock;
6037                         bc.CurrentTryBlock = this;
6038
6039                         if (stmt is TryCatch) {
6040                                 ok = stmt.Resolve (bc);
6041                         } else {
6042                                 using (bc.Set (ResolveContext.Options.TryScope)) {
6043                                         ok = stmt.Resolve (bc);
6044                                 }
6045                         }
6046
6047                         bc.CurrentTryBlock = parent_try_block;
6048
6049                         //
6050                         // Finally block inside iterator is called from MoveNext and
6051                         // Dispose methods that means we need to lift the block into
6052                         // newly created host method to emit the body only once. The
6053                         // original block then simply calls the newly generated method.
6054                         //
6055                         if (bc.CurrentIterator != null && !bc.IsInProbingMode) {
6056                                 var b = stmt as Block;
6057                                 if (b != null && b.Explicit.HasYield) {
6058                                         finally_host = bc.CurrentIterator.CreateFinallyHost (this);
6059                                 }
6060                         }
6061
6062                         return base.Resolve (bc) && ok;
6063                 }
6064         }
6065
6066         //
6067         // Base class for blocks using exception handling
6068         //
6069         public abstract class ExceptionStatement : ResumableStatement
6070         {
6071                 protected List<ResumableStatement> resume_points;
6072                 protected int first_resume_pc;
6073                 protected ExceptionStatement parent_try_block;
6074                 protected int first_catch_resume_pc = -1;
6075
6076                 protected ExceptionStatement (Location loc)
6077                 {
6078                         this.loc = loc;
6079                 }
6080
6081                 protected virtual void EmitTryBodyPrepare (EmitContext ec)
6082                 {
6083                         StateMachineInitializer state_machine = null;
6084                         if (resume_points != null) {
6085                                 state_machine = (StateMachineInitializer) ec.CurrentAnonymousMethod;
6086
6087                                 ec.EmitInt ((int) IteratorStorey.State.Running);
6088                                 ec.Emit (OpCodes.Stloc, state_machine.CurrentPC);
6089                         }
6090
6091                         //
6092                         // The resume points in catch section when this is try-catch-finally
6093                         //
6094                         if (IsRewrittenTryCatchFinally ()) {
6095                                 ec.BeginExceptionBlock ();
6096
6097                                 if (first_catch_resume_pc >= 0) {
6098
6099                                         ec.MarkLabel (resume_point);
6100
6101                                         // For normal control flow, we want to fall-through the Switch
6102                                         // So, we use CurrentPC rather than the $PC field, and initialize it to an outside value above
6103                                         ec.Emit (OpCodes.Ldloc, state_machine.CurrentPC);
6104                                         ec.EmitInt (first_resume_pc + first_catch_resume_pc);
6105                                         ec.Emit (OpCodes.Sub);
6106
6107                                         var labels = new Label [resume_points.Count - first_catch_resume_pc];
6108                                         for (int i = 0; i < labels.Length; ++i)
6109                                                 labels [i] = resume_points [i + first_catch_resume_pc].PrepareForEmit (ec);
6110                                         ec.Emit (OpCodes.Switch, labels);
6111                                 }
6112                         }
6113
6114                         ec.BeginExceptionBlock ();
6115
6116                         //
6117                         // The resume points for try section
6118                         //
6119                         if (resume_points != null && first_catch_resume_pc != 0) {
6120                                 if (first_catch_resume_pc < 0)
6121                                         ec.MarkLabel (resume_point);
6122
6123                                 // For normal control flow, we want to fall-through the Switch
6124                                 // So, we use CurrentPC rather than the $PC field, and initialize it to an outside value above
6125                                 ec.Emit (OpCodes.Ldloc, state_machine.CurrentPC);
6126                                 ec.EmitInt (first_resume_pc);
6127                                 ec.Emit (OpCodes.Sub);
6128
6129                                 var labels = new Label [first_catch_resume_pc > 0 ? first_catch_resume_pc : resume_points.Count];
6130                                 for (int i = 0; i < labels.Length; ++i)
6131                                         labels[i] = resume_points[i].PrepareForEmit (ec);
6132                                 ec.Emit (OpCodes.Switch, labels);
6133                         }
6134                 }
6135
6136                 bool IsRewrittenTryCatchFinally ()
6137                 {
6138                         var tf = this as TryFinally;
6139                         if (tf == null)
6140                                 return false;
6141
6142                         var tc = tf.Statement as TryCatch;
6143                         if (tc == null)
6144                                 return false;
6145
6146                         return tf.FinallyBlock.HasAwait || tc.HasClauseWithAwait;
6147                 }
6148
6149                 public int AddResumePoint (ResumableStatement stmt, int pc, StateMachineInitializer stateMachine, TryCatch catchBlock)
6150                 {
6151                         if (parent_try_block != null) {
6152                                 pc = parent_try_block.AddResumePoint (this, pc, stateMachine, catchBlock);
6153                         } else {
6154                                 pc = stateMachine.AddResumePoint (this);
6155                         }
6156
6157                         if (resume_points == null) {
6158                                 resume_points = new List<ResumableStatement> ();
6159                                 first_resume_pc = pc;
6160                         }
6161
6162                         if (pc != first_resume_pc + resume_points.Count)
6163                                 throw new InternalErrorException ("missed an intervening AddResumePoint?");
6164
6165                         var tf = this as TryFinally;
6166                         if (tf != null && tf.Statement == catchBlock && first_catch_resume_pc < 0) {
6167                                 first_catch_resume_pc = resume_points.Count;
6168                         }
6169
6170                         resume_points.Add (stmt);
6171                         return pc;
6172                 }
6173         }
6174
6175         public class Lock : TryFinallyBlock
6176         {
6177                 Expression expr;
6178                 TemporaryVariableReference expr_copy;
6179                 TemporaryVariableReference lock_taken;
6180                         
6181                 public Lock (Expression expr, Statement stmt, Location loc)
6182                         : base (stmt, loc)
6183                 {
6184                         this.expr = expr;
6185                 }
6186
6187                 public Expression Expr {
6188                         get {
6189                                 return this.expr;
6190                         }
6191                 }
6192
6193                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6194                 {
6195                         expr.FlowAnalysis (fc);
6196                         return base.DoFlowAnalysis (fc);
6197                 }
6198
6199                 public override bool Resolve (BlockContext ec)
6200                 {
6201                         expr = expr.Resolve (ec);
6202                         if (expr == null)
6203                                 return false;
6204
6205                         if (!TypeSpec.IsReferenceType (expr.Type) && expr.Type != InternalType.ErrorType) {
6206                                 ec.Report.Error (185, loc,
6207                                         "`{0}' is not a reference type as required by the lock statement",
6208                                         expr.Type.GetSignatureForError ());
6209                         }
6210
6211                         if (expr.Type.IsGenericParameter) {
6212                                 expr = Convert.ImplicitTypeParameterConversion (expr, (TypeParameterSpec)expr.Type, ec.BuiltinTypes.Object);
6213                         }
6214
6215                         VariableReference lv = expr as VariableReference;
6216                         bool locked;
6217                         if (lv != null) {
6218                                 locked = lv.IsLockedByStatement;
6219                                 lv.IsLockedByStatement = true;
6220                         } else {
6221                                 lv = null;
6222                                 locked = false;
6223                         }
6224
6225                         //
6226                         // Have to keep original lock value around to unlock same location
6227                         // in the case of original value has changed or is null
6228                         //
6229                         expr_copy = TemporaryVariableReference.Create (ec.BuiltinTypes.Object, ec.CurrentBlock, loc);
6230                         expr_copy.Resolve (ec);
6231
6232                         //
6233                         // Ensure Monitor methods are available
6234                         //
6235                         if (ResolvePredefinedMethods (ec) > 1) {
6236                                 lock_taken = TemporaryVariableReference.Create (ec.BuiltinTypes.Bool, ec.CurrentBlock, loc);
6237                                 lock_taken.Resolve (ec);
6238                         }
6239
6240                         using (ec.Set (ResolveContext.Options.LockScope)) {
6241                                 base.Resolve (ec);
6242                         }
6243
6244                         if (lv != null) {
6245                                 lv.IsLockedByStatement = locked;
6246                         }
6247
6248                         return true;
6249                 }
6250                 
6251                 protected override void EmitTryBodyPrepare (EmitContext ec)
6252                 {
6253                         expr_copy.EmitAssign (ec, expr);
6254
6255                         if (lock_taken != null) {
6256                                 //
6257                                 // Initialize ref variable
6258                                 //
6259                                 lock_taken.EmitAssign (ec, new BoolLiteral (ec.BuiltinTypes, false, loc));
6260                         } else {
6261                                 //
6262                                 // Monitor.Enter (expr_copy)
6263                                 //
6264                                 expr_copy.Emit (ec);
6265                                 ec.Emit (OpCodes.Call, ec.Module.PredefinedMembers.MonitorEnter.Get ());
6266                         }
6267
6268                         base.EmitTryBodyPrepare (ec);
6269                 }
6270
6271                 protected override void EmitTryBody (EmitContext ec)
6272                 {
6273                         //
6274                         // Monitor.Enter (expr_copy, ref lock_taken)
6275                         //
6276                         if (lock_taken != null) {
6277                                 expr_copy.Emit (ec);
6278                                 lock_taken.LocalInfo.CreateBuilder (ec);
6279                                 lock_taken.AddressOf (ec, AddressOp.Load);
6280                                 ec.Emit (OpCodes.Call, ec.Module.PredefinedMembers.MonitorEnter_v4.Get ());
6281                         }
6282
6283                         Statement.Emit (ec);
6284                 }
6285
6286                 public override void EmitFinallyBody (EmitContext ec)
6287                 {
6288                         //
6289                         // if (lock_taken) Monitor.Exit (expr_copy)
6290                         //
6291                         Label skip = ec.DefineLabel ();
6292
6293                         if (lock_taken != null) {
6294                                 lock_taken.Emit (ec);
6295                                 ec.Emit (OpCodes.Brfalse_S, skip);
6296                         }
6297
6298                         expr_copy.Emit (ec);
6299                         var m = ec.Module.PredefinedMembers.MonitorExit.Resolve (loc);
6300                         if (m != null)
6301                                 ec.Emit (OpCodes.Call, m);
6302
6303                         ec.MarkLabel (skip);
6304                 }
6305
6306                 int ResolvePredefinedMethods (ResolveContext rc)
6307                 {
6308                         // Try 4.0 Monitor.Enter (object, ref bool) overload first
6309                         var m = rc.Module.PredefinedMembers.MonitorEnter_v4.Get ();
6310                         if (m != null)
6311                                 return 4;
6312
6313                         m = rc.Module.PredefinedMembers.MonitorEnter.Get ();
6314                         if (m != null)
6315                                 return 1;
6316
6317                         rc.Module.PredefinedMembers.MonitorEnter_v4.Resolve (loc);
6318                         return 0;
6319                 }
6320
6321                 protected override void CloneTo (CloneContext clonectx, Statement t)
6322                 {
6323                         Lock target = (Lock) t;
6324
6325                         target.expr = expr.Clone (clonectx);
6326                         target.stmt = Statement.Clone (clonectx);
6327                 }
6328                 
6329                 public override object Accept (StructuralVisitor visitor)
6330                 {
6331                         return visitor.Visit (this);
6332                 }
6333
6334         }
6335
6336         public class Unchecked : Statement {
6337                 public Block Block;
6338                 
6339                 public Unchecked (Block b, Location loc)
6340                 {
6341                         Block = b;
6342                         b.Unchecked = true;
6343                         this.loc = loc;
6344                 }
6345
6346                 public override bool Resolve (BlockContext ec)
6347                 {
6348                         using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
6349                                 return Block.Resolve (ec);
6350                 }
6351                 
6352                 protected override void DoEmit (EmitContext ec)
6353                 {
6354                         using (ec.With (EmitContext.Options.CheckedScope, false))
6355                                 Block.Emit (ec);
6356                 }
6357
6358                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6359                 {
6360                         return Block.FlowAnalysis (fc);
6361                 }
6362
6363                 public override Reachability MarkReachable (Reachability rc)
6364                 {
6365                         base.MarkReachable (rc);
6366                         return Block.MarkReachable (rc);
6367                 }
6368
6369                 protected override void CloneTo (CloneContext clonectx, Statement t)
6370                 {
6371                         Unchecked target = (Unchecked) t;
6372
6373                         target.Block = clonectx.LookupBlock (Block);
6374                 }
6375                 
6376                 public override object Accept (StructuralVisitor visitor)
6377                 {
6378                         return visitor.Visit (this);
6379                 }
6380         }
6381
6382         public class Checked : Statement {
6383                 public Block Block;
6384                 
6385                 public Checked (Block b, Location loc)
6386                 {
6387                         Block = b;
6388                         b.Unchecked = false;
6389                         this.loc = loc;
6390                 }
6391
6392                 public override bool Resolve (BlockContext ec)
6393                 {
6394                         using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
6395                                 return Block.Resolve (ec);
6396                 }
6397
6398                 protected override void DoEmit (EmitContext ec)
6399                 {
6400                         using (ec.With (EmitContext.Options.CheckedScope, true))
6401                                 Block.Emit (ec);
6402                 }
6403
6404                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6405                 {
6406                         return Block.FlowAnalysis (fc);
6407                 }
6408
6409                 public override Reachability MarkReachable (Reachability rc)
6410                 {
6411                         base.MarkReachable (rc);
6412                         return Block.MarkReachable (rc);
6413                 }
6414
6415                 protected override void CloneTo (CloneContext clonectx, Statement t)
6416                 {
6417                         Checked target = (Checked) t;
6418
6419                         target.Block = clonectx.LookupBlock (Block);
6420                 }
6421                 
6422                 public override object Accept (StructuralVisitor visitor)
6423                 {
6424                         return visitor.Visit (this);
6425                 }
6426         }
6427
6428         public class Unsafe : Statement {
6429                 public Block Block;
6430
6431                 public Unsafe (Block b, Location loc)
6432                 {
6433                         Block = b;
6434                         Block.Unsafe = true;
6435                         this.loc = loc;
6436                 }
6437
6438                 public override bool Resolve (BlockContext ec)
6439                 {
6440                         if (ec.CurrentIterator != null)
6441                                 Expression.UnsafeInsideIteratorError (ec, loc);
6442
6443                         using (ec.Set (ResolveContext.Options.UnsafeScope))
6444                                 return Block.Resolve (ec);
6445                 }
6446                 
6447                 protected override void DoEmit (EmitContext ec)
6448                 {
6449                         Block.Emit (ec);
6450                 }
6451
6452                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6453                 {
6454                         return Block.FlowAnalysis (fc);
6455                 }
6456
6457                 public override Reachability MarkReachable (Reachability rc)
6458                 {
6459                         base.MarkReachable (rc);
6460                         return Block.MarkReachable (rc);
6461                 }
6462
6463                 protected override void CloneTo (CloneContext clonectx, Statement t)
6464                 {
6465                         Unsafe target = (Unsafe) t;
6466
6467                         target.Block = clonectx.LookupBlock (Block);
6468                 }
6469                 
6470                 public override object Accept (StructuralVisitor visitor)
6471                 {
6472                         return visitor.Visit (this);
6473                 }
6474         }
6475
6476         // 
6477         // Fixed statement
6478         //
6479         public class Fixed : Statement
6480         {
6481                 abstract class Emitter : ShimExpression
6482                 {
6483                         protected LocalVariable vi;
6484
6485                         protected Emitter (Expression expr, LocalVariable li)
6486                                 : base (expr)
6487                         {
6488                                 vi = li;
6489                         }
6490
6491                         public abstract void EmitExit (EmitContext ec);
6492
6493                         public override void FlowAnalysis (FlowAnalysisContext fc)
6494                         {
6495                                 expr.FlowAnalysis (fc);
6496                         }
6497                 }
6498
6499                 sealed class ExpressionEmitter : Emitter {
6500                         public ExpressionEmitter (Expression converted, LocalVariable li)
6501                                 : base (converted, li)
6502                         {
6503                         }
6504
6505                         protected override Expression DoResolve (ResolveContext rc)
6506                         {
6507                                 throw new NotImplementedException ();
6508                         }
6509
6510                         public override void Emit (EmitContext ec) {
6511                                 //
6512                                 // Store pointer in pinned location
6513                                 //
6514                                 expr.Emit (ec);
6515                                 vi.EmitAssign (ec);
6516                         }
6517
6518                         public override void EmitExit (EmitContext ec)
6519                         {
6520                                 ec.EmitInt (0);
6521                                 ec.Emit (OpCodes.Conv_U);
6522                                 vi.EmitAssign (ec);
6523                         }
6524                 }
6525
6526                 class StringEmitter : Emitter
6527                 {
6528                         LocalVariable pinned_string;
6529
6530                         public StringEmitter (Expression expr, LocalVariable li)
6531                                 : base (expr, li)
6532                         {
6533                         }
6534
6535                         protected override Expression DoResolve (ResolveContext rc)
6536                         {
6537                                 pinned_string = new LocalVariable (vi.Block, "$pinned",
6538                                         LocalVariable.Flags.FixedVariable | LocalVariable.Flags.CompilerGenerated | LocalVariable.Flags.Used,
6539                                         vi.Location);
6540                                 pinned_string.Type = rc.BuiltinTypes.String;
6541                                 vi.IsFixed = false;
6542
6543                                 eclass = ExprClass.Variable;
6544                                 type = rc.BuiltinTypes.Int;
6545                                 return this;
6546                         }
6547
6548                         public override void Emit (EmitContext ec)
6549                         {
6550                                 pinned_string.CreateBuilder (ec);
6551
6552                                 expr.Emit (ec);
6553                                 pinned_string.EmitAssign (ec);
6554
6555                                 // TODO: Should use Binary::Add
6556                                 pinned_string.Emit (ec);
6557                                 ec.Emit (OpCodes.Conv_I);
6558
6559                                 var m = ec.Module.PredefinedMembers.RuntimeHelpersOffsetToStringData.Resolve (loc);
6560                                 if (m == null)
6561                                         return;
6562
6563                                 PropertyExpr pe = new PropertyExpr (m, pinned_string.Location);
6564                                 //pe.InstanceExpression = pinned_string;
6565                                 pe.Resolve (new ResolveContext (ec.MemberContext)).Emit (ec);
6566
6567                                 ec.Emit (OpCodes.Add);
6568                                 vi.EmitAssign (ec);
6569                         }
6570
6571                         public override void EmitExit (EmitContext ec)
6572                         {
6573                                 ec.EmitNull ();
6574                                 pinned_string.EmitAssign (ec);
6575                         }
6576                 }
6577
6578                 public class VariableDeclaration : BlockVariable
6579                 {
6580                         public VariableDeclaration (FullNamedExpression type, LocalVariable li)
6581                                 : base (type, li)
6582                         {
6583                         }
6584
6585                         protected override Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
6586                         {
6587                                 if (!Variable.Type.IsPointer && li == Variable) {
6588                                         bc.Report.Error (209, TypeExpression.Location,
6589                                                 "The type of locals declared in a fixed statement must be a pointer type");
6590                                         return null;
6591                                 }
6592
6593                                 var res = initializer.Resolve (bc);
6594                                 if (res == null)
6595                                         return null;
6596
6597                                 //
6598                                 // Case 1: Array
6599                                 //
6600                                 var ac = res.Type as ArrayContainer;
6601                                 if (ac != null) {
6602                                         TypeSpec array_type = ac.Element;
6603
6604                                         //
6605                                         // Provided that array_type is unmanaged,
6606                                         //
6607                                         if (!TypeManager.VerifyUnmanaged (bc.Module, array_type, loc))
6608                                                 return null;
6609
6610                                         Expression res_init;
6611                                         if (ExpressionAnalyzer.IsInexpensiveLoad (res)) {
6612                                                 res_init = res;
6613                                         } else {
6614                                                 var expr_variable = LocalVariable.CreateCompilerGenerated (ac, bc.CurrentBlock, loc);
6615                                                 res_init = new CompilerAssign (expr_variable.CreateReferenceExpression (bc, loc), res, loc);
6616                                                 res = expr_variable.CreateReferenceExpression (bc, loc);
6617                                         }
6618
6619                                         //
6620                                         // and T* is implicitly convertible to the
6621                                         // pointer type given in the fixed statement.
6622                                         //
6623                                         ArrayPtr array_ptr = new ArrayPtr (res, array_type, loc);
6624
6625                                         Expression converted = Convert.ImplicitConversionRequired (bc, array_ptr.Resolve (bc), li.Type, loc);
6626                                         if (converted == null)
6627                                                 return null;
6628
6629                                         //
6630                                         // fixed (T* e_ptr = (e == null || e.Length == 0) ? null : converted [0])
6631                                         //
6632                                         converted = new Conditional (new BooleanExpression (new Binary (Binary.Operator.LogicalOr,
6633                                                 new Binary (Binary.Operator.Equality, res_init, new NullLiteral (loc)),
6634                                                 new Binary (Binary.Operator.Equality, new MemberAccess (res, "Length"), new IntConstant (bc.BuiltinTypes, 0, loc)))),
6635                                                         new NullLiteral (loc),
6636                                                         converted, loc);
6637
6638                                         converted = converted.Resolve (bc);
6639
6640                                         return new ExpressionEmitter (converted, li);
6641                                 }
6642
6643                                 //
6644                                 // Case 2: string
6645                                 //
6646                                 if (res.Type.BuiltinType == BuiltinTypeSpec.Type.String) {
6647                                         return new StringEmitter (res, li).Resolve (bc);
6648                                 }
6649
6650                                 // Case 3: fixed buffer
6651                                 if (res is FixedBufferPtr) {
6652                                         return new ExpressionEmitter (res, li);
6653                                 }
6654
6655                                 bool already_fixed = true;
6656
6657                                 //
6658                                 // Case 4: & object.
6659                                 //
6660                                 Unary u = res as Unary;
6661                                 if (u != null) {
6662                                         if (u.Oper == Unary.Operator.AddressOf) {
6663                                                 IVariableReference vr = u.Expr as IVariableReference;
6664                                                 if (vr == null || !vr.IsFixed) {
6665                                                         already_fixed = false;
6666                                                 }
6667                                         }
6668                                 } else if (initializer is Cast) {
6669                                         bc.Report.Error (254, initializer.Location, "The right hand side of a fixed statement assignment may not be a cast expression");
6670                                         return null;
6671                                 }
6672
6673                                 if (already_fixed) {
6674                                         bc.Report.Error (213, loc, "You cannot use the fixed statement to take the address of an already fixed expression");
6675                                 }
6676
6677                                 res = Convert.ImplicitConversionRequired (bc, res, li.Type, loc);
6678                                 return new ExpressionEmitter (res, li);
6679                         }
6680                 }
6681
6682
6683                 VariableDeclaration decl;
6684                 Statement statement;
6685                 bool has_ret;
6686
6687                 public Fixed (VariableDeclaration decl, Statement stmt, Location l)
6688                 {
6689                         this.decl = decl;
6690                         statement = stmt;
6691                         loc = l;
6692                 }
6693
6694                 #region Properties
6695
6696                 public Statement Statement {
6697                         get {
6698                                 return statement;
6699                         }
6700                 }
6701
6702                 public BlockVariable Variables {
6703                         get {
6704                                 return decl;
6705                         }
6706                 }
6707
6708                 #endregion
6709
6710                 public override bool Resolve (BlockContext bc)
6711                 {
6712                         using (bc.Set (ResolveContext.Options.FixedInitializerScope)) {
6713                                 if (!decl.Resolve (bc))
6714                                         return false;
6715                         }
6716
6717                         return statement.Resolve (bc);
6718                 }
6719
6720                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6721                 {
6722                         decl.FlowAnalysis (fc);
6723                         return statement.FlowAnalysis (fc);
6724                 }
6725                 
6726                 protected override void DoEmit (EmitContext ec)
6727                 {
6728                         decl.Variable.CreateBuilder (ec);
6729                         decl.Initializer.Emit (ec);
6730                         if (decl.Declarators != null) {
6731                                 foreach (var d in decl.Declarators) {
6732                                         d.Variable.CreateBuilder (ec);
6733                                         d.Initializer.Emit (ec);
6734                                 }
6735                         }
6736
6737                         statement.Emit (ec);
6738
6739                         if (has_ret)
6740                                 return;
6741
6742                         //
6743                         // Clear the pinned variable
6744                         //
6745                         ((Emitter) decl.Initializer).EmitExit (ec);
6746                         if (decl.Declarators != null) {
6747                                 foreach (var d in decl.Declarators) {
6748                                         ((Emitter)d.Initializer).EmitExit (ec);
6749                                 }
6750                         }
6751                 }
6752
6753                 public override Reachability MarkReachable (Reachability rc)
6754                 {
6755                         base.MarkReachable (rc);
6756
6757                         decl.MarkReachable (rc);
6758
6759                         rc = statement.MarkReachable (rc);
6760
6761                         // TODO: What if there is local exit?
6762                         has_ret = rc.IsUnreachable;
6763                         return rc;
6764                 }
6765
6766                 protected override void CloneTo (CloneContext clonectx, Statement t)
6767                 {
6768                         Fixed target = (Fixed) t;
6769
6770                         target.decl = (VariableDeclaration) decl.Clone (clonectx);
6771                         target.statement = statement.Clone (clonectx);
6772                 }
6773                 
6774                 public override object Accept (StructuralVisitor visitor)
6775                 {
6776                         return visitor.Visit (this);
6777                 }
6778         }
6779
6780         public class Catch : Statement
6781         {
6782                 class CatchVariableStore : Statement
6783                 {
6784                         readonly Catch ctch;
6785
6786                         public CatchVariableStore (Catch ctch)
6787                         {
6788                                 this.ctch = ctch;
6789                         }
6790
6791                         protected override void CloneTo (CloneContext clonectx, Statement target)
6792                         {
6793                         }
6794
6795                         protected override void DoEmit (EmitContext ec)
6796                         {
6797                                 // Emits catch variable debug information inside correct block
6798                                 ctch.EmitCatchVariableStore (ec);
6799                         }
6800
6801                         protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6802                         {
6803                                 return true;
6804                         }
6805                 }
6806
6807                 class FilterStatement : Statement
6808                 {
6809                         readonly Catch ctch;
6810
6811                         public FilterStatement (Catch ctch)
6812                         {
6813                                 this.ctch = ctch;
6814                         }
6815
6816                         protected override void CloneTo (CloneContext clonectx, Statement target)
6817                         {
6818                         }
6819
6820                         protected override void DoEmit (EmitContext ec)
6821                         {
6822                                 if (ctch.li != null) {
6823                                         if (ctch.hoisted_temp != null)
6824                                                 ctch.hoisted_temp.Emit (ec);
6825                                         else
6826                                                 ctch.li.Emit (ec);
6827
6828                                         if (!ctch.IsGeneral && ctch.type.Kind == MemberKind.TypeParameter)
6829                                                 ec.Emit (OpCodes.Box, ctch.type);
6830                                 }
6831
6832                                 var expr_start = ec.DefineLabel ();
6833                                 var end = ec.DefineLabel ();
6834
6835                                 ec.Emit (OpCodes.Brtrue_S, expr_start);
6836                                 ec.EmitInt (0);
6837                                 ec.Emit (OpCodes.Br, end);
6838                                 ec.MarkLabel (expr_start);
6839
6840                                 ctch.Filter.Emit (ec);
6841
6842                                 ec.MarkLabel (end);
6843                                 ec.Emit (OpCodes.Endfilter);
6844                                 ec.BeginFilterHandler ();
6845                                 ec.Emit (OpCodes.Pop);
6846                         }
6847
6848                         protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6849                         {
6850                                 ctch.Filter.FlowAnalysis (fc);
6851                                 return true;
6852                         }
6853
6854                         public override bool Resolve (BlockContext bc)
6855                         {
6856                                 ctch.Filter = ctch.Filter.Resolve (bc);
6857
6858                                 if (ctch.Filter != null) {
6859                                         if (ctch.Filter.ContainsEmitWithAwait ()) {
6860                                                 bc.Report.Error (7094, ctch.Filter.Location, "The `await' operator cannot be used in the filter expression of a catch clause");
6861                                         }
6862
6863                                         var c = ctch.Filter as Constant;
6864                                         if (c != null && !c.IsDefaultValue) {
6865                                                 bc.Report.Warning (7095, 1, ctch.Filter.Location, "Exception filter expression is a constant");
6866                                         }
6867                                 }
6868
6869                                 return true;
6870                         }
6871                 }
6872
6873                 ExplicitBlock block;
6874                 LocalVariable li;
6875                 FullNamedExpression type_expr;
6876                 CompilerAssign assign;
6877                 TypeSpec type;
6878                 LocalTemporary hoisted_temp;
6879
6880                 public Catch (ExplicitBlock block, Location loc)
6881                 {
6882                         this.block = block;
6883                         this.loc = loc;
6884                 }
6885
6886                 #region Properties
6887
6888                 public ExplicitBlock Block {
6889                         get {
6890                                 return block;
6891                         }
6892                 }
6893
6894                 public TypeSpec CatchType {
6895                         get {
6896                                 return type;
6897                         }
6898                 }
6899
6900                 public Expression Filter {
6901                         get; set;
6902                 }
6903
6904                 public bool IsGeneral {
6905                         get {
6906                                 return type_expr == null;
6907                         }
6908                 }
6909
6910                 public FullNamedExpression TypeExpression {
6911                         get {
6912                                 return type_expr;
6913                         }
6914                         set {
6915                                 type_expr = value;
6916                         }
6917                 }
6918
6919                 public LocalVariable Variable {
6920                         get {
6921                                 return li;
6922                         }
6923                         set {
6924                                 li = value;
6925                         }
6926                 }
6927
6928                 #endregion
6929
6930                 protected override void DoEmit (EmitContext ec)
6931                 {
6932                         if (Filter != null) {
6933                                 ec.BeginExceptionFilterBlock ();
6934                                 ec.Emit (OpCodes.Isinst, IsGeneral ? ec.BuiltinTypes.Object : CatchType);
6935
6936                                 if (Block.HasAwait) {
6937                                         Block.EmitScopeInitialization (ec);
6938                                 } else {
6939                                         Block.Emit (ec);
6940                                 }
6941
6942                                 return;
6943                         }
6944
6945                         if (IsGeneral)
6946                                 ec.BeginCatchBlock (ec.BuiltinTypes.Object);
6947                         else
6948                                 ec.BeginCatchBlock (CatchType);
6949
6950                         if (li == null)
6951                                 ec.Emit (OpCodes.Pop);
6952
6953                         if (Block.HasAwait) {
6954                                 if (li != null)
6955                                         EmitCatchVariableStore (ec);
6956                         } else {
6957                                 Block.Emit (ec);
6958                         }
6959                 }
6960
6961                 void EmitCatchVariableStore (EmitContext ec)
6962                 {
6963                         li.CreateBuilder (ec);
6964
6965                         //
6966                         // For hoisted catch variable we have to use a temporary local variable
6967                         // for captured variable initialization during storey setup because variable
6968                         // needs to be on the stack after storey instance for stfld operation
6969                         //
6970                         if (li.HoistedVariant != null) {
6971                                 hoisted_temp = new LocalTemporary (li.Type);
6972                                 hoisted_temp.Store (ec);
6973
6974                                 // switch to assignment from temporary variable and not from top of the stack
6975                                 assign.UpdateSource (hoisted_temp);
6976                         }
6977                 }
6978
6979                 public override bool Resolve (BlockContext bc)
6980                 {
6981                         using (bc.Set (ResolveContext.Options.CatchScope)) {
6982                                 if (type_expr == null) {
6983                                         if (CreateExceptionVariable (bc.Module.Compiler.BuiltinTypes.Object)) {
6984                                                 if (!block.HasAwait || Filter != null)
6985                                                         block.AddScopeStatement (new CatchVariableStore (this));
6986
6987                                                 Expression source = new EmptyExpression (li.Type);
6988                                                 assign = new CompilerAssign (new LocalVariableReference (li, Location.Null), source, Location.Null);
6989                                                 Block.AddScopeStatement (new StatementExpression (assign, Location.Null));
6990                                         }
6991                                 } else {
6992                                         type = type_expr.ResolveAsType (bc);
6993                                         if (type == null)
6994                                                 return false;
6995
6996                                         if (li == null)
6997                                                 CreateExceptionVariable (type);
6998
6999                                         if (type.BuiltinType != BuiltinTypeSpec.Type.Exception && !TypeSpec.IsBaseClass (type, bc.BuiltinTypes.Exception, false)) {
7000                                                 bc.Report.Error (155, loc, "The type caught or thrown must be derived from System.Exception");
7001                                         } else if (li != null) {
7002                                                 li.Type = type;
7003                                                 li.PrepareAssignmentAnalysis (bc);
7004
7005                                                 // source variable is at the top of the stack
7006                                                 Expression source = new EmptyExpression (li.Type);
7007                                                 if (li.Type.IsGenericParameter)
7008                                                         source = new UnboxCast (source, li.Type);
7009
7010                                                 if (!block.HasAwait || Filter != null)
7011                                                         block.AddScopeStatement (new CatchVariableStore (this));
7012
7013                                                 //
7014                                                 // Uses Location.Null to hide from symbol file
7015                                                 //
7016                                                 assign = new CompilerAssign (new LocalVariableReference (li, Location.Null), source, Location.Null);
7017                                                 Block.AddScopeStatement (new StatementExpression (assign, Location.Null));
7018                                         }
7019                                 }
7020
7021                                 if (Filter != null) {
7022                                         Block.AddScopeStatement (new FilterStatement (this));
7023                                 }
7024
7025                                 Block.SetCatchBlock ();
7026                                 return Block.Resolve (bc);
7027                         }
7028                 }
7029
7030                 bool CreateExceptionVariable (TypeSpec type)
7031                 {
7032                         if (!Block.HasAwait)
7033                                 return false;
7034
7035                         // TODO: Scan the block for rethrow expression
7036                         //if (!Block.HasRethrow)
7037                         //      return;
7038
7039                         li = LocalVariable.CreateCompilerGenerated (type, block, Location.Null);
7040                         return true;
7041                 }
7042
7043                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7044                 {
7045                         if (li != null && !li.IsCompilerGenerated) {
7046                                 fc.SetVariableAssigned (li.VariableInfo, true);
7047                         }
7048
7049                         return block.FlowAnalysis (fc);
7050                 }
7051
7052                 public override Reachability MarkReachable (Reachability rc)
7053                 {
7054                         base.MarkReachable (rc);
7055
7056                         var c = Filter as Constant;
7057                         if (c != null && c.IsDefaultValue)
7058                                 return Reachability.CreateUnreachable ();
7059
7060                         return block.MarkReachable (rc);
7061                 }
7062
7063                 protected override void CloneTo (CloneContext clonectx, Statement t)
7064                 {
7065                         Catch target = (Catch) t;
7066
7067                         if (type_expr != null)
7068                                 target.type_expr = (FullNamedExpression) type_expr.Clone (clonectx);
7069
7070                         if (Filter != null)
7071                                 target.Filter = Filter.Clone (clonectx);
7072
7073                         target.block = (ExplicitBlock) clonectx.LookupBlock (block);
7074                 }
7075         }
7076
7077         public class TryFinally : TryFinallyBlock
7078         {
7079                 ExplicitBlock fini;
7080                 List<DefiniteAssignmentBitSet> try_exit_dat;
7081                 List<Tuple<Label, bool>> redirected_jumps;
7082                 Label? start_fin_label;
7083
7084                 public TryFinally (Statement stmt, ExplicitBlock fini, Location loc)
7085                          : base (stmt, loc)
7086                 {
7087                         this.fini = fini;
7088                 }
7089
7090                 public ExplicitBlock FinallyBlock {
7091                         get {
7092                                 return fini;
7093                         }
7094                 }
7095
7096                 public void RegisterForControlExitCheck (DefiniteAssignmentBitSet vector)
7097                 {
7098                         if (try_exit_dat == null)
7099                                 try_exit_dat = new List<DefiniteAssignmentBitSet> ();
7100
7101                         try_exit_dat.Add (vector);
7102                 }
7103
7104                 public override bool Resolve (BlockContext bc)
7105                 {
7106                         bool ok = base.Resolve (bc);
7107
7108                         fini.SetFinallyBlock ();
7109                         using (bc.Set (ResolveContext.Options.FinallyScope)) {
7110                                 ok &= fini.Resolve (bc);
7111                         }
7112
7113                         return ok;
7114                 }
7115
7116                 protected override void EmitTryBody (EmitContext ec)
7117                 {
7118                         if (fini.HasAwait) {
7119                                 if (ec.TryFinallyUnwind == null)
7120                                         ec.TryFinallyUnwind = new List<TryFinally> ();
7121
7122                                 ec.TryFinallyUnwind.Add (this);
7123                                 stmt.Emit (ec);
7124
7125                                 if (first_catch_resume_pc < 0 && stmt is TryCatch)
7126                                         ec.EndExceptionBlock ();
7127
7128                                 ec.TryFinallyUnwind.Remove (this);
7129
7130                                 if (start_fin_label != null)
7131                                         ec.MarkLabel (start_fin_label.Value);
7132
7133                                 return;
7134                         }
7135
7136                         stmt.Emit (ec);
7137                 }
7138
7139                 protected override bool EmitBeginFinallyBlock (EmitContext ec)
7140                 {
7141                         if (fini.HasAwait)
7142                                 return false;
7143
7144                         return base.EmitBeginFinallyBlock (ec);
7145                 }
7146
7147                 public override void EmitFinallyBody (EmitContext ec)
7148                 {
7149                         if (!fini.HasAwait) {
7150                                 fini.Emit (ec);
7151                                 return;
7152                         }
7153
7154                         //
7155                         // Emits catch block like
7156                         //
7157                         // catch (object temp) {
7158                         //      this.exception_field = temp;
7159                         // }
7160                         //
7161                         var type = ec.BuiltinTypes.Object;
7162                         ec.BeginCatchBlock (type);
7163
7164                         var temp = ec.GetTemporaryLocal (type);
7165                         ec.Emit (OpCodes.Stloc, temp);
7166
7167                         var exception_field = ec.GetTemporaryField (type);
7168                         exception_field.AutomaticallyReuse = false;
7169                         ec.EmitThis ();
7170                         ec.Emit (OpCodes.Ldloc, temp);
7171                         exception_field.EmitAssignFromStack (ec);
7172
7173                         ec.EndExceptionBlock ();
7174
7175                         ec.FreeTemporaryLocal (temp, type);
7176
7177                         fini.Emit (ec);
7178
7179                         //
7180                         // Emits exception rethrow
7181                         //
7182                         // if (this.exception_field != null)
7183                         //      throw this.exception_field;
7184                         //
7185                         exception_field.Emit (ec);
7186                         var skip_throw = ec.DefineLabel ();
7187                         ec.Emit (OpCodes.Brfalse_S, skip_throw);
7188                         exception_field.Emit (ec);
7189                         ec.Emit (OpCodes.Throw);
7190                         ec.MarkLabel (skip_throw);
7191
7192                         exception_field.PrepareCleanup (ec);
7193
7194                         EmitUnwindFinallyTable (ec);
7195                 }
7196
7197                 bool IsParentBlock (Block block)
7198                 {
7199                         for (Block b = fini; b != null; b = b.Parent) {
7200                                 if (b == block)
7201                                         return true;
7202                         }
7203
7204                         return false;
7205                 }
7206
7207                 public static Label EmitRedirectedJump (EmitContext ec, AsyncInitializer initializer, Label label, Block labelBlock, bool unwindProtect)
7208                 {
7209                         int idx;
7210                         if (labelBlock != null) {
7211                                 for (idx = ec.TryFinallyUnwind.Count; idx != 0; --idx) {
7212                                         var fin = ec.TryFinallyUnwind [idx - 1];
7213                                         if (!fin.IsParentBlock (labelBlock))
7214                                                 break;
7215                                 }
7216                         } else {
7217                                 idx = 0;
7218                         }
7219
7220                         bool set_return_state = true;
7221
7222                         for (; idx < ec.TryFinallyUnwind.Count; ++idx) {
7223                                 var fin = ec.TryFinallyUnwind [idx];
7224                                 if (labelBlock != null && !fin.IsParentBlock (labelBlock))
7225                                         break;
7226
7227                                 fin.EmitRedirectedExit (ec, label, initializer, set_return_state, unwindProtect);
7228                                 set_return_state = false;
7229
7230                                 if (fin.start_fin_label == null) {
7231                                         fin.start_fin_label = ec.DefineLabel ();
7232                                 }
7233
7234                                 label = fin.start_fin_label.Value;
7235                         }
7236
7237                         return label;
7238                 }
7239
7240                 public static Label EmitRedirectedReturn (EmitContext ec, AsyncInitializer initializer, bool unwindProtect)
7241                 {
7242                         return EmitRedirectedJump (ec, initializer, initializer.BodyEnd, null, unwindProtect);
7243                 }
7244
7245                 void EmitRedirectedExit (EmitContext ec, Label label, AsyncInitializer initializer, bool setReturnState, bool unwindProtect)
7246                 {
7247                         if (redirected_jumps == null) {
7248                                 redirected_jumps = new List<Tuple<Label, bool>> ();
7249
7250                                 // Add fallthrough label
7251                                 redirected_jumps.Add (Tuple.Create (ec.DefineLabel (), false));
7252
7253                                 if (setReturnState)
7254                                         initializer.HoistedReturnState = ec.GetTemporaryField (ec.Module.Compiler.BuiltinTypes.Int, true);
7255                         }
7256
7257                         int index = redirected_jumps.FindIndex (l => l.Item1 == label);
7258                         if (index < 0) {
7259                                 redirected_jumps.Add (Tuple.Create (label, unwindProtect));
7260                                 index = redirected_jumps.Count - 1;
7261                         }
7262
7263                         //
7264                         // Indicates we have captured exit jump
7265                         //
7266                         if (setReturnState) {
7267                                 var value = new IntConstant (initializer.HoistedReturnState.Type, index, Location.Null);
7268                                 initializer.HoistedReturnState.EmitAssign (ec, value, false, false);
7269                         }
7270                 }
7271
7272                 //
7273                 // Emits state table of jumps outside of try block and reload of return
7274                 // value when try block returns value
7275                 //
7276                 void EmitUnwindFinallyTable (EmitContext ec)
7277                 {
7278                         if (redirected_jumps == null)
7279                                 return;
7280
7281                         var initializer = (AsyncInitializer)ec.CurrentAnonymousMethod;
7282                         initializer.HoistedReturnState.EmitLoad (ec);
7283
7284                         var jumps_table = new Label [redirected_jumps.Count];
7285                         List<Tuple<Label, Label>> leave_redirect = null;
7286                         for (int i = 0; i < jumps_table.Length; ++i) {
7287                                 var val = redirected_jumps [i];
7288
7289                                 if (val.Item2) {
7290                                         if (leave_redirect == null)
7291                                                 leave_redirect = new List<Tuple<Label, Label>> ();
7292                                         var label = ec.DefineLabel ();
7293                                         leave_redirect.Add (Tuple.Create (label, val.Item1));
7294                                         jumps_table [i] = label;
7295                                 } else {
7296                                         jumps_table [i] = val.Item1;
7297                                 }
7298                         }
7299
7300                         ec.Emit (OpCodes.Switch, jumps_table);
7301
7302                         if (leave_redirect != null) {
7303                                 foreach (var entry in leave_redirect) {
7304                                         ec.MarkLabel (entry.Item1);
7305                                         ec.Emit (OpCodes.Leave, entry.Item2);
7306                                 }
7307                         }
7308
7309                         // Mark fallthrough label
7310                         ec.MarkLabel (jumps_table [0]);
7311                 }
7312
7313                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7314                 {
7315                         var da = fc.BranchDefiniteAssignment ();
7316
7317                         var tf = fc.TryFinally;
7318                         fc.TryFinally = this;
7319
7320                         var res_stmt = Statement.FlowAnalysis (fc);
7321
7322                         fc.TryFinally = tf;
7323
7324                         var try_da = fc.DefiniteAssignment;
7325                         fc.DefiniteAssignment = da;
7326
7327                         var res_fin = fini.FlowAnalysis (fc);
7328
7329                         if (try_exit_dat != null) {
7330                                 //
7331                                 // try block has global exit but we need to run definite assignment check
7332                                 // for parameter block out parameter after finally block because it's always
7333                                 // executed before exit
7334                                 //
7335                                 foreach (var try_da_part in try_exit_dat)
7336                                         fc.ParametersBlock.CheckControlExit (fc, fc.DefiniteAssignment | try_da_part);
7337
7338                                 try_exit_dat = null;
7339                         }
7340
7341                         fc.DefiniteAssignment |= try_da;
7342                         return res_stmt | res_fin;
7343                 }
7344
7345                 public override Reachability MarkReachable (Reachability rc)
7346                 {
7347                         //
7348                         // Mark finally block first for any exit statement in try block
7349                         // to know whether the code which follows finally is reachable
7350                         //
7351                         return fini.MarkReachable (rc) | base.MarkReachable (rc);
7352                 }
7353
7354                 protected override void CloneTo (CloneContext clonectx, Statement t)
7355                 {
7356                         TryFinally target = (TryFinally) t;
7357
7358                         target.stmt = stmt.Clone (clonectx);
7359                         if (fini != null)
7360                                 target.fini = (ExplicitBlock) clonectx.LookupBlock (fini);
7361                 }
7362                 
7363                 public override object Accept (StructuralVisitor visitor)
7364                 {
7365                         return visitor.Visit (this);
7366                 }
7367         }
7368
7369         public class TryCatch : ExceptionStatement
7370         {
7371                 public Block Block;
7372                 List<Catch> clauses;
7373                 readonly bool inside_try_finally;
7374                 List<Catch> catch_sm;
7375
7376                 public TryCatch (Block block, List<Catch> catch_clauses, Location l, bool inside_try_finally)
7377                         : base (l)
7378                 {
7379                         this.Block = block;
7380                         this.clauses = catch_clauses;
7381                         this.inside_try_finally = inside_try_finally;
7382                 }
7383
7384                 public List<Catch> Clauses {
7385                         get {
7386                                 return clauses;
7387                         }
7388                 }
7389
7390                 public bool HasClauseWithAwait {
7391                         get {
7392                                 return catch_sm != null;
7393                         }
7394                 }
7395
7396                 public bool IsTryCatchFinally {
7397                         get {
7398                                 return inside_try_finally;
7399                         }
7400                 }
7401
7402                 public override bool Resolve (BlockContext bc)
7403                 {
7404                         bool ok;
7405
7406                         using (bc.Set (ResolveContext.Options.TryScope)) {
7407
7408                                 parent_try_block = bc.CurrentTryBlock;
7409
7410                                 if (IsTryCatchFinally) {
7411                                         ok = Block.Resolve (bc);
7412                                 } else {
7413                                         using (bc.Set (ResolveContext.Options.TryWithCatchScope)) {
7414                                                 bc.CurrentTryBlock = this;
7415                                                 ok = Block.Resolve (bc);
7416                                                 bc.CurrentTryBlock = parent_try_block;
7417                                         }
7418                                 }
7419                         }
7420
7421                         var prev_catch = bc.CurrentTryCatch;
7422                         bc.CurrentTryCatch = this;
7423
7424                         for (int i = 0; i < clauses.Count; ++i) {
7425                                 var c = clauses[i];
7426
7427                                 ok &= c.Resolve (bc);
7428
7429                                 if (c.Block.HasAwait) {
7430                                         if (catch_sm == null)
7431                                                 catch_sm = new List<Catch> ();
7432
7433                                         catch_sm.Add (c);
7434                                 }
7435
7436                                 if (c.Filter != null)
7437                                         continue;
7438
7439                                 TypeSpec resolved_type = c.CatchType;
7440                                 if (resolved_type == null)
7441                                         continue;
7442
7443                                 for (int ii = 0; ii < clauses.Count; ++ii) {
7444                                         if (ii == i)
7445                                                 continue;
7446
7447                                         if (clauses[ii].Filter != null)
7448                                                 continue;
7449
7450                                         if (clauses[ii].IsGeneral) {
7451                                                 if (resolved_type.BuiltinType != BuiltinTypeSpec.Type.Exception)
7452                                                         continue;
7453
7454                                                 if (!bc.Module.DeclaringAssembly.WrapNonExceptionThrows)
7455                                                         continue;
7456
7457                                                 if (!bc.Module.PredefinedAttributes.RuntimeCompatibility.IsDefined)
7458                                                         continue;
7459
7460                                                 bc.Report.Warning (1058, 1, c.loc,
7461                                                         "A previous catch clause already catches all exceptions. All non-exceptions thrown will be wrapped in a `System.Runtime.CompilerServices.RuntimeWrappedException'");
7462
7463                                                 continue;
7464                                         }
7465
7466                                         if (ii >= i)
7467                                                 continue;
7468
7469                                         var ct = clauses[ii].CatchType;
7470                                         if (ct == null)
7471                                                 continue;
7472
7473                                         if (resolved_type == ct || TypeSpec.IsBaseClass (resolved_type, ct, true)) {
7474                                                 bc.Report.Error (160, c.loc,
7475                                                         "A previous catch clause already catches all exceptions of this or a super type `{0}'",
7476                                                         ct.GetSignatureForError ());
7477                                                 ok = false;
7478                                         }
7479                                 }
7480                         }
7481
7482                         bc.CurrentTryCatch = prev_catch;
7483
7484                         return base.Resolve (bc) && ok;
7485                 }
7486
7487                 protected sealed override void DoEmit (EmitContext ec)
7488                 {
7489                         if (!inside_try_finally)
7490                                 EmitTryBodyPrepare (ec);
7491
7492                         Block.Emit (ec);
7493
7494                         LocalBuilder state_variable = null;
7495                         foreach (Catch c in clauses) {
7496                                 c.Emit (ec);
7497
7498                                 if (catch_sm != null) {
7499                                         if (state_variable == null) {
7500                                                 //
7501                                                 // Cannot reuse temp variable because non-catch path assumes the value is 0
7502                                                 // which may not be true for reused local variable
7503                                                 //
7504                                                 state_variable = ec.DeclareLocal (ec.Module.Compiler.BuiltinTypes.Int, false);
7505                                         }
7506
7507                                         var index = catch_sm.IndexOf (c);
7508                                         if (index < 0)
7509                                                 continue;
7510
7511                                         ec.EmitInt (index + 1);
7512                                         ec.Emit (OpCodes.Stloc, state_variable);
7513                                 }
7514                         }
7515
7516                         if (state_variable == null) {
7517                                 if (!inside_try_finally)
7518                                         ec.EndExceptionBlock ();
7519                         } else {
7520                                 ec.EndExceptionBlock ();
7521
7522                                 ec.Emit (OpCodes.Ldloc, state_variable);
7523
7524                                 var labels = new Label [catch_sm.Count + 1];
7525                                 for (int i = 0; i < labels.Length; ++i) {
7526                                         labels [i] = ec.DefineLabel ();
7527                                 }
7528
7529                                 var end = ec.DefineLabel ();
7530                                 ec.Emit (OpCodes.Switch, labels);
7531
7532                                 // 0 value is default label
7533                                 ec.MarkLabel (labels [0]);
7534                                 ec.Emit (OpCodes.Br, end);
7535
7536                                 var atv = ec.AsyncThrowVariable;
7537                                 Catch c = null;
7538                                 for (int i = 0; i < catch_sm.Count; ++i) {
7539                                         if (c != null && c.Block.HasReachableClosingBrace)
7540                                                 ec.Emit (OpCodes.Br, end);
7541
7542                                         ec.MarkLabel (labels [i + 1]);
7543
7544                                         ec.EmitInt (0);
7545                                         ec.Emit (OpCodes.Stloc, state_variable);
7546
7547                                         c = catch_sm [i];
7548                                         ec.AsyncThrowVariable = c.Variable;
7549                                         c.Block.Emit (ec);
7550                                 }
7551                                 ec.AsyncThrowVariable = atv;
7552
7553                                 ec.MarkLabel (end);
7554                         }
7555                 }
7556
7557                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7558                 {
7559                         var start_fc = fc.BranchDefiniteAssignment ();
7560                         var res = Block.FlowAnalysis (fc);
7561
7562                         DefiniteAssignmentBitSet try_fc = res ? null : fc.DefiniteAssignment;
7563
7564                         foreach (var c in clauses) {
7565                                 fc.BranchDefiniteAssignment (start_fc);
7566                                 if (!c.FlowAnalysis (fc)) {
7567                                         if (try_fc == null)
7568                                                 try_fc = fc.DefiniteAssignment;
7569                                         else
7570                                                 try_fc &= fc.DefiniteAssignment;
7571
7572                                         res = false;
7573                                 }
7574                         }
7575
7576                         fc.DefiniteAssignment = try_fc ?? start_fc;
7577                         parent_try_block = null;
7578                         return res;
7579                 }
7580
7581                 public override Reachability MarkReachable (Reachability rc)
7582                 {
7583                         if (rc.IsUnreachable)
7584                                 return rc;
7585
7586                         base.MarkReachable (rc);
7587
7588                         var tc_rc = Block.MarkReachable (rc);
7589
7590                         foreach (var c in clauses)
7591                                 tc_rc &= c.MarkReachable (rc);
7592
7593                         return tc_rc;
7594                 }
7595
7596                 protected override void CloneTo (CloneContext clonectx, Statement t)
7597                 {
7598                         TryCatch target = (TryCatch) t;
7599
7600                         target.Block = clonectx.LookupBlock (Block);
7601                         if (clauses != null){
7602                                 target.clauses = new List<Catch> ();
7603                                 foreach (Catch c in clauses)
7604                                         target.clauses.Add ((Catch) c.Clone (clonectx));
7605                         }
7606                 }
7607
7608                 public override object Accept (StructuralVisitor visitor)
7609                 {
7610                         return visitor.Visit (this);
7611                 }
7612         }
7613
7614         public class Using : TryFinallyBlock
7615         {
7616                 public class VariableDeclaration : BlockVariable
7617                 {
7618                         Statement dispose_call;
7619
7620                         public VariableDeclaration (FullNamedExpression type, LocalVariable li)
7621                                 : base (type, li)
7622                         {
7623                         }
7624
7625                         public VariableDeclaration (LocalVariable li, Location loc)
7626                                 : base (li)
7627                         {
7628                                 reachable = true;
7629                                 this.loc = loc;
7630                         }
7631
7632                         public VariableDeclaration (Expression expr)
7633                                 : base (null)
7634                         {
7635                                 loc = expr.Location;
7636                                 Initializer = expr;
7637                         }
7638
7639                         #region Properties
7640
7641                         public bool IsNested { get; private set; }
7642
7643                         #endregion
7644
7645                         public void EmitDispose (EmitContext ec)
7646                         {
7647                                 dispose_call.Emit (ec);
7648                         }
7649
7650                         public override bool Resolve (BlockContext bc)
7651                         {
7652                                 if (IsNested)
7653                                         return true;
7654
7655                                 return base.Resolve (bc, false);
7656                         }
7657
7658                         public Expression ResolveExpression (BlockContext bc)
7659                         {
7660                                 var e = Initializer.Resolve (bc);
7661                                 if (e == null)
7662                                         return null;
7663
7664                                 li = LocalVariable.CreateCompilerGenerated (e.Type, bc.CurrentBlock, loc);
7665                                 Initializer = ResolveInitializer (bc, Variable, e);
7666                                 return e;
7667                         }
7668
7669                         protected override Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
7670                         {
7671                                 if (li.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
7672                                         initializer = initializer.Resolve (bc);
7673                                         if (initializer == null)
7674                                                 return null;
7675
7676                                         // Once there is dynamic used defer conversion to runtime even if we know it will never succeed
7677                                         Arguments args = new Arguments (1);
7678                                         args.Add (new Argument (initializer));
7679                                         initializer = new DynamicConversion (bc.BuiltinTypes.IDisposable, 0, args, initializer.Location).Resolve (bc);
7680                                         if (initializer == null)
7681                                                 return null;
7682
7683                                         var var = LocalVariable.CreateCompilerGenerated (initializer.Type, bc.CurrentBlock, loc);
7684                                         dispose_call = CreateDisposeCall (bc, var);
7685                                         dispose_call.Resolve (bc);
7686
7687                                         return base.ResolveInitializer (bc, li, new SimpleAssign (var.CreateReferenceExpression (bc, loc), initializer, loc));
7688                                 }
7689
7690                                 if (li == Variable) {
7691                                         CheckIDiposableConversion (bc, li, initializer);
7692                                         dispose_call = CreateDisposeCall (bc, li);
7693                                         dispose_call.Resolve (bc);
7694                                 }
7695
7696                                 return base.ResolveInitializer (bc, li, initializer);
7697                         }
7698
7699                         protected virtual void CheckIDiposableConversion (BlockContext bc, LocalVariable li, Expression initializer)
7700                         {
7701                                 var type = li.Type;
7702
7703                                 if (type.BuiltinType != BuiltinTypeSpec.Type.IDisposable && !CanConvertToIDisposable (bc, type)) {
7704                                         if (type.IsNullableType) {
7705                                                 // it's handled in CreateDisposeCall
7706                                                 return;
7707                                         }
7708
7709                                         if (type != InternalType.ErrorType) {
7710                                                 bc.Report.SymbolRelatedToPreviousError (type);
7711                                                 var loc = type_expr == null ? initializer.Location : type_expr.Location;
7712                                                 bc.Report.Error (1674, loc, "`{0}': type used in a using statement must be implicitly convertible to `System.IDisposable'",
7713                                                         type.GetSignatureForError ());
7714                                         }
7715
7716                                         return;
7717                                 }
7718                         }
7719
7720                         static bool CanConvertToIDisposable (BlockContext bc, TypeSpec type)
7721                         {
7722                                 var target = bc.BuiltinTypes.IDisposable;
7723                                 var tp = type as TypeParameterSpec;
7724                                 if (tp != null)
7725                                         return Convert.ImplicitTypeParameterConversion (null, tp, target) != null;
7726
7727                                 return type.ImplementsInterface (target, false);
7728                         }
7729
7730                         protected virtual Statement CreateDisposeCall (BlockContext bc, LocalVariable lv)
7731                         {
7732                                 var lvr = lv.CreateReferenceExpression (bc, lv.Location);
7733                                 var type = lv.Type;
7734                                 var loc = lv.Location;
7735
7736                                 var idt = bc.BuiltinTypes.IDisposable;
7737                                 var m = bc.Module.PredefinedMembers.IDisposableDispose.Resolve (loc);
7738
7739                                 var dispose_mg = MethodGroupExpr.CreatePredefined (m, idt, loc);
7740                                 dispose_mg.InstanceExpression = type.IsNullableType ?
7741                                         new Cast (new TypeExpression (idt, loc), lvr, loc).Resolve (bc) :
7742                                         lvr;
7743
7744                                 //
7745                                 // Hide it from symbol file via null location
7746                                 //
7747                                 Statement dispose = new StatementExpression (new Invocation (dispose_mg, null), Location.Null);
7748
7749                                 // Add conditional call when disposing possible null variable
7750                                 if (!TypeSpec.IsValueType (type) || type.IsNullableType)
7751                                         dispose = new If (new Binary (Binary.Operator.Inequality, lvr, new NullLiteral (loc)), dispose, dispose.loc);
7752
7753                                 return dispose;
7754                         }
7755
7756                         public void ResolveDeclaratorInitializer (BlockContext bc)
7757                         {
7758                                 Initializer = base.ResolveInitializer (bc, Variable, Initializer);
7759                         }
7760
7761                         public Statement RewriteUsingDeclarators (BlockContext bc, Statement stmt)
7762                         {
7763                                 for (int i = declarators.Count - 1; i >= 0; --i) {
7764                                         var d = declarators [i];
7765                                         var vd = new VariableDeclaration (d.Variable, d.Variable.Location);
7766                                         vd.Initializer = d.Initializer;
7767                                         vd.IsNested = true;
7768                                         vd.dispose_call = CreateDisposeCall (bc, d.Variable);
7769                                         vd.dispose_call.Resolve (bc);
7770
7771                                         stmt = new Using (vd, stmt, d.Variable.Location);
7772                                 }
7773
7774                                 declarators = null;
7775                                 return stmt;
7776                         }       
7777
7778                         public override object Accept (StructuralVisitor visitor)
7779                         {
7780                                 return visitor.Visit (this);
7781                         }       
7782                 }
7783
7784                 VariableDeclaration decl;
7785
7786                 public Using (VariableDeclaration decl, Statement stmt, Location loc)
7787                         : base (stmt, loc)
7788                 {
7789                         this.decl = decl;
7790                 }
7791
7792                 public Using (Expression expr, Statement stmt, Location loc)
7793                         : base (stmt, loc)
7794                 {
7795                         this.decl = new VariableDeclaration (expr);
7796                 }
7797
7798                 #region Properties
7799
7800                 public Expression Expr {
7801                         get {
7802                                 return decl.Variable == null ? decl.Initializer : null;
7803                         }
7804                 }
7805
7806                 public BlockVariable Variables {
7807                         get {
7808                                 return decl;
7809                         }
7810                 }
7811
7812                 #endregion
7813
7814                 public override void Emit (EmitContext ec)
7815                 {
7816                         //
7817                         // Don't emit sequence point it will be set on variable declaration
7818                         //
7819                         DoEmit (ec);
7820                 }
7821
7822                 protected override void EmitTryBodyPrepare (EmitContext ec)
7823                 {
7824                         decl.Emit (ec);
7825                         base.EmitTryBodyPrepare (ec);
7826                 }
7827
7828                 protected override void EmitTryBody (EmitContext ec)
7829                 {
7830                         stmt.Emit (ec);
7831                 }
7832
7833                 public override void EmitFinallyBody (EmitContext ec)
7834                 {
7835                         decl.EmitDispose (ec);
7836                 }
7837
7838                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7839                 {
7840                         decl.FlowAnalysis (fc);
7841                         return stmt.FlowAnalysis (fc);
7842                 }
7843
7844                 public override Reachability MarkReachable (Reachability rc)
7845                 {
7846                         decl.MarkReachable (rc);
7847                         return base.MarkReachable (rc);
7848                 }
7849
7850                 public override bool Resolve (BlockContext ec)
7851                 {
7852                         VariableReference vr;
7853                         bool vr_locked = false;
7854
7855                         using (ec.Set (ResolveContext.Options.UsingInitializerScope)) {
7856                                 if (decl.Variable == null) {
7857                                         vr = decl.ResolveExpression (ec) as VariableReference;
7858                                         if (vr != null) {
7859                                                 vr_locked = vr.IsLockedByStatement;
7860                                                 vr.IsLockedByStatement = true;
7861                                         }
7862                                 } else {
7863                                         if (decl.IsNested) {
7864                                                 decl.ResolveDeclaratorInitializer (ec);
7865                                         } else {
7866                                                 if (!decl.Resolve (ec))
7867                                                         return false;
7868
7869                                                 if (decl.Declarators != null) {
7870                                                         stmt = decl.RewriteUsingDeclarators (ec, stmt);
7871                                                 }
7872                                         }
7873
7874                                         vr = null;
7875                                 }
7876                         }
7877
7878                         var ok = base.Resolve (ec);
7879
7880                         if (vr != null)
7881                                 vr.IsLockedByStatement = vr_locked;
7882
7883                         return ok;
7884                 }
7885
7886                 protected override void CloneTo (CloneContext clonectx, Statement t)
7887                 {
7888                         Using target = (Using) t;
7889
7890                         target.decl = (VariableDeclaration) decl.Clone (clonectx);
7891                         target.stmt = stmt.Clone (clonectx);
7892                 }
7893
7894                 public override object Accept (StructuralVisitor visitor)
7895                 {
7896                         return visitor.Visit (this);
7897                 }
7898         }
7899
7900         /// <summary>
7901         ///   Implementation of the foreach C# statement
7902         /// </summary>
7903         public class Foreach : LoopStatement
7904         {
7905                 abstract class IteratorStatement : Statement
7906                 {
7907                         protected readonly Foreach for_each;
7908
7909                         protected IteratorStatement (Foreach @foreach)
7910                         {
7911                                 this.for_each = @foreach;
7912                                 this.loc = @foreach.expr.Location;
7913                         }
7914
7915                         protected override void CloneTo (CloneContext clonectx, Statement target)
7916                         {
7917                                 throw new NotImplementedException ();
7918                         }
7919
7920                         public override void Emit (EmitContext ec)
7921                         {
7922                                 if (ec.EmitAccurateDebugInfo) {
7923                                         ec.Emit (OpCodes.Nop);
7924                                 }
7925
7926                                 base.Emit (ec);
7927                         }
7928
7929                         protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7930                         {
7931                                 throw new NotImplementedException ();
7932                         }
7933                 }
7934
7935                 sealed class ArrayForeach : IteratorStatement
7936                 {
7937                         TemporaryVariableReference[] lengths;
7938                         Expression [] length_exprs;
7939                         StatementExpression[] counter;
7940                         TemporaryVariableReference[] variables;
7941
7942                         TemporaryVariableReference copy;
7943
7944                         public ArrayForeach (Foreach @foreach, int rank)
7945                                 : base (@foreach)
7946                         {
7947                                 counter = new StatementExpression[rank];
7948                                 variables = new TemporaryVariableReference[rank];
7949                                 length_exprs = new Expression [rank];
7950
7951                                 //
7952                                 // Only use temporary length variables when dealing with
7953                                 // multi-dimensional arrays
7954                                 //
7955                                 if (rank > 1)
7956                                         lengths = new TemporaryVariableReference [rank];
7957                         }
7958
7959                         public override bool Resolve (BlockContext ec)
7960                         {
7961                                 Block variables_block = for_each.variable.Block;
7962                                 copy = TemporaryVariableReference.Create (for_each.expr.Type, variables_block, loc);
7963                                 copy.Resolve (ec);
7964
7965                                 int rank = length_exprs.Length;
7966                                 Arguments list = new Arguments (rank);
7967                                 for (int i = 0; i < rank; i++) {
7968                                         var v = TemporaryVariableReference.Create (ec.BuiltinTypes.Int, variables_block, loc);
7969                                         variables[i] = v;
7970                                         counter[i] = new StatementExpression (new UnaryMutator (UnaryMutator.Mode.PostIncrement, v, Location.Null));
7971                                         counter[i].Resolve (ec);
7972
7973                                         if (rank == 1) {
7974                                                 length_exprs [i] = new MemberAccess (copy, "Length").Resolve (ec);
7975                                         } else {
7976                                                 lengths[i] = TemporaryVariableReference.Create (ec.BuiltinTypes.Int, variables_block, loc);
7977                                                 lengths[i].Resolve (ec);
7978
7979                                                 Arguments args = new Arguments (1);
7980                                                 args.Add (new Argument (new IntConstant (ec.BuiltinTypes, i, loc)));
7981                                                 length_exprs [i] = new Invocation (new MemberAccess (copy, "GetLength"), args).Resolve (ec);
7982                                         }
7983
7984                                         list.Add (new Argument (v));
7985                                 }
7986
7987                                 var access = new ElementAccess (copy, list, loc).Resolve (ec);
7988                                 if (access == null)
7989                                         return false;
7990
7991                                 TypeSpec var_type;
7992                                 if (for_each.type is VarExpr) {
7993                                         // Infer implicitly typed local variable from foreach array type
7994                                         var_type = access.Type;
7995                                 } else {
7996                                         var_type = for_each.type.ResolveAsType (ec);
7997
7998                                         if (var_type == null)
7999                                                 return false;
8000
8001                                         access = Convert.ExplicitConversion (ec, access, var_type, loc);
8002                                         if (access == null)
8003                                                 return false;
8004                                 }
8005
8006                                 for_each.variable.Type = var_type;
8007
8008                                 var prev_block = ec.CurrentBlock;
8009                                 ec.CurrentBlock = variables_block;
8010                                 var variable_ref = new LocalVariableReference (for_each.variable, loc).Resolve (ec);
8011                                 ec.CurrentBlock = prev_block;
8012
8013                                 if (variable_ref == null)
8014                                         return false;
8015
8016                                 for_each.body.AddScopeStatement (new StatementExpression (new CompilerAssign (variable_ref, access, Location.Null), for_each.type.Location));
8017
8018                                 return for_each.body.Resolve (ec);
8019                         }
8020
8021                         protected override void DoEmit (EmitContext ec)
8022                         {
8023                                 copy.EmitAssign (ec, for_each.expr);
8024
8025                                 int rank = length_exprs.Length;
8026                                 Label[] test = new Label [rank];
8027                                 Label[] loop = new Label [rank];
8028
8029                                 for (int i = 0; i < rank; i++) {
8030                                         test [i] = ec.DefineLabel ();
8031                                         loop [i] = ec.DefineLabel ();
8032
8033                                         if (lengths != null)
8034                                                 lengths [i].EmitAssign (ec, length_exprs [i]);
8035                                 }
8036
8037                                 IntConstant zero = new IntConstant (ec.BuiltinTypes, 0, loc);
8038                                 for (int i = 0; i < rank; i++) {
8039                                         variables [i].EmitAssign (ec, zero);
8040
8041                                         ec.Emit (OpCodes.Br, test [i]);
8042                                         ec.MarkLabel (loop [i]);
8043                                 }
8044
8045                                 for_each.body.Emit (ec);
8046
8047                                 ec.MarkLabel (ec.LoopBegin);
8048                                 ec.Mark (for_each.expr.Location);
8049
8050                                 for (int i = rank - 1; i >= 0; i--){
8051                                         counter [i].Emit (ec);
8052
8053                                         ec.MarkLabel (test [i]);
8054                                         variables [i].Emit (ec);
8055
8056                                         if (lengths != null)
8057                                                 lengths [i].Emit (ec);
8058                                         else
8059                                                 length_exprs [i].Emit (ec);
8060
8061                                         ec.Emit (OpCodes.Blt, loop [i]);
8062                                 }
8063
8064                                 ec.MarkLabel (ec.LoopEnd);
8065                         }
8066                 }
8067
8068                 sealed class CollectionForeach : IteratorStatement, OverloadResolver.IErrorHandler
8069                 {
8070                         class RuntimeDispose : Using.VariableDeclaration
8071                         {
8072                                 public RuntimeDispose (LocalVariable lv, Location loc)
8073                                         : base (lv, loc)
8074                                 {
8075                                         reachable = true;
8076                                 }
8077
8078                                 protected override void CheckIDiposableConversion (BlockContext bc, LocalVariable li, Expression initializer)
8079                                 {
8080                                         // Defered to runtime check
8081                                 }
8082
8083                                 protected override Statement CreateDisposeCall (BlockContext bc, LocalVariable lv)
8084                                 {
8085                                         var idt = bc.BuiltinTypes.IDisposable;
8086
8087                                         //
8088                                         // Fabricates code like
8089                                         //
8090                                         // if ((temp = vr as IDisposable) != null) temp.Dispose ();
8091                                         //
8092
8093                                         var dispose_variable = LocalVariable.CreateCompilerGenerated (idt, bc.CurrentBlock, loc);
8094
8095                                         var idisaposable_test = new Binary (Binary.Operator.Inequality, new CompilerAssign (
8096                                                 dispose_variable.CreateReferenceExpression (bc, loc),
8097                                                 new As (lv.CreateReferenceExpression (bc, loc), new TypeExpression (dispose_variable.Type, loc), loc),
8098                                                 loc), new NullLiteral (loc));
8099
8100                                         var m = bc.Module.PredefinedMembers.IDisposableDispose.Resolve (loc);
8101
8102                                         var dispose_mg = MethodGroupExpr.CreatePredefined (m, idt, loc);
8103                                         dispose_mg.InstanceExpression = dispose_variable.CreateReferenceExpression (bc, loc);
8104
8105                                         Statement dispose = new StatementExpression (new Invocation (dispose_mg, null));
8106                                         return new If (idisaposable_test, dispose, loc);
8107                                 }
8108                         }
8109
8110                         LocalVariable variable;
8111                         Expression expr;
8112                         Statement statement;
8113                         ExpressionStatement init;
8114                         TemporaryVariableReference enumerator_variable;
8115                         bool ambiguous_getenumerator_name;
8116
8117                         public CollectionForeach (Foreach @foreach, LocalVariable var, Expression expr)
8118                                 : base (@foreach)
8119                         {
8120                                 this.variable = var;
8121                                 this.expr = expr;
8122                         }
8123
8124                         void Error_WrongEnumerator (ResolveContext rc, MethodSpec enumerator)
8125                         {
8126                                 rc.Report.SymbolRelatedToPreviousError (enumerator);
8127                                 rc.Report.Error (202, loc,
8128                                         "foreach statement requires that the return type `{0}' of `{1}' must have a suitable public MoveNext method and public Current property",
8129                                                 enumerator.ReturnType.GetSignatureForError (), enumerator.GetSignatureForError ());
8130                         }
8131
8132                         MethodGroupExpr ResolveGetEnumerator (ResolveContext rc)
8133                         {
8134                                 //
8135                                 // Option 1: Try to match by name GetEnumerator first
8136                                 //
8137                                 var mexpr = Expression.MemberLookup (rc, false, expr.Type,
8138                                         "GetEnumerator", 0, Expression.MemberLookupRestrictions.ExactArity, loc);               // TODO: What if CS0229 ?
8139
8140                                 var mg = mexpr as MethodGroupExpr;
8141                                 if (mg != null) {
8142                                         mg.InstanceExpression = expr;
8143                                         Arguments args = new Arguments (0);
8144                                         mg = mg.OverloadResolve (rc, ref args, this, OverloadResolver.Restrictions.ProbingOnly | OverloadResolver.Restrictions.GetEnumeratorLookup);
8145
8146                                         // For ambiguous GetEnumerator name warning CS0278 was reported, but Option 2 could still apply
8147                                         if (ambiguous_getenumerator_name)
8148                                                 mg = null;
8149
8150                                         if (mg != null && !mg.BestCandidate.IsStatic && mg.BestCandidate.IsPublic) {
8151                                                 return mg;
8152                                         }
8153                                 }
8154
8155                                 //
8156                                 // Option 2: Try to match using IEnumerable interfaces with preference of generic version
8157                                 //
8158                                 var t = expr.Type;
8159                                 PredefinedMember<MethodSpec> iface_candidate = null;
8160                                 var ptypes = rc.Module.PredefinedTypes;
8161                                 var gen_ienumerable = ptypes.IEnumerableGeneric;
8162                                 if (!gen_ienumerable.Define ())
8163                                         gen_ienumerable = null;
8164
8165                                 var ifaces = t.Interfaces;
8166                                 if (ifaces != null) {
8167                                         foreach (var iface in ifaces) {
8168                                                 if (gen_ienumerable != null && iface.MemberDefinition == gen_ienumerable.TypeSpec.MemberDefinition) {
8169                                                         if (iface_candidate != null && iface_candidate != rc.Module.PredefinedMembers.IEnumerableGetEnumerator) {
8170                                                                 rc.Report.SymbolRelatedToPreviousError (expr.Type);
8171                                                                 rc.Report.Error (1640, loc,
8172                                                                         "foreach statement cannot operate on variables of type `{0}' because it contains multiple implementation of `{1}'. Try casting to a specific implementation",
8173                                                                         expr.Type.GetSignatureForError (), gen_ienumerable.TypeSpec.GetSignatureForError ());
8174
8175                                                                 return null;
8176                                                         }
8177
8178                                                         // TODO: Cache this somehow
8179                                                         iface_candidate = new PredefinedMember<MethodSpec> (rc.Module, iface,
8180                                                                 MemberFilter.Method ("GetEnumerator", 0, ParametersCompiled.EmptyReadOnlyParameters, null));
8181
8182                                                         continue;
8183                                                 }
8184
8185                                                 if (iface.BuiltinType == BuiltinTypeSpec.Type.IEnumerable && iface_candidate == null) {
8186                                                         iface_candidate = rc.Module.PredefinedMembers.IEnumerableGetEnumerator;
8187                                                 }
8188                                         }
8189                                 }
8190
8191                                 if (iface_candidate == null) {
8192                                         if (expr.Type != InternalType.ErrorType) {
8193                                                 rc.Report.Error (1579, loc,
8194                                                         "foreach statement cannot operate on variables of type `{0}' because it does not contain a definition for `{1}' or is inaccessible",
8195                                                         expr.Type.GetSignatureForError (), "GetEnumerator");
8196                                         }
8197
8198                                         return null;
8199                                 }
8200
8201                                 var method = iface_candidate.Resolve (loc);
8202                                 if (method == null)
8203                                         return null;
8204
8205                                 mg = MethodGroupExpr.CreatePredefined (method, expr.Type, loc);
8206                                 mg.InstanceExpression = expr;
8207                                 return mg;
8208                         }
8209
8210                         MethodGroupExpr ResolveMoveNext (ResolveContext rc, MethodSpec enumerator)
8211                         {
8212                                 var ms = MemberCache.FindMember (enumerator.ReturnType,
8213                                         MemberFilter.Method ("MoveNext", 0, ParametersCompiled.EmptyReadOnlyParameters, rc.BuiltinTypes.Bool),
8214                                         BindingRestriction.InstanceOnly) as MethodSpec;
8215
8216                                 if (ms == null || !ms.IsPublic) {
8217                                         Error_WrongEnumerator (rc, enumerator);
8218                                         return null;
8219                                 }
8220
8221                                 return MethodGroupExpr.CreatePredefined (ms, enumerator.ReturnType, expr.Location);
8222                         }
8223
8224                         PropertySpec ResolveCurrent (ResolveContext rc, MethodSpec enumerator)
8225                         {
8226                                 var ps = MemberCache.FindMember (enumerator.ReturnType,
8227                                         MemberFilter.Property ("Current", null),
8228                                         BindingRestriction.InstanceOnly) as PropertySpec;
8229
8230                                 if (ps == null || !ps.IsPublic) {
8231                                         Error_WrongEnumerator (rc, enumerator);
8232                                         return null;
8233                                 }
8234
8235                                 return ps;
8236                         }
8237
8238                         public override bool Resolve (BlockContext ec)
8239                         {
8240                                 bool is_dynamic = expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
8241
8242                                 if (is_dynamic) {
8243                                         expr = Convert.ImplicitConversionRequired (ec, expr, ec.BuiltinTypes.IEnumerable, loc);
8244                                 } else if (expr.Type.IsNullableType) {
8245                                         expr = new Nullable.UnwrapCall (expr).Resolve (ec);
8246                                 }
8247
8248                                 var get_enumerator_mg = ResolveGetEnumerator (ec);
8249                                 if (get_enumerator_mg == null) {
8250                                         return false;
8251                                 }
8252
8253                                 var get_enumerator = get_enumerator_mg.BestCandidate;
8254                                 enumerator_variable = TemporaryVariableReference.Create (get_enumerator.ReturnType, variable.Block, loc);
8255                                 enumerator_variable.Resolve (ec);
8256
8257                                 // Prepare bool MoveNext ()
8258                                 var move_next_mg = ResolveMoveNext (ec, get_enumerator);
8259                                 if (move_next_mg == null) {
8260                                         return false;
8261                                 }
8262
8263                                 move_next_mg.InstanceExpression = enumerator_variable;
8264
8265                                 // Prepare ~T~ Current { get; }
8266                                 var current_prop = ResolveCurrent (ec, get_enumerator);
8267                                 if (current_prop == null) {
8268                                         return false;
8269                                 }
8270
8271                                 var current_pe = new PropertyExpr (current_prop, loc) { InstanceExpression = enumerator_variable }.Resolve (ec);
8272                                 if (current_pe == null)
8273                                         return false;
8274
8275                                 VarExpr ve = for_each.type as VarExpr;
8276
8277                                 if (ve != null) {
8278                                         if (is_dynamic) {
8279                                                 // Source type is dynamic, set element type to dynamic too
8280                                                 variable.Type = ec.BuiltinTypes.Dynamic;
8281                                         } else {
8282                                                 // Infer implicitly typed local variable from foreach enumerable type
8283                                                 variable.Type = current_pe.Type;
8284                                         }
8285                                 } else {
8286                                         if (is_dynamic) {
8287                                                 // Explicit cast of dynamic collection elements has to be done at runtime
8288                                                 current_pe = EmptyCast.Create (current_pe, ec.BuiltinTypes.Dynamic);
8289                                         }
8290
8291                                         variable.Type = for_each.type.ResolveAsType (ec);
8292
8293                                         if (variable.Type == null)
8294                                                 return false;
8295
8296                                         current_pe = Convert.ExplicitConversion (ec, current_pe, variable.Type, loc);
8297                                         if (current_pe == null)
8298                                                 return false;
8299                                 }
8300
8301                                 var prev_block = ec.CurrentBlock;
8302                                 ec.CurrentBlock = for_each.variable.Block;
8303                                 var variable_ref = new LocalVariableReference (variable, loc).Resolve (ec);
8304                                 ec.CurrentBlock = prev_block;
8305                                 if (variable_ref == null)
8306                                         return false;
8307
8308                                 for_each.body.AddScopeStatement (new StatementExpression (new CompilerAssign (variable_ref, current_pe, Location.Null), for_each.type.Location));
8309
8310                                 var init = new Invocation.Predefined (get_enumerator_mg, null);
8311
8312                                 statement = new While (new BooleanExpression (new Invocation (move_next_mg, null)),
8313                                          for_each.body, Location.Null);
8314
8315                                 var enum_type = enumerator_variable.Type;
8316
8317                                 //
8318                                 // Add Dispose method call when enumerator can be IDisposable
8319                                 //
8320                                 if (!enum_type.ImplementsInterface (ec.BuiltinTypes.IDisposable, false)) {
8321                                         if (!enum_type.IsSealed && !TypeSpec.IsValueType (enum_type)) {
8322                                                 //
8323                                                 // Runtime Dispose check
8324                                                 //
8325                                                 var vd = new RuntimeDispose (enumerator_variable.LocalInfo, Location.Null);
8326                                                 vd.Initializer = init;
8327                                                 statement = new Using (vd, statement, Location.Null);
8328                                         } else {
8329                                                 //
8330                                                 // No Dispose call needed
8331                                                 //
8332                                                 this.init = new SimpleAssign (enumerator_variable, init, Location.Null);
8333                                                 this.init.Resolve (ec);
8334                                         }
8335                                 } else {
8336                                         //
8337                                         // Static Dispose check
8338                                         //
8339                                         var vd = new Using.VariableDeclaration (enumerator_variable.LocalInfo, Location.Null);
8340                                         vd.Initializer = init;
8341                                         statement = new Using (vd, statement, Location.Null);
8342                                 }
8343
8344                                 return statement.Resolve (ec);
8345                         }
8346
8347                         protected override void DoEmit (EmitContext ec)
8348                         {
8349                                 enumerator_variable.LocalInfo.CreateBuilder (ec);
8350
8351                                 if (init != null)
8352                                         init.EmitStatement (ec);
8353
8354                                 statement.Emit (ec);
8355                         }
8356
8357                         #region IErrorHandler Members
8358
8359                         bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext ec, MemberSpec best, MemberSpec ambiguous)
8360                         {
8361                                 ec.Report.SymbolRelatedToPreviousError (best);
8362                                 ec.Report.Warning (278, 2, expr.Location,
8363                                         "`{0}' contains ambiguous implementation of `{1}' pattern. Method `{2}' is ambiguous with method `{3}'",
8364                                         expr.Type.GetSignatureForError (), "enumerable",
8365                                         best.GetSignatureForError (), ambiguous.GetSignatureForError ());
8366
8367                                 ambiguous_getenumerator_name = true;
8368                                 return true;
8369                         }
8370
8371                         bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
8372                         {
8373                                 return false;
8374                         }
8375
8376                         bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
8377                         {
8378                                 return false;
8379                         }
8380
8381                         bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
8382                         {
8383                                 return false;
8384                         }
8385
8386                         #endregion
8387                 }
8388
8389                 Expression type;
8390                 LocalVariable variable;
8391                 Expression expr;
8392                 Block body;
8393
8394                 public Foreach (Expression type, LocalVariable var, Expression expr, Statement stmt, Block body, Location l)
8395                         : base (stmt)
8396                 {
8397                         this.type = type;
8398                         this.variable = var;
8399                         this.expr = expr;
8400                         this.body = body;
8401                         loc = l;
8402                 }
8403
8404                 public Expression Expr {
8405                         get { return expr; }
8406                 }
8407
8408                 public Expression TypeExpression {
8409                         get { return type; }
8410                 }
8411
8412                 public LocalVariable Variable {
8413                         get { return variable; }
8414                 }
8415
8416                 public override Reachability MarkReachable (Reachability rc)
8417                 {
8418                         base.MarkReachable (rc);
8419
8420                         body.MarkReachable (rc);
8421
8422                         return rc;
8423                 }
8424
8425                 public override bool Resolve (BlockContext ec)
8426                 {
8427                         expr = expr.Resolve (ec);
8428                         if (expr == null)
8429                                 return false;
8430
8431                         if (expr.IsNull) {
8432                                 ec.Report.Error (186, loc, "Use of null is not valid in this context");
8433                                 return false;
8434                         }
8435
8436                         body.AddStatement (Statement);
8437
8438                         if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.String) {
8439                                 Statement = new ArrayForeach (this, 1);
8440                         } else if (expr.Type is ArrayContainer) {
8441                                 Statement = new ArrayForeach (this, ((ArrayContainer) expr.Type).Rank);
8442                         } else {
8443                                 if (expr.eclass == ExprClass.MethodGroup || expr is AnonymousMethodExpression) {
8444                                         ec.Report.Error (446, expr.Location, "Foreach statement cannot operate on a `{0}'",
8445                                                 expr.ExprClassName);
8446                                         return false;
8447                                 }
8448
8449                                 Statement = new CollectionForeach (this, variable, expr);
8450                         }
8451
8452                         return base.Resolve (ec);
8453                 }
8454
8455                 protected override void DoEmit (EmitContext ec)
8456                 {
8457                         Label old_begin = ec.LoopBegin, old_end = ec.LoopEnd;
8458                         ec.LoopBegin = ec.DefineLabel ();
8459                         ec.LoopEnd = ec.DefineLabel ();
8460
8461                         ec.BeginCompilerScope (variable.Block.Explicit.GetDebugSymbolScopeIndex ());
8462                         body.Explicit.DisableDebugScopeIndex ();
8463
8464                         variable.CreateBuilder (ec);
8465
8466                         Statement.Emit (ec);
8467
8468                         ec.EndScope ();
8469
8470                         ec.LoopBegin = old_begin;
8471                         ec.LoopEnd = old_end;
8472                 }
8473
8474                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
8475                 {
8476                         expr.FlowAnalysis (fc);
8477
8478                         var da = fc.BranchDefiniteAssignment ();
8479                         body.FlowAnalysis (fc);
8480                         fc.DefiniteAssignment = da;
8481                         return false;
8482                 }
8483
8484                 protected override void CloneTo (CloneContext clonectx, Statement t)
8485                 {
8486                         Foreach target = (Foreach) t;
8487
8488                         target.type = type.Clone (clonectx);
8489                         target.expr = expr.Clone (clonectx);
8490                         target.body = (Block) body.Clone (clonectx);
8491                         target.Statement = Statement.Clone (clonectx);
8492                 }
8493                 
8494                 public override object Accept (StructuralVisitor visitor)
8495                 {
8496                         return visitor.Visit (this);
8497                 }
8498         }
8499
8500         class SentinelStatement: Statement
8501         {
8502                 protected override void CloneTo (CloneContext clonectx, Statement target)
8503                 {
8504                 }
8505
8506                 protected override void DoEmit (EmitContext ec)
8507                 {
8508                         var l = ec.DefineLabel ();
8509                         ec.MarkLabel (l);
8510                         ec.Emit (OpCodes.Br_S, l);
8511                 }
8512
8513                 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
8514                 {
8515                         throw new NotImplementedException ();
8516                 }
8517         }
8518 }