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