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