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