mirror of
https://github.com/astral-sh/ruff.git
synced 2025-11-18 11:41:21 +00:00
fix typeguard overriding logic
This commit is contained in:
parent
69e84b055c
commit
01b4b96047
2 changed files with 42 additions and 5 deletions
|
|
@ -359,7 +359,33 @@ def narrowed_type_must_be_exact(a: object, b: Baz):
|
||||||
reveal_type(a) # revealed: Foo
|
reveal_type(a) # revealed: Foo
|
||||||
```
|
```
|
||||||
|
|
||||||
## Complex boolean logic with TypeGuard and TypeIs
|
## TypeGuard overrides normal constraints
|
||||||
|
|
||||||
|
TypeGuard constraints override any previous narrowing, but additional "regular" constraints can be
|
||||||
|
added on to TypeGuard constraints.
|
||||||
|
|
||||||
|
```py
|
||||||
|
from typing_extensions import TypeGuard, TypeIs
|
||||||
|
|
||||||
|
class A: ...
|
||||||
|
class B: ...
|
||||||
|
class C: ...
|
||||||
|
|
||||||
|
def f(x: object) -> TypeGuard[A]:
|
||||||
|
return True
|
||||||
|
|
||||||
|
def g(x: object) -> TypeGuard[B]:
|
||||||
|
return True
|
||||||
|
|
||||||
|
def h(x: object) -> TypeIs[C]:
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _(x: object):
|
||||||
|
if f(x) and g(x) and h(x):
|
||||||
|
reveal_type(x) # revealed: B & C
|
||||||
|
```
|
||||||
|
|
||||||
|
## Boolean logic with TypeGuard and TypeIs
|
||||||
|
|
||||||
TypeGuard constraints need to properly distribute through boolean operations.
|
TypeGuard constraints need to properly distribute through boolean operations.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -313,8 +313,16 @@ impl<'db> Conjunction<'db> {
|
||||||
/// Evaluate this conjunction to a single type.
|
/// Evaluate this conjunction to a single type.
|
||||||
/// If there's a `TypeGuard` constraint, it replaces the regular constraint.
|
/// If there's a `TypeGuard` constraint, it replaces the regular constraint.
|
||||||
/// Otherwise, returns the regular constraint.
|
/// Otherwise, returns the regular constraint.
|
||||||
fn evaluate_type_constraint(self) -> Type<'db> {
|
fn evaluate_type_constraint(self, db: &'db dyn Db) -> Type<'db> {
|
||||||
self.typeguard.unwrap_or(self.constraint)
|
self.typeguard.map_or_else(
|
||||||
|
|| self.constraint,
|
||||||
|
|typeguard_constraint| {
|
||||||
|
IntersectionBuilder::new(db)
|
||||||
|
.add_positive(typeguard_constraint)
|
||||||
|
.add_positive(self.constraint)
|
||||||
|
.build()
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -363,7 +371,7 @@ impl<'db> NarrowingConstraint<'db> {
|
||||||
db,
|
db,
|
||||||
self.disjuncts
|
self.disjuncts
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(Conjunction::evaluate_type_constraint),
|
.map(|disjunct| Conjunction::evaluate_type_constraint(disjunct, db)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1214,7 +1222,10 @@ impl<'db, 'ast> NarrowingConstraintsBuilder<'db, 'ast> {
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(InternalConstraints::from_iter([(place, NarrowingConstraint::regular(narrowed_type))]))
|
Some(InternalConstraints::from_iter([(
|
||||||
|
place,
|
||||||
|
NarrowingConstraint::regular(narrowed_type),
|
||||||
|
)]))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn evaluate_match_pattern_value(
|
fn evaluate_match_pattern_value(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue