namespace Mono.CSharp
{
- // <summary>
- // A new instance of this class is created every time a new block is resolved
- // and if there's branching in the block's control flow.
- // </summary>
- public abstract class FlowBranching
- {
- // <summary>
- // The type of a FlowBranching.
- // </summary>
- public enum BranchingType : byte {
- // Normal (conditional or toplevel) block.
- Block,
-
- // Conditional.
- Conditional,
-
- // A loop block.
- Loop,
-
- // The statement embedded inside a loop
- Embedded,
-
- // part of a block headed by a jump target
- Labeled,
-
- // TryCatch block.
- TryCatch,
-
- // TryFinally, Using, Lock, CollectionForeach
- Exception,
-
- // Switch block.
- Switch,
-
- // The toplevel block of a function
- Toplevel,
-
- // An iterator block
- Iterator
- }
-
- // <summary>
- // The type of one sibling of a branching.
- // </summary>
- public enum SiblingType : byte {
- Block,
- Conditional,
- SwitchSection,
- Try,
- Catch,
- Finally
- }
-
- public static FlowBranching CreateBranching (FlowBranching parent, BranchingType type, Block block, Location loc)
- {
- switch (type) {
- case BranchingType.Exception:
- case BranchingType.Labeled:
- case BranchingType.Toplevel:
- case BranchingType.TryCatch:
- throw new InvalidOperationException ();
-
- case BranchingType.Switch:
- return new FlowBranchingBreakable (parent, type, SiblingType.SwitchSection, block, loc);
-
- case BranchingType.Block:
- return new FlowBranchingBlock (parent, type, SiblingType.Block, block, loc);
-
- case BranchingType.Loop:
- return new FlowBranchingBreakable (parent, type, SiblingType.Conditional, block, loc);
-
- case BranchingType.Embedded:
- return new FlowBranchingContinuable (parent, type, SiblingType.Conditional, block, loc);
-
- default:
- return new FlowBranchingBlock (parent, type, SiblingType.Conditional, block, loc);
- }
- }
-
- // <summary>
- // The type of this flow branching.
- // </summary>
- public readonly BranchingType Type;
-
- // <summary>
- // The block this branching is contained in. This may be null if it's not
- // a top-level block and it doesn't declare any local variables.
- // </summary>
- public readonly Block Block;
-
- // <summary>
- // The parent of this branching or null if this is the top-block.
- // </summary>
- public readonly FlowBranching Parent;
-
- // <summary>
- // Start-Location of this flow branching.
- // </summary>
- public readonly Location Location;
-
- static int next_id;
- int id;
-
- // <summary>
- // The vector contains a BitArray with information about which local variables
- // and parameters are already initialized at the current code position.
- // </summary>
- public class UsageVector {
- // <summary>
- // The type of this branching.
- // </summary>
- public readonly SiblingType Type;
-
- // <summary>
- // Start location of this branching.
- // </summary>
- public Location Location;
-
- // <summary>
- // This is only valid for SwitchSection, Try, Catch and Finally.
- // </summary>
- public readonly Block Block;
-
- // <summary>
- // The number of locals in this block.
- // </summary>
- public readonly int CountLocals;
-
- // <summary>
- // If not null, then we inherit our state from this vector and do a
- // copy-on-write. If null, then we're the first sibling in a top-level
- // block and inherit from the empty vector.
- // </summary>
- public readonly UsageVector InheritsFrom;
-
- // <summary>
- // This is used to construct a list of UsageVector's.
- // </summary>
- public UsageVector Next;
-
- //
- // Private.
- //
- MyBitVector locals;
- bool is_unreachable;
-
- static int next_id;
- int id;
-
- //
- // Normally, you should not use any of these constructors.
- //
- public UsageVector (SiblingType type, UsageVector parent, Block block, Location loc, int num_locals)
- {
- this.Type = type;
- this.Block = block;
- this.Location = loc;
- this.InheritsFrom = parent;
- this.CountLocals = num_locals;
-
- locals = num_locals == 0
- ? MyBitVector.Empty
- : new MyBitVector (parent == null ? MyBitVector.Empty : parent.locals, num_locals);
-
- if (parent != null)
- is_unreachable = parent.is_unreachable;
-
- id = ++next_id;
-
- }
-
- public UsageVector (SiblingType type, UsageVector parent, Block block, Location loc)
- : this (type, parent, block, loc, parent.CountLocals)
- { }
-
- private UsageVector (MyBitVector locals, bool is_unreachable, Block block, Location loc)
- {
- this.Type = SiblingType.Block;
- this.Location = loc;
- this.Block = block;
-
- this.is_unreachable = is_unreachable;
-
- this.locals = locals;
-
- id = ++next_id;
-
- }
-
- // <summary>
- // This does a deep copy of the usage vector.
- // </summary>
- public UsageVector Clone ()
- {
- UsageVector retval = new UsageVector (Type, null, Block, Location, CountLocals);
-
- retval.locals = locals.Clone ();
- retval.is_unreachable = is_unreachable;
-
- return retval;
- }
-
- public bool IsAssigned (VariableInfo var, bool ignoreReachability)
- {
- if (!ignoreReachability && !var.IsParameter && IsUnreachable)
- return true;
-
- return var.IsAssigned (locals);
- }
-
- public void SetAssigned (VariableInfo var)
- {
- if (!var.IsParameter && IsUnreachable)
- return;
-
- var.SetAssigned (locals);
- }
-
- public bool IsFieldAssigned (VariableInfo var, string name)
- {
- if (/*!var.IsParameter &&*/ IsUnreachable)
- return true;
-
- return var.IsStructFieldAssigned (locals, name);
- }
-
- public void SetFieldAssigned (VariableInfo var, string name)
- {
- if (/*!var.IsParameter &&*/ IsUnreachable)
- return;
-
- var.SetStructFieldAssigned (locals, name);
- }
-
- public bool IsUnreachable {
- get {
- return is_unreachable;
- }
- set {
- is_unreachable = value;
- }
- }
-
- public void ResetBarrier ()
- {
- is_unreachable = false;
- }
-
- public void Goto ()
- {
- is_unreachable = true;
- }
-
- public static UsageVector MergeSiblings (UsageVector sibling_list, Location loc)
- {
- if (sibling_list.Next == null)
- return sibling_list;
-
- MyBitVector locals = null;
- bool is_unreachable = sibling_list.is_unreachable;
-
- if (!sibling_list.IsUnreachable)
- locals &= sibling_list.locals;
-
- for (UsageVector child = sibling_list.Next; child != null; child = child.Next) {
- is_unreachable &= child.is_unreachable;
-
- if (!child.IsUnreachable)
- locals &= child.locals;
- }
-
- return new UsageVector (locals, is_unreachable, null, loc);
- }
-
- // <summary>
- // Merges a child branching.
- // </summary>
- public UsageVector MergeChild (UsageVector child, bool overwrite)
- {
- Report.Debug (2, " MERGING CHILD EFFECTS", this, child, Type);
-
- bool new_isunr = child.is_unreachable;
-
- //
- // We've now either reached the point after the branching or we will
- // never get there since we always return or always throw an exception.
- //
- // If we can reach the point after the branching, mark all locals and
- // parameters as initialized which have been initialized in all branches
- // we need to look at (see above).
- //
-
- if ((Type == SiblingType.SwitchSection) && !new_isunr) {
- Report.Error (163, Location,
- "Control cannot fall through from one " +
- "case label to another");
- return child;
- }
-
- locals |= child.locals;
-
- // throw away un-necessary information about variables in child blocks
- if (locals.Count != CountLocals)
- locals = new MyBitVector (locals, CountLocals);
-
- if (overwrite)
- is_unreachable = new_isunr;
- else
- is_unreachable |= new_isunr;
-
- return child;
- }
-
- public void MergeOrigins (UsageVector o_vectors)
- {
- Report.Debug (1, " MERGING BREAK ORIGINS", this);
-
- if (o_vectors == null)
- return;
-
- if (IsUnreachable && locals != null)
- locals.SetAll (true);
-
- for (UsageVector vector = o_vectors; vector != null; vector = vector.Next) {
- Report.Debug (1, " MERGING BREAK ORIGIN", vector);
- if (vector.IsUnreachable)
- continue;
- locals &= vector.locals;
- is_unreachable &= vector.is_unreachable;
- }
-
- Report.Debug (1, " MERGING BREAK ORIGINS DONE", this);
- }
-
- //
- // Debugging stuff.
- //
-
- public override string ToString ()
- {
- return String.Format ("Vector ({0},{1},{2}-{3})", Type, id, is_unreachable, locals);
- }
- }
-
- // <summary>
- // Creates a new flow branching which is contained in `parent'.
- // You should only pass non-null for the `block' argument if this block
- // introduces any new variables - in this case, we need to create a new
- // usage vector with a different size than our parent's one.
- // </summary>
- protected FlowBranching (FlowBranching parent, BranchingType type, SiblingType stype,
- Block block, Location loc)
- {
- Parent = parent;
- Block = block;
- Location = loc;
- Type = type;
- id = ++next_id;
-
- UsageVector vector;
- if (Block != null) {
- UsageVector parent_vector = parent != null ? parent.CurrentUsageVector : null;
- vector = new UsageVector (stype, parent_vector, Block, loc, Block.AssignableSlots);
- } else {
- vector = new UsageVector (stype, Parent.CurrentUsageVector, null, loc);
- }
-
- AddSibling (vector);
- }
-
- public abstract UsageVector CurrentUsageVector {
- get;
- }
-
- // <summary>
- // Creates a sibling of the current usage vector.
- // </summary>
- public void CreateSibling (Block block, SiblingType type)
- {
- UsageVector vector = new UsageVector (
- type, Parent.CurrentUsageVector, block, Location);
- AddSibling (vector);
-
- Report.Debug (1, " CREATED SIBLING", CurrentUsageVector);
- }
-
- public void CreateSibling ()
- {
- CreateSibling (null, SiblingType.Conditional);
- }
-
- protected abstract void AddSibling (UsageVector uv);
-
- protected abstract UsageVector Merge ();
-
- public UsageVector MergeChild (FlowBranching child)
- {
- return CurrentUsageVector.MergeChild (child.Merge (), true);
- }
-
- public virtual bool CheckRethrow (Location loc)
- {
- return Parent.CheckRethrow (loc);
- }
-
- public virtual bool AddResumePoint (ResumableStatement stmt, ResumableStatement current, out int pc)
- {
- return Parent.AddResumePoint (stmt, current, out pc);
- }
-
- // returns true if we crossed an unwind-protected region (try/catch/finally, lock, using, ...)
- public virtual bool AddBreakOrigin (UsageVector vector, Location loc)
- {
- return Parent.AddBreakOrigin (vector, loc);
- }
-
- // returns true if we crossed an unwind-protected region (try/catch/finally, lock, using, ...)
- public virtual bool AddContinueOrigin (UsageVector vector, Location loc)
- {
- return Parent.AddContinueOrigin (vector, loc);
- }
-
- // returns true if we crossed an unwind-protected region (try/catch/finally, lock, using, ...)
- public virtual bool AddReturnOrigin (UsageVector vector, ExitStatement stmt)
- {
- return Parent.AddReturnOrigin (vector, stmt);
- }
-
- // returns true if we crossed an unwind-protected region (try/catch/finally, lock, using, ...)
- public virtual bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
- {
- return Parent.AddGotoOrigin (vector, goto_stmt);
- }
-
- public bool IsAssigned (VariableInfo vi)
- {
- return CurrentUsageVector.IsAssigned (vi, false);
- }
-
- public bool IsStructFieldAssigned (VariableInfo vi, string field_name)
- {
- return CurrentUsageVector.IsAssigned (vi, false) || CurrentUsageVector.IsFieldAssigned (vi, field_name);
- }
-
- protected static Report Report {
- get { return RootContext.ToplevelTypes.Compiler.Report; }
- }
-
- public void SetAssigned (VariableInfo vi)
- {
- CurrentUsageVector.SetAssigned (vi);
- }
-
- public void SetFieldAssigned (VariableInfo vi, string name)
- {
- CurrentUsageVector.SetFieldAssigned (vi, name);
- }
-
-#if DEBUG
- public override string ToString ()
- {
- StringBuilder sb = new StringBuilder ();
- sb.Append (GetType ());
- sb.Append (" (");
-
- sb.Append (id);
- sb.Append (",");
- sb.Append (Type);
- if (Block != null) {
- sb.Append (" - ");
- sb.Append (Block.ID);
- sb.Append (" - ");
- sb.Append (Block.StartLocation);
- }
- sb.Append (" - ");
- // sb.Append (Siblings.Length);
- // sb.Append (" - ");
- sb.Append (CurrentUsageVector);
- sb.Append (")");
- return sb.ToString ();
- }
-#endif
-
- public string Name {
- get { return String.Format ("{0} ({1}:{2}:{3})", GetType (), id, Type, Location); }
- }
- }
-
- public class FlowBranchingBlock : FlowBranching
- {
- UsageVector sibling_list = null;
-
- public FlowBranchingBlock (FlowBranching parent, BranchingType type,
- SiblingType stype, Block block, Location loc)
- : base (parent, type, stype, block, loc)
- { }
-
- public override UsageVector CurrentUsageVector {
- get { return sibling_list; }
- }
-
- protected override void AddSibling (UsageVector sibling)
- {
- if (sibling_list != null && sibling_list.Type == SiblingType.Block)
- throw new InternalErrorException ("Blocks don't have sibling flow paths");
- sibling.Next = sibling_list;
- sibling_list = sibling;
- }
-
- public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
- {
- LabeledStatement stmt = Block == null ? null : Block.LookupLabel (goto_stmt.Target);
- if (stmt == null)
- return Parent.AddGotoOrigin (vector, goto_stmt);
-
- // forward jump
- goto_stmt.SetResolvedTarget (stmt);
- stmt.AddUsageVector (vector);
- return false;
- }
-
- public static void Error_UnknownLabel (Location loc, string label, Report Report)
- {
- Report.Error(159, loc, "The label `{0}:' could not be found within the scope of the goto statement",
- label);
- }
-
- protected override UsageVector Merge ()
- {
- Report.Debug (2, " MERGING SIBLINGS", Name);
- UsageVector vector = UsageVector.MergeSiblings (sibling_list, Location);
- Report.Debug (2, " MERGING SIBLINGS DONE", Name, vector);
- return vector;
- }
- }
-
- public class FlowBranchingBreakable : FlowBranchingBlock
- {
- UsageVector break_origins;
-
- public FlowBranchingBreakable (FlowBranching parent, BranchingType type, SiblingType stype, Block block, Location loc)
- : base (parent, type, stype, block, loc)
- { }
-
- public override bool AddBreakOrigin (UsageVector vector, Location loc)
- {
- vector = vector.Clone ();
- vector.Next = break_origins;
- break_origins = vector;
- return false;
- }
-
- protected override UsageVector Merge ()
- {
- UsageVector vector = base.Merge ();
- vector.MergeOrigins (break_origins);
- return vector;
- }
- }
-
- public class FlowBranchingContinuable : FlowBranchingBlock
- {
- UsageVector continue_origins;
-
- public FlowBranchingContinuable (FlowBranching parent, BranchingType type, SiblingType stype, Block block, Location loc)
- : base (parent, type, stype, block, loc)
- { }
-
- public override bool AddContinueOrigin (UsageVector vector, Location loc)
- {
- vector = vector.Clone ();
- vector.Next = continue_origins;
- continue_origins = vector;
- return false;
- }
-
- protected override UsageVector Merge ()
- {
- UsageVector vector = base.Merge ();
- vector.MergeOrigins (continue_origins);
- return vector;
- }
- }
-
- public class FlowBranchingLabeled : FlowBranchingBlock
- {
- LabeledStatement stmt;
- UsageVector actual;
-
- public FlowBranchingLabeled (FlowBranching parent, LabeledStatement stmt)
- : base (parent, BranchingType.Labeled, SiblingType.Conditional, null, stmt.loc)
- {
- this.stmt = stmt;
- CurrentUsageVector.MergeOrigins (stmt.JumpOrigins);
- actual = CurrentUsageVector.Clone ();
-
- // stand-in for backward jumps
- CurrentUsageVector.ResetBarrier ();
- }
-
- public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
- {
- if (goto_stmt.Target != stmt.Name)
- return Parent.AddGotoOrigin (vector, goto_stmt);
-
- // backward jump
- goto_stmt.SetResolvedTarget (stmt);
- actual.MergeOrigins (vector.Clone ());
-
- return false;
- }
-
- protected override UsageVector Merge ()
- {
- UsageVector vector = base.Merge ();
-
- if (actual.IsUnreachable)
- Report.Warning (162, 2, stmt.loc, "Unreachable code detected");
-
- actual.MergeChild (vector, false);
- return actual;
- }
- }
-
- public class FlowBranchingIterator : FlowBranchingBlock
- {
- readonly Iterator iterator;
-
- public FlowBranchingIterator (FlowBranching parent, Iterator iterator)
- : base (parent, BranchingType.Iterator, SiblingType.Block, iterator.Block, iterator.Location)
- {
- this.iterator = iterator;
- }
-
- public override bool AddResumePoint (ResumableStatement stmt, ResumableStatement current, out int pc)
- {
- pc = iterator.AddResumePoint (current);
- return false;
- }
- }
-
- public class FlowBranchingToplevel : FlowBranchingBlock
- {
- UsageVector return_origins;
-
- public FlowBranchingToplevel (FlowBranching parent, ParametersBlock stmt)
- : base (parent, BranchingType.Toplevel, SiblingType.Conditional, stmt, stmt.loc)
- {
- }
-
- public override bool CheckRethrow (Location loc)
- {
- Report.Error (156, loc, "A throw statement with no arguments is not allowed outside of a catch clause");
- return false;
- }
-
- public override bool AddResumePoint (ResumableStatement stmt, ResumableStatement current, out int pc)
- {
- throw new InternalErrorException ("A yield in a non-iterator block");
- }
-
- public override bool AddBreakOrigin (UsageVector vector, Location loc)
- {
- Report.Error (139, loc, "No enclosing loop out of which to break or continue");
- return false;
- }
-
- public override bool AddContinueOrigin (UsageVector vector, Location loc)
- {
- Report.Error (139, loc, "No enclosing loop out of which to break or continue");
- return false;
- }
-
- public override bool AddReturnOrigin (UsageVector vector, ExitStatement stmt)
- {
- vector = vector.Clone ();
- vector.Location = stmt.loc;
- vector.Next = return_origins;
- return_origins = vector;
- return false;
- }
-
- public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
- {
- string name = goto_stmt.Target;
- LabeledStatement s = Block.LookupLabel (name);
- if (s != null)
- throw new InternalErrorException ("Shouldn't get here");
-
- if (Parent == null) {
- Error_UnknownLabel (goto_stmt.loc, name, Report);
- return false;
- }
-
- int errors = Report.Errors;
- Parent.AddGotoOrigin (vector, goto_stmt);
- if (errors == Report.Errors)
- Report.Error (1632, goto_stmt.loc, "Control cannot leave the body of an anonymous method");
- return false;
- }
-
- protected override UsageVector Merge ()
- {
- for (UsageVector origin = return_origins; origin != null; origin = origin.Next)
- Block.ParametersBlock.CheckOutParameters (origin);
-
- UsageVector vector = base.Merge ();
- Block.ParametersBlock.CheckOutParameters (vector);
- // Note: we _do_not_ merge in the return origins
- return vector;
- }
-
- public bool End ()
- {
- return Merge ().IsUnreachable;
- }
- }
-
- public class FlowBranchingTryCatch : FlowBranchingBlock
- {
- readonly TryCatch tc;
-
- public FlowBranchingTryCatch (FlowBranching parent, TryCatch stmt)
- : base (parent, BranchingType.Block, SiblingType.Try, null, stmt.loc)
- {
- this.tc = stmt;
- }
-
- public override bool CheckRethrow (Location loc)
- {
- return CurrentUsageVector.Next != null || Parent.CheckRethrow (loc);
- }
-
- public override bool AddResumePoint (ResumableStatement stmt, ResumableStatement current, out int pc)
- {
- int errors = Report.Errors;
- Parent.AddResumePoint (stmt, tc.IsTryCatchFinally ? current : tc, out pc);
- if (errors == Report.Errors) {
- if (stmt is AwaitStatement) {
- if (CurrentUsageVector.Next != null) {
- Report.Error (1985, stmt.loc, "The `await' operator cannot be used in the body of a catch clause");
- } else {
- this.tc.AddResumePoint (current, pc);
- }
- } else {
- if (CurrentUsageVector.Next == null)
- Report.Error (1626, stmt.loc, "Cannot yield a value in the body of a try block with a catch clause");
- else
- Report.Error (1631, stmt.loc, "Cannot yield a value in the body of a catch clause");
- }
- }
-
- return true;
- }
-
- public override bool AddBreakOrigin (UsageVector vector, Location loc)
- {
- Parent.AddBreakOrigin (vector, loc);
- tc.SomeCodeFollows ();
- return true;
- }
-
- public override bool AddContinueOrigin (UsageVector vector, Location loc)
- {
- Parent.AddContinueOrigin (vector, loc);
- tc.SomeCodeFollows ();
- return true;
- }
-
- public override bool AddReturnOrigin (UsageVector vector, ExitStatement exit_stmt)
- {
- Parent.AddReturnOrigin (vector, exit_stmt);
- tc.SomeCodeFollows ();
- return true;
- }
-
- public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
- {
- Parent.AddGotoOrigin (vector, goto_stmt);
- return true;
- }
- }
-
- public class FlowBranchingAsync : FlowBranchingBlock
- {
- readonly AsyncInitializer async_init;
-
- public FlowBranchingAsync (FlowBranching parent, AsyncInitializer async_init)
- : base (parent, BranchingType.Block, SiblingType.Try, null, async_init.Location)
- {
- this.async_init = async_init;
- }
-/*
- public override bool CheckRethrow (Location loc)
- {
- return CurrentUsageVector.Next != null || Parent.CheckRethrow (loc);
- }
-*/
- public override bool AddResumePoint (ResumableStatement stmt, ResumableStatement current, out int pc)
- {
- pc = async_init.AddResumePoint (current);
- return true;
- }
-
- public override bool AddBreakOrigin (UsageVector vector, Location loc)
- {
- Parent.AddBreakOrigin (vector, loc);
- return true;
- }
-
- public override bool AddContinueOrigin (UsageVector vector, Location loc)
- {
- Parent.AddContinueOrigin (vector, loc);
- return true;
- }
-
- public override bool AddReturnOrigin (UsageVector vector, ExitStatement exit_stmt)
- {
- Parent.AddReturnOrigin (vector, exit_stmt);
- return true;
- }
-
- public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
- {
- Parent.AddGotoOrigin (vector, goto_stmt);
- return true;
- }
- }
-
- public class FlowBranchingTryFinally : FlowBranching
- {
- ExceptionStatement stmt;
- UsageVector current_vector;
- UsageVector try_vector;
- UsageVector finally_vector;
-
- abstract class SavedOrigin {
- public readonly SavedOrigin Next;
- public readonly UsageVector Vector;
-
- protected SavedOrigin (SavedOrigin next, UsageVector vector)
- {
- Next = next;
- Vector = vector.Clone ();
- }
-
- protected abstract void DoPropagateFinally (FlowBranching parent);
- public void PropagateFinally (UsageVector finally_vector, FlowBranching parent)
- {
- if (finally_vector != null)
- Vector.MergeChild (finally_vector, false);
- DoPropagateFinally (parent);
- }
- }
-
- class BreakOrigin : SavedOrigin {
- Location Loc;
- public BreakOrigin (SavedOrigin next, UsageVector vector, Location loc)
- : base (next, vector)
- {
- Loc = loc;
- }
-
- protected override void DoPropagateFinally (FlowBranching parent)
- {
- parent.AddBreakOrigin (Vector, Loc);
- }
- }
-
- class ContinueOrigin : SavedOrigin {
- Location Loc;
- public ContinueOrigin (SavedOrigin next, UsageVector vector, Location loc)
- : base (next, vector)
- {
- Loc = loc;
- }
-
- protected override void DoPropagateFinally (FlowBranching parent)
- {
- parent.AddContinueOrigin (Vector, Loc);
- }
- }
-
- class ReturnOrigin : SavedOrigin {
- public ExitStatement Stmt;
-
- public ReturnOrigin (SavedOrigin next, UsageVector vector, ExitStatement stmt)
- : base (next, vector)
- {
- Stmt = stmt;
- }
-
- protected override void DoPropagateFinally (FlowBranching parent)
- {
- parent.AddReturnOrigin (Vector, Stmt);
- }
- }
-
- class GotoOrigin : SavedOrigin {
- public Goto Stmt;
-
- public GotoOrigin (SavedOrigin next, UsageVector vector, Goto stmt)
- : base (next, vector)
- {
- Stmt = stmt;
- }
-
- protected override void DoPropagateFinally (FlowBranching parent)
- {
- parent.AddGotoOrigin (Vector, Stmt);
- }
- }
-
- SavedOrigin saved_origins;
-
- public FlowBranchingTryFinally (FlowBranching parent,
- ExceptionStatement stmt)
- : base (parent, BranchingType.Exception, SiblingType.Try,
- null, stmt.loc)
- {
- this.stmt = stmt;
- }
-
- protected override void AddSibling (UsageVector sibling)
- {
- switch (sibling.Type) {
- case SiblingType.Try:
- try_vector = sibling;
- break;
- case SiblingType.Finally:
- finally_vector = sibling;
- break;
- default:
- throw new InvalidOperationException ();
- }
- current_vector = sibling;
- }
-
- public override UsageVector CurrentUsageVector {
- get { return current_vector; }
- }
-
- public override bool CheckRethrow (Location loc)
- {
- if (!Parent.CheckRethrow (loc))
- return false;
- if (finally_vector == null)
- return true;
- Report.Error (724, loc, "A throw statement with no arguments is not allowed inside of a finally clause nested inside of the innermost catch clause");
- return false;
- }
-
- public override bool AddResumePoint (ResumableStatement stmt, ResumableStatement current, out int pc)
- {
- int errors = Report.Errors;
- Parent.AddResumePoint (stmt, this.stmt, out pc);
- if (errors == Report.Errors) {
- if (finally_vector == null)
- this.stmt.AddResumePoint (current, pc);
- else {
- if (stmt is AwaitStatement) {
- Report.Error (1984, stmt.loc, "The `await' operator cannot be used in the body of a finally clause");
- } else {
- Report.Error (1625, stmt.loc, "Cannot yield in the body of a finally clause");
- }
- }
- }
- return true;
- }
-
- public override bool AddBreakOrigin (UsageVector vector, Location loc)
- {
- if (finally_vector != null) {
- int errors = Report.Errors;
- Parent.AddBreakOrigin (vector, loc);
- if (errors == Report.Errors)
- Report.Error (157, loc, "Control cannot leave the body of a finally clause");
- } else {
- saved_origins = new BreakOrigin (saved_origins, vector, loc);
- }
-
- // either the loop test or a back jump will follow code
- stmt.SomeCodeFollows ();
- return true;
- }
-
- public override bool AddContinueOrigin (UsageVector vector, Location loc)
- {
- if (finally_vector != null) {
- int errors = Report.Errors;
- Parent.AddContinueOrigin (vector, loc);
- if (errors == Report.Errors)
- Report.Error (157, loc, "Control cannot leave the body of a finally clause");
- } else {
- saved_origins = new ContinueOrigin (saved_origins, vector, loc);
- }
-
- // either the loop test or a back jump will follow code
- stmt.SomeCodeFollows ();
- return true;
- }
-
- public override bool AddReturnOrigin (UsageVector vector, ExitStatement exit_stmt)
- {
- if (finally_vector != null) {
- int errors = Report.Errors;
- Parent.AddReturnOrigin (vector, exit_stmt);
- if (errors == Report.Errors)
- exit_stmt.Error_FinallyClause (Report);
- } else {
- saved_origins = new ReturnOrigin (saved_origins, vector, exit_stmt);
- }
-
- // sets ec.NeedReturnLabel()
- stmt.SomeCodeFollows ();
- return true;
- }
-
- public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
- {
- LabeledStatement s = current_vector.Block == null ? null : current_vector.Block.LookupLabel (goto_stmt.Target);
- if (s != null)
- throw new InternalErrorException ("Shouldn't get here");
-
- if (finally_vector != null) {
- int errors = Report.Errors;
- Parent.AddGotoOrigin (vector, goto_stmt);
- if (errors == Report.Errors)
- Report.Error (157, goto_stmt.loc, "Control cannot leave the body of a finally clause");
- } else {
- saved_origins = new GotoOrigin (saved_origins, vector, goto_stmt);
- }
- return true;
- }
-
- protected override UsageVector Merge ()
- {
- UsageVector vector = try_vector.Clone ();
-
- if (finally_vector != null)
- vector.MergeChild (finally_vector, false);
-
- for (SavedOrigin origin = saved_origins; origin != null; origin = origin.Next)
- origin.PropagateFinally (finally_vector, Parent);
-
- return vector;
- }
- }
-
// <summary>
// This is used by the flow analysis code to keep track of the type of local variables.
//
public TypeInfo[] SubStructInfo;
readonly StructInfo struct_info;
- private static Dictionary<TypeSpec, TypeInfo> type_hash;
static readonly TypeInfo simple_type = new TypeInfo (1);
-
+
static TypeInfo ()
{
Reset ();
public static void Reset ()
{
- type_hash = new Dictionary<TypeSpec, TypeInfo> ();
StructInfo.field_type_hash = new Dictionary<TypeSpec, StructInfo> ();
}
return struct_info.GetStructField (name);
}
- public static TypeInfo GetTypeInfo (TypeSpec type)
+ public static TypeInfo GetTypeInfo (TypeSpec type, IMemberContext context)
{
if (!type.IsStruct)
return simple_type;
TypeInfo info;
- if (type_hash.TryGetValue (type, out info))
- return info;
+ Dictionary<TypeSpec, TypeInfo> type_hash;
+ if (type.BuiltinType > 0) {
+ // Don't cache built-in types, they are null in most cases except for
+ // corlib compilation when we need to distinguish between declaration
+ // and referencing
+ type_hash = null;
+ } else {
+ type_hash = context.Module.TypeInfoCache;
+ if (type_hash.TryGetValue (type, out info))
+ return info;
+ }
- var struct_info = StructInfo.GetStructInfo (type);
+ var struct_info = StructInfo.GetStructInfo (type, context);
if (struct_info != null) {
info = new TypeInfo (struct_info, 0);
} else {
info = simple_type;
}
- type_hash.Add (type, info);
+ if (type_hash != null)
+ type_hash.Add (type, info);
+
return info;
}
// A struct's constructor must always assign all fields.
// This method checks whether it actually does so.
// </summary>
- public bool IsFullyInitialized (BlockContext ec, VariableInfo vi, Location loc)
+ public bool IsFullyInitialized (FlowAnalysisContext fc, VariableInfo vi, Location loc)
{
if (struct_info == null)
return true;
bool ok = true;
- FlowBranching branching = ec.CurrentBranching;
for (int i = 0; i < struct_info.Count; i++) {
- var field = struct_info.Fields [i];
+ var field = struct_info.Fields[i];
- if (!branching.IsStructFieldAssigned (vi, field.Name)) {
- if (field.MemberDefinition is Property.BackingField) {
- ec.Report.Error (843, loc,
+ if (!fc.IsStructFieldDefinitelyAssigned (vi, field.Name)) {
+ var bf = field.MemberDefinition as Property.BackingFieldDeclaration;
+ if (bf != null) {
+ if (bf.Initializer != null)
+ continue;
+
+ fc.Report.Error (843, loc,
"An automatically implemented property `{0}' must be fully assigned before control leaves the constructor. Consider calling the default struct contructor from a constructor initializer",
field.GetSignatureForError ());
- } else {
- ec.Report.Error (171, loc,
- "Field `{0}' must be fully assigned before control leaves the constructor",
- field.GetSignatureForError ());
+
+ ok = false;
+ continue;
}
+
+ fc.Report.Error (171, loc,
+ "Field `{0}' must be fully assigned before control leaves the constructor",
+ field.GetSignatureForError ());
ok = false;
}
}
//
// We only need one instance per type
//
- StructInfo (TypeSpec type)
+ StructInfo (TypeSpec type, IMemberContext context)
{
field_type_hash.Add (type, this);
- fields = MemberCache.GetAllFieldsForDefiniteAssignment (type);
+ fields = MemberCache.GetAllFieldsForDefiniteAssignment (type, context);
struct_field_hash = new Dictionary<string, TypeInfo> ();
field_hash = new Dictionary<string, int> (fields.Count);
var field = fields [i];
if (field.MemberType.IsStruct)
- sinfo [i] = GetStructInfo (field.MemberType);
+ sinfo [i] = GetStructInfo (field.MemberType, context);
if (sinfo [i] == null)
field_hash.Add (field.Name, ++Length);
return null;
}
- public static StructInfo GetStructInfo (TypeSpec type)
+ public static StructInfo GetStructInfo (TypeSpec type, IMemberContext context)
{
- if (type.BuiltinType > 0)
+ if (type.BuiltinType > 0 && type != context.CurrentType)
return null;
StructInfo info;
if (field_type_hash.TryGetValue (type, out info))
return info;
- return new StructInfo (type);
+ return new StructInfo (type, context);
}
}
}
- // <summary>
- // This is used by the flow analysis code to store information about a single local variable
- // or parameter. Depending on the variable's type, we need to allocate one or more elements
- // in the BitVector - if it's a fundamental or reference type, we just need to know whether
- // it has been assigned or not, but for structs, we need this information for each of its fields.
- // </summary>
- public class VariableInfo {
+ //
+ // This is used by definite assignment analysis code to store information about a local variable
+ // or parameter. Depending on the variable's type, we need to allocate one or more elements
+ // in the BitVector - if it's a fundamental or reference type, we just need to know whether
+ // it has been assigned or not, but for structs, we need this information for each of its fields.
+ //
+ public class VariableInfo
+ {
readonly string Name;
+
readonly TypeInfo TypeInfo;
// <summary>
// The first bit always specifies whether the variable as such has been assigned while
// the remaining bits contain this information for each of a struct's fields.
// </summary>
- public readonly int Length;
+ readonly int Length;
// <summary>
// If this is a parameter of local variable.
// </summary>
- public readonly bool IsParameter;
+ public bool IsParameter;
VariableInfo[] sub_info;
- VariableInfo (string name, TypeSpec type, int offset)
+ VariableInfo (string name, TypeSpec type, int offset, IMemberContext context)
{
this.Name = name;
this.Offset = offset;
- this.TypeInfo = TypeInfo.GetTypeInfo (type);
+ this.TypeInfo = TypeInfo.GetTypeInfo (type, context);
Length = TypeInfo.TotalLength;
Initialize ();
}
- protected void Initialize ()
+ void Initialize ()
{
TypeInfo[] sub_fields = TypeInfo.SubStructInfo;
if (sub_fields != null) {
sub_info = new VariableInfo [0];
}
- public VariableInfo (LocalVariable local_info, int offset)
- : this (local_info.Name, local_info.Type, offset)
+ public static VariableInfo Create (BlockContext bc, LocalVariable variable)
{
- this.IsParameter = false;
+ var info = new VariableInfo (variable.Name, variable.Type, bc.AssignmentInfoOffset, bc);
+ bc.AssignmentInfoOffset += info.Length;
+ return info;
}
- public VariableInfo (ParametersCompiled ip, int i, int offset)
- : this (ip.FixedParameters [i].Name, ip.Types [i], offset)
+ public static VariableInfo Create (BlockContext bc, Parameter parameter)
{
- this.IsParameter = true;
- }
+ var info = new VariableInfo (parameter.Name, parameter.Type, bc.AssignmentInfoOffset, bc) {
+ IsParameter = true
+ };
- public bool IsAssigned (ResolveContext ec)
- {
- return !ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (this);
+ bc.AssignmentInfoOffset += info.Length;
+ return info;
}
- public bool IsAssigned (MyBitVector vector)
+ public bool IsAssigned (DefiniteAssignmentBitSet vector)
{
if (vector == null)
return true;
return false;
}
- vector [Offset] = true;
+ vector.Set (Offset);
return true;
}
public bool IsEverAssigned { get; set; }
- public bool IsStructFieldAssigned (ResolveContext ec, string name)
- {
- return !ec.DoFlowAnalysis || ec.CurrentBranching.IsStructFieldAssigned (this, name);
- }
-
- public bool IsFullyInitialized (BlockContext bc, Location loc)
+ public bool IsFullyInitialized (FlowAnalysisContext fc, Location loc)
{
- return TypeInfo.IsFullyInitialized (bc, this, loc);
+ return TypeInfo.IsFullyInitialized (fc, this, loc);
}
- public bool IsStructFieldAssigned (MyBitVector vector, string field_name)
+ public bool IsStructFieldAssigned (DefiniteAssignmentBitSet vector, string field_name)
{
int field_idx = TypeInfo.GetFieldIndex (field_name);
return vector [Offset + field_idx];
}
- public void SetStructFieldAssigned (ResolveContext ec, string name)
- {
- if (ec.DoFlowAnalysis)
- ec.CurrentBranching.SetFieldAssigned (this, name);
- }
-
- public void SetAssigned (ResolveContext ec)
- {
- if (ec.DoFlowAnalysis)
- ec.CurrentBranching.SetAssigned (this);
- }
-
- public void SetAssigned (MyBitVector vector)
+ public void SetAssigned (DefiniteAssignmentBitSet vector, bool generatedAssignment)
{
if (Length == 1)
- vector[Offset] = true;
+ vector.Set (Offset);
else
- vector.SetRange (Offset, Length);
+ vector.Set (Offset, Length);
- IsEverAssigned = true;
+ if (!generatedAssignment)
+ IsEverAssigned = true;
}
- public void SetStructFieldAssigned (MyBitVector vector, string field_name)
+ public void SetStructFieldAssigned (DefiniteAssignmentBitSet vector, string field_name)
{
- if (vector[Offset])
+ if (vector [Offset])
return;
int field_idx = TypeInfo.GetFieldIndex (field_name);
var complex_field = TypeInfo.GetStructField (field_name);
if (complex_field != null) {
- vector.SetRange (Offset + complex_field.Offset, complex_field.TotalLength);
+ vector.Set (Offset + complex_field.Offset, complex_field.TotalLength);
} else {
- vector[Offset + field_idx] = true;
+ vector.Set (Offset + field_idx);
}
IsEverAssigned = true;
//
- // Each field must be assigned
+ // Each field must be assigned before setting master bit
//
for (int i = Offset + 1; i < TypeInfo.TotalLength + Offset; i++) {
if (!vector[i])
// Set master struct flag to assigned when all tested struct
// fields have been assigned
//
- vector[Offset] = true;
+ vector.Set (Offset);
}
public VariableInfo GetStructFieldInfo (string fieldName)
public override string ToString ()
{
- return String.Format ("VariableInfo ({0}:{1}:{2}:{3}:{4})",
- Name, TypeInfo, Offset, Length, IsParameter);
+ return String.Format ("Name={0} Offset={1} Length={2} {3})", Name, Offset, Length, TypeInfo);
}
}
- // <summary>
- // This is a special bit vector which can inherit from another bit vector doing a
- // copy-on-write strategy. The inherited vector may have a smaller size than the
- // current one.
- // </summary>
- public class MyBitVector {
- public readonly int Count;
- public static readonly MyBitVector Empty = new MyBitVector ();
-
- // Invariant: vector != null => vector.Count == Count
- // Invariant: vector == null || shared == null
- // i.e., at most one of 'vector' and 'shared' can be non-null. They can both be null -- that means all-ones
- // The object in 'shared' cannot be modified, while 'vector' can be freely modified
- System.Collections.BitArray vector, shared;
+ public struct Reachability
+ {
+ readonly bool unreachable;
- MyBitVector ()
+ Reachability (bool unreachable)
{
- shared = new System.Collections.BitArray (0, false);
+ this.unreachable = unreachable;
+ }
+
+ public bool IsUnreachable {
+ get {
+ return unreachable;
+ }
}
- public MyBitVector (MyBitVector InheritsFrom, int Count)
+ public static Reachability CreateUnreachable ()
{
- if (InheritsFrom != null)
- shared = InheritsFrom.MakeShared (Count);
+ return new Reachability (true);
+ }
- this.Count = Count;
+ public static Reachability operator & (Reachability a, Reachability b)
+ {
+ return new Reachability (a.unreachable && b.unreachable);
}
- System.Collections.BitArray MakeShared (int new_count)
+ public static Reachability operator | (Reachability a, Reachability b)
{
- // Post-condition: vector == null
+ return new Reachability (a.unreachable | b.unreachable);
+ }
+ }
- // ensure we don't leak out dirty bits from the BitVector we inherited from
- if (new_count > Count &&
- ((shared != null && shared.Count > Count) ||
- (shared == null && vector == null)))
- initialize_vector ();
+ //
+ // Special version of bit array. Many operations can be simplified because
+ // we are always dealing with arrays of same sizes
+ //
+ public class DefiniteAssignmentBitSet
+ {
+ const uint copy_on_write_flag = 1u << 31;
- if (vector != null) {
- shared = vector;
- vector = null;
- }
+ uint bits;
- return shared;
- }
+ // Used when bits overflows
+ int[] large_bits;
- // <summary>
- // Get/set bit `index' in the bit vector.
- // </summary>
- public bool this [int index] {
- get {
- if (index >= Count)
- // FIXME: Disabled due to missing anonymous method flow analysis
- // throw new ArgumentOutOfRangeException ();
- return true;
-
- if (vector != null)
- return vector [index];
- if (shared == null)
- return true;
- if (index < shared.Count)
- return shared [index];
- return false;
- }
+ public static readonly DefiniteAssignmentBitSet Empty = new DefiniteAssignmentBitSet (0);
- set {
- // Only copy the vector if we're actually modifying it.
- if (this [index] != value) {
- if (vector == null)
- initialize_vector ();
- vector [index] = value;
- }
- }
+ public DefiniteAssignmentBitSet (int length)
+ {
+ if (length > 31)
+ large_bits = new int[(length + 31) / 32];
}
- // <summary>
- // Performs an `or' operation on the bit vector. The `new_vector' may have a
- // different size than the current one.
- // </summary>
- private MyBitVector Or (MyBitVector new_vector)
+ public DefiniteAssignmentBitSet (DefiniteAssignmentBitSet source)
{
- if (Count == 0 || new_vector.Count == 0)
- return this;
-
- var o = new_vector.vector != null ? new_vector.vector : new_vector.shared;
-
- if (o == null) {
- int n = new_vector.Count;
- if (n < Count) {
- for (int i = 0; i < n; ++i)
- this [i] = true;
- } else {
- SetAll (true);
- }
- return this;
+ if (source.large_bits != null) {
+ large_bits = source.large_bits;
+ bits = source.bits | copy_on_write_flag;
+ } else {
+ bits = source.bits & ~copy_on_write_flag;
}
+ }
- if (Count == o.Count) {
- if (vector == null) {
- if (shared == null)
- return this;
- initialize_vector ();
- }
- vector.Or (o);
- return this;
- }
+ public static DefiniteAssignmentBitSet operator & (DefiniteAssignmentBitSet a, DefiniteAssignmentBitSet b)
+ {
+ if (IsEqual (a, b))
+ return a;
- int min = o.Count;
- if (Count < min)
- min = Count;
+ DefiniteAssignmentBitSet res;
+ if (a.large_bits == null) {
+ res = new DefiniteAssignmentBitSet (a);
+ res.bits &= (b.bits & ~copy_on_write_flag);
+ return res;
+ }
- for (int i = 0; i < min; i++) {
- if (o [i])
- this [i] = true;
+ res = new DefiniteAssignmentBitSet (a);
+ res.Clone ();
+ var dest = res.large_bits;
+ var src = b.large_bits;
+ for (int i = 0; i < dest.Length; ++i) {
+ dest[i] &= src[i];
}
- return this;
+ return res;
}
- // <summary>
- // Performs an `and' operation on the bit vector. The `new_vector' may have
- // a different size than the current one.
- // </summary>
- private MyBitVector And (MyBitVector new_vector)
+ public static DefiniteAssignmentBitSet operator | (DefiniteAssignmentBitSet a, DefiniteAssignmentBitSet b)
{
- if (Count == 0)
- return this;
-
- var o = new_vector.vector != null ? new_vector.vector : new_vector.shared;
+ if (IsEqual (a, b))
+ return a;
- if (o == null) {
- for (int i = new_vector.Count; i < Count; ++i)
- this [i] = false;
- return this;
+ DefiniteAssignmentBitSet res;
+ if (a.large_bits == null) {
+ res = new DefiniteAssignmentBitSet (a);
+ res.bits |= b.bits;
+ res.bits &= ~copy_on_write_flag;
+ return res;
}
- if (o.Count == 0) {
- SetAll (false);
- return this;
- }
+ res = new DefiniteAssignmentBitSet (a);
+ res.Clone ();
+ var dest = res.large_bits;
+ var src = b.large_bits;
- if (Count == o.Count) {
- if (vector == null) {
- if (shared == null) {
- shared = new_vector.MakeShared (Count);
- return this;
- }
- initialize_vector ();
- }
- vector.And (o);
- return this;
+ for (int i = 0; i < dest.Length; ++i) {
+ dest[i] |= src[i];
}
- int min = o.Count;
- if (Count < min)
- min = Count;
+ return res;
+ }
- for (int i = 0; i < min; i++) {
- if (! o [i])
- this [i] = false;
- }
+ public static DefiniteAssignmentBitSet And (List<DefiniteAssignmentBitSet> das)
+ {
+ if (das.Count == 0)
+ throw new ArgumentException ("Empty das");
- for (int i = min; i < Count; i++)
- this [i] = false;
+ DefiniteAssignmentBitSet res = das[0];
+ for (int i = 1; i < das.Count; ++i) {
+ res &= das[i];
+ }
- return this;
+ return res;
}
- public static MyBitVector operator & (MyBitVector a, MyBitVector b)
- {
- if (a == b)
- return a;
- if (a == null)
- return b.Clone ();
- if (b == null)
- return a.Clone ();
- if (a.Count > b.Count)
- return a.Clone ().And (b);
- else
- return b.Clone ().And (a);
+ bool CopyOnWrite {
+ get {
+ return (bits & copy_on_write_flag) != 0;
+ }
}
- public static MyBitVector operator | (MyBitVector a, MyBitVector b)
- {
- if (a == b)
- return a;
- if (a == null)
- return new MyBitVector (null, b.Count);
- if (b == null)
- return new MyBitVector (null, a.Count);
- if (a.Count > b.Count)
- return a.Clone ().Or (b);
- else
- return b.Clone ().Or (a);
+ int Length {
+ get {
+ return large_bits == null ? 31 : large_bits.Length * 32;
+ }
}
- public MyBitVector Clone ()
+ public void Set (int index)
{
- return Count == 0 ? Empty : new MyBitVector (this, Count);
+ if (CopyOnWrite && !this[index])
+ Clone ();
+
+ SetBit (index);
}
- public void SetRange (int offset, int length)
+ public void Set (int index, int length)
{
- if (offset > Count || offset + length > Count)
- throw new ArgumentOutOfRangeException ("flow-analysis");
+ for (int i = 0; i < length; ++i) {
+ if (CopyOnWrite && !this[index + i])
+ Clone ();
- if (shared == null && vector == null)
- return;
+ SetBit (index + i);
+ }
+ }
- int i = 0;
- if (shared != null) {
- if (offset + length <= shared.Count) {
- for (; i < length; ++i)
- if (!shared [i+offset])
- break;
- if (i == length)
- return;
- }
- initialize_vector ();
+ public bool this[int index] {
+ get {
+ return GetBit (index);
+ }
+ }
+
+ public override string ToString ()
+ {
+ var length = Length;
+ StringBuilder sb = new StringBuilder (length);
+ for (int i = 0; i < length; ++i) {
+ sb.Append (this[i] ? '1' : '0');
}
- for (; i < length; ++i)
- vector [i+offset] = true;
+ return sb.ToString ();
}
- public void SetAll (bool value)
+ void Clone ()
{
- // Don't clobber Empty
- if (Count == 0)
- return;
- shared = value ? null : Empty.MakeShared (Count);
- vector = null;
+ large_bits = (int[]) large_bits.Clone ();
}
- void initialize_vector ()
+ bool GetBit (int index)
{
- // Post-condition: vector != null
- if (shared == null) {
- vector = new System.Collections.BitArray (Count, true);
- return;
- }
+ return large_bits == null ?
+ (bits & (1 << index)) != 0 :
+ (large_bits[index >> 5] & (1 << (index & 31))) != 0;
+ }
- vector = new System.Collections.BitArray (shared);
- if (Count != vector.Count)
- vector.Length = Count;
- shared = null;
+ void SetBit (int index)
+ {
+ if (large_bits == null)
+ bits = (uint) ((int) bits | (1 << index));
+ else
+ large_bits[index >> 5] |= (1 << (index & 31));
}
- StringBuilder Dump (StringBuilder sb)
+ static bool IsEqual (DefiniteAssignmentBitSet a, DefiniteAssignmentBitSet b)
{
- var dump = vector == null ? shared : vector;
- if (dump == null)
- return sb.Append ("/");
- if (dump == shared)
- sb.Append ("=");
- for (int i = 0; i < dump.Count; i++)
- sb.Append (dump [i] ? "1" : "0");
- return sb;
+ if (a.large_bits == null)
+ return (a.bits & ~copy_on_write_flag) == (b.bits & ~copy_on_write_flag);
+
+ for (int i = 0; i < a.large_bits.Length; ++i) {
+ if (a.large_bits[i] != b.large_bits[i])
+ return false;
+ }
+
+ return true;
}
- public override string ToString ()
+ public static bool IsIncluded (DefiniteAssignmentBitSet set, DefiniteAssignmentBitSet test)
{
- return Dump (new StringBuilder ("{")).Append ("}").ToString ();
+ var set_bits = set.large_bits;
+ if (set_bits == null)
+ return (set.bits & test.bits & ~copy_on_write_flag) == (set.bits & ~copy_on_write_flag);
+
+ var test_bits = test.large_bits;
+ for (int i = 0; i < set_bits.Length; ++i) {
+ if ((set_bits[i] & test_bits[i]) != set_bits[i])
+ return false;
+ }
+
+ return true;
}
}
}