@@ -236,60 +236,15 @@ impl std::fmt::Debug for ScopedVisibilityConstraintId {
236236
237237#[ derive( Clone , Copy , Debug , Eq , Hash , PartialEq ) ]
238238struct InteriorNode {
239- atom : Atom ,
239+ /// A "variable" that is evaluated as part of a TDD ternary function. For visibility
240+ /// constraints, this is a `Constraint` that represents some runtime property of the Python
241+ /// code that we are evaluating.
242+ atom : ScopedConstraintId ,
240243 if_true : ScopedVisibilityConstraintId ,
241244 if_ambiguous : ScopedVisibilityConstraintId ,
242245 if_false : ScopedVisibilityConstraintId ,
243246}
244247
245- /// A "variable" that is evaluated as part of a TDD ternary function. For visibility constraints,
246- /// this is a `Constraint` that represents some runtime property of the Python code that we are
247- /// evaluating. We intern these constraints in an arena ([`VisibilityConstraints::constraints`]).
248- /// An atom is then an index into this arena.
249- ///
250- /// By using a 32-bit index, we would typically allow 4 billion distinct constraints within a
251- /// scope. However, we sometimes have to model how a `Constraint` can have a different runtime
252- /// value at different points in the execution of the program. To handle this, we reserve the top
253- /// byte of an atom to represent a "copy number". This is just an opaque value that allows
254- /// different `Atom`s to evaluate the same `Constraint`. This yields a maximum of 16 million
255- /// distinct `Constraint`s in a scope, and 256 possible copies of each of those constraints.
256- #[ derive( Clone , Copy , Eq , Hash , Ord , PartialEq , PartialOrd ) ]
257- struct Atom ( u32 ) ;
258-
259- impl Atom {
260- /// Deconstruct an atom into a constraint index and a copy number.
261- #[ inline]
262- fn into_index_and_copy ( self ) -> ( ScopedConstraintId , u8 ) {
263- let copy = self . 0 >> 24 ;
264- let index = self . 0 & 0x00ff_ffff ;
265- ( index. into ( ) , copy as u8 )
266- }
267-
268- #[ inline]
269- fn copy_of ( mut self , copy : u8 ) -> Self {
270- // Clear out the previous copy number
271- self . 0 &= 0x00ff_ffff ;
272- // OR in the new one
273- self . 0 |= u32:: from ( copy) << 24 ;
274- self
275- }
276- }
277-
278- impl From < ScopedConstraintId > for Atom {
279- fn from ( constraint : ScopedConstraintId ) -> Atom {
280- Atom ( constraint. as_u32 ( ) )
281- }
282- }
283-
284- // A custom Debug implementation that prints out the constraint index and copy number as distinct
285- // fields.
286- impl std:: fmt:: Debug for Atom {
287- fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
288- let ( index, copy) = self . into_index_and_copy ( ) ;
289- f. debug_tuple ( "Atom" ) . field ( & index) . field ( & copy) . finish ( )
290- }
291- }
292-
293248impl ScopedVisibilityConstraintId {
294249 /// A special ID that is used for an "always true" / "always visible" constraint.
295250 pub ( crate ) const ALWAYS_TRUE : ScopedVisibilityConstraintId =
@@ -377,11 +332,6 @@ impl VisibilityConstraintsBuilder {
377332 }
378333 }
379334
380- /// Adds a constraint, ensuring that we only store any particular constraint once.
381- fn add_constraint ( & mut self , constraint : ScopedConstraintId , copy : u8 ) -> Atom {
382- Atom :: from ( constraint) . copy_of ( copy)
383- }
384-
385335 /// Adds an interior node, ensuring that we always use the same visibility constraint ID for
386336 /// equal nodes.
387337 fn add_interior ( & mut self , node : InteriorNode ) -> ScopedVisibilityConstraintId {
@@ -397,17 +347,23 @@ impl VisibilityConstraintsBuilder {
397347 . or_insert_with ( || self . interiors . push ( node) )
398348 }
399349
400- /// Adds a new visibility constraint that checks a single [`Constraint`]. Provide different
401- /// values for `copy` if you need to model that the constraint can evaluate to different
402- /// results at different points in the execution of the program being modeled.
350+ /// Adds a new visibility constraint that checks a single [`Constraint`].
351+ ///
352+ /// [`ScopedConstraintId`]s are the “variables” that are evaluated by a TDD. A TDD variable has
353+ /// the same value no matter how many times it appears in the ternary formula that the TDD
354+ /// represents.
355+ ///
356+ /// However, we sometimes have to model how a `Constraint` can have a different runtime
357+ /// value at different points in the execution of the program. To handle this, you can take
358+ /// advantage of the fact that the [`Constraints`] arena does not deduplicate `Constraint`s.
359+ /// You can add a `Constraint` multiple times, yielding different `ScopeConstraintId`s, which
360+ /// you can then create separate TDD atoms for.
403361 pub ( crate ) fn add_atom (
404362 & mut self ,
405363 constraint : ScopedConstraintId ,
406- copy : u8 ,
407364 ) -> ScopedVisibilityConstraintId {
408- let atom = self . add_constraint ( constraint, copy) ;
409365 self . add_interior ( InteriorNode {
410- atom,
366+ atom : constraint ,
411367 if_true : ALWAYS_TRUE ,
412368 if_ambiguous : AMBIGUOUS ,
413369 if_false : ALWAYS_FALSE ,
@@ -592,8 +548,7 @@ impl VisibilityConstraints {
592548 ALWAYS_FALSE => return Truthiness :: AlwaysFalse ,
593549 _ => self . interiors [ id] ,
594550 } ;
595- let ( constraint_id, _) = node. atom . into_index_and_copy ( ) ;
596- let constraint = & constraints[ constraint_id] ;
551+ let constraint = & constraints[ node. atom ] ;
597552 match Self :: analyze_single ( db, constraint) {
598553 Truthiness :: AlwaysTrue => id = node. if_true ,
599554 Truthiness :: Ambiguous => id = node. if_ambiguous ,
0 commit comments