Skip to content

Commit 7b2ac83

Browse files
committed
[ty] Generalize union-type subtyping fast path
1 parent 880513a commit 7b2ac83

2 files changed

Lines changed: 10 additions & 9 deletions

File tree

crates/ty_python_semantic/src/types.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1833,7 +1833,7 @@ impl<'db> Type<'db> {
18331833
///
18341834
/// This method may have false negatives, but it should not have false positives. It should be
18351835
/// a cheap shallow check, not an exhaustive recursive check.
1836-
fn subtyping_is_always_reflexive(self) -> bool {
1836+
const fn subtyping_is_always_reflexive(self) -> bool {
18371837
match self {
18381838
Type::Never
18391839
| Type::FunctionLiteral(..)
@@ -1854,6 +1854,7 @@ impl<'db> Type<'db> {
18541854
| Type::AlwaysFalsy
18551855
| Type::AlwaysTruthy
18561856
| Type::PropertyInstance(_)
1857+
| Type::TypeVar(_)
18571858
// might inherit `Any`, but subtyping is still reflexive
18581859
| Type::ClassLiteral(_)
18591860
=> true,
@@ -1865,7 +1866,6 @@ impl<'db> Type<'db> {
18651866
| Type::Union(_)
18661867
| Type::Intersection(_)
18671868
| Type::Callable(_)
1868-
| Type::TypeVar(_)
18691869
| Type::BoundSuper(_)
18701870
| Type::TypeIs(_)
18711871
| Type::TypeGuard(_)

crates/ty_python_semantic/src/types/relation.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -467,23 +467,24 @@ impl<'db> Type<'db> {
467467
//
468468
// However, there is one exception to this general rule: for any given typevar `T`,
469469
// `T` will always be a subtype of any union containing `T`.
470-
(Type::TypeVar(bound_typevar), Type::Union(union))
471-
if !bound_typevar.is_inferable(db, inferable)
470+
(_, Type::Union(union))
471+
if (!relation.is_subtyping() || self.subtyping_is_always_reflexive())
472472
&& union.elements(db).contains(&self) =>
473473
{
474474
ConstraintSet::from(true)
475475
}
476476

477477
// A similar rule applies in reverse to intersection types.
478-
(Type::Intersection(intersection), Type::TypeVar(bound_typevar))
479-
if !bound_typevar.is_inferable(db, inferable)
478+
(Type::Intersection(intersection), _)
479+
if (!relation.is_subtyping() || target.subtyping_is_always_reflexive())
480480
&& intersection.positive(db).contains(&target) =>
481481
{
482482
ConstraintSet::from(true)
483483
}
484-
(Type::Intersection(intersection), Type::TypeVar(bound_typevar))
485-
if !bound_typevar.is_inferable(db, inferable)
486-
&& intersection.negative(db).contains(&target) =>
484+
(Type::Intersection(intersection), _)
485+
if (!relation.is_subtyping() || target.subtyping_is_always_reflexive())
486+
&& intersection.negative(db).contains(&target)
487+
&& !intersection.positive(db).iter().any(Type::is_dynamic) =>
487488
{
488489
ConstraintSet::from(false)
489490
}

0 commit comments

Comments
 (0)