mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-30 05:44:56 +00:00
[ty] Fix incorrect diagnostic when calling __setitem__
(#19645)
## Summary Resolves https://github.com/astral-sh/ty/issues/862 by not emitting a diagnostic. ## Test Plan Add test to show we don't emit the diagnostic
This commit is contained in:
parent
7b4103bcb6
commit
4739bc8d14
3 changed files with 35 additions and 19 deletions
|
@ -253,7 +253,6 @@ does["not"]["exist"] = 0
|
|||
reveal_type(does["not"]["exist"]) # revealed: Unknown
|
||||
|
||||
non_subscriptable = 1
|
||||
# error: [non-subscriptable]
|
||||
non_subscriptable[0] = 0
|
||||
# error: [non-subscriptable]
|
||||
reveal_type(non_subscriptable[0]) # revealed: Unknown
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Instance subscript
|
||||
|
||||
## Getitem unbound
|
||||
## `__getitem__` unbound
|
||||
|
||||
```py
|
||||
class NotSubscriptable: ...
|
||||
|
@ -8,7 +8,7 @@ class NotSubscriptable: ...
|
|||
a = NotSubscriptable()[0] # error: "Cannot subscript object of type `NotSubscriptable` with no `__getitem__` method"
|
||||
```
|
||||
|
||||
## Getitem not callable
|
||||
## `__getitem__` not callable
|
||||
|
||||
```py
|
||||
class NotSubscriptable:
|
||||
|
@ -18,7 +18,7 @@ class NotSubscriptable:
|
|||
a = NotSubscriptable()[0]
|
||||
```
|
||||
|
||||
## Valid getitem
|
||||
## Valid `__getitem__`
|
||||
|
||||
```py
|
||||
class Identity:
|
||||
|
@ -28,7 +28,7 @@ class Identity:
|
|||
reveal_type(Identity()[0]) # revealed: int
|
||||
```
|
||||
|
||||
## Getitem union
|
||||
## `__getitem__` union
|
||||
|
||||
```py
|
||||
def _(flag: bool):
|
||||
|
@ -42,3 +42,14 @@ def _(flag: bool):
|
|||
|
||||
reveal_type(Identity()[0]) # revealed: int | str
|
||||
```
|
||||
|
||||
## `__setitem__` with no `__getitem__`
|
||||
|
||||
```py
|
||||
class NoGetitem:
|
||||
def __setitem__(self, index: int, value: int) -> None:
|
||||
pass
|
||||
|
||||
a = NoGetitem()
|
||||
a[0] = 0
|
||||
```
|
||||
|
|
|
@ -1900,13 +1900,14 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
} else if let AnyNodeRef::ExprSubscript(ast::ExprSubscript {
|
||||
value,
|
||||
slice,
|
||||
ctx,
|
||||
..
|
||||
}) = node
|
||||
{
|
||||
let value_ty = self.infer_expression(value);
|
||||
let slice_ty = self.infer_expression(slice);
|
||||
let result_ty =
|
||||
self.infer_subscript_expression_types(value, value_ty, slice_ty);
|
||||
let result_ty = self
|
||||
.infer_subscript_expression_types(value, value_ty, slice_ty, *ctx);
|
||||
return (result_ty, is_modifiable);
|
||||
}
|
||||
}
|
||||
|
@ -8291,7 +8292,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
ExprContext::Store => {
|
||||
let value_ty = self.infer_expression(value);
|
||||
let slice_ty = self.infer_expression(slice);
|
||||
self.infer_subscript_expression_types(value, value_ty, slice_ty);
|
||||
self.infer_subscript_expression_types(value, value_ty, slice_ty, *ctx);
|
||||
Type::Never
|
||||
}
|
||||
ExprContext::Del => {
|
||||
|
@ -8301,7 +8302,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
ExprContext::Invalid => {
|
||||
let value_ty = self.infer_expression(value);
|
||||
let slice_ty = self.infer_expression(slice);
|
||||
self.infer_subscript_expression_types(value, value_ty, slice_ty);
|
||||
self.infer_subscript_expression_types(value, value_ty, slice_ty, *ctx);
|
||||
Type::unknown()
|
||||
}
|
||||
}
|
||||
|
@ -8313,7 +8314,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
node_index: _,
|
||||
value,
|
||||
slice,
|
||||
ctx: _,
|
||||
ctx,
|
||||
} = subscript;
|
||||
let value_ty = self.infer_expression(value);
|
||||
let mut constraint_keys = vec![];
|
||||
|
@ -8330,7 +8331,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
// Even if we can obtain the subscript type based on the assignments, we still perform default type inference
|
||||
// (to store the expression type and to report errors).
|
||||
let slice_ty = self.infer_expression(slice);
|
||||
self.infer_subscript_expression_types(value, value_ty, slice_ty);
|
||||
self.infer_subscript_expression_types(value, value_ty, slice_ty, *ctx);
|
||||
return ty;
|
||||
}
|
||||
}
|
||||
|
@ -8364,7 +8365,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
}
|
||||
|
||||
let slice_ty = self.infer_expression(slice);
|
||||
let result_ty = self.infer_subscript_expression_types(value, value_ty, slice_ty);
|
||||
let result_ty = self.infer_subscript_expression_types(value, value_ty, slice_ty, *ctx);
|
||||
self.narrow_expr_with_applicable_constraints(subscript, result_ty, &constraint_keys)
|
||||
}
|
||||
|
||||
|
@ -8418,6 +8419,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
value_node: &ast::Expr,
|
||||
value_ty: Type<'db>,
|
||||
slice_ty: Type<'db>,
|
||||
expr_context: ExprContext,
|
||||
) -> Type<'db> {
|
||||
match (value_ty, slice_ty, slice_ty.slice_literal(self.db())) {
|
||||
(Type::NominalInstance(instance), _, _)
|
||||
|
@ -8427,11 +8429,12 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
value_node,
|
||||
Type::version_info_tuple(self.db()),
|
||||
slice_ty,
|
||||
expr_context,
|
||||
)
|
||||
}
|
||||
|
||||
(Type::Union(union), _, _) => union.map(self.db(), |element| {
|
||||
self.infer_subscript_expression_types(value_node, *element, slice_ty)
|
||||
self.infer_subscript_expression_types(value_node, *element, slice_ty, expr_context)
|
||||
}),
|
||||
|
||||
// TODO: we can map over the intersection and fold the results back into an intersection,
|
||||
|
@ -8562,6 +8565,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
value_node,
|
||||
value_ty,
|
||||
Type::IntLiteral(i64::from(bool)),
|
||||
expr_context,
|
||||
),
|
||||
|
||||
(Type::SpecialForm(SpecialFormType::Protocol), Type::Tuple(typevars), _) => {
|
||||
|
@ -8754,12 +8758,14 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
);
|
||||
}
|
||||
} else {
|
||||
report_non_subscriptable(
|
||||
&self.context,
|
||||
value_node.into(),
|
||||
value_ty,
|
||||
"__getitem__",
|
||||
);
|
||||
if expr_context != ExprContext::Store {
|
||||
report_non_subscriptable(
|
||||
&self.context,
|
||||
value_node.into(),
|
||||
value_ty,
|
||||
"__getitem__",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Type::unknown()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue