mirror of https://github.com/astral-sh/ruff
[ty] Avoid expression reinference for diagnostics (#21267)
## Summary We now use the type context for a lot of things, so re-inferring without type context actually makes diagnostics more confusing (in most cases).
This commit is contained in:
parent
4628180fac
commit
294f863523
|
|
@ -222,10 +222,10 @@ reveal_type(r) # revealed: dict[int | str, int | str]
|
||||||
## Incorrect collection literal assignments are complained about
|
## Incorrect collection literal assignments are complained about
|
||||||
|
|
||||||
```py
|
```py
|
||||||
# error: [invalid-assignment] "Object of type `list[Unknown | int]` is not assignable to `list[str]`"
|
# error: [invalid-assignment] "Object of type `list[str | int]` is not assignable to `list[str]`"
|
||||||
a: list[str] = [1, 2, 3]
|
a: list[str] = [1, 2, 3]
|
||||||
|
|
||||||
# error: [invalid-assignment] "Object of type `set[Unknown | int | str]` is not assignable to `set[int]`"
|
# error: [invalid-assignment] "Object of type `set[int | str]` is not assignable to `set[int]`"
|
||||||
b: set[int] = {1, 2, "3"}
|
b: set[int] = {1, 2, "3"}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -422,7 +422,7 @@ reveal_type(d) # revealed: list[int | tuple[int, int]]
|
||||||
e: list[int] = f(True)
|
e: list[int] = f(True)
|
||||||
reveal_type(e) # revealed: list[int]
|
reveal_type(e) # revealed: list[int]
|
||||||
|
|
||||||
# error: [invalid-assignment] "Object of type `list[str]` is not assignable to `list[int]`"
|
# error: [invalid-assignment] "Object of type `list[int | str]` is not assignable to `list[int]`"
|
||||||
g: list[int] = f("a")
|
g: list[int] = f("a")
|
||||||
|
|
||||||
# error: [invalid-assignment] "Object of type `list[str]` is not assignable to `tuple[int]`"
|
# error: [invalid-assignment] "Object of type `list[str]` is not assignable to `tuple[int]`"
|
||||||
|
|
@ -459,12 +459,12 @@ reveal_type(b) # revealed: TD
|
||||||
|
|
||||||
# error: [missing-typed-dict-key] "Missing required key 'x' in TypedDict `TD` constructor"
|
# error: [missing-typed-dict-key] "Missing required key 'x' in TypedDict `TD` constructor"
|
||||||
# error: [invalid-key] "Unknown key "y" for TypedDict `TD`"
|
# error: [invalid-key] "Unknown key "y" for TypedDict `TD`"
|
||||||
# error: [invalid-assignment] "Object of type `Unknown | dict[Unknown | str, Unknown | int]` is not assignable to `TD`"
|
# error: [invalid-assignment] "Object of type `TD | dict[Unknown | str, Unknown | int]` is not assignable to `TD`"
|
||||||
c: TD = f([{"y": 0}, {"x": 1}])
|
c: TD = f([{"y": 0}, {"x": 1}])
|
||||||
|
|
||||||
# error: [missing-typed-dict-key] "Missing required key 'x' in TypedDict `TD` constructor"
|
# error: [missing-typed-dict-key] "Missing required key 'x' in TypedDict `TD` constructor"
|
||||||
# error: [invalid-key] "Unknown key "y" for TypedDict `TD`"
|
# error: [invalid-key] "Unknown key "y" for TypedDict `TD`"
|
||||||
# error: [invalid-assignment] "Object of type `Unknown | dict[Unknown | str, Unknown | int]` is not assignable to `TD | None`"
|
# error: [invalid-assignment] "Object of type `TD | None | dict[Unknown | str, Unknown | int]` is not assignable to `TD | None`"
|
||||||
c: TD | None = f([{"y": 0}, {"x": 1}])
|
c: TD | None = f([{"y": 0}, {"x": 1}])
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -268,8 +268,8 @@ class A:
|
||||||
|
|
||||||
A(f(1))
|
A(f(1))
|
||||||
|
|
||||||
# error: [invalid-argument-type] "Argument to function `__new__` is incorrect: Expected `list[int | str]`, found `list[list[Unknown]]`"
|
# error: [invalid-argument-type] "Argument to function `__new__` is incorrect: Expected `list[int | str]`, found `list[int | None | list[Unknown]] & list[int | str | list[Unknown]] & list[list[Unknown]]`"
|
||||||
# error: [invalid-argument-type] "Argument to bound method `__init__` is incorrect: Expected `list[int | None]`, found `list[list[Unknown]]`"
|
# error: [invalid-argument-type] "Argument to bound method `__init__` is incorrect: Expected `list[int | None]`, found `list[int | None | list[Unknown]] & list[int | str | list[Unknown]] & list[list[Unknown]]`"
|
||||||
A(f([]))
|
A(f([]))
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ type("Foo", Base, {})
|
||||||
# error: [invalid-argument-type] "Argument to class `type` is incorrect: Expected `tuple[type, ...]`, found `tuple[Literal[1], Literal[2]]`"
|
# error: [invalid-argument-type] "Argument to class `type` is incorrect: Expected `tuple[type, ...]`, found `tuple[Literal[1], Literal[2]]`"
|
||||||
type("Foo", (1, 2), {})
|
type("Foo", (1, 2), {})
|
||||||
|
|
||||||
# error: [invalid-argument-type] "Argument to class `type` is incorrect: Expected `dict[str, Any]`, found `dict[Unknown | bytes, Unknown | int]`"
|
# error: [invalid-argument-type] "Argument to class `type` is incorrect: Expected `dict[str, Any]`, found `dict[str | bytes, Any]`"
|
||||||
type("Foo", (Base,), {b"attr": 1})
|
type("Foo", (Base,), {b"attr": 1})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -277,6 +277,6 @@ def _(flag: bool):
|
||||||
x = f({"x": 1})
|
x = f({"x": 1})
|
||||||
reveal_type(x) # revealed: int
|
reveal_type(x) # revealed: int
|
||||||
|
|
||||||
# error: [invalid-argument-type] "Argument to function `f` is incorrect: Expected `T`, found `dict[Unknown | str, Unknown | int]`"
|
# error: [invalid-argument-type] "Argument to function `f` is incorrect: Expected `T`, found `dict[str, int] & dict[Unknown | str, Unknown | int]`"
|
||||||
f({"y": 1})
|
f({"y": 1})
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -273,7 +273,7 @@ class C(Generic[T]):
|
||||||
|
|
||||||
reveal_type(C(1)) # revealed: C[int]
|
reveal_type(C(1)) # revealed: C[int]
|
||||||
|
|
||||||
# error: [invalid-assignment] "Object of type `C[str]` is not assignable to `C[int]`"
|
# error: [invalid-assignment] "Object of type `C[int | str]` is not assignable to `C[int]`"
|
||||||
wrong_innards: C[int] = C("five")
|
wrong_innards: C[int] = C("five")
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -289,7 +289,7 @@ class C(Generic[T]):
|
||||||
|
|
||||||
reveal_type(C(1)) # revealed: C[int]
|
reveal_type(C(1)) # revealed: C[int]
|
||||||
|
|
||||||
# error: [invalid-assignment] "Object of type `C[str]` is not assignable to `C[int]`"
|
# error: [invalid-assignment] "Object of type `C[int | str]` is not assignable to `C[int]`"
|
||||||
wrong_innards: C[int] = C("five")
|
wrong_innards: C[int] = C("five")
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -308,7 +308,7 @@ class C(Generic[T]):
|
||||||
|
|
||||||
reveal_type(C(1)) # revealed: C[int]
|
reveal_type(C(1)) # revealed: C[int]
|
||||||
|
|
||||||
# error: [invalid-assignment] "Object of type `C[str]` is not assignable to `C[int]`"
|
# error: [invalid-assignment] "Object of type `C[int | str]` is not assignable to `C[int]`"
|
||||||
wrong_innards: C[int] = C("five")
|
wrong_innards: C[int] = C("five")
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -327,7 +327,7 @@ class C(Generic[T]):
|
||||||
|
|
||||||
reveal_type(C(1)) # revealed: C[int]
|
reveal_type(C(1)) # revealed: C[int]
|
||||||
|
|
||||||
# error: [invalid-assignment] "Object of type `C[str]` is not assignable to `C[int]`"
|
# error: [invalid-assignment] "Object of type `C[int | str]` is not assignable to `C[int]`"
|
||||||
wrong_innards: C[int] = C("five")
|
wrong_innards: C[int] = C("five")
|
||||||
|
|
||||||
class D(Generic[T]):
|
class D(Generic[T]):
|
||||||
|
|
@ -338,7 +338,7 @@ class D(Generic[T]):
|
||||||
|
|
||||||
reveal_type(D(1)) # revealed: D[int]
|
reveal_type(D(1)) # revealed: D[int]
|
||||||
|
|
||||||
# error: [invalid-assignment] "Object of type `D[str]` is not assignable to `D[int]`"
|
# error: [invalid-assignment] "Object of type `D[int | str]` is not assignable to `D[int]`"
|
||||||
wrong_innards: D[int] = D("five")
|
wrong_innards: D[int] = D("five")
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -454,7 +454,7 @@ reveal_type(C(1, 1)) # revealed: C[int]
|
||||||
reveal_type(C(1, "string")) # revealed: C[int]
|
reveal_type(C(1, "string")) # revealed: C[int]
|
||||||
reveal_type(C(1, True)) # revealed: C[int]
|
reveal_type(C(1, True)) # revealed: C[int]
|
||||||
|
|
||||||
# error: [invalid-assignment] "Object of type `C[str]` is not assignable to `C[int]`"
|
# error: [invalid-assignment] "Object of type `C[int | str]` is not assignable to `C[int]`"
|
||||||
wrong_innards: C[int] = C("five", 1)
|
wrong_innards: C[int] = C("five", 1)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -249,7 +249,7 @@ class C[T]:
|
||||||
|
|
||||||
reveal_type(C(1)) # revealed: C[int]
|
reveal_type(C(1)) # revealed: C[int]
|
||||||
|
|
||||||
# error: [invalid-assignment] "Object of type `C[str]` is not assignable to `C[int]`"
|
# error: [invalid-assignment] "Object of type `C[int | str]` is not assignable to `C[int]`"
|
||||||
wrong_innards: C[int] = C("five")
|
wrong_innards: C[int] = C("five")
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -263,7 +263,7 @@ class C[T]:
|
||||||
|
|
||||||
reveal_type(C(1)) # revealed: C[int]
|
reveal_type(C(1)) # revealed: C[int]
|
||||||
|
|
||||||
# error: [invalid-assignment] "Object of type `C[str]` is not assignable to `C[int]`"
|
# error: [invalid-assignment] "Object of type `C[int | str]` is not assignable to `C[int]`"
|
||||||
wrong_innards: C[int] = C("five")
|
wrong_innards: C[int] = C("five")
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -280,7 +280,7 @@ class C[T]:
|
||||||
|
|
||||||
reveal_type(C(1)) # revealed: C[int]
|
reveal_type(C(1)) # revealed: C[int]
|
||||||
|
|
||||||
# error: [invalid-assignment] "Object of type `C[str]` is not assignable to `C[int]`"
|
# error: [invalid-assignment] "Object of type `C[int | str]` is not assignable to `C[int]`"
|
||||||
wrong_innards: C[int] = C("five")
|
wrong_innards: C[int] = C("five")
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -297,7 +297,7 @@ class C[T]:
|
||||||
|
|
||||||
reveal_type(C(1)) # revealed: C[int]
|
reveal_type(C(1)) # revealed: C[int]
|
||||||
|
|
||||||
# error: [invalid-assignment] "Object of type `C[str]` is not assignable to `C[int]`"
|
# error: [invalid-assignment] "Object of type `C[int | str]` is not assignable to `C[int]`"
|
||||||
wrong_innards: C[int] = C("five")
|
wrong_innards: C[int] = C("five")
|
||||||
|
|
||||||
class D[T]:
|
class D[T]:
|
||||||
|
|
@ -310,7 +310,7 @@ class D[T]:
|
||||||
|
|
||||||
reveal_type(D(1)) # revealed: D[int]
|
reveal_type(D(1)) # revealed: D[int]
|
||||||
|
|
||||||
# error: [invalid-assignment] "Object of type `D[str]` is not assignable to `D[int]`"
|
# error: [invalid-assignment] "Object of type `D[int | str]` is not assignable to `D[int]`"
|
||||||
wrong_innards: D[int] = D("five")
|
wrong_innards: D[int] = D("five")
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -395,7 +395,7 @@ reveal_type(C(1, 1)) # revealed: C[int]
|
||||||
reveal_type(C(1, "string")) # revealed: C[int]
|
reveal_type(C(1, "string")) # revealed: C[int]
|
||||||
reveal_type(C(1, True)) # revealed: C[int]
|
reveal_type(C(1, True)) # revealed: C[int]
|
||||||
|
|
||||||
# error: [invalid-assignment] "Object of type `C[str]` is not assignable to `C[int]`"
|
# error: [invalid-assignment] "Object of type `C[int | str]` is not assignable to `C[int]`"
|
||||||
wrong_innards: C[int] = C("five", 1)
|
wrong_innards: C[int] = C("five", 1)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,13 +23,13 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/invalid_assi
|
||||||
# Diagnostics
|
# Diagnostics
|
||||||
|
|
||||||
```
|
```
|
||||||
error[invalid-assignment]: Object of type `tuple[Literal["a"], Literal["b"]]` is not assignable to `int`
|
error[invalid-assignment]: Object of type `Literal["a"]` is not assignable to `int`
|
||||||
--> src/mdtest_snippet.py:4:1
|
--> src/mdtest_snippet.py:4:1
|
||||||
|
|
|
|
||||||
2 | y: str
|
2 | y: str
|
||||||
3 |
|
3 |
|
||||||
4 | x, y = ("a", "b") # error: [invalid-assignment]
|
4 | x, y = ("a", "b") # error: [invalid-assignment]
|
||||||
| - ^^^^^^^^^^ Incompatible value of type `tuple[Literal["a"], Literal["b"]]`
|
| - ^^^^^^^^^^ Incompatible value of type `Literal["a"]`
|
||||||
| |
|
| |
|
||||||
| Declared type `int`
|
| Declared type `int`
|
||||||
5 |
|
5 |
|
||||||
|
|
@ -40,13 +40,13 @@ info: rule `invalid-assignment` is enabled by default
|
||||||
```
|
```
|
||||||
|
|
||||||
```
|
```
|
||||||
error[invalid-assignment]: Object of type `tuple[Literal[0], Literal[0]]` is not assignable to `str`
|
error[invalid-assignment]: Object of type `Literal[0]` is not assignable to `str`
|
||||||
--> src/mdtest_snippet.py:6:4
|
--> src/mdtest_snippet.py:6:4
|
||||||
|
|
|
|
||||||
4 | x, y = ("a", "b") # error: [invalid-assignment]
|
4 | x, y = ("a", "b") # error: [invalid-assignment]
|
||||||
5 |
|
5 |
|
||||||
6 | x, y = (0, 0) # error: [invalid-assignment]
|
6 | x, y = (0, 0) # error: [invalid-assignment]
|
||||||
| - ^^^^^^ Incompatible value of type `tuple[Literal[0], Literal[0]]`
|
| - ^^^^^^ Incompatible value of type `Literal[0]`
|
||||||
| |
|
| |
|
||||||
| Declared type `str`
|
| Declared type `str`
|
||||||
|
|
|
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,7 @@ pub(crate) use self::diagnostic::register_lints;
|
||||||
pub use self::diagnostic::{TypeCheckDiagnostics, UNDEFINED_REVEAL};
|
pub use self::diagnostic::{TypeCheckDiagnostics, UNDEFINED_REVEAL};
|
||||||
pub(crate) use self::infer::{
|
pub(crate) use self::infer::{
|
||||||
TypeContext, infer_deferred_types, infer_definition_types, infer_expression_type,
|
TypeContext, infer_deferred_types, infer_definition_types, infer_expression_type,
|
||||||
infer_expression_types, infer_isolated_expression, infer_scope_types,
|
infer_expression_types, infer_scope_types, static_expression_truthiness,
|
||||||
static_expression_truthiness,
|
|
||||||
};
|
};
|
||||||
pub(crate) use self::signatures::{CallableSignature, Parameter, Parameters, Signature};
|
pub(crate) use self::signatures::{CallableSignature, Parameter, Parameters, Signature};
|
||||||
pub(crate) use self::subclass_of::{SubclassOfInner, SubclassOfType};
|
pub(crate) use self::subclass_of::{SubclassOfInner, SubclassOfType};
|
||||||
|
|
@ -1369,14 +1368,13 @@ impl<'db> Type<'db> {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Avoid literal promotion if it leads to an unassignable type.
|
// Avoid literal promotion if it leads to an unassignable type.
|
||||||
if tcx
|
if tcx.annotation.is_some_and(|annotation| {
|
||||||
.annotation
|
self.is_assignable_to(db, annotation) && !promoted.is_assignable_to(db, annotation)
|
||||||
.is_none_or(|annotation| promoted.is_assignable_to(db, annotation))
|
}) {
|
||||||
{
|
return self;
|
||||||
return promoted;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self
|
promoted
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a "normalized" version of `self` that ensures that equivalent types have the same Salsa ID.
|
/// Return a "normalized" version of `self` that ensures that equivalent types have the same Salsa ID.
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ use crate::types::{
|
||||||
DataclassParams, FieldInstance, KnownBoundMethodType, KnownClass, KnownInstanceType,
|
DataclassParams, FieldInstance, KnownBoundMethodType, KnownClass, KnownInstanceType,
|
||||||
MemberLookupPolicy, NominalInstanceType, PropertyInstanceType, SpecialFormType,
|
MemberLookupPolicy, NominalInstanceType, PropertyInstanceType, SpecialFormType,
|
||||||
TrackedConstraintSet, TypeAliasType, TypeContext, TypeVarVariance, UnionBuilder, UnionType,
|
TrackedConstraintSet, TypeAliasType, TypeContext, TypeVarVariance, UnionBuilder, UnionType,
|
||||||
WrapperDescriptorKind, enums, ide_support, infer_isolated_expression, todo_type,
|
WrapperDescriptorKind, enums, ide_support, todo_type,
|
||||||
};
|
};
|
||||||
use ruff_db::diagnostic::{Annotation, Diagnostic, SubDiagnostic, SubDiagnosticSeverity};
|
use ruff_db::diagnostic::{Annotation, Diagnostic, SubDiagnostic, SubDiagnosticSeverity};
|
||||||
use ruff_python_ast::{self as ast, ArgOrKeyword, PythonVersion};
|
use ruff_python_ast::{self as ast, ArgOrKeyword, PythonVersion};
|
||||||
|
|
@ -3800,23 +3800,6 @@ impl<'db> BindingError<'db> {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Re-infer the argument type of call expressions, ignoring the type context for more
|
|
||||||
// precise error messages.
|
|
||||||
let provided_ty = match Self::get_argument_node(node, *argument_index) {
|
|
||||||
None => *provided_ty,
|
|
||||||
|
|
||||||
// Ignore starred arguments, as those are difficult to re-infer.
|
|
||||||
Some(
|
|
||||||
ast::ArgOrKeyword::Arg(ast::Expr::Starred(_))
|
|
||||||
| ast::ArgOrKeyword::Keyword(ast::Keyword { arg: None, .. }),
|
|
||||||
) => *provided_ty,
|
|
||||||
|
|
||||||
Some(
|
|
||||||
ast::ArgOrKeyword::Arg(value)
|
|
||||||
| ast::ArgOrKeyword::Keyword(ast::Keyword { value, .. }),
|
|
||||||
) => infer_isolated_expression(context.db(), context.scope(), value),
|
|
||||||
};
|
|
||||||
|
|
||||||
let provided_ty_display = provided_ty.display(context.db());
|
let provided_ty_display = provided_ty.display(context.db());
|
||||||
let expected_ty_display = expected_ty.display(context.db());
|
let expected_ty_display = expected_ty.display(context.db());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ use crate::types::string_annotation::{
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
BoundTypeVarInstance, ClassType, DynamicType, LintDiagnosticGuard, Protocol,
|
BoundTypeVarInstance, ClassType, DynamicType, LintDiagnosticGuard, Protocol,
|
||||||
ProtocolInstanceType, SpecialFormType, SubclassOfInner, Type, TypeContext, binding_type,
|
ProtocolInstanceType, SpecialFormType, SubclassOfInner, Type, TypeContext, binding_type,
|
||||||
infer_isolated_expression, protocol_class::ProtocolClass,
|
protocol_class::ProtocolClass,
|
||||||
};
|
};
|
||||||
use crate::types::{KnownInstanceType, MemberLookupPolicy};
|
use crate::types::{KnownInstanceType, MemberLookupPolicy};
|
||||||
use crate::{Db, DisplaySettings, FxIndexMap, Module, ModuleName, Program, declare_lint};
|
use crate::{Db, DisplaySettings, FxIndexMap, Module, ModuleName, Program, declare_lint};
|
||||||
|
|
@ -2190,7 +2190,7 @@ pub(super) fn report_invalid_assignment<'db>(
|
||||||
target_node: AnyNodeRef,
|
target_node: AnyNodeRef,
|
||||||
definition: Definition<'db>,
|
definition: Definition<'db>,
|
||||||
target_ty: Type,
|
target_ty: Type,
|
||||||
mut value_ty: Type<'db>,
|
value_ty: Type<'db>,
|
||||||
) {
|
) {
|
||||||
let definition_kind = definition.kind(context.db());
|
let definition_kind = definition.kind(context.db());
|
||||||
let value_node = match definition_kind {
|
let value_node = match definition_kind {
|
||||||
|
|
@ -2209,13 +2209,6 @@ pub(super) fn report_invalid_assignment<'db>(
|
||||||
let settings =
|
let settings =
|
||||||
DisplaySettings::from_possibly_ambiguous_type_pair(context.db(), target_ty, value_ty);
|
DisplaySettings::from_possibly_ambiguous_type_pair(context.db(), target_ty, value_ty);
|
||||||
|
|
||||||
if let Some(value_node) = value_node {
|
|
||||||
// Re-infer the RHS of the annotated assignment, ignoring the type context for more precise
|
|
||||||
// error messages.
|
|
||||||
value_ty =
|
|
||||||
infer_isolated_expression(context.db(), definition.scope(context.db()), value_node);
|
|
||||||
}
|
|
||||||
|
|
||||||
let diagnostic_range = if let Some(value_node) = value_node {
|
let diagnostic_range = if let Some(value_node) = value_node {
|
||||||
// Expand the range to include parentheses around the value, if any. This allows
|
// Expand the range to include parentheses around the value, if any. This allows
|
||||||
// invalid-assignment diagnostics to be suppressed on the opening or closing parenthesis:
|
// invalid-assignment diagnostics to be suppressed on the opening or closing parenthesis:
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,6 @@
|
||||||
//! be considered a bug.)
|
//! be considered a bug.)
|
||||||
|
|
||||||
use ruff_db::parsed::{ParsedModuleRef, parsed_module};
|
use ruff_db::parsed::{ParsedModuleRef, parsed_module};
|
||||||
use ruff_python_ast as ast;
|
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
use salsa;
|
use salsa;
|
||||||
|
|
@ -206,24 +205,6 @@ fn infer_expression_types_impl<'db>(
|
||||||
.finish_expression()
|
.finish_expression()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Infer the type of an expression in isolation.
|
|
||||||
///
|
|
||||||
/// The type returned by this function may be different than the type of the expression
|
|
||||||
/// if it was inferred within its region, as it does not account for surrounding type context.
|
|
||||||
/// This can be useful to re-infer the type of an expression for diagnostics.
|
|
||||||
pub(crate) fn infer_isolated_expression<'db>(
|
|
||||||
db: &'db dyn Db,
|
|
||||||
scope: ScopeId<'db>,
|
|
||||||
expr: &ast::Expr,
|
|
||||||
) -> Type<'db> {
|
|
||||||
let file = scope.file(db);
|
|
||||||
let module = parsed_module(db, file).load(db);
|
|
||||||
let index = semantic_index(db, file);
|
|
||||||
|
|
||||||
TypeInferenceBuilder::new(db, InferenceRegion::Scope(scope), index, &module)
|
|
||||||
.infer_isolated_expression(expr)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn expression_cycle_recover<'db>(
|
fn expression_cycle_recover<'db>(
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
cycle: &salsa::Cycle,
|
cycle: &salsa::Cycle,
|
||||||
|
|
|
||||||
|
|
@ -11703,13 +11703,6 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Infer the type of the given expression in isolation, ignoring the surrounding region.
|
|
||||||
pub(super) fn infer_isolated_expression(mut self, expr: &ast::Expr) -> Type<'db> {
|
|
||||||
let expr_ty = self.infer_expression_impl(expr, TypeContext::default());
|
|
||||||
let _ = self.context.finish();
|
|
||||||
expr_ty
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn finish_expression(mut self) -> ExpressionInference<'db> {
|
pub(super) fn finish_expression(mut self) -> ExpressionInference<'db> {
|
||||||
self.infer_region();
|
self.infer_region();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue