Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
b644025
add constraint sets
dcreager Aug 19, 2025
3dea816
use constraint sets instead of bool everywhere!
dcreager Aug 19, 2025
650655b
negative constraints
dcreager Aug 20, 2025
a5fa906
simplify IntersectionResult
dcreager Aug 20, 2025
d9ff400
new clause might subsume more than one existing
dcreager Aug 20, 2025
f95056a
add some nice ascii art
dcreager Aug 21, 2025
ae2bf01
call binding is "ever assignable", not "always"!
dcreager Aug 25, 2025
f06c0f6
display impl for constraint sets
dcreager Aug 25, 2025
6eee16c
simplify constraint subsumes
dcreager Aug 25, 2025
cba0393
IntersectionResult → Simplified
dcreager Aug 25, 2025
443e05d
rework union_clause
dcreager Aug 25, 2025
7a92ea8
sort clause constraints by typevar
dcreager Aug 25, 2025
7e8b1da
simplify clauses via union
dcreager Aug 26, 2025
b6861d6
better docs
dcreager Aug 27, 2025
5fb66c2
simpler representation of atomic constraints
dcreager Aug 26, 2025
494301f
open equivalent is never too
dcreager Aug 27, 2025
cbdbbec
always saturates
dcreager Aug 27, 2025
251edee
subtype not assignable
dcreager Aug 27, 2025
a4adc53
these can't be Two
dcreager Aug 27, 2025
70c9792
hey that's not rust
dcreager Aug 27, 2025
a683142
docs
dcreager Aug 27, 2025
fce1bb6
simplify intersect_clause
dcreager Aug 27, 2025
8437cd9
document clause simplification
dcreager Aug 27, 2025
a33ae0c
more docs
dcreager Aug 28, 2025
90045ce
document Satisfiable and Simplified
dcreager Aug 28, 2025
ab61385
more commentary on call binding
dcreager Aug 28, 2025
9399e2f
fix doc links
dcreager Aug 28, 2025
6a7f2c6
grr clippy
dcreager Aug 28, 2025
34d49fc
you've gotta be f--in kidding me
dcreager Aug 28, 2025
29c07a8
reword this comment
dcreager Aug 28, 2025
8a85909
Apply suggestions from code review
dcreager Aug 28, 2025
d1d4545
revert one const
dcreager Aug 28, 2025
a49e14d
reflow
dcreager Aug 28, 2025
b6e42a0
no Copy for AtomicConstraints
dcreager Aug 28, 2025
b24d95d
document smallvec choices
dcreager Aug 28, 2025
6124350
Merge branch 'main' into dcreager/dummy-constraint-sets
dcreager Aug 28, 2025
80a6b61
expect not allow dead code
dcreager Aug 28, 2025
dac9742
clarify docs about rendering constraints
dcreager Aug 28, 2025
c36e1ee
better doc comment
dcreager Aug 28, 2025
aa84703
add python example
dcreager Aug 28, 2025
6be181c
add python examples for union simplification
dcreager Aug 28, 2025
b66e3ab
Apply suggestions from code review
dcreager Aug 28, 2025
b37f939
consider one-pass subsumption check
dcreager Aug 28, 2025
5257624
types are partially ordered
dcreager Aug 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 19 additions & 5 deletions crates/ty_python_semantic/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ use crate::suppression::check_suppressions;
use crate::types::call::{Binding, Bindings, CallArguments, CallableBinding};
pub(crate) use crate::types::class_base::ClassBase;
use crate::types::constraints::{
Constraints, IteratorConstraintsExtension, OptionConstraintsExtension,
ConstraintSet, Constraints, IteratorConstraintsExtension, OptionConstraintsExtension,
};
use crate::types::context::{LintDiagnosticGuard, LintDiagnosticGuardBuilder};
use crate::types::diagnostic::{INVALID_AWAIT, INVALID_TYPE_FORM, UNSUPPORTED_BOOL_CONVERSION};
Expand Down Expand Up @@ -1360,7 +1360,8 @@ impl<'db> Type<'db> {
/// intersection simplification dependent on the order in which elements are added), so we do
/// not use this more general definition of subtyping.
pub(crate) fn is_subtype_of(self, db: &'db dyn Db, target: Type<'db>) -> bool {
self.when_subtype_of(db, target)
self.when_subtype_of::<ConstraintSet>(db, target)
.is_always_satisfied(db)
}

fn when_subtype_of<C: Constraints<'db>>(self, db: &'db dyn Db, target: Type<'db>) -> C {
Expand All @@ -1371,7 +1372,8 @@ impl<'db> Type<'db> {
///
/// [assignable to]: https://typing.python.org/en/latest/spec/concepts.html#the-assignable-to-or-consistent-subtyping-relation
pub(crate) fn is_assignable_to(self, db: &'db dyn Db, target: Type<'db>) -> bool {
self.when_assignable_to(db, target)
self.when_assignable_to::<ConstraintSet>(db, target)
.is_always_satisfied(db)
}

fn when_assignable_to<C: Constraints<'db>>(self, db: &'db dyn Db, target: Type<'db>) -> C {
Expand Down Expand Up @@ -1849,7 +1851,8 @@ impl<'db> Type<'db> {
///
/// [equivalent to]: https://typing.python.org/en/latest/spec/glossary.html#term-equivalent
pub(crate) fn is_equivalent_to(self, db: &'db dyn Db, other: Type<'db>) -> bool {
self.when_equivalent_to(db, other)
self.when_equivalent_to::<ConstraintSet>(db, other)
.is_always_satisfied(db)
}

fn when_equivalent_to<C: Constraints<'db>>(self, db: &'db dyn Db, other: Type<'db>) -> C {
Expand Down Expand Up @@ -1949,7 +1952,8 @@ impl<'db> Type<'db> {
/// Note: This function aims to have no false positives, but might return
/// wrong `false` answers in some cases.
pub(crate) fn is_disjoint_from(self, db: &'db dyn Db, other: Type<'db>) -> bool {
self.when_disjoint_from(db, other)
self.when_disjoint_from::<ConstraintSet>(db, other)
.is_always_satisfied(db)
}

fn when_disjoint_from<C: Constraints<'db>>(self, db: &'db dyn Db, other: Type<'db>) -> C {
Expand Down Expand Up @@ -9703,6 +9707,16 @@ pub(super) fn walk_intersection_type<'db, V: visitor::TypeVisitor<'db> + ?Sized>
}

impl<'db> IntersectionType<'db> {
pub(crate) fn from_elements<I, T>(db: &'db dyn Db, elements: I) -> Type<'db>
where
I: IntoIterator<Item = T>,
T: Into<Type<'db>>,
{
IntersectionBuilder::new(db)
.positive_elements(elements)
.build()
}

/// Return a new `IntersectionType` instance with the positive and negative types sorted
/// according to a canonical ordering, and other normalizations applied to each element as applicable.
///
Expand Down
12 changes: 11 additions & 1 deletion crates/ty_python_semantic/src/types/call/bind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use crate::db::Db;
use crate::dunder_all::dunder_all_names;
use crate::place::{Boundness, Place};
use crate::types::call::arguments::{Expansion, is_expandable_type};
use crate::types::constraints::{ConstraintSet, Constraints};
use crate::types::diagnostic::{
CALL_NON_CALLABLE, CONFLICTING_ARGUMENT_FORMS, INVALID_ARGUMENT_TYPE, MISSING_ARGUMENT,
NO_MATCHING_OVERLOAD, PARAMETER_ALREADY_ASSIGNED, TOO_MANY_POSITIONAL_ARGUMENTS,
Expand Down Expand Up @@ -2198,7 +2199,16 @@ impl<'a, 'db> ArgumentTypeChecker<'a, 'db> {
argument_type.apply_specialization(self.db, inherited_specialization);
expected_ty = expected_ty.apply_specialization(self.db, inherited_specialization);
}
if !argument_type.is_assignable_to(self.db, expected_ty) {
// This is one of the few places where we want to check if there's _any_ specialization
// where assignability holds; normally we want to check that assignability holds for
// _all_ specializations.
// TODO: Soon we will go further, and build the actual specializations from the
// constraint set that we get from this assignability check, instead of inferring and
// building them in an earlier separate step.
if argument_type
.when_assignable_to::<ConstraintSet>(self.db, expected_ty)
.is_never_satisfied(self.db)
{
let positional = matches!(argument, Argument::Positional | Argument::Synthetic)
&& !parameter.is_variadic();
self.errors.push(BindingError::InvalidArgumentType {
Expand Down
5 changes: 3 additions & 2 deletions crates/ty_python_semantic/src/types/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use crate::semantic_index::{
BindingWithConstraints, DeclarationWithConstraint, SemanticIndex, attribute_declarations,
attribute_scopes,
};
use crate::types::constraints::{Constraints, IteratorConstraintsExtension};
use crate::types::constraints::{ConstraintSet, Constraints, IteratorConstraintsExtension};
use crate::types::context::InferContext;
use crate::types::diagnostic::{INVALID_LEGACY_TYPE_VARIABLE, INVALID_TYPE_ALIAS_TYPE};
use crate::types::enums::enum_metadata;
Expand Down Expand Up @@ -552,7 +552,8 @@ impl<'db> ClassType<'db> {

/// Return `true` if `other` is present in this class's MRO.
pub(super) fn is_subclass_of(self, db: &'db dyn Db, other: ClassType<'db>) -> bool {
self.when_subclass_of(db, other)
self.when_subclass_of::<ConstraintSet>(db, other)
.is_always_satisfied(db)
}

pub(super) fn when_subclass_of<C: Constraints<'db>>(
Expand Down
Loading
Loading