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
|
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
|
## Possibly-not-callable `__iter__` method
|
||||||
|
|
||||||
```py
|
```py
|
||||||
|
|
|
||||||
|
|
@ -6615,11 +6615,19 @@ impl<'db> Type<'db> {
|
||||||
Type::Intersection(intersection) => {
|
Type::Intersection(intersection) => {
|
||||||
// For intersections, we iterate over each positive element and intersect
|
// For intersections, we iterate over each positive element and intersect
|
||||||
// the resulting element types. Negative elements don't affect iteration.
|
// the resulting element types. Negative elements don't affect iteration.
|
||||||
let mut elements_iter = intersection.positive_elements_or_object(db);
|
// We only fail if all elements fail to iterate; as long as at least one
|
||||||
let first_element_spec = elements_iter.next()?.try_iterate_with_mode(db, EvaluationMode::Sync).ok()?;
|
// element can be iterated over, we can produce a result.
|
||||||
let mut builder = TupleSpecBuilder::from(&*first_element_spec);
|
let mut specs_iter = intersection
|
||||||
for element in elements_iter {
|
.positive_elements_or_object(db)
|
||||||
builder = builder.intersect(db, &*element.try_iterate_with_mode(db, EvaluationMode::Sync).ok()?);
|
.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()))
|
Some(Cow::Owned(builder.build()))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue