Merge pull request #600 from tr8dr/master
[mono.git] / mcs / mcs / flowanalysis.cs
1 //
2 // flowanalyis.cs: The control flow analysis code
3 //
4 // Authors:
5 //   Martin Baulig (martin@ximian.com)
6 //   Raja R Harinath (rharinath@novell.com)
7 //   Marek Safar (marek.safar@gmail.com)
8 //
9 // Copyright 2001, 2002, 2003 Ximian, Inc.
10 // Copyright 2003-2008 Novell, Inc.
11 // Copyright 2011 Xamarin, Inc.
12 //
13
14 using System;
15 using System.Text;
16 using System.Collections.Generic;
17
18 namespace Mono.CSharp
19 {
20         // <summary>
21         //   A new instance of this class is created every time a new block is resolved
22         //   and if there's branching in the block's control flow.
23         // </summary>
24         public abstract class FlowBranching
25         {
26                 // <summary>
27                 //   The type of a FlowBranching.
28                 // </summary>
29                 public enum BranchingType : byte {
30                         // Normal (conditional or toplevel) block.
31                         Block,
32
33                         // Conditional.
34                         Conditional,
35
36                         // A loop block.
37                         Loop,
38
39                         // The statement embedded inside a loop
40                         Embedded,
41
42                         // part of a block headed by a jump target
43                         Labeled,
44
45                         // TryCatch block.
46                         TryCatch,
47
48                         // TryFinally, Using, Lock, CollectionForeach
49                         Exception,
50
51                         // Switch block.
52                         Switch,
53
54                         // The toplevel block of a function
55                         Toplevel,
56
57                         // An iterator block
58                         Iterator
59                 }
60
61                 // <summary>
62                 //   The type of one sibling of a branching.
63                 // </summary>
64                 public enum SiblingType : byte {
65                         Block,
66                         Conditional,
67                         SwitchSection,
68                         Try,
69                         Catch,
70                         Finally
71                 }
72
73                 public static FlowBranching CreateBranching (FlowBranching parent, BranchingType type, Block block, Location loc)
74                 {
75                         switch (type) {
76                         case BranchingType.Exception:
77                         case BranchingType.Labeled:
78                         case BranchingType.Toplevel:
79                         case BranchingType.TryCatch:
80                                 throw new InvalidOperationException ();
81
82                         case BranchingType.Switch:
83                                 return new FlowBranchingBreakable (parent, type, SiblingType.SwitchSection, block, loc);
84
85                         case BranchingType.Block:
86                                 return new FlowBranchingBlock (parent, type, SiblingType.Block, block, loc);
87
88                         case BranchingType.Loop:
89                                 return new FlowBranchingBreakable (parent, type, SiblingType.Conditional, block, loc);
90
91                         case BranchingType.Embedded:
92                                 return new FlowBranchingContinuable (parent, type, SiblingType.Conditional, block, loc);
93
94                         default:
95                                 return new FlowBranchingBlock (parent, type, SiblingType.Conditional, block, loc);
96                         }
97                 }
98
99                 // <summary>
100                 //   The type of this flow branching.
101                 // </summary>
102                 public readonly BranchingType Type;
103
104                 // <summary>
105                 //   The block this branching is contained in.  This may be null if it's not
106                 //   a top-level block and it doesn't declare any local variables.
107                 // </summary>
108                 public readonly Block Block;
109
110                 // <summary>
111                 //   The parent of this branching or null if this is the top-block.
112                 // </summary>
113                 public readonly FlowBranching Parent;
114
115                 // <summary>
116                 //   Start-Location of this flow branching.
117                 // </summary>
118                 public readonly Location Location;
119
120                 static int next_id;
121                 int id;
122
123                 // <summary>
124                 //   The vector contains a BitArray with information about which local variables
125                 //   and parameters are already initialized at the current code position.
126                 // </summary>
127                 public class UsageVector {
128                         // <summary>
129                         //   The type of this branching.
130                         // </summary>
131                         public readonly SiblingType Type;
132
133                         // <summary>
134                         //   Start location of this branching.
135                         // </summary>
136                         public Location Location;
137
138                         // <summary>
139                         //   This is only valid for SwitchSection, Try, Catch and Finally.
140                         // </summary>
141                         public readonly Block Block;
142
143                         // <summary>
144                         //   The number of locals in this block.
145                         // </summary>
146                         public readonly int CountLocals;
147
148                         // <summary>
149                         //   If not null, then we inherit our state from this vector and do a
150                         //   copy-on-write.  If null, then we're the first sibling in a top-level
151                         //   block and inherit from the empty vector.
152                         // </summary>
153                         public readonly UsageVector InheritsFrom;
154
155                         // <summary>
156                         //   This is used to construct a list of UsageVector's.
157                         // </summary>
158                         public UsageVector Next;
159
160                         //
161                         // Private.
162                         //
163                         MyBitVector locals;
164                         bool is_unreachable;
165
166                         static int next_id;
167                         int id;
168
169                         //
170                         // Normally, you should not use any of these constructors.
171                         //
172                         public UsageVector (SiblingType type, UsageVector parent, Block block, Location loc, int num_locals)
173                         {
174                                 this.Type = type;
175                                 this.Block = block;
176                                 this.Location = loc;
177                                 this.InheritsFrom = parent;
178                                 this.CountLocals = num_locals;
179
180                                 locals = num_locals == 0 
181                                         ? MyBitVector.Empty
182                                         : new MyBitVector (parent == null ? MyBitVector.Empty : parent.locals, num_locals);
183
184                                 if (parent != null)
185                                         is_unreachable = parent.is_unreachable;
186
187                                 id = ++next_id;
188
189                         }
190
191                         public UsageVector (SiblingType type, UsageVector parent, Block block, Location loc)
192                                 : this (type, parent, block, loc, parent.CountLocals)
193                         { }
194
195                         private UsageVector (MyBitVector locals, bool is_unreachable, Block block, Location loc)
196                         {
197                                 this.Type = SiblingType.Block;
198                                 this.Location = loc;
199                                 this.Block = block;
200
201                                 this.is_unreachable = is_unreachable;
202
203                                 this.locals = locals;
204
205                                 id = ++next_id;
206
207                         }
208
209                         // <summary>
210                         //   This does a deep copy of the usage vector.
211                         // </summary>
212                         public UsageVector Clone ()
213                         {
214                                 UsageVector retval = new UsageVector (Type, null, Block, Location, CountLocals);
215
216                                 retval.locals = locals.Clone ();
217                                 retval.is_unreachable = is_unreachable;
218
219                                 return retval;
220                         }
221
222                         public bool IsAssigned (VariableInfo var, bool ignoreReachability)
223                         {
224                                 if (!ignoreReachability && !var.IsParameter && IsUnreachable)
225                                         return true;
226
227                                 return var.IsAssigned (locals);
228                         }
229
230                         public void SetAssigned (VariableInfo var)
231                         {
232                                 if (!var.IsParameter && IsUnreachable)
233                                         return;
234
235                                 var.SetAssigned (locals);
236                         }
237
238                         public bool IsFieldAssigned (VariableInfo var, string name)
239                         {
240                                 if (/*!var.IsParameter &&*/ IsUnreachable)
241                                         return true;
242
243                                 return var.IsStructFieldAssigned (locals, name);
244                         }
245
246                         public void SetFieldAssigned (VariableInfo var, string name)
247                         {
248                                 if (/*!var.IsParameter &&*/ IsUnreachable)
249                                         return;
250
251                                 var.SetStructFieldAssigned (locals, name);
252                         }
253
254                         public bool IsUnreachable {
255                                 get {
256                                         return is_unreachable;
257                                 }
258                                 set {
259                                         is_unreachable = value;
260                                 }
261                         }
262
263                         public void ResetBarrier ()
264                         {
265                                 is_unreachable = false;
266                         }
267
268                         public void Goto ()
269                         {
270                                 is_unreachable = true;
271                         }
272
273                         public static UsageVector MergeSiblings (UsageVector sibling_list, Location loc)
274                         {
275                                 if (sibling_list.Next == null)
276                                         return sibling_list;
277
278                                 MyBitVector locals = null;
279                                 bool is_unreachable = sibling_list.is_unreachable;
280
281                                 if (!sibling_list.IsUnreachable)
282                                         locals &= sibling_list.locals;
283
284                                 for (UsageVector child = sibling_list.Next; child != null; child = child.Next) {
285                                         is_unreachable &= child.is_unreachable;
286
287                                         if (!child.IsUnreachable)
288                                                 locals &= child.locals;
289                                 }
290
291                                 return new UsageVector (locals, is_unreachable, null, loc);
292                         }
293
294                         // <summary>
295                         //   Merges a child branching.
296                         // </summary>
297                         public UsageVector MergeChild (UsageVector child, bool overwrite)
298                         {
299                                 Report.Debug (2, "    MERGING CHILD EFFECTS", this, child, Type);
300
301                                 bool new_isunr = child.is_unreachable;
302
303                                 //
304                                 // We've now either reached the point after the branching or we will
305                                 // never get there since we always return or always throw an exception.
306                                 //
307                                 // If we can reach the point after the branching, mark all locals and
308                                 // parameters as initialized which have been initialized in all branches
309                                 // we need to look at (see above).
310                                 //
311
312                                 if ((Type == SiblingType.SwitchSection) && !new_isunr) {
313                                         Report.Error (163, Location,
314                                                       "Control cannot fall through from one " +
315                                                       "case label to another");
316                                         return child;
317                                 }
318
319                                 locals |= child.locals;
320
321                                 // throw away un-necessary information about variables in child blocks
322                                 if (locals.Count != CountLocals)
323                                         locals = new MyBitVector (locals, CountLocals);
324
325                                 if (overwrite)
326                                         is_unreachable = new_isunr;
327                                 else
328                                         is_unreachable |= new_isunr;
329
330                                 return child;
331                         }
332
333                         public void MergeOrigins (UsageVector o_vectors)
334                         {
335                                 Report.Debug (1, "  MERGING BREAK ORIGINS", this);
336
337                                 if (o_vectors == null)
338                                         return;
339
340                                 if (IsUnreachable && locals != null)
341                                         locals.SetAll (true);
342
343                                 for (UsageVector vector = o_vectors; vector != null; vector = vector.Next) {
344                                         Report.Debug (1, "    MERGING BREAK ORIGIN", vector);
345                                         if (vector.IsUnreachable)
346                                                 continue;
347                                         locals &= vector.locals;
348                                         is_unreachable &= vector.is_unreachable;
349                                 }
350
351                                 Report.Debug (1, "  MERGING BREAK ORIGINS DONE", this);
352                         }
353
354                         //
355                         // Debugging stuff.
356                         //
357
358                         public override string ToString ()
359                         {
360                                 return String.Format ("Vector ({0},{1},{2}-{3})", Type, id, is_unreachable, locals);
361                         }
362                 }
363
364                 // <summary>
365                 //   Creates a new flow branching which is contained in `parent'.
366                 //   You should only pass non-null for the `block' argument if this block
367                 //   introduces any new variables - in this case, we need to create a new
368                 //   usage vector with a different size than our parent's one.
369                 // </summary>
370                 protected FlowBranching (FlowBranching parent, BranchingType type, SiblingType stype,
371                                          Block block, Location loc)
372                 {
373                         Parent = parent;
374                         Block = block;
375                         Location = loc;
376                         Type = type;
377                         id = ++next_id;
378
379                         UsageVector vector;
380                         if (Block != null) {
381                                 UsageVector parent_vector = parent != null ? parent.CurrentUsageVector : null;
382                                 vector = new UsageVector (stype, parent_vector, Block, loc, Block.AssignableSlots);
383                         } else {
384                                 vector = new UsageVector (stype, Parent.CurrentUsageVector, null, loc);
385                         }
386
387                         AddSibling (vector);
388                 }
389
390                 public abstract UsageVector CurrentUsageVector {
391                         get;
392                 }                               
393
394                 // <summary>
395                 //   Creates a sibling of the current usage vector.
396                 // </summary>
397                 public void CreateSibling (Block block, SiblingType type)
398                 {
399                         UsageVector vector = new UsageVector (
400                                 type, Parent.CurrentUsageVector, block, Location);
401                         AddSibling (vector);
402
403                         Report.Debug (1, "  CREATED SIBLING", CurrentUsageVector);
404                 }
405
406                 public void CreateSibling ()
407                 {
408                         CreateSibling (null, SiblingType.Conditional);
409                 }
410
411                 protected abstract void AddSibling (UsageVector uv);
412
413                 protected abstract UsageVector Merge ();
414
415                 public UsageVector MergeChild (FlowBranching child)
416                 {
417                         return CurrentUsageVector.MergeChild (child.Merge (), true);
418                 }
419
420                 public virtual bool CheckRethrow (Location loc)
421                 {
422                         return Parent.CheckRethrow (loc);
423                 }
424
425                 public virtual bool AddResumePoint (ResumableStatement stmt, ResumableStatement current, out int pc)
426                 {
427                         return Parent.AddResumePoint (stmt, current, out pc);
428                 }
429
430                 // returns true if we crossed an unwind-protected region (try/catch/finally, lock, using, ...)
431                 public virtual bool AddBreakOrigin (UsageVector vector, Location loc)
432                 {
433                         return Parent.AddBreakOrigin (vector, loc);
434                 }
435
436                 // returns true if we crossed an unwind-protected region (try/catch/finally, lock, using, ...)
437                 public virtual bool AddContinueOrigin (UsageVector vector, Location loc)
438                 {
439                         return Parent.AddContinueOrigin (vector, loc);
440                 }
441
442                 // returns true if we crossed an unwind-protected region (try/catch/finally, lock, using, ...)
443                 public virtual bool AddReturnOrigin (UsageVector vector, ExitStatement stmt)
444                 {
445                         return Parent.AddReturnOrigin (vector, stmt);
446                 }
447
448                 // returns true if we crossed an unwind-protected region (try/catch/finally, lock, using, ...)
449                 public virtual bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
450                 {
451                         return Parent.AddGotoOrigin (vector, goto_stmt);
452                 }
453
454                 public bool IsAssigned (VariableInfo vi)
455                 {
456                         return CurrentUsageVector.IsAssigned (vi, false);
457                 }
458
459                 public bool IsStructFieldAssigned (VariableInfo vi, string field_name)
460                 {
461                         return CurrentUsageVector.IsAssigned (vi, false) || CurrentUsageVector.IsFieldAssigned (vi, field_name);
462                 }
463
464                 protected static Report Report {
465                         get { return RootContext.ToplevelTypes.Compiler.Report; }
466                 }
467
468                 public void SetAssigned (VariableInfo vi)
469                 {
470                         CurrentUsageVector.SetAssigned (vi);
471                 }
472
473                 public void SetFieldAssigned (VariableInfo vi, string name)
474                 {
475                         CurrentUsageVector.SetFieldAssigned (vi, name);
476                 }
477
478 #if DEBUG
479                 public override string ToString ()
480                 {
481                         StringBuilder sb = new StringBuilder ();
482                         sb.Append (GetType ());
483                         sb.Append (" (");
484
485                         sb.Append (id);
486                         sb.Append (",");
487                         sb.Append (Type);
488                         if (Block != null) {
489                                 sb.Append (" - ");
490                                 sb.Append (Block.ID);
491                                 sb.Append (" - ");
492                                 sb.Append (Block.StartLocation);
493                         }
494                         sb.Append (" - ");
495                         // sb.Append (Siblings.Length);
496                         // sb.Append (" - ");
497                         sb.Append (CurrentUsageVector);
498                         sb.Append (")");
499                         return sb.ToString ();
500                 }
501 #endif
502
503                 public string Name {
504                         get { return String.Format ("{0} ({1}:{2}:{3})", GetType (), id, Type, Location); }
505                 }
506         }
507
508         public class FlowBranchingBlock : FlowBranching
509         {
510                 UsageVector sibling_list = null;
511
512                 public FlowBranchingBlock (FlowBranching parent, BranchingType type,
513                                            SiblingType stype, Block block, Location loc)
514                         : base (parent, type, stype, block, loc)
515                 { }
516
517                 public override UsageVector CurrentUsageVector {
518                         get { return sibling_list; }
519                 }
520
521                 protected override void AddSibling (UsageVector sibling)
522                 {
523                         if (sibling_list != null && sibling_list.Type == SiblingType.Block)
524                                 throw new InternalErrorException ("Blocks don't have sibling flow paths");
525                         sibling.Next = sibling_list;
526                         sibling_list = sibling;
527                 }
528
529                 public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
530                 {
531                         LabeledStatement stmt = Block == null ? null : Block.LookupLabel (goto_stmt.Target);
532                         if (stmt == null)
533                                 return Parent.AddGotoOrigin (vector, goto_stmt);
534
535                         // forward jump
536                         goto_stmt.SetResolvedTarget (stmt);
537                         stmt.AddUsageVector (vector);
538                         return false;
539                 }
540                 
541                 public static void Error_UnknownLabel (Location loc, string label, Report Report)
542                 {
543                         Report.Error(159, loc, "The label `{0}:' could not be found within the scope of the goto statement",
544                                 label);
545                 }
546
547                 protected override UsageVector Merge ()
548                 {
549                         Report.Debug (2, "  MERGING SIBLINGS", Name);
550                         UsageVector vector = UsageVector.MergeSiblings (sibling_list, Location);
551                         Report.Debug (2, "  MERGING SIBLINGS DONE", Name, vector);
552                         return vector;
553                 }
554         }
555
556         public class FlowBranchingBreakable : FlowBranchingBlock
557         {
558                 UsageVector break_origins;
559
560                 public FlowBranchingBreakable (FlowBranching parent, BranchingType type, SiblingType stype, Block block, Location loc)
561                         : base (parent, type, stype, block, loc)
562                 { }
563
564                 public override bool AddBreakOrigin (UsageVector vector, Location loc)
565                 {
566                         vector = vector.Clone ();
567                         vector.Next = break_origins;
568                         break_origins = vector;
569                         return false;
570                 }
571
572                 protected override UsageVector Merge ()
573                 {
574                         UsageVector vector = base.Merge ();
575                         vector.MergeOrigins (break_origins);
576                         return vector;
577                 }
578         }
579
580         public class FlowBranchingContinuable : FlowBranchingBlock
581         {
582                 UsageVector continue_origins;
583
584                 public FlowBranchingContinuable (FlowBranching parent, BranchingType type, SiblingType stype, Block block, Location loc)
585                         : base (parent, type, stype, block, loc)
586                 { }
587
588                 public override bool AddContinueOrigin (UsageVector vector, Location loc)
589                 {
590                         vector = vector.Clone ();
591                         vector.Next = continue_origins;
592                         continue_origins = vector;
593                         return false;
594                 }
595
596                 protected override UsageVector Merge ()
597                 {
598                         UsageVector vector = base.Merge ();
599                         vector.MergeOrigins (continue_origins);
600                         return vector;
601                 }
602         }
603
604         public class FlowBranchingLabeled : FlowBranchingBlock
605         {
606                 LabeledStatement stmt;
607                 UsageVector actual;
608
609                 public FlowBranchingLabeled (FlowBranching parent, LabeledStatement stmt)
610                         : base (parent, BranchingType.Labeled, SiblingType.Conditional, null, stmt.loc)
611                 {
612                         this.stmt = stmt;
613                         CurrentUsageVector.MergeOrigins (stmt.JumpOrigins);
614                         actual = CurrentUsageVector.Clone ();
615
616                         // stand-in for backward jumps
617                         CurrentUsageVector.ResetBarrier ();
618                 }
619
620                 public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
621                 {
622                         if (goto_stmt.Target != stmt.Name)
623                                 return Parent.AddGotoOrigin (vector, goto_stmt);
624
625                         // backward jump
626                         goto_stmt.SetResolvedTarget (stmt);
627                         actual.MergeOrigins (vector.Clone ());
628
629                         return false;
630                 }
631
632                 protected override UsageVector Merge ()
633                 {
634                         UsageVector vector = base.Merge ();
635
636                         if (actual.IsUnreachable)
637                                 Report.Warning (162, 2, stmt.loc, "Unreachable code detected");
638
639                         actual.MergeChild (vector, false);
640                         return actual;
641                 }
642         }
643
644         public class FlowBranchingIterator : FlowBranchingBlock
645         {
646                 readonly Iterator iterator;
647
648                 public FlowBranchingIterator (FlowBranching parent, Iterator iterator)
649                         : base (parent, BranchingType.Iterator, SiblingType.Block, iterator.Block, iterator.Location)
650                 {
651                         this.iterator = iterator;
652                 }
653
654                 public override bool AddResumePoint (ResumableStatement stmt, ResumableStatement current, out int pc)
655                 {
656                         pc = iterator.AddResumePoint (current);
657                         return false;
658                 }
659         }
660
661         public class FlowBranchingToplevel : FlowBranchingBlock
662         {
663                 UsageVector return_origins;
664
665                 public FlowBranchingToplevel (FlowBranching parent, ParametersBlock stmt)
666                         : base (parent, BranchingType.Toplevel, SiblingType.Conditional, stmt, stmt.loc)
667                 {
668                 }
669
670                 public override bool CheckRethrow (Location loc)
671                 {
672                         Report.Error (156, loc, "A throw statement with no arguments is not allowed outside of a catch clause");
673                         return false;
674                 }
675
676                 public override bool AddResumePoint (ResumableStatement stmt, ResumableStatement current, out int pc)
677                 {
678                         throw new InternalErrorException ("A yield in a non-iterator block");
679                 }
680
681                 public override bool AddBreakOrigin (UsageVector vector, Location loc)
682                 {
683                         Report.Error (139, loc, "No enclosing loop out of which to break or continue");
684                         return false;
685                 }
686
687                 public override bool AddContinueOrigin (UsageVector vector, Location loc)
688                 {
689                         Report.Error (139, loc, "No enclosing loop out of which to break or continue");
690                         return false;
691                 }
692
693                 public override bool AddReturnOrigin (UsageVector vector, ExitStatement stmt)
694                 {
695                         vector = vector.Clone ();
696                         vector.Location = stmt.loc;
697                         vector.Next = return_origins;
698                         return_origins = vector;
699                         return false;
700                 }
701
702                 public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
703                 {
704                         string name = goto_stmt.Target;
705                         LabeledStatement s = Block.LookupLabel (name);
706                         if (s != null)
707                                 throw new InternalErrorException ("Shouldn't get here");
708
709                         if (Parent == null) {
710                                 Error_UnknownLabel (goto_stmt.loc, name, Report);
711                                 return false;
712                         }
713
714                         int errors = Report.Errors;
715                         Parent.AddGotoOrigin (vector, goto_stmt);
716                         if (errors == Report.Errors)
717                                 Report.Error (1632, goto_stmt.loc, "Control cannot leave the body of an anonymous method");
718                         return false;
719                 }
720
721                 protected override UsageVector Merge ()
722                 {
723                         for (UsageVector origin = return_origins; origin != null; origin = origin.Next)
724                                 Block.ParametersBlock.CheckOutParameters (origin);
725
726                         UsageVector vector = base.Merge ();
727                         Block.ParametersBlock.CheckOutParameters (vector);
728                         // Note: we _do_not_ merge in the return origins
729                         return vector;
730                 }
731
732                 public bool End ()
733                 {
734                         return Merge ().IsUnreachable;
735                 }
736         }
737
738         public class FlowBranchingTryCatch : FlowBranchingBlock
739         {
740                 readonly TryCatch tc;
741
742                 public FlowBranchingTryCatch (FlowBranching parent, TryCatch stmt)
743                         : base (parent, BranchingType.Block, SiblingType.Try, null, stmt.loc)
744                 {
745                         this.tc = stmt;
746                 }
747
748                 public override bool CheckRethrow (Location loc)
749                 {
750                         return CurrentUsageVector.Next != null || Parent.CheckRethrow (loc);
751                 }
752
753                 public override bool AddResumePoint (ResumableStatement stmt, ResumableStatement current, out int pc)
754                 {
755                         int errors = Report.Errors;
756                         Parent.AddResumePoint (stmt, tc.IsTryCatchFinally ? current : tc, out pc);
757                         if (errors == Report.Errors) {
758                                 if (stmt is AwaitStatement) {
759                                         if (CurrentUsageVector.Next != null) {
760                                                 Report.Error (1985, stmt.loc, "The `await' operator cannot be used in the body of a catch clause");
761                                         } else {
762                                                 this.tc.AddResumePoint (current, pc);
763                                         }
764                                 } else {
765                                         if (CurrentUsageVector.Next == null)
766                                                 Report.Error (1626, stmt.loc, "Cannot yield a value in the body of a try block with a catch clause");
767                                         else
768                                                 Report.Error (1631, stmt.loc, "Cannot yield a value in the body of a catch clause");
769                                 }
770                         }
771
772                         return true;
773                 }
774
775                 public override bool AddBreakOrigin (UsageVector vector, Location loc)
776                 {
777                         Parent.AddBreakOrigin (vector, loc);
778                         tc.SomeCodeFollows ();
779                         return true;
780                 }
781
782                 public override bool AddContinueOrigin (UsageVector vector, Location loc)
783                 {
784                         Parent.AddContinueOrigin (vector, loc);
785                         tc.SomeCodeFollows ();
786                         return true;
787                 }
788
789                 public override bool AddReturnOrigin (UsageVector vector, ExitStatement exit_stmt)
790                 {
791                         Parent.AddReturnOrigin (vector, exit_stmt);
792                         tc.SomeCodeFollows ();
793                         return true;
794                 }
795
796                 public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
797                 {
798                         Parent.AddGotoOrigin (vector, goto_stmt);
799                         return true;
800                 }
801         }
802
803         public class FlowBranchingAsync : FlowBranchingBlock
804         {
805                 readonly AsyncInitializer async_init;
806
807                 public FlowBranchingAsync (FlowBranching parent, AsyncInitializer async_init)
808                         : base (parent, BranchingType.Block, SiblingType.Try, null, async_init.Location)
809                 {
810                         this.async_init = async_init;
811                 }
812 /*
813                 public override bool CheckRethrow (Location loc)
814                 {
815                         return CurrentUsageVector.Next != null || Parent.CheckRethrow (loc);
816                 }
817 */
818                 public override bool AddResumePoint (ResumableStatement stmt, ResumableStatement current, out int pc)
819                 {
820                         pc = async_init.AddResumePoint (current);
821                         return true;
822                 }
823
824                 public override bool AddBreakOrigin (UsageVector vector, Location loc)
825                 {
826                         Parent.AddBreakOrigin (vector, loc);
827                         return true;
828                 }
829
830                 public override bool AddContinueOrigin (UsageVector vector, Location loc)
831                 {
832                         Parent.AddContinueOrigin (vector, loc);
833                         return true;
834                 }
835
836                 public override bool AddReturnOrigin (UsageVector vector, ExitStatement exit_stmt)
837                 {
838                         Parent.AddReturnOrigin (vector, exit_stmt);
839                         return true;
840                 }
841
842                 public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
843                 {
844                         Parent.AddGotoOrigin (vector, goto_stmt);
845                         return true;
846                 }
847         }
848
849         public class FlowBranchingTryFinally : FlowBranching
850         {
851                 ExceptionStatement stmt;
852                 UsageVector current_vector;
853                 UsageVector try_vector;
854                 UsageVector finally_vector;
855
856                 abstract class SavedOrigin {
857                         public readonly SavedOrigin Next;
858                         public readonly UsageVector Vector;
859
860                         protected SavedOrigin (SavedOrigin next, UsageVector vector)
861                         {
862                                 Next = next;
863                                 Vector = vector.Clone ();
864                         }
865
866                         protected abstract void DoPropagateFinally (FlowBranching parent);
867                         public void PropagateFinally (UsageVector finally_vector, FlowBranching parent)
868                         {
869                                 if (finally_vector != null)
870                                         Vector.MergeChild (finally_vector, false);
871                                 DoPropagateFinally (parent);
872                         }
873                 }
874
875                 class BreakOrigin : SavedOrigin {
876                         Location Loc;
877                         public BreakOrigin (SavedOrigin next, UsageVector vector, Location loc)
878                                 : base (next, vector)
879                         {
880                                 Loc = loc;
881                         }
882
883                         protected override void DoPropagateFinally (FlowBranching parent)
884                         {
885                                 parent.AddBreakOrigin (Vector, Loc);
886                         }
887                 }
888
889                 class ContinueOrigin : SavedOrigin {
890                         Location Loc;
891                         public ContinueOrigin (SavedOrigin next, UsageVector vector, Location loc)
892                                 : base (next, vector)
893                         {
894                                 Loc = loc;
895                         }
896
897                         protected override void DoPropagateFinally (FlowBranching parent)
898                         {
899                                 parent.AddContinueOrigin (Vector, Loc);
900                         }
901                 }
902
903                 class ReturnOrigin : SavedOrigin {
904                         public ExitStatement Stmt;
905
906                         public ReturnOrigin (SavedOrigin next, UsageVector vector, ExitStatement stmt)
907                                 : base (next, vector)
908                         {
909                                 Stmt = stmt;
910                         }
911
912                         protected override void DoPropagateFinally (FlowBranching parent)
913                         {
914                                 parent.AddReturnOrigin (Vector, Stmt);
915                         }
916                 }
917
918                 class GotoOrigin : SavedOrigin {
919                         public Goto Stmt;
920
921                         public GotoOrigin (SavedOrigin next, UsageVector vector, Goto stmt)
922                                 : base (next, vector)
923                         {
924                                 Stmt = stmt;
925                         }
926
927                         protected override void DoPropagateFinally (FlowBranching parent)
928                         {
929                                 parent.AddGotoOrigin (Vector, Stmt);
930                         }
931                 }
932
933                 SavedOrigin saved_origins;
934
935                 public FlowBranchingTryFinally (FlowBranching parent,
936                                                ExceptionStatement stmt)
937                         : base (parent, BranchingType.Exception, SiblingType.Try,
938                                 null, stmt.loc)
939                 {
940                         this.stmt = stmt;
941                 }
942
943                 protected override void AddSibling (UsageVector sibling)
944                 {
945                         switch (sibling.Type) {
946                         case SiblingType.Try:
947                                 try_vector = sibling;
948                                 break;
949                         case SiblingType.Finally:
950                                 finally_vector = sibling;
951                                 break;
952                         default:
953                                 throw new InvalidOperationException ();
954                         }
955                         current_vector = sibling;
956                 }
957
958                 public override UsageVector CurrentUsageVector {
959                         get { return current_vector; }
960                 }
961
962                 public override bool CheckRethrow (Location loc)
963                 {
964                         if (!Parent.CheckRethrow (loc))
965                                 return false;
966                         if (finally_vector == null)
967                                 return true;
968                         Report.Error (724, loc, "A throw statement with no arguments is not allowed inside of a finally clause nested inside of the innermost catch clause");
969                         return false;
970                 }
971
972                 public override bool AddResumePoint (ResumableStatement stmt, ResumableStatement current, out int pc)
973                 {
974                         int errors = Report.Errors;
975                         Parent.AddResumePoint (stmt, this.stmt, out pc);
976                         if (errors == Report.Errors) {
977                                 if (finally_vector == null)
978                                         this.stmt.AddResumePoint (current, pc);
979                                 else {
980                                         if (stmt is AwaitStatement) {
981                                                 Report.Error (1984, stmt.loc, "The `await' operator cannot be used in the body of a finally clause");
982                                         } else {
983                                                 Report.Error (1625, stmt.loc, "Cannot yield in the body of a finally clause");
984                                         }
985                                 }
986                         }
987                         return true;
988                 }
989
990                 public override bool AddBreakOrigin (UsageVector vector, Location loc)
991                 {
992                         if (finally_vector != null) {
993                                 int errors = Report.Errors;
994                                 Parent.AddBreakOrigin (vector, loc);
995                                 if (errors == Report.Errors)
996                                         Report.Error (157, loc, "Control cannot leave the body of a finally clause");
997                         } else {
998                                 saved_origins = new BreakOrigin (saved_origins, vector, loc);
999                         }
1000
1001                         // either the loop test or a back jump will follow code
1002                         stmt.SomeCodeFollows ();
1003                         return true;
1004                 }
1005
1006                 public override bool AddContinueOrigin (UsageVector vector, Location loc)
1007                 {
1008                         if (finally_vector != null) {
1009                                 int errors = Report.Errors;
1010                                 Parent.AddContinueOrigin (vector, loc);
1011                                 if (errors == Report.Errors)
1012                                         Report.Error (157, loc, "Control cannot leave the body of a finally clause");
1013                         } else {
1014                                 saved_origins = new ContinueOrigin (saved_origins, vector, loc);
1015                         }
1016
1017                         // either the loop test or a back jump will follow code
1018                         stmt.SomeCodeFollows ();
1019                         return true;
1020                 }
1021
1022                 public override bool AddReturnOrigin (UsageVector vector, ExitStatement exit_stmt)
1023                 {
1024                         if (finally_vector != null) {
1025                                 int errors = Report.Errors;
1026                                 Parent.AddReturnOrigin (vector, exit_stmt);
1027                                 if (errors == Report.Errors)
1028                                         exit_stmt.Error_FinallyClause (Report);
1029                         } else {
1030                                 saved_origins = new ReturnOrigin (saved_origins, vector, exit_stmt);
1031                         }
1032
1033                         // sets ec.NeedReturnLabel()
1034                         stmt.SomeCodeFollows ();
1035                         return true;
1036                 }
1037
1038                 public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
1039                 {
1040                         LabeledStatement s = current_vector.Block == null ? null : current_vector.Block.LookupLabel (goto_stmt.Target);
1041                         if (s != null)
1042                                 throw new InternalErrorException ("Shouldn't get here");
1043
1044                         if (finally_vector != null) {
1045                                 int errors = Report.Errors;
1046                                 Parent.AddGotoOrigin (vector, goto_stmt);
1047                                 if (errors == Report.Errors)
1048                                         Report.Error (157, goto_stmt.loc, "Control cannot leave the body of a finally clause");
1049                         } else {
1050                                 saved_origins = new GotoOrigin (saved_origins, vector, goto_stmt);
1051                         }
1052                         return true;
1053                 }
1054
1055                 protected override UsageVector Merge ()
1056                 {
1057                         UsageVector vector = try_vector.Clone ();
1058
1059                         if (finally_vector != null)
1060                                 vector.MergeChild (finally_vector, false);
1061
1062                         for (SavedOrigin origin = saved_origins; origin != null; origin = origin.Next)
1063                                 origin.PropagateFinally (finally_vector, Parent);
1064
1065                         return vector;
1066                 }
1067         }
1068
1069         // <summary>
1070         //   This is used by the flow analysis code to keep track of the type of local variables.
1071         //
1072         //   The flow code uses a BitVector to keep track of whether a variable has been assigned
1073         //   or not.  This is easy for fundamental types (int, char etc.) or reference types since
1074         //   you can only assign the whole variable as such.
1075         //
1076         //   For structs, we also need to keep track of all its fields.  To do this, we allocate one
1077         //   bit for the struct itself (it's used if you assign/access the whole struct) followed by
1078         //   one bit for each of its fields.
1079         //
1080         //   This class computes this `layout' for each type.
1081         // </summary>
1082         public class TypeInfo
1083         {
1084                 // <summary>
1085                 //   Total number of bits a variable of this type consumes in the flow vector.
1086                 // </summary>
1087                 public readonly int TotalLength;
1088
1089                 // <summary>
1090                 //   Number of bits the simple fields of a variable of this type consume
1091                 //   in the flow vector.
1092                 // </summary>
1093                 public readonly int Length;
1094
1095                 // <summary>
1096                 //   This is only used by sub-structs.
1097                 // </summary>
1098                 public readonly int Offset;
1099
1100                 // <summary>
1101                 //   If this is a struct.
1102                 // </summary>
1103                 public readonly bool IsStruct;
1104
1105                 // <summary>
1106                 //   If this is a struct, all fields which are structs theirselves.
1107                 // </summary>
1108                 public TypeInfo[] SubStructInfo;
1109
1110                 readonly StructInfo struct_info;
1111                 private static Dictionary<TypeSpec, TypeInfo> type_hash;
1112
1113                 static readonly TypeInfo simple_type = new TypeInfo (1);
1114                 
1115                 static TypeInfo ()
1116                 {
1117                         Reset ();
1118                 }
1119                 
1120                 public static void Reset ()
1121                 {
1122                         type_hash = new Dictionary<TypeSpec, TypeInfo> ();
1123                         StructInfo.field_type_hash = new Dictionary<TypeSpec, StructInfo> ();
1124                 }
1125
1126                 TypeInfo (int totalLength)
1127                 {
1128                         this.TotalLength = totalLength;
1129                 }
1130                 
1131                 TypeInfo (StructInfo struct_info, int offset)
1132                 {
1133                         this.struct_info = struct_info;
1134                         this.Offset = offset;
1135                         this.Length = struct_info.Length;
1136                         this.TotalLength = struct_info.TotalLength;
1137                         this.SubStructInfo = struct_info.StructFields;
1138                         this.IsStruct = true;
1139                 }
1140                 
1141                 public int GetFieldIndex (string name)
1142                 {
1143                         if (struct_info == null)
1144                                 return 0;
1145
1146                         return struct_info [name];
1147                 }
1148
1149                 public TypeInfo GetStructField (string name)
1150                 {
1151                         if (struct_info == null)
1152                                 return null;
1153
1154                         return struct_info.GetStructField (name);
1155                 }
1156
1157                 public static TypeInfo GetTypeInfo (TypeSpec type)
1158                 {
1159                         if (!type.IsStruct)
1160                                 return simple_type;
1161
1162                         TypeInfo info;
1163                         if (type_hash.TryGetValue (type, out info))
1164                                 return info;
1165
1166                         var struct_info = StructInfo.GetStructInfo (type);
1167                         if (struct_info != null) {
1168                                 info = new TypeInfo (struct_info, 0);
1169                         } else {
1170                                 info = simple_type;
1171                         }
1172
1173                         type_hash.Add (type, info);
1174                         return info;
1175                 }
1176
1177                 // <summary>
1178                 //   A struct's constructor must always assign all fields.
1179                 //   This method checks whether it actually does so.
1180                 // </summary>
1181                 public bool IsFullyInitialized (BlockContext ec, VariableInfo vi, Location loc)
1182                 {
1183                         if (struct_info == null)
1184                                 return true;
1185
1186                         bool ok = true;
1187                         FlowBranching branching = ec.CurrentBranching;
1188                         for (int i = 0; i < struct_info.Count; i++) {
1189                                 var field = struct_info.Fields [i];
1190
1191                                 if (!branching.IsStructFieldAssigned (vi, field.Name)) {
1192                                         if (field.MemberDefinition is Property.BackingField) {
1193                                                 ec.Report.Error (843, loc,
1194                                                         "An automatically implemented property `{0}' must be fully assigned before control leaves the constructor. Consider calling the default struct contructor from a constructor initializer",
1195                                                         field.GetSignatureForError ());
1196                                         } else {
1197                                                 ec.Report.Error (171, loc,
1198                                                         "Field `{0}' must be fully assigned before control leaves the constructor",
1199                                                         field.GetSignatureForError ());
1200                                         }
1201                                         ok = false;
1202                                 }
1203                         }
1204
1205                         return ok;
1206                 }
1207
1208                 public override string ToString ()
1209                 {
1210                         return String.Format ("TypeInfo ({0}:{1}:{2})",
1211                                               Offset, Length, TotalLength);
1212                 }
1213
1214                 class StructInfo
1215                 {
1216                         readonly List<FieldSpec> fields;
1217                         public readonly TypeInfo[] StructFields;
1218                         public readonly int Length;
1219                         public readonly int TotalLength;
1220
1221                         public static Dictionary<TypeSpec, StructInfo> field_type_hash;
1222                         private Dictionary<string, TypeInfo> struct_field_hash;
1223                         private Dictionary<string, int> field_hash;
1224
1225                         bool InTransit;
1226
1227                         //
1228                         // We only need one instance per type
1229                         //
1230                         StructInfo (TypeSpec type)
1231                         {
1232                                 field_type_hash.Add (type, this);
1233
1234                                 fields = MemberCache.GetAllFieldsForDefiniteAssignment (type);
1235
1236                                 struct_field_hash = new Dictionary<string, TypeInfo> ();
1237                                 field_hash = new Dictionary<string, int> (fields.Count);
1238
1239                                 StructFields = new TypeInfo[fields.Count];
1240                                 StructInfo[] sinfo = new StructInfo[fields.Count];
1241
1242                                 InTransit = true;
1243
1244                                 for (int i = 0; i < fields.Count; i++) {
1245                                         var field = fields [i];
1246
1247                                         if (field.MemberType.IsStruct)
1248                                                 sinfo [i] = GetStructInfo (field.MemberType);
1249
1250                                         if (sinfo [i] == null)
1251                                                 field_hash.Add (field.Name, ++Length);
1252                                         else if (sinfo [i].InTransit) {
1253                                                 sinfo [i] = null;
1254                                                 return;
1255                                         }
1256                                 }
1257
1258                                 InTransit = false;
1259
1260                                 TotalLength = Length + 1;
1261                                 for (int i = 0; i < fields.Count; i++) {
1262                                         var field = fields [i];
1263
1264                                         if (sinfo [i] == null)
1265                                                 continue;
1266
1267                                         field_hash.Add (field.Name, TotalLength);
1268
1269                                         StructFields [i] = new TypeInfo (sinfo [i], TotalLength);
1270                                         struct_field_hash.Add (field.Name, StructFields [i]);
1271                                         TotalLength += sinfo [i].TotalLength;
1272                                 }
1273                         }
1274
1275                         public int Count {
1276                                 get {
1277                                         return fields.Count;
1278                                 }
1279                         }
1280
1281                         public List<FieldSpec> Fields {
1282                                 get {
1283                                         return fields;
1284                                 }
1285                         }
1286
1287                         public int this [string name] {
1288                                 get {
1289                                         int val;
1290                                         if (!field_hash.TryGetValue (name, out val))
1291                                                 return 0;
1292
1293                                         return val;
1294                                 }
1295                         }
1296
1297                         public TypeInfo GetStructField (string name)
1298                         {
1299                                 TypeInfo ti;
1300                                 if (struct_field_hash.TryGetValue (name, out ti))
1301                                         return ti;
1302
1303                                 return null;
1304                         }
1305
1306                         public static StructInfo GetStructInfo (TypeSpec type)
1307                         {
1308                                 if (type.BuiltinType > 0)
1309                                         return null;
1310
1311                                 StructInfo info;
1312                                 if (field_type_hash.TryGetValue (type, out info))
1313                                         return info;
1314
1315                                 return new StructInfo (type);
1316                         }
1317                 }
1318         }
1319
1320         // <summary>
1321         //   This is used by the flow analysis code to store information about a single local variable
1322         //   or parameter.  Depending on the variable's type, we need to allocate one or more elements
1323         //   in the BitVector - if it's a fundamental or reference type, we just need to know whether
1324         //   it has been assigned or not, but for structs, we need this information for each of its fields.
1325         // </summary>
1326         public class VariableInfo {
1327                 readonly string Name;
1328                 readonly TypeInfo TypeInfo;
1329
1330                 // <summary>
1331                 //   The bit offset of this variable in the flow vector.
1332                 // </summary>
1333                 readonly int Offset;
1334
1335                 // <summary>
1336                 //   The number of bits this variable needs in the flow vector.
1337                 //   The first bit always specifies whether the variable as such has been assigned while
1338                 //   the remaining bits contain this information for each of a struct's fields.
1339                 // </summary>
1340                 public readonly int Length;
1341
1342                 // <summary>
1343                 //   If this is a parameter of local variable.
1344                 // </summary>
1345                 public readonly bool IsParameter;
1346
1347                 VariableInfo[] sub_info;
1348
1349                 VariableInfo (string name, TypeSpec type, int offset)
1350                 {
1351                         this.Name = name;
1352                         this.Offset = offset;
1353                         this.TypeInfo = TypeInfo.GetTypeInfo (type);
1354
1355                         Length = TypeInfo.TotalLength;
1356
1357                         Initialize ();
1358                 }
1359
1360                 VariableInfo (VariableInfo parent, TypeInfo type)
1361                 {
1362                         this.Name = parent.Name;
1363                         this.TypeInfo = type;
1364                         this.Offset = parent.Offset + type.Offset;
1365                         this.Length = type.TotalLength;
1366
1367                         this.IsParameter = parent.IsParameter;
1368
1369                         Initialize ();
1370                 }
1371
1372                 protected void Initialize ()
1373                 {
1374                         TypeInfo[] sub_fields = TypeInfo.SubStructInfo;
1375                         if (sub_fields != null) {
1376                                 sub_info = new VariableInfo [sub_fields.Length];
1377                                 for (int i = 0; i < sub_fields.Length; i++) {
1378                                         if (sub_fields [i] != null)
1379                                                 sub_info [i] = new VariableInfo (this, sub_fields [i]);
1380                                 }
1381                         } else
1382                                 sub_info = new VariableInfo [0];
1383                 }
1384
1385                 public VariableInfo (LocalVariable local_info, int offset)
1386                         : this (local_info.Name, local_info.Type, offset)
1387                 {
1388                         this.IsParameter = false;
1389                 }
1390
1391                 public VariableInfo (ParametersCompiled ip, int i, int offset)
1392                         : this (ip.FixedParameters [i].Name, ip.Types [i], offset)
1393                 {
1394                         this.IsParameter = true;
1395                 }
1396
1397                 public bool IsAssigned (ResolveContext ec)
1398                 {
1399                         return !ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (this);
1400                 }
1401
1402                 public bool IsAssigned (MyBitVector vector)
1403                 {
1404                         if (vector == null)
1405                                 return true;
1406
1407                         if (vector [Offset])
1408                                 return true;
1409
1410                         // Unless this is a struct
1411                         if (!TypeInfo.IsStruct)
1412                                 return false;
1413
1414                         //
1415                         // Following case cannot be handled fully by SetStructFieldAssigned
1416                         // because we may encounter following case
1417                         // 
1418                         // struct A { B b }
1419                         // struct B { int value; }
1420                         //
1421                         // setting a.b.value is propagated only to B's vector and not upwards to possible parents
1422                         //
1423                         //
1424                         // Each field must be assigned
1425                         //
1426                         for (int i = Offset + 1; i <= TypeInfo.Length + Offset; i++) {
1427                                 if (!vector[i])
1428                                         return false;
1429                         }
1430
1431                         // Ok, now check all fields which are structs.
1432                         for (int i = 0; i < sub_info.Length; i++) {
1433                                 VariableInfo sinfo = sub_info[i];
1434                                 if (sinfo == null)
1435                                         continue;
1436
1437                                 if (!sinfo.IsAssigned (vector))
1438                                         return false;
1439                         }
1440                         
1441                         vector [Offset] = true;
1442                         return true;
1443                 }
1444
1445                 public bool IsEverAssigned { get; set; }
1446
1447                 public bool IsStructFieldAssigned (ResolveContext ec, string name)
1448                 {
1449                         return !ec.DoFlowAnalysis || ec.CurrentBranching.IsStructFieldAssigned (this, name);
1450                 }
1451
1452                 public bool IsFullyInitialized (BlockContext bc, Location loc)
1453                 {
1454                         return TypeInfo.IsFullyInitialized (bc, this, loc);
1455                 }
1456
1457                 public bool IsStructFieldAssigned (MyBitVector vector, string field_name)
1458                 {
1459                         int field_idx = TypeInfo.GetFieldIndex (field_name);
1460
1461                         if (field_idx == 0)
1462                                 return true;
1463
1464                         return vector [Offset + field_idx];
1465                 }
1466
1467                 public void SetStructFieldAssigned (ResolveContext ec, string name)
1468                 {
1469                         if (ec.DoFlowAnalysis)
1470                                 ec.CurrentBranching.SetFieldAssigned (this, name);
1471                 }
1472
1473                 public void SetAssigned (ResolveContext ec)
1474                 {
1475                         if (ec.DoFlowAnalysis)
1476                                 ec.CurrentBranching.SetAssigned (this);
1477                 }
1478
1479                 public void SetAssigned (MyBitVector vector)
1480                 {
1481                         if (Length == 1)
1482                                 vector[Offset] = true;
1483                         else
1484                                 vector.SetRange (Offset, Length);
1485
1486                         IsEverAssigned = true;
1487                 }
1488
1489                 public void SetStructFieldAssigned (MyBitVector vector, string field_name)
1490                 {
1491                         if (vector[Offset])
1492                                 return;
1493
1494                         int field_idx = TypeInfo.GetFieldIndex (field_name);
1495
1496                         if (field_idx == 0)
1497                                 return;
1498
1499                         var complex_field = TypeInfo.GetStructField (field_name);
1500                         if (complex_field != null) {
1501                                 vector.SetRange (Offset + complex_field.Offset, complex_field.TotalLength);
1502                         } else {
1503                                 vector[Offset + field_idx] = true;
1504                         }
1505
1506                         IsEverAssigned = true;
1507
1508                         //
1509                         // Each field must be assigned
1510                         //
1511                         for (int i = Offset + 1; i < TypeInfo.TotalLength + Offset; i++) {
1512                                 if (!vector[i])
1513                                         return;
1514                         }
1515
1516                         //
1517                         // Set master struct flag to assigned when all tested struct
1518                         // fields have been assigned
1519                         //
1520                         vector[Offset] = true;
1521                 }
1522
1523                 public VariableInfo GetStructFieldInfo (string fieldName)
1524                 {
1525                         TypeInfo type = TypeInfo.GetStructField (fieldName);
1526
1527                         if (type == null)
1528                                 return null;
1529
1530                         return new VariableInfo (this, type);
1531                 }
1532
1533                 public override string ToString ()
1534                 {
1535                         return String.Format ("VariableInfo ({0}:{1}:{2}:{3}:{4})",
1536                                               Name, TypeInfo, Offset, Length, IsParameter);
1537                 }
1538         }
1539
1540         // <summary>
1541         //   This is a special bit vector which can inherit from another bit vector doing a
1542         //   copy-on-write strategy.  The inherited vector may have a smaller size than the
1543         //   current one.
1544         // </summary>
1545         public class MyBitVector {
1546                 public readonly int Count;
1547                 public static readonly MyBitVector Empty = new MyBitVector ();
1548
1549                 // Invariant: vector != null => vector.Count == Count
1550                 // Invariant: vector == null || shared == null
1551                 //            i.e., at most one of 'vector' and 'shared' can be non-null.  They can both be null -- that means all-ones
1552                 // The object in 'shared' cannot be modified, while 'vector' can be freely modified
1553                 System.Collections.BitArray vector, shared;
1554
1555                 MyBitVector ()
1556                 {
1557                         shared = new System.Collections.BitArray (0, false);
1558                 }
1559
1560                 public MyBitVector (MyBitVector InheritsFrom, int Count)
1561                 {
1562                         if (InheritsFrom != null)
1563                                 shared = InheritsFrom.MakeShared (Count);
1564
1565                         this.Count = Count;
1566                 }
1567
1568                 System.Collections.BitArray MakeShared (int new_count)
1569                 {
1570                         // Post-condition: vector == null
1571
1572                         // ensure we don't leak out dirty bits from the BitVector we inherited from
1573                         if (new_count > Count &&
1574                             ((shared != null && shared.Count > Count) ||
1575                              (shared == null && vector == null)))
1576                                 initialize_vector ();
1577
1578                         if (vector != null) {
1579                                 shared = vector;
1580                                 vector = null;
1581                         }
1582
1583                         return shared;
1584                 }
1585
1586                 // <summary>
1587                 //   Get/set bit `index' in the bit vector.
1588                 // </summary>
1589                 public bool this [int index] {
1590                         get {
1591                                 if (index >= Count)
1592                                         // FIXME: Disabled due to missing anonymous method flow analysis
1593                                         // throw new ArgumentOutOfRangeException ();
1594                                         return true; 
1595
1596                                 if (vector != null)
1597                                         return vector [index];
1598                                 if (shared == null)
1599                                         return true;
1600                                 if (index < shared.Count)
1601                                         return shared [index];
1602                                 return false;
1603                         }
1604
1605                         set {
1606                                 // Only copy the vector if we're actually modifying it.
1607                                 if (this [index] != value) {
1608                                         if (vector == null)
1609                                                 initialize_vector ();
1610                                         vector [index] = value;
1611                                 }
1612                         }
1613                 }
1614
1615                 // <summary>
1616                 //   Performs an `or' operation on the bit vector.  The `new_vector' may have a
1617                 //   different size than the current one.
1618                 // </summary>
1619                 private MyBitVector Or (MyBitVector new_vector)
1620                 {
1621                         if (Count == 0 || new_vector.Count == 0)
1622                                 return this;
1623
1624                         var o = new_vector.vector != null ? new_vector.vector : new_vector.shared;
1625
1626                         if (o == null) {
1627                                 int n = new_vector.Count;
1628                                 if (n < Count) {
1629                                         for (int i = 0; i < n; ++i)
1630                                                 this [i] = true;
1631                                 } else {
1632                                         SetAll (true);
1633                                 }
1634                                 return this;
1635                         }
1636
1637                         if (Count == o.Count) {
1638                                 if (vector == null) {
1639                                         if (shared == null)
1640                                                 return this;
1641                                         initialize_vector ();
1642                                 }
1643                                 vector.Or (o);
1644                                 return this;
1645                         }
1646
1647                         int min = o.Count;
1648                         if (Count < min)
1649                                 min = Count;
1650
1651                         for (int i = 0; i < min; i++) {
1652                                 if (o [i])
1653                                         this [i] = true;
1654                         }
1655
1656                         return this;
1657                 }
1658
1659                 // <summary>
1660                 //   Performs an `and' operation on the bit vector.  The `new_vector' may have
1661                 //   a different size than the current one.
1662                 // </summary>
1663                 private MyBitVector And (MyBitVector new_vector)
1664                 {
1665                         if (Count == 0)
1666                                 return this;
1667
1668                         var o = new_vector.vector != null ? new_vector.vector : new_vector.shared;
1669
1670                         if (o == null) {
1671                                 for (int i = new_vector.Count; i < Count; ++i)
1672                                         this [i] = false;
1673                                 return this;
1674                         }
1675
1676                         if (o.Count == 0) {
1677                                 SetAll (false);
1678                                 return this;
1679                         }
1680
1681                         if (Count == o.Count) {
1682                                 if (vector == null) {
1683                                         if (shared == null) {
1684                                                 shared = new_vector.MakeShared (Count);
1685                                                 return this;
1686                                         }
1687                                         initialize_vector ();
1688                                 }
1689                                 vector.And (o);
1690                                 return this;
1691                         }
1692
1693                         int min = o.Count;
1694                         if (Count < min)
1695                                 min = Count;
1696
1697                         for (int i = 0; i < min; i++) {
1698                                 if (! o [i])
1699                                         this [i] = false;
1700                         }
1701
1702                         for (int i = min; i < Count; i++)
1703                                 this [i] = false;
1704
1705                         return this;
1706                 }
1707
1708                 public static MyBitVector operator & (MyBitVector a, MyBitVector b)
1709                 {
1710                         if (a == b)
1711                                 return a;
1712                         if (a == null)
1713                                 return b.Clone ();
1714                         if (b == null)
1715                                 return a.Clone ();
1716                         if (a.Count > b.Count)
1717                                 return a.Clone ().And (b);
1718                         else
1719                                 return b.Clone ().And (a);                                      
1720                 }
1721
1722                 public static MyBitVector operator | (MyBitVector a, MyBitVector b)
1723                 {
1724                         if (a == b)
1725                                 return a;
1726                         if (a == null)
1727                                 return new MyBitVector (null, b.Count);
1728                         if (b == null)
1729                                 return new MyBitVector (null, a.Count);
1730                         if (a.Count > b.Count)
1731                                 return a.Clone ().Or (b);
1732                         else
1733                                 return b.Clone ().Or (a);
1734                 }
1735
1736                 public MyBitVector Clone ()
1737                 {
1738                         return Count == 0 ? Empty : new MyBitVector (this, Count);
1739                 }
1740
1741                 public void SetRange (int offset, int length)
1742                 {
1743                         if (offset > Count || offset + length > Count)
1744                                 throw new ArgumentOutOfRangeException ("flow-analysis");
1745
1746                         if (shared == null && vector == null)
1747                                 return;
1748
1749                         int i = 0;
1750                         if (shared != null) {
1751                                 if (offset + length <= shared.Count) {
1752                                         for (; i < length; ++i)
1753                                                 if (!shared [i+offset])
1754                                                     break;
1755                                         if (i == length)
1756                                                 return;
1757                                 }
1758                                 initialize_vector ();
1759                         }
1760                         for (; i < length; ++i)
1761                                 vector [i+offset] = true;
1762
1763                 }
1764
1765                 public void SetAll (bool value)
1766                 {
1767                         // Don't clobber Empty
1768                         if (Count == 0)
1769                                 return;
1770                         shared = value ? null : Empty.MakeShared (Count);
1771                         vector = null;
1772                 }
1773
1774                 void initialize_vector ()
1775                 {
1776                         // Post-condition: vector != null
1777                         if (shared == null) {
1778                                 vector = new System.Collections.BitArray (Count, true);
1779                                 return;
1780                         }
1781
1782                         vector = new System.Collections.BitArray (shared);
1783                         if (Count != vector.Count)
1784                                 vector.Length = Count;
1785                         shared = null;
1786                 }
1787
1788                 StringBuilder Dump (StringBuilder sb)
1789                 {
1790                         var dump = vector == null ? shared : vector;
1791                         if (dump == null)
1792                                 return sb.Append ("/");
1793                         if (dump == shared)
1794                                 sb.Append ("=");
1795                         for (int i = 0; i < dump.Count; i++)
1796                                 sb.Append (dump [i] ? "1" : "0");
1797                         return sb;
1798                 }
1799
1800                 public override string ToString ()
1801                 {
1802                         return Dump (new StringBuilder ("{")).Append ("}").ToString ();
1803                 }
1804         }
1805 }