mirror of https://github.com/astral-sh/ruff
Change error conditions
This commit is contained in:
parent
99655b54c3
commit
d1ceb75960
|
|
@ -362,6 +362,45 @@ def _(x: Sequence[int], y: object):
|
|||
reveal_type(item) # revealed: int
|
||||
```
|
||||
|
||||
## Intersection where some elements are not iterable
|
||||
|
||||
When iterating over an intersection type, we should only fail if all positive elements fail to
|
||||
iterate. If some elements are iterable and some are not, we should iterate over the iterable ones
|
||||
and intersect their element types.
|
||||
|
||||
```py
|
||||
from ty_extensions import Intersection
|
||||
|
||||
class NotIterable:
|
||||
pass
|
||||
|
||||
def _(x: Intersection[list[int], NotIterable]):
|
||||
# `list[int]` is iterable (yielding `int`), but `NotIterable` is not.
|
||||
# We should still be able to iterate over the intersection.
|
||||
for item in x:
|
||||
reveal_type(item) # revealed: int
|
||||
```
|
||||
|
||||
## Intersection where all elements are not iterable
|
||||
|
||||
When iterating over an intersection type where all positive elements are not iterable, we should
|
||||
fail to iterate.
|
||||
|
||||
```py
|
||||
from ty_extensions import Intersection
|
||||
|
||||
class NotIterable1:
|
||||
pass
|
||||
|
||||
class NotIterable2:
|
||||
pass
|
||||
|
||||
def _(x: Intersection[NotIterable1, NotIterable2]):
|
||||
# error: [not-iterable]
|
||||
for item in x:
|
||||
reveal_type(item) # revealed: Unknown
|
||||
```
|
||||
|
||||
## Possibly-not-callable `__iter__` method
|
||||
|
||||
```py
|
||||
|
|
|
|||
|
|
@ -6615,11 +6615,19 @@ impl<'db> Type<'db> {
|
|||
Type::Intersection(intersection) => {
|
||||
// For intersections, we iterate over each positive element and intersect
|
||||
// the resulting element types. Negative elements don't affect iteration.
|
||||
let mut elements_iter = intersection.positive_elements_or_object(db);
|
||||
let first_element_spec = elements_iter.next()?.try_iterate_with_mode(db, EvaluationMode::Sync).ok()?;
|
||||
let mut builder = TupleSpecBuilder::from(&*first_element_spec);
|
||||
for element in elements_iter {
|
||||
builder = builder.intersect(db, &*element.try_iterate_with_mode(db, EvaluationMode::Sync).ok()?);
|
||||
// We only fail if all elements fail to iterate; as long as at least one
|
||||
// element can be iterated over, we can produce a result.
|
||||
let mut specs_iter = intersection
|
||||
.positive_elements_or_object(db)
|
||||
.filter_map(|element| {
|
||||
element
|
||||
.try_iterate_with_mode(db, EvaluationMode::Sync)
|
||||
.ok()
|
||||
});
|
||||
let first_spec = specs_iter.next()?;
|
||||
let mut builder = TupleSpecBuilder::from(&*first_spec);
|
||||
for spec in specs_iter {
|
||||
builder = builder.intersect(db, &spec);
|
||||
}
|
||||
Some(Cow::Owned(builder.build()))
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue