Kill Block.Implicit
[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                 public virtual void StealFinallyClauses (ref ArrayList list)
458                 {
459                         Parent.StealFinallyClauses (ref list);
460                 }
461
462                 public bool IsAssigned (VariableInfo vi)
463                 {
464                         return CurrentUsageVector.IsAssigned (vi, false);
465                 }
466
467                 public bool IsFieldAssigned (VariableInfo vi, string field_name)
468                 {
469                         return CurrentUsageVector.IsAssigned (vi, false) || CurrentUsageVector.IsFieldAssigned (vi, field_name);
470                 }
471
472                 public void SetAssigned (VariableInfo vi)
473                 {
474                         CurrentUsageVector.SetAssigned (vi);
475                 }
476
477                 public void SetFieldAssigned (VariableInfo vi, string name)
478                 {
479                         CurrentUsageVector.SetFieldAssigned (vi, name);
480                 }
481
482                 public override string ToString ()
483                 {
484                         StringBuilder sb = new StringBuilder ();
485                         sb.Append (GetType ());
486                         sb.Append (" (");
487
488                         sb.Append (id);
489                         sb.Append (",");
490                         sb.Append (Type);
491                         if (Block != null) {
492                                 sb.Append (" - ");
493                                 sb.Append (Block.ID);
494                                 sb.Append (" - ");
495                                 sb.Append (Block.StartLocation);
496                         }
497                         sb.Append (" - ");
498                         // sb.Append (Siblings.Length);
499                         // sb.Append (" - ");
500                         sb.Append (CurrentUsageVector);
501                         sb.Append (")");
502                         return sb.ToString ();
503                 }
504
505                 public string Name {
506                         get { return String.Format ("{0} ({1}:{2}:{3})", GetType (), id, Type, Location); }
507                 }
508         }
509
510         public class FlowBranchingBlock : FlowBranching
511         {
512                 UsageVector sibling_list = null;
513
514                 public FlowBranchingBlock (FlowBranching parent, BranchingType type,
515                                            SiblingType stype, Block block, Location loc)
516                         : base (parent, type, stype, block, loc)
517                 { }
518
519                 public override UsageVector CurrentUsageVector {
520                         get { return sibling_list; }
521                 }
522
523                 protected override void AddSibling (UsageVector sibling)
524                 {
525                         sibling.Next = sibling_list;
526                         sibling_list = sibling;
527                 }
528
529                 public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
530                 {
531                         LabeledStatement stmt = Block == null ? null : Block.LookupLabel (goto_stmt.Target);
532                         if (stmt == null)
533                                 return Parent.AddGotoOrigin (vector, goto_stmt);
534
535                         // forward jump
536                         goto_stmt.SetResolvedTarget (stmt);
537                         stmt.AddUsageVector (vector);
538                         return false;
539                 }
540                 
541                 public static void Error_UnknownLabel (Location loc, string label)
542                 {
543                         Report.Error(159, loc, "The label `{0}:' could not be found within the scope of the goto statement",
544                                 label);
545                 }
546
547                 protected override UsageVector Merge ()
548                 {
549                         Report.Debug (2, "  MERGING SIBLINGS", Name);
550                         UsageVector vector = UsageVector.MergeSiblings (sibling_list, Location);
551                         Report.Debug (2, "  MERGING SIBLINGS DONE", Name, vector);
552                         return vector;
553                 }
554         }
555
556         public class FlowBranchingBreakable : FlowBranchingBlock
557         {
558                 UsageVector break_origins;
559
560                 public FlowBranchingBreakable (FlowBranching parent, BranchingType type, SiblingType stype, Block block, Location loc)
561                         : base (parent, type, stype, block, loc)
562                 { }
563
564                 public override bool AddBreakOrigin (UsageVector vector, Location loc)
565                 {
566                         vector = vector.Clone ();
567                         vector.Next = break_origins;
568                         break_origins = vector;
569                         return false;
570                 }
571
572                 protected override UsageVector Merge ()
573                 {
574                         UsageVector vector = base.Merge ();
575                         vector.MergeOrigins (break_origins);
576                         return vector;
577                 }
578         }
579
580         public class FlowBranchingContinuable : FlowBranchingBlock
581         {
582                 UsageVector continue_origins;
583
584                 public FlowBranchingContinuable (FlowBranching parent, BranchingType type, SiblingType stype, Block block, Location loc)
585                         : base (parent, type, stype, block, loc)
586                 { }
587
588                 public override bool AddContinueOrigin (UsageVector vector, Location loc)
589                 {
590                         vector = vector.Clone ();
591                         vector.Next = continue_origins;
592                         continue_origins = vector;
593                         return false;
594                 }
595
596                 protected override UsageVector Merge ()
597                 {
598                         UsageVector vector = base.Merge ();
599                         vector.MergeOrigins (continue_origins);
600                         return vector;
601                 }
602         }
603
604         public class FlowBranchingLabeled : FlowBranchingBlock
605         {
606                 LabeledStatement stmt;
607                 UsageVector actual;
608
609                 public FlowBranchingLabeled (FlowBranching parent, LabeledStatement stmt)
610                         : base (parent, BranchingType.Labeled, SiblingType.Conditional, null, stmt.loc)
611                 {
612                         this.stmt = stmt;
613                         CurrentUsageVector.MergeOrigins (stmt.JumpOrigins);
614                         actual = CurrentUsageVector.Clone ();
615
616                         // stand-in for backward jumps
617                         CurrentUsageVector.ResetBarrier ();
618                 }
619
620                 public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
621                 {
622                         if (goto_stmt.Target != stmt.Name)
623                                 return Parent.AddGotoOrigin (vector, goto_stmt);
624
625                         // backward jump
626                         goto_stmt.SetResolvedTarget (stmt);
627                         actual.MergeOrigins (vector.Clone ());
628
629                         return false;
630                 }
631
632                 protected override UsageVector Merge ()
633                 {
634                         UsageVector vector = base.Merge ();
635
636                         if (actual.IsUnreachable)
637                                 Report.Warning (162, 2, stmt.loc, "Unreachable code detected");
638
639                         actual.MergeChild (vector, false);
640                         return actual;
641                 }
642         }
643
644         public class FlowBranchingToplevel : FlowBranchingBlock
645         {
646                 UsageVector return_origins;
647
648                 public FlowBranchingToplevel (FlowBranching parent, ToplevelBlock stmt)
649                         : base (parent, BranchingType.Toplevel, SiblingType.Conditional, stmt, stmt.loc)
650                 {
651                 }
652
653                 // <summary>
654                 //   Check whether all `out' parameters have been assigned.
655                 // </summary>
656                 void CheckOutParameters (UsageVector vector, Location loc)
657                 {
658                         if (vector.IsUnreachable)
659                                 return;
660                         VariableInfo [] param_map = Block.Toplevel.ParameterMap;
661                         if (param_map == null)
662                                 return;
663                         for (int i = 0; i < param_map.Length; i++) {
664                                 VariableInfo var = param_map [i];
665
666                                 if (var == null)
667                                         continue;
668
669                                 if (vector.IsAssigned (var, false))
670                                         continue;
671
672                                 Report.Error (177, loc, "The out parameter `{0}' must be assigned to before control leaves the current method",
673                                         var.Name);
674                         }
675                 }
676
677                 public override bool InTryWithCatch ()
678                 {
679                         return false;
680                 }
681
682                 public override bool AddBreakOrigin (UsageVector vector, Location loc)
683                 {
684                         Report.Error (139, loc, "No enclosing loop out of which to break or continue");
685                         return false;
686                 }
687
688                 public override bool AddContinueOrigin (UsageVector vector, Location loc)
689                 {
690                         Report.Error (139, loc, "No enclosing loop out of which to break or continue");
691                         return false;
692                 }
693
694                 public override bool AddReturnOrigin (UsageVector vector, Location loc)
695                 {
696                         vector = vector.Clone ();
697                         vector.Location = loc;
698                         vector.Next = return_origins;
699                         return_origins = vector;
700                         return false;
701                 }
702
703                 public override void StealFinallyClauses (ref ArrayList list)
704                 {
705                         // nothing to do
706                 }
707
708                 public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
709                 {
710                         string name = goto_stmt.Target;
711                         LabeledStatement s = Block.LookupLabel (name);
712                         if (s != null)
713                                 throw new InternalErrorException ("Shouldn't get here");
714
715                         if (Parent == null) {
716                                 Error_UnknownLabel (goto_stmt.loc, name);
717                                 return false;
718                         }
719
720                         int errors = Report.Errors;
721                         Parent.AddGotoOrigin (vector, goto_stmt);
722                         if (errors == Report.Errors)
723                                 Report.Error (1632, goto_stmt.loc, "Control cannot leave the body of an anonymous method");
724                         return false;
725                 }
726
727                 protected override UsageVector Merge ()
728                 {
729                         for (UsageVector origin = return_origins; origin != null; origin = origin.Next)
730                                 CheckOutParameters (origin, origin.Location);
731
732                         UsageVector vector = base.Merge ();
733                         CheckOutParameters (vector, Block.loc);
734                         // Note: we _do_not_ merge in the return origins
735                         return vector;
736                 }
737
738                 public bool End ()
739                 {
740                         return Merge ().IsUnreachable;
741                 }
742         }
743
744         public class FlowBranchingException : FlowBranching
745         {
746                 ExceptionStatement stmt;
747                 UsageVector current_vector;
748                 UsageVector catch_vectors;
749                 UsageVector finally_vector;
750
751                 UsageVector break_origins;
752                 UsageVector continue_origins;
753                 UsageVector return_origins;
754                 GotoOrigin goto_origins;
755
756                 class GotoOrigin {
757                         public GotoOrigin Next;
758                         public Goto GotoStmt;
759                         public UsageVector Vector;
760
761                         public GotoOrigin (UsageVector vector, Goto goto_stmt, GotoOrigin next)
762                         {
763                                 Vector = vector;
764                                 GotoStmt = goto_stmt;
765                                 Next = next;
766                         }
767                 }
768
769                 bool emit_finally;
770
771                 public FlowBranchingException (FlowBranching parent,
772                                                ExceptionStatement stmt)
773                         : base (parent, BranchingType.Exception, SiblingType.Try,
774                                 null, stmt.loc)
775                 {
776                         this.stmt = stmt;
777                         this.emit_finally = true;
778                 }
779
780                 protected override void AddSibling (UsageVector sibling)
781                 {
782                         switch (sibling.Type) {
783                         case SiblingType.Try:
784                         case SiblingType.Catch:
785                                 sibling.Next = catch_vectors;
786                                 catch_vectors = sibling;
787                                 break;
788                         case SiblingType.Finally:
789                                 finally_vector = sibling;
790                                 break;
791                         default:
792                                 throw new InvalidOperationException ();
793                         }
794                         current_vector = sibling;
795                 }
796
797                 public override UsageVector CurrentUsageVector {
798                         get { return current_vector; }
799                 }
800
801                 public override bool InTryWithCatch ()
802                 {
803                         if (finally_vector == null) {
804                                 Try t = stmt as Try;
805                                 if (t != null && t.HasCatch)
806                                         return true;
807                         }
808
809                         return base.InTryWithCatch ();
810                 }
811
812                 public override bool AddBreakOrigin (UsageVector vector, Location loc)
813                 {
814                         vector = vector.Clone ();
815                         if (finally_vector != null) {
816                                 vector.MergeChild (finally_vector, false);
817                                 int errors = Report.Errors;
818                                 Parent.AddBreakOrigin (vector, loc);
819                                 if (errors == Report.Errors)
820                                         Report.Error (157, loc, "Control cannot leave the body of a finally clause");
821                         } else {
822                                 vector.Location = loc;
823                                 vector.Next = break_origins;
824                                 break_origins = vector;
825                         }
826                         return true;
827                 }
828
829                 public override bool AddContinueOrigin (UsageVector vector, Location loc)
830                 {
831                         vector = vector.Clone ();
832                         if (finally_vector != null) {
833                                 vector.MergeChild (finally_vector, false);
834                                 int errors = Report.Errors;
835                                 Parent.AddContinueOrigin (vector, loc);
836                                 if (errors == Report.Errors)
837                                         Report.Error (157, loc, "Control cannot leave the body of a finally clause");
838                         } else {
839                                 vector.Location = loc;
840                                 vector.Next = continue_origins;
841                                 continue_origins = vector;
842                         }
843                         return true;
844                 }
845
846                 public override bool AddReturnOrigin (UsageVector vector, Location loc)
847                 {
848                         vector = vector.Clone ();
849                         if (finally_vector != null) {
850                                 vector.MergeChild (finally_vector, false);
851                                 int errors = Report.Errors;
852                                 Parent.AddReturnOrigin (vector, loc);
853                                 if (errors == Report.Errors)
854                                         Report.Error (157, loc, "Control cannot leave the body of a finally clause");
855                         } else {
856                                 vector.Location = loc;
857                                 vector.Next = return_origins;
858                                 return_origins = vector;
859                         }
860                         return true;
861                 }
862
863                 public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
864                 {
865                         LabeledStatement s = current_vector.Block == null ? null : current_vector.Block.LookupLabel (goto_stmt.Target);
866                         if (s != null)
867                                 throw new InternalErrorException ("Shouldn't get here");
868
869                         vector = vector.Clone ();
870                         if (finally_vector != null) {
871                                 vector.MergeChild (finally_vector, false);
872                                 int errors = Report.Errors;
873                                 Parent.AddGotoOrigin (vector, goto_stmt);
874                                 if (errors == Report.Errors)
875                                         Report.Error (157, goto_stmt.loc, "Control cannot leave the body of a finally clause");
876                         } else {
877                                 goto_origins = new GotoOrigin (vector, goto_stmt, goto_origins);
878                         }
879                         return true;
880                 }
881
882                 public override void StealFinallyClauses (ref ArrayList list)
883                 {
884                         if (list == null)
885                                 list = new ArrayList ();
886                         list.Add (stmt);
887                         emit_finally = false;
888                         base.StealFinallyClauses (ref list);
889                 }
890
891                 public bool EmitFinally {
892                         get { return emit_finally; }
893                 }
894
895                 protected override UsageVector Merge ()
896                 {
897                         Report.Debug (2, "  MERGING TRY/CATCH", Name);
898                         UsageVector vector = UsageVector.MergeSiblings (catch_vectors, Location);
899                         Report.Debug (2, "  MERGING TRY/CATCH DONE", vector);
900
901                         if (finally_vector != null)
902                                 vector.MergeChild (finally_vector, false);
903
904                         for (UsageVector origin = break_origins; origin != null; origin = origin.Next) {
905                                 if (finally_vector != null)
906                                         origin.MergeChild (finally_vector, false);
907                                 Parent.AddBreakOrigin (origin, origin.Location);
908                         }
909
910                         for (UsageVector origin = continue_origins; origin != null; origin = origin.Next) {
911                                 if (finally_vector != null)
912                                         origin.MergeChild (finally_vector, false);
913                                 Parent.AddContinueOrigin (origin, origin.Location);
914                         }
915
916                         for (UsageVector origin = return_origins; origin != null; origin = origin.Next) {
917                                 if (finally_vector != null)
918                                         origin.MergeChild (finally_vector, false);
919                                 Parent.AddReturnOrigin (origin, origin.Location);
920                         }
921
922                         for (GotoOrigin origin = goto_origins; origin != null; origin = origin.Next) {
923                                 if (finally_vector != null)
924                                         origin.Vector.MergeChild (finally_vector, false);
925                                 Parent.AddGotoOrigin (origin.Vector, origin.GotoStmt);
926                         }
927
928                         return vector;
929                 }
930         }
931
932         // <summary>
933         //   This is used by the flow analysis code to keep track of the type of local variables
934         //   and variables.
935         //
936         //   The flow code uses a BitVector to keep track of whether a variable has been assigned
937         //   or not.  This is easy for fundamental types (int, char etc.) or reference types since
938         //   you can only assign the whole variable as such.
939         //
940         //   For structs, we also need to keep track of all its fields.  To do this, we allocate one
941         //   bit for the struct itself (it's used if you assign/access the whole struct) followed by
942         //   one bit for each of its fields.
943         //
944         //   This class computes this `layout' for each type.
945         // </summary>
946         public class TypeInfo
947         {
948                 public readonly Type Type;
949
950                 // <summary>
951                 //   Total number of bits a variable of this type consumes in the flow vector.
952                 // </summary>
953                 public readonly int TotalLength;
954
955                 // <summary>
956                 //   Number of bits the simple fields of a variable of this type consume
957                 //   in the flow vector.
958                 // </summary>
959                 public readonly int Length;
960
961                 // <summary>
962                 //   This is only used by sub-structs.
963                 // </summary>
964                 public readonly int Offset;
965
966                 // <summary>
967                 //   If this is a struct.
968                 // </summary>
969                 public readonly bool IsStruct;       
970
971                 // <summary>
972                 //   If this is a struct, all fields which are structs theirselves.
973                 // </summary>
974                 public TypeInfo[] SubStructInfo;
975
976                 protected readonly StructInfo struct_info;
977                 private static Hashtable type_hash = new Hashtable ();
978
979                 public static TypeInfo GetTypeInfo (Type type)
980                 {
981                         TypeInfo info = (TypeInfo) type_hash [type];
982                         if (info != null)
983                                 return info;
984
985                         info = new TypeInfo (type);
986                         type_hash.Add (type, info);
987                         return info;
988                 }
989
990                 public static TypeInfo GetTypeInfo (TypeContainer tc)
991                 {
992                         TypeInfo info = (TypeInfo) type_hash [tc.TypeBuilder];
993                         if (info != null)
994                                 return info;
995
996                         info = new TypeInfo (tc);
997                         type_hash.Add (tc.TypeBuilder, info);
998                         return info;
999                 }
1000
1001                 private TypeInfo (Type type)
1002                 {
1003                         this.Type = type;
1004
1005                         struct_info = StructInfo.GetStructInfo (type);
1006                         if (struct_info != null) {
1007                                 Length = struct_info.Length;
1008                                 TotalLength = struct_info.TotalLength;
1009                                 SubStructInfo = struct_info.StructFields;
1010                                 IsStruct = true;
1011                         } else {
1012                                 Length = 0;
1013                                 TotalLength = 1;
1014                                 IsStruct = false;
1015                         }
1016                 }
1017
1018                 private TypeInfo (TypeContainer tc)
1019                 {
1020                         this.Type = tc.TypeBuilder;
1021
1022                         struct_info = StructInfo.GetStructInfo (tc);
1023                         if (struct_info != null) {
1024                                 Length = struct_info.Length;
1025                                 TotalLength = struct_info.TotalLength;
1026                                 SubStructInfo = struct_info.StructFields;
1027                                 IsStruct = true;
1028                         } else {
1029                                 Length = 0;
1030                                 TotalLength = 1;
1031                                 IsStruct = false;
1032                         }
1033                 }
1034
1035                 protected TypeInfo (StructInfo struct_info, int offset)
1036                 {
1037                         this.struct_info = struct_info;
1038                         this.Offset = offset;
1039                         this.Length = struct_info.Length;
1040                         this.TotalLength = struct_info.TotalLength;
1041                         this.SubStructInfo = struct_info.StructFields;
1042                         this.Type = struct_info.Type;
1043                         this.IsStruct = true;
1044                 }
1045
1046                 public int GetFieldIndex (string name)
1047                 {
1048                         if (struct_info == null)
1049                                 return 0;
1050
1051                         return struct_info [name];
1052                 }
1053
1054                 public TypeInfo GetSubStruct (string name)
1055                 {
1056                         if (struct_info == null)
1057                                 return null;
1058
1059                         return struct_info.GetStructField (name);
1060                 }
1061
1062                 // <summary>
1063                 //   A struct's constructor must always assign all fields.
1064                 //   This method checks whether it actually does so.
1065                 // </summary>
1066                 public bool IsFullyInitialized (FlowBranching branching, VariableInfo vi, Location loc)
1067                 {
1068                         if (struct_info == null)
1069                                 return true;
1070
1071                         bool ok = true;
1072                         for (int i = 0; i < struct_info.Count; i++) {
1073                                 FieldInfo field = struct_info.Fields [i];
1074
1075                                 if (!branching.IsFieldAssigned (vi, field.Name)) {
1076                                         Report.Error (171, loc,
1077                                                 "Field `{0}' must be fully assigned before control leaves the constructor",
1078                                                 TypeManager.GetFullNameSignature (field));
1079                                         ok = false;
1080                                 }
1081                         }
1082
1083                         return ok;
1084                 }
1085
1086                 public override string ToString ()
1087                 {
1088                         return String.Format ("TypeInfo ({0}:{1}:{2}:{3})",
1089                                               Type, Offset, Length, TotalLength);
1090                 }
1091
1092                 protected class StructInfo {
1093                         public readonly Type Type;
1094                         public readonly FieldInfo[] Fields;
1095                         public readonly TypeInfo[] StructFields;
1096                         public readonly int Count;
1097                         public readonly int CountPublic;
1098                         public readonly int CountNonPublic;
1099                         public readonly int Length;
1100                         public readonly int TotalLength;
1101                         public readonly bool HasStructFields;
1102
1103                         private static Hashtable field_type_hash = new Hashtable ();
1104                         private Hashtable struct_field_hash;
1105                         private Hashtable field_hash;
1106
1107                         protected bool InTransit = false;
1108
1109                         // Private constructor.  To save memory usage, we only need to create one instance
1110                         // of this class per struct type.
1111                         private StructInfo (Type type)
1112                         {
1113                                 this.Type = type;
1114
1115                                 field_type_hash.Add (type, this);
1116
1117                                 if (type is TypeBuilder) {
1118                                         TypeContainer tc = TypeManager.LookupTypeContainer (type);
1119
1120                                         ArrayList fields = null;
1121                                         if (tc != null)
1122                                                 fields = tc.Fields;
1123
1124                                         ArrayList public_fields = new ArrayList ();
1125                                         ArrayList non_public_fields = new ArrayList ();
1126
1127                                         if (fields != null) {
1128                                                 foreach (FieldBase field in fields) {
1129                                                         if ((field.ModFlags & Modifiers.STATIC) != 0)
1130                                                                 continue;
1131                                                         if ((field.ModFlags & Modifiers.PUBLIC) != 0)
1132                                                                 public_fields.Add (field.FieldBuilder);
1133                                                         else
1134                                                                 non_public_fields.Add (field.FieldBuilder);
1135                                                 }
1136                                         }
1137
1138                                         CountPublic = public_fields.Count;
1139                                         CountNonPublic = non_public_fields.Count;
1140                                         Count = CountPublic + CountNonPublic;
1141
1142                                         Fields = new FieldInfo [Count];
1143                                         public_fields.CopyTo (Fields, 0);
1144                                         non_public_fields.CopyTo (Fields, CountPublic);
1145 #if GMCS_SOURCE
1146                                 } else if (type is GenericTypeParameterBuilder) {
1147                                         CountPublic = CountNonPublic = Count = 0;
1148
1149                                         Fields = new FieldInfo [0];
1150 #endif
1151                                 } else {
1152                                         FieldInfo[] public_fields = type.GetFields (
1153                                                 BindingFlags.Instance|BindingFlags.Public);
1154                                         FieldInfo[] non_public_fields = type.GetFields (
1155                                                 BindingFlags.Instance|BindingFlags.NonPublic);
1156
1157                                         CountPublic = public_fields.Length;
1158                                         CountNonPublic = non_public_fields.Length;
1159                                         Count = CountPublic + CountNonPublic;
1160
1161                                         Fields = new FieldInfo [Count];
1162                                         public_fields.CopyTo (Fields, 0);
1163                                         non_public_fields.CopyTo (Fields, CountPublic);
1164                                 }
1165
1166                                 struct_field_hash = new Hashtable ();
1167                                 field_hash = new Hashtable ();
1168
1169                                 Length = 0;
1170                                 StructFields = new TypeInfo [Count];
1171                                 StructInfo[] sinfo = new StructInfo [Count];
1172
1173                                 InTransit = true;
1174
1175                                 for (int i = 0; i < Count; i++) {
1176                                         FieldInfo field = (FieldInfo) Fields [i];
1177
1178                                         sinfo [i] = GetStructInfo (field.FieldType);
1179                                         if (sinfo [i] == null)
1180                                                 field_hash.Add (field.Name, ++Length);
1181                                         else if (sinfo [i].InTransit) {
1182                                                 Report.Error (523, String.Format (
1183                                                                       "Struct member `{0}.{1}' of type `{2}' causes " +
1184                                                                       "a cycle in the structure layout",
1185                                                                       type, field.Name, sinfo [i].Type));
1186                                                 sinfo [i] = null;
1187                                                 return;
1188                                         }
1189                                 }
1190
1191                                 InTransit = false;
1192
1193                                 TotalLength = Length + 1;
1194                                 for (int i = 0; i < Count; i++) {
1195                                         FieldInfo field = (FieldInfo) Fields [i];
1196
1197                                         if (sinfo [i] == null)
1198                                                 continue;
1199
1200                                         field_hash.Add (field.Name, TotalLength);
1201
1202                                         HasStructFields = true;
1203                                         StructFields [i] = new TypeInfo (sinfo [i], TotalLength);
1204                                         struct_field_hash.Add (field.Name, StructFields [i]);
1205                                         TotalLength += sinfo [i].TotalLength;
1206                                 }
1207                         }
1208
1209                         public int this [string name] {
1210                                 get {
1211                                         if (field_hash.Contains (name))
1212                                                 return (int) field_hash [name];
1213                                         else
1214                                                 return 0;
1215                                 }
1216                         }
1217
1218                         public TypeInfo GetStructField (string name)
1219                         {
1220                                 return (TypeInfo) struct_field_hash [name];
1221                         }
1222
1223                         public static StructInfo GetStructInfo (Type type)
1224                         {
1225                                 if (!TypeManager.IsValueType (type) || TypeManager.IsEnumType (type) ||
1226                                     TypeManager.IsBuiltinType (type))
1227                                         return null;
1228
1229                                 StructInfo info = (StructInfo) field_type_hash [type];
1230                                 if (info != null)
1231                                         return info;
1232
1233                                 return new StructInfo (type);
1234                         }
1235
1236                         public static StructInfo GetStructInfo (TypeContainer tc)
1237                         {
1238                                 StructInfo info = (StructInfo) field_type_hash [tc.TypeBuilder];
1239                                 if (info != null)
1240                                         return info;
1241
1242                                 return new StructInfo (tc.TypeBuilder);
1243                         }
1244                 }
1245         }
1246
1247         // <summary>
1248         //   This is used by the flow analysis code to store information about a single local variable
1249         //   or parameter.  Depending on the variable's type, we need to allocate one or more elements
1250         //   in the BitVector - if it's a fundamental or reference type, we just need to know whether
1251         //   it has been assigned or not, but for structs, we need this information for each of its fields.
1252         // </summary>
1253         public class VariableInfo {
1254                 public readonly string Name;
1255                 public readonly TypeInfo TypeInfo;
1256
1257                 // <summary>
1258                 //   The bit offset of this variable in the flow vector.
1259                 // </summary>
1260                 public readonly int Offset;
1261
1262                 // <summary>
1263                 //   The number of bits this variable needs in the flow vector.
1264                 //   The first bit always specifies whether the variable as such has been assigned while
1265                 //   the remaining bits contain this information for each of a struct's fields.
1266                 // </summary>
1267                 public readonly int Length;
1268
1269                 // <summary>
1270                 //   If this is a parameter of local variable.
1271                 // </summary>
1272                 public readonly bool IsParameter;
1273
1274                 public readonly LocalInfo LocalInfo;
1275
1276                 readonly VariableInfo Parent;
1277                 VariableInfo[] sub_info;
1278
1279                 protected VariableInfo (string name, Type type, int offset)
1280                 {
1281                         this.Name = name;
1282                         this.Offset = offset;
1283                         this.TypeInfo = TypeInfo.GetTypeInfo (type);
1284
1285                         Length = TypeInfo.TotalLength;
1286
1287                         Initialize ();
1288                 }
1289
1290                 protected VariableInfo (VariableInfo parent, TypeInfo type)
1291                 {
1292                         this.Name = parent.Name;
1293                         this.TypeInfo = type;
1294                         this.Offset = parent.Offset + type.Offset;
1295                         this.Parent = parent;
1296                         this.Length = type.TotalLength;
1297
1298                         this.IsParameter = parent.IsParameter;
1299                         this.LocalInfo = parent.LocalInfo;
1300
1301                         Initialize ();
1302                 }
1303
1304                 protected void Initialize ()
1305                 {
1306                         TypeInfo[] sub_fields = TypeInfo.SubStructInfo;
1307                         if (sub_fields != null) {
1308                                 sub_info = new VariableInfo [sub_fields.Length];
1309                                 for (int i = 0; i < sub_fields.Length; i++) {
1310                                         if (sub_fields [i] != null)
1311                                                 sub_info [i] = new VariableInfo (this, sub_fields [i]);
1312                                 }
1313                         } else
1314                                 sub_info = new VariableInfo [0];
1315                 }
1316
1317                 public VariableInfo (LocalInfo local_info, int offset)
1318                         : this (local_info.Name, local_info.VariableType, offset)
1319                 {
1320                         this.LocalInfo = local_info;
1321                         this.IsParameter = false;
1322                 }
1323
1324                 public VariableInfo (Parameters ip, int i, int offset)
1325                         : this (ip.ParameterName (i), TypeManager.GetElementType (ip.ParameterType (i)), offset)
1326                 {
1327                         this.IsParameter = true;
1328                 }
1329
1330                 public bool IsAssigned (EmitContext ec)
1331                 {
1332                         return !ec.DoFlowAnalysis ||
1333                                 ec.OmitStructFlowAnalysis && TypeInfo.IsStruct ||
1334                                 ec.CurrentBranching.IsAssigned (this);
1335                 }
1336
1337                 public bool IsAssigned (EmitContext ec, Location loc)
1338                 {
1339                         if (IsAssigned (ec))
1340                                 return true;
1341
1342                         Report.Error (165, loc,
1343                                       "Use of unassigned local variable `" + Name + "'");
1344                         ec.CurrentBranching.SetAssigned (this);
1345                         return false;
1346                 }
1347
1348                 public bool IsAssigned (MyBitVector vector)
1349                 {
1350                         if (vector == null)
1351                                 return true;
1352
1353                         if (vector [Offset])
1354                                 return true;
1355
1356                         // FIXME: Fix SetFieldAssigned to set the whole range like SetAssigned below. Then, get rid of this stanza
1357                         for (VariableInfo parent = Parent; parent != null; parent = parent.Parent) {
1358                                 if (vector [parent.Offset]) {
1359                                         // 'parent' is assigned, but someone forgot to note that all its components are assigned too
1360                                         parent.SetAssigned (vector);
1361                                         return true;
1362                                 }
1363                         }
1364
1365                         // Return unless this is a struct.
1366                         if (!TypeInfo.IsStruct)
1367                                 return false;
1368
1369                         // Ok, so each field must be assigned.
1370                         for (int i = 0; i < TypeInfo.Length; i++) {
1371                                 if (!vector [Offset + i + 1])
1372                                         return false;
1373                         }
1374
1375                         // Ok, now check all fields which are structs.
1376                         for (int i = 0; i < sub_info.Length; i++) {
1377                                 VariableInfo sinfo = sub_info [i];
1378                                 if (sinfo == null)
1379                                         continue;
1380
1381                                 if (!sinfo.IsAssigned (vector))
1382                                         return false;
1383                         }
1384
1385                         vector [Offset] = true;
1386                         return true;
1387                 }
1388
1389                 public void SetAssigned (EmitContext ec)
1390                 {
1391                         if (ec.DoFlowAnalysis)
1392                                 ec.CurrentBranching.SetAssigned (this);
1393                 }
1394
1395                 public void SetAssigned (MyBitVector vector)
1396                 {
1397                         if (Length == 1)
1398                                 vector [Offset] = true;
1399                         else
1400                                 vector.SetRange (Offset, Length);
1401                 }
1402
1403                 public bool IsFieldAssigned (EmitContext ec, string name, Location loc)
1404                 {
1405                         if (!ec.DoFlowAnalysis ||
1406                                 ec.OmitStructFlowAnalysis && TypeInfo.IsStruct ||
1407                                 ec.CurrentBranching.IsFieldAssigned (this, name))
1408                                 return true;
1409
1410                         Report.Error (170, loc,
1411                                       "Use of possibly unassigned field `" + name + "'");
1412                         ec.CurrentBranching.SetFieldAssigned (this, name);
1413                         return false;
1414                 }
1415
1416                 public bool IsFieldAssigned (MyBitVector vector, string field_name)
1417                 {
1418                         int field_idx = TypeInfo.GetFieldIndex (field_name);
1419
1420                         if (field_idx == 0)
1421                                 return true;
1422
1423                         return vector [Offset + field_idx];
1424                 }
1425
1426                 public void SetFieldAssigned (EmitContext ec, string name)
1427                 {
1428                         if (ec.DoFlowAnalysis)
1429                                 ec.CurrentBranching.SetFieldAssigned (this, name);
1430                 }
1431
1432                 public void SetFieldAssigned (MyBitVector vector, string field_name)
1433                 {
1434                         int field_idx = TypeInfo.GetFieldIndex (field_name);
1435
1436                         if (field_idx == 0)
1437                                 return;
1438
1439                         vector [Offset + field_idx] = true;
1440                 }
1441
1442                 public VariableInfo GetSubStruct (string name)
1443                 {
1444                         TypeInfo type = TypeInfo.GetSubStruct (name);
1445
1446                         if (type == null)
1447                                 return null;
1448
1449                         return new VariableInfo (this, type);
1450                 }
1451
1452                 public override string ToString ()
1453                 {
1454                         return String.Format ("VariableInfo ({0}:{1}:{2}:{3}:{4})",
1455                                               Name, TypeInfo, Offset, Length, IsParameter);
1456                 }
1457         }
1458
1459         // <summary>
1460         //   This is a special bit vector which can inherit from another bit vector doing a
1461         //   copy-on-write strategy.  The inherited vector may have a smaller size than the
1462         //   current one.
1463         // </summary>
1464         public class MyBitVector {
1465                 public readonly int Count;
1466                 public static readonly MyBitVector Empty = new MyBitVector ();
1467
1468                 // Invariant: vector != null => vector.Count == Count
1469                 // Invariant: vector == null || shared == null
1470                 //            i.e., at most one of 'vector' and 'shared' can be non-null.  They can both be null -- that means all-ones
1471                 // The object in 'shared' cannot be modified, while 'vector' can be freely modified
1472                 BitArray vector, shared;
1473
1474                 MyBitVector ()
1475                 {
1476                         shared = new BitArray (0, false);
1477                 }
1478
1479                 public MyBitVector (MyBitVector InheritsFrom, int Count)
1480                 {
1481                         if (InheritsFrom != null)
1482                                 shared = InheritsFrom.Shared;
1483
1484                         this.Count = Count;
1485                 }
1486
1487                 // Use this accessor to get a shareable copy of the underlying BitArray representation
1488                 BitArray Shared {
1489                         get {
1490                                 // Post-condition: vector == null
1491                                 if (shared == null) {
1492                                         shared = vector;
1493                                         vector = null;
1494                                 }
1495                                 return shared;
1496                         }
1497                 }
1498
1499                 // <summary>
1500                 //   Get/set bit `index' in the bit vector.
1501                 // </summary>
1502                 public bool this [int index] {
1503                         get {
1504                                 if (index >= Count)
1505                                         throw new ArgumentOutOfRangeException ();
1506
1507                                 if (vector != null)
1508                                         return vector [index];
1509                                 if (shared == null)
1510                                         return true;
1511                                 if (index < shared.Count)
1512                                         return shared [index];
1513                                 return false;
1514                         }
1515
1516                         set {
1517                                 // Only copy the vector if we're actually modifying it.
1518                                 if (this [index] != value) {
1519                                         if (vector == null)
1520                                                 initialize_vector ();
1521                                         vector [index] = value;
1522                                 }
1523                         }
1524                 }
1525
1526                 // <summary>
1527                 //   Performs an `or' operation on the bit vector.  The `new_vector' may have a
1528                 //   different size than the current one.
1529                 // </summary>
1530                 private MyBitVector Or (MyBitVector new_vector)
1531                 {
1532                         if (Count == 0 || new_vector.Count == 0)
1533                                 return this;
1534
1535                         BitArray o = new_vector.vector != null ? new_vector.vector : new_vector.shared;
1536
1537                         if (o == null) {
1538                                 int n = new_vector.Count;
1539                                 if (n < Count) {
1540                                         for (int i = 0; i < n; ++i)
1541                                                 this [i] = true;
1542                                 } else {
1543                                         SetAll (true);
1544                                 }
1545                                 return this;
1546                         }
1547
1548                         if (Count == o.Count) {
1549                                 if (vector == null) {
1550                                         if (shared == null)
1551                                                 return this;
1552                                         initialize_vector ();
1553                                 }
1554                                 vector.Or (o);
1555                                 return this;
1556                         }
1557
1558                         int min = o.Count;
1559                         if (Count < min)
1560                                 min = Count;
1561
1562                         for (int i = 0; i < min; i++) {
1563                                 if (o [i])
1564                                         this [i] = true;
1565                         }
1566
1567                         return this;
1568                 }
1569
1570                 // <summary>
1571                 //   Performs an `and' operation on the bit vector.  The `new_vector' may have
1572                 //   a different size than the current one.
1573                 // </summary>
1574                 private MyBitVector And (MyBitVector new_vector)
1575                 {
1576                         if (Count == 0)
1577                                 return this;
1578
1579                         BitArray o = new_vector.vector != null ? new_vector.vector : new_vector.shared;
1580
1581                         if (o == null) {
1582                                 for (int i = new_vector.Count; i < Count; ++i)
1583                                         this [i] = false;
1584                                 return this;
1585                         }
1586
1587                         if (o.Count == 0) {
1588                                 SetAll (false);
1589                                 return this;
1590                         }
1591
1592                         if (Count == o.Count) {
1593                                 if (vector == null) {
1594                                         if (shared == null) {
1595                                                 shared = new_vector.Shared;
1596                                                 return this;
1597                                         }
1598                                         initialize_vector ();
1599                                 }
1600                                 vector.And (o);
1601                                 return this;
1602                         }
1603
1604                         int min = o.Count;
1605                         if (Count < min)
1606                                 min = Count;
1607
1608                         for (int i = 0; i < min; i++) {
1609                                 if (! o [i])
1610                                         this [i] = false;
1611                         }
1612
1613                         for (int i = min; i < Count; i++)
1614                                 this [i] = false;
1615
1616                         return this;
1617                 }
1618
1619                 public static MyBitVector operator & (MyBitVector a, MyBitVector b)
1620                 {
1621                         if (a == b)
1622                                 return a;
1623                         if (a == null)
1624                                 return b.Clone ();
1625                         if (b == null)
1626                                 return a.Clone ();
1627                         if (a.Count > b.Count)
1628                                 return a.Clone ().And (b);
1629                         else
1630                                 return b.Clone ().And (a);                                      
1631                 }
1632
1633                 public static MyBitVector operator | (MyBitVector a, MyBitVector b)
1634                 {
1635                         if (a == b)
1636                                 return a;
1637                         if (a == null)
1638                                 return new MyBitVector (null, b.Count);
1639                         if (b == null)
1640                                 return new MyBitVector (null, a.Count);
1641                         if (a.Count > b.Count)
1642                                 return a.Clone ().Or (b);
1643                         else
1644                                 return b.Clone ().Or (a);
1645                 }
1646
1647                 public MyBitVector Clone ()
1648                 {
1649                         return Count == 0 ? Empty : new MyBitVector (this, Count);
1650                 }
1651
1652                 public void SetRange (int offset, int length)
1653                 {
1654                         if (offset > Count || offset + length > Count)
1655                                 throw new ArgumentOutOfRangeException ();
1656
1657                         if (shared == null && vector == null)
1658                                 return;
1659
1660                         int i = 0;
1661                         if (shared != null) {
1662                                 if (offset + length <= shared.Count) {
1663                                         for (; i < length; ++i)
1664                                                 if (!shared [i+offset])
1665                                                     break;
1666                                         if (i == length)
1667                                                 return;
1668                                 }
1669                                 initialize_vector ();
1670                         }
1671                         for (; i < length; ++i)
1672                                 vector [i+offset] = true;
1673
1674                 }
1675
1676                 public void SetAll (bool value)
1677                 {
1678                         // Don't clobber Empty
1679                         if (Count == 0)
1680                                 return;
1681                         shared = value ? null : Empty.Shared;
1682                         vector = null;
1683                 }
1684
1685                 void initialize_vector ()
1686                 {
1687                         // Post-condition: vector != null
1688                         if (shared == null) {
1689                                 vector = new BitArray (Count, true);
1690                                 return;
1691                         }
1692
1693                         vector = new BitArray (shared);
1694                         if (Count != vector.Count)
1695                                 vector.Length = Count;
1696                         shared = null;
1697                 }
1698
1699                 StringBuilder Dump (StringBuilder sb)
1700                 {
1701                         BitArray dump = vector == null ? shared : vector;
1702                         if (dump == null)
1703                                 return sb.Append ("/");
1704                         if (dump == shared)
1705                                 sb.Append ("=");
1706                         for (int i = 0; i < dump.Count; i++)
1707                                 sb.Append (dump [i] ? "1" : "0");
1708                         return sb;
1709                 }
1710
1711                 public override string ToString ()
1712                 {
1713                         return Dump (new StringBuilder ("{")).Append ("}").ToString ();
1714                 }
1715         }
1716 }