store inferable in constraint set

This commit is contained in:
Douglas Creager
2025-11-07 16:09:04 -05:00
parent a1a3953cac
commit b033a42ced
4 changed files with 48 additions and 22 deletions

View File

@@ -1627,12 +1627,11 @@ impl<'db> Type<'db> {
db: &'db dyn Db,
target: Type<'db>,
constraints: ConstraintSet<'db>,
inferable: InferableTypeVars<'db>,
) -> ConstraintSet<'db> {
self.has_relation_to(
db,
target,
inferable,
constraints.inferable,
TypeRelation::ConstraintImplication(constraints),
)
}

View File

@@ -1142,7 +1142,13 @@ impl<'db> Bindings<'db> {
else {
return;
};
let constraints = ConstraintSet::range(db, *lower, *typevar, *upper);
let constraints = ConstraintSet::range(
db,
*lower,
*typevar,
*upper,
InferableTypeVars::none(),
);
let tracked = TrackedConstraintSet::new(db, constraints);
overload.set_return_type(Type::KnownInstance(
KnownInstanceType::ConstraintSet(tracked),
@@ -1178,12 +1184,7 @@ impl<'db> Bindings<'db> {
continue;
};
let result = ty_a.when_subtype_of_given(
db,
*ty_b,
tracked.constraints(db),
InferableTypeVars::none(),
);
let result = ty_a.when_subtype_of_given(db, *ty_b, tracked.constraints(db));
let tracked = TrackedConstraintSet::new(db, result);
overload.set_return_type(Type::KnownInstance(
KnownInstanceType::ConstraintSet(tracked),
@@ -1241,7 +1242,8 @@ impl<'db> Bindings<'db> {
let result = tracked
.constraints(db)
.satisfied_by_all_typevars(db, inferable);
.with_inferable(inferable)
.satisfied_by_all_typevars(db);
overload.set_return_type(Type::BooleanLiteral(result));
}

View File

@@ -164,18 +164,23 @@ where
pub struct ConstraintSet<'db> {
/// The BDD representing this constraint set
node: Node<'db>,
/// The typevars that were inferable when constructing this constraint set
pub(crate) inferable: InferableTypeVars<'db>,
}
impl<'db> ConstraintSet<'db> {
fn never() -> Self {
Self {
node: Node::AlwaysFalse,
inferable: InferableTypeVars::none(),
}
}
fn always() -> Self {
Self {
node: Node::AlwaysTrue,
inferable: InferableTypeVars::none(),
}
}
@@ -185,6 +190,7 @@ impl<'db> ConstraintSet<'db> {
typevar: BoundTypeVarInstance<'db>,
lower: Type<'db>,
upper: Type<'db>,
inferable: InferableTypeVars<'db>,
relation: TypeRelation<'db>,
) -> Self {
let (lower, upper) = match relation {
@@ -202,6 +208,14 @@ impl<'db> ConstraintSet<'db> {
Self {
node: ConstrainedTypeVar::new_node(db, typevar, lower, upper),
inferable,
}
}
pub(crate) fn with_inferable(self, inferable: InferableTypeVars<'db>) -> Self {
Self {
node: self.node,
inferable,
}
}
@@ -226,6 +240,7 @@ impl<'db> ConstraintSet<'db> {
) -> Self {
Self {
node: self.node.when_subtype_of_given(db, lhs, rhs),
inferable: self.inferable,
}
}
@@ -243,22 +258,20 @@ impl<'db> ConstraintSet<'db> {
/// since the constraint set cannot be affected by any typevars that it does not mention. That
/// means that those additional typevars trivially satisfy the constraint set, regardless of
/// whether they are inferable or not.
pub(crate) fn satisfied_by_all_typevars(
self,
db: &'db dyn Db,
inferable: InferableTypeVars<'db>,
) -> bool {
self.node.satisfied_by_all_typevars(db, inferable)
pub(crate) fn satisfied_by_all_typevars(self, db: &'db dyn Db) -> bool {
self.node.satisfied_by_all_typevars(db, self.inferable)
}
/// Updates this constraint set to hold the union of itself and another constraint set.
pub(crate) fn union(&mut self, db: &'db dyn Db, other: Self) -> Self {
debug_assert!(self.inferable == other.inferable);
self.node = self.node.or(db, other.node);
*self
}
/// Updates this constraint set to hold the intersection of itself and another constraint set.
pub(crate) fn intersect(&mut self, db: &'db dyn Db, other: Self) -> Self {
debug_assert!(self.inferable == other.inferable);
self.node = self.node.and(db, other.node);
*self
}
@@ -267,6 +280,7 @@ impl<'db> ConstraintSet<'db> {
pub(crate) fn negate(self, db: &'db dyn Db) -> Self {
Self {
node: self.node.negate(db),
inferable: self.inferable,
}
}
@@ -296,8 +310,10 @@ impl<'db> ConstraintSet<'db> {
}
pub(crate) fn iff(self, db: &'db dyn Db, other: Self) -> Self {
debug_assert!(self.inferable == other.inferable);
ConstraintSet {
node: self.node.iff(db, other.node),
inferable: self.inferable,
}
}
@@ -306,8 +322,16 @@ impl<'db> ConstraintSet<'db> {
lower: Type<'db>,
typevar: BoundTypeVarInstance<'db>,
upper: Type<'db>,
inferable: InferableTypeVars<'db>,
) -> Self {
Self::constrain_typevar(db, typevar, lower, upper, TypeRelation::Assignability)
Self::constrain_typevar(
db,
typevar,
lower,
upper,
inferable,
TypeRelation::Assignability,
)
}
pub(crate) fn display(self, db: &'db dyn Db) -> impl Display {
@@ -2106,10 +2130,10 @@ mod tests {
let u = BoundTypeVarInstance::synthetic(&db, "U", TypeVarVariance::Invariant);
let bool_type = KnownClass::Bool.to_instance(&db);
let str_type = KnownClass::Str.to_instance(&db);
let t_str = ConstraintSet::range(&db, str_type, t, str_type);
let t_bool = ConstraintSet::range(&db, bool_type, t, bool_type);
let u_str = ConstraintSet::range(&db, str_type, u, str_type);
let u_bool = ConstraintSet::range(&db, bool_type, u, bool_type);
let t_str = ConstraintSet::range(&db, str_type, t, str_type, InferableTypeVars::none());
let t_bool = ConstraintSet::range(&db, bool_type, t, bool_type, InferableTypeVars::none());
let u_str = ConstraintSet::range(&db, str_type, u, str_type, InferableTypeVars::none());
let u_bool = ConstraintSet::range(&db, bool_type, u, bool_type, InferableTypeVars::none());
let constraints = (t_str.or(&db, || t_bool)).and(&db, || u_str.or(&db, || u_bool));
let actual = constraints.node.display_graph(&db, &"").to_string();
assert_eq!(actual, expected);

View File

@@ -119,7 +119,7 @@ pub(crate) fn typing_self<'db>(
.map(Type::TypeVar)
}
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, get_size2::GetSize, salsa::Update)]
pub(crate) struct InferableTypeVars<'db> {
inner: Option<InferableTypeVarsInner<'db>>,
}
@@ -167,6 +167,7 @@ impl<'db> InferableTypeVars<'db> {
(None, None) => self,
(Some(_), None) => self,
(None, Some(_)) => other,
(Some(self_inner), Some(other_inner)) if self_inner == other_inner => self,
(Some(self_inner), Some(other_inner)) => InferableTypeVars {
inner: Some(self_inner.merge(db, other_inner)),
},