Skip to content

Commit dbecc68

Browse files
committed
it works!
1 parent 333e98f commit dbecc68

File tree

3 files changed

+78
-19
lines changed

3 files changed

+78
-19
lines changed

crates/ty_python_semantic/src/types/constraints.rs

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,10 @@ impl<'db> ConstraintSet<'db> {
409409
Self { node }
410410
}
411411

412+
pub(crate) fn for_each_path(self, db: &'db dyn Db, f: impl FnMut(&PathAssignments<'db>)) {
413+
self.node.for_each_path(db, f);
414+
}
415+
412416
pub(crate) fn range(
413417
db: &'db dyn Db,
414418
lower: Type<'db>,
@@ -448,9 +452,9 @@ impl<'db> BoundTypeVarInstance<'db> {
448452
/// lower and upper bound.
449453
#[salsa::interned(debug, heap_size=ruff_memory_usage::heap_size)]
450454
pub(crate) struct ConstrainedTypeVar<'db> {
451-
typevar: BoundTypeVarInstance<'db>,
452-
lower: Type<'db>,
453-
upper: Type<'db>,
455+
pub(crate) typevar: BoundTypeVarInstance<'db>,
456+
pub(crate) lower: Type<'db>,
457+
pub(crate) upper: Type<'db>,
454458
}
455459

456460
// The Salsa heap is tracked separately.
@@ -659,7 +663,7 @@ impl<'db> ConstrainedTypeVar<'db> {
659663
Some(Self::new(db, self.typevar(db), lower, upper))
660664
}
661665

662-
fn display(self, db: &'db dyn Db) -> impl Display {
666+
pub(crate) fn display(self, db: &'db dyn Db) -> impl Display {
663667
self.display_inner(db, false)
664668
}
665669

@@ -825,6 +829,40 @@ impl<'db> Node<'db> {
825829
}
826830
}
827831

832+
fn for_each_path(self, db: &'db dyn Db, mut f: impl FnMut(&PathAssignments<'db>)) {
833+
match self {
834+
Node::AlwaysTrue => {}
835+
Node::AlwaysFalse => {}
836+
Node::Interior(interior) => {
837+
let map = interior.sequent_map(db);
838+
let mut path = PathAssignments::default();
839+
self.for_each_path_inner(db, &mut f, map, &mut path);
840+
}
841+
}
842+
}
843+
844+
fn for_each_path_inner(
845+
self,
846+
db: &'db dyn Db,
847+
f: &mut dyn FnMut(&PathAssignments<'db>),
848+
map: &SequentMap<'db>,
849+
path: &mut PathAssignments<'db>,
850+
) {
851+
match self {
852+
Node::AlwaysTrue => f(path),
853+
Node::AlwaysFalse => {}
854+
Node::Interior(interior) => {
855+
let constraint = interior.constraint(db);
856+
path.walk_edge(map, constraint.when_true(), |path, _| {
857+
interior.if_true(db).for_each_path_inner(db, f, map, path);
858+
});
859+
path.walk_edge(map, constraint.when_false(), |path, _| {
860+
interior.if_false(db).for_each_path_inner(db, f, map, path);
861+
});
862+
}
863+
}
864+
}
865+
828866
/// Returns whether this BDD represent the constant function `true`.
829867
fn is_always_satisfied(self, db: &'db dyn Db) -> bool {
830868
match self {
@@ -2147,7 +2185,7 @@ fn sequent_map_cycle_initial<'db>(
21472185
/// An assignment of one BDD variable to either `true` or `false`. (When evaluating a BDD, we
21482186
/// must provide an assignment for each variable present in the BDD.)
21492187
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
2150-
enum ConstraintAssignment<'db> {
2188+
pub(crate) enum ConstraintAssignment<'db> {
21512189
Positive(ConstrainedTypeVar<'db>),
21522190
Negative(ConstrainedTypeVar<'db>),
21532191
}
@@ -2227,7 +2265,7 @@ impl<'db> ConstraintAssignment<'db> {
22272265
// Keep this for future debugging needs, even though it's not currently used when rendering
22282266
// constraint sets.
22292267
#[expect(dead_code)]
2230-
fn display(self, db: &'db dyn Db) -> impl Display {
2268+
pub(crate) fn display(self, db: &'db dyn Db) -> impl Display {
22312269
struct DisplayConstraintAssignment<'db> {
22322270
constraint: ConstraintAssignment<'db>,
22332271
db: &'db dyn Db,
@@ -2694,7 +2732,7 @@ impl<'db> SequentMap<'db> {
26942732
/// The collection of constraints that we know to be true or false at a certain point when
26952733
/// traversing a BDD.
26962734
#[derive(Debug, Default)]
2697-
struct PathAssignments<'db> {
2735+
pub(crate) struct PathAssignments<'db> {
26982736
assignments: FxOrderSet<ConstraintAssignment<'db>>,
26992737
}
27002738

@@ -2753,6 +2791,17 @@ impl<'db> PathAssignments<'db> {
27532791
result
27542792
}
27552793

2794+
pub(crate) fn positive_constraints(
2795+
&self,
2796+
) -> impl Iterator<Item = ConstrainedTypeVar<'db>> + '_ {
2797+
self.assignments
2798+
.iter()
2799+
.filter_map(|assignment| match assignment {
2800+
ConstraintAssignment::Positive(constraint) => Some(*constraint),
2801+
ConstraintAssignment::Negative(_) => None,
2802+
})
2803+
}
2804+
27562805
fn assignment_holds(&self, assignment: ConstraintAssignment<'db>) -> bool {
27572806
self.assignments.contains(&assignment)
27582807
}

crates/ty_python_semantic/src/types/generics.rs

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1390,7 +1390,7 @@ impl<'db> SpecializationBuilder<'db> {
13901390
.map(|(identity, _)| self.types.get(identity).copied());
13911391

13921392
// TODO Infer the tuple spec for a tuple type
1393-
generic_context.specialize_partial(self.db, types)
1393+
generic_context.specialize_recursive(self.db, types)
13941394
}
13951395

13961396
fn add_type_mapping(
@@ -1682,20 +1682,24 @@ impl<'db> SpecializationBuilder<'db> {
16821682
actual_signature,
16831683
self.inferable,
16841684
);
1685-
for formal_signature in &formal_callable.signatures(self.db).overloads {
1686-
for actual_signature in &actual_callable.signatures(self.db).overloads {
1687-
if let Some(formal_return_ty) = formal_signature.return_ty
1688-
&& let Some(actual_return_ty) = actual_signature.return_ty
1689-
{
1690-
self.infer_map_impl(
1691-
formal_return_ty,
1692-
actual_return_ty,
1685+
when.for_each_path(self.db, |path| {
1686+
for constraint in path.positive_constraints() {
1687+
let typevar = constraint.typevar(self.db);
1688+
let lower = constraint.lower(self.db);
1689+
let upper = constraint.upper(self.db);
1690+
if !upper.is_object() {
1691+
self.add_type_mapping(typevar, upper, polarity, &mut f);
1692+
}
1693+
if let Type::TypeVar(lower_bound_typevar) = lower {
1694+
self.add_type_mapping(
1695+
lower_bound_typevar,
1696+
Type::TypeVar(typevar),
16931697
polarity,
16941698
&mut f,
1695-
)?;
1699+
);
16961700
}
16971701
}
1698-
}
1702+
});
16991703
}
17001704

17011705
// TODO: Add more forms that we can structurally induct into: type[C], callables

crates/ty_python_semantic/src/types/signatures.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -965,7 +965,13 @@ impl<'db> Signature<'db> {
965965
// If either of the parameter lists is gradual (`...`), then it is assignable to and from
966966
// any other parameter list, but not a subtype or supertype of any other parameter list.
967967
if self.parameters.is_gradual() || other.parameters.is_gradual() {
968-
return ConstraintSet::from(relation.is_assignability());
968+
result.intersect(
969+
db,
970+
ConstraintSet::from(
971+
relation.is_assignability() || relation.is_constraint_set_assignability(),
972+
),
973+
);
974+
return result;
969975
}
970976

971977
let mut parameters = ParametersZip {

0 commit comments

Comments
 (0)