mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-04 02:38:25 +00:00
[ty] Add hints to invalid-type-form
for common mistakes (#18543)
Co-authored-by: Ben Bar-Or <ben.baror@ridewithvia.com> Co-authored-by: Alex Waygood <alex.waygood@gmail.com>
This commit is contained in:
parent
301b9f4135
commit
1dc8f8f903
7 changed files with 462 additions and 74 deletions
|
@ -47,7 +47,7 @@ def _(flag: bool):
|
|||
def _(x: Annotated | bool):
|
||||
reveal_type(x) # revealed: Unknown | bool
|
||||
|
||||
# error: [invalid-type-form]
|
||||
# error: [invalid-type-form] "Special form `typing.Annotated` expected at least 2 arguments (one type and at least one metadata element)"
|
||||
def _(x: Annotated[()]):
|
||||
reveal_type(x) # revealed: Unknown
|
||||
|
||||
|
|
|
@ -116,6 +116,21 @@ def _(c: Callable[
|
|||
reveal_type(c) # revealed: (...) -> Unknown
|
||||
```
|
||||
|
||||
### Tuple as the second argument
|
||||
|
||||
```py
|
||||
from typing import Callable
|
||||
|
||||
# fmt: off
|
||||
|
||||
def _(c: Callable[
|
||||
int, # error: [invalid-type-form] "The first argument to `Callable` must be either a list of types, ParamSpec, Concatenate, or `...`"
|
||||
(str, ) # error: [invalid-type-form] "Tuple literals are not allowed in this context in a type expression"
|
||||
]
|
||||
):
|
||||
reveal_type(c) # revealed: (...) -> Unknown
|
||||
```
|
||||
|
||||
### List as both arguments
|
||||
|
||||
```py
|
||||
|
|
|
@ -95,6 +95,11 @@ async def outer(): # avoid unrelated syntax errors on yield, yield from, and aw
|
|||
|
||||
## Invalid Collection based AST nodes
|
||||
|
||||
```toml
|
||||
[environment]
|
||||
python-version = "3.12"
|
||||
```
|
||||
|
||||
```py
|
||||
def _(
|
||||
a: {1: 2}, # error: [invalid-type-form] "Dict literals are not allowed in type expressions"
|
||||
|
@ -103,7 +108,11 @@ def _(
|
|||
d: [k for k in [1, 2]], # error: [invalid-type-form] "List comprehensions are not allowed in type expressions"
|
||||
e: {k for k in [1, 2]}, # error: [invalid-type-form] "Set comprehensions are not allowed in type expressions"
|
||||
f: (k for k in [1, 2]), # error: [invalid-type-form] "Generator expressions are not allowed in type expressions"
|
||||
g: [int, str], # error: [invalid-type-form] "List literals are not allowed in this context in a type expression"
|
||||
# error: [invalid-type-form] "List literals are not allowed in this context in a type expression: Did you mean `tuple[int, str]`?"
|
||||
g: [int, str],
|
||||
# error: [invalid-type-form] "Tuple literals are not allowed in this context in a type expression: Did you mean `tuple[int, str]`?"
|
||||
h: (int, str),
|
||||
i: (), # error: [invalid-type-form] "Tuple literals are not allowed in this context in a type expression: Did you mean `tuple[()]`?"
|
||||
):
|
||||
reveal_type(a) # revealed: Unknown
|
||||
reveal_type(b) # revealed: Unknown
|
||||
|
@ -112,6 +121,17 @@ def _(
|
|||
reveal_type(e) # revealed: Unknown
|
||||
reveal_type(f) # revealed: Unknown
|
||||
reveal_type(g) # revealed: Unknown
|
||||
reveal_type(h) # revealed: Unknown
|
||||
reveal_type(i) # revealed: Unknown
|
||||
|
||||
# error: [invalid-type-form] "List literals are not allowed in this context in a type expression: Did you mean `list[int]`?"
|
||||
class name_0[name_2: [int]]:
|
||||
pass
|
||||
|
||||
# error: [invalid-type-form] "List literals are not allowed in this context in a type expression"
|
||||
# error: [invalid-type-form] "Dict literals are not allowed in type expressions"
|
||||
class name_4[name_1: [{}]]:
|
||||
pass
|
||||
```
|
||||
|
||||
## Diagnostics for common errors
|
||||
|
@ -145,3 +165,42 @@ from PIL import Image
|
|||
|
||||
def g(x: Image): ... # error: [invalid-type-form]
|
||||
```
|
||||
|
||||
### List-literal used when you meant to use a list or tuple
|
||||
|
||||
```py
|
||||
def _(
|
||||
x: [int], # error: [invalid-type-form]
|
||||
) -> [int]: # error: [invalid-type-form]
|
||||
return x
|
||||
```
|
||||
|
||||
```py
|
||||
def _(
|
||||
x: [int, str], # error: [invalid-type-form]
|
||||
) -> [int, str]: # error: [invalid-type-form]
|
||||
return x
|
||||
```
|
||||
|
||||
### Tuple-literal used when you meant to use a tuple
|
||||
|
||||
```py
|
||||
def _(
|
||||
x: (), # error: [invalid-type-form]
|
||||
) -> (): # error: [invalid-type-form]
|
||||
return x
|
||||
```
|
||||
|
||||
```py
|
||||
def _(
|
||||
x: (int,), # error: [invalid-type-form]
|
||||
) -> (int,): # error: [invalid-type-form]
|
||||
return x
|
||||
```
|
||||
|
||||
```py
|
||||
def _(
|
||||
x: (int, str), # error: [invalid-type-form]
|
||||
) -> (int, str): # error: [invalid-type-form]
|
||||
return x
|
||||
```
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
---
|
||||
source: crates/ty_test/src/lib.rs
|
||||
expression: snapshot
|
||||
---
|
||||
---
|
||||
mdtest name: invalid.md - Tests for invalid types in type expressions - Diagnostics for common errors - List-literal used when you meant to use a list or tuple
|
||||
mdtest path: crates/ty_python_semantic/resources/mdtest/annotations/invalid.md
|
||||
---
|
||||
|
||||
# Python source files
|
||||
|
||||
## mdtest_snippet.py
|
||||
|
||||
```
|
||||
1 | def _(
|
||||
2 | x: [int], # error: [invalid-type-form]
|
||||
3 | ) -> [int]: # error: [invalid-type-form]
|
||||
4 | return x
|
||||
5 | def _(
|
||||
6 | x: [int, str], # error: [invalid-type-form]
|
||||
7 | ) -> [int, str]: # error: [invalid-type-form]
|
||||
8 | return x
|
||||
```
|
||||
|
||||
# Diagnostics
|
||||
|
||||
```
|
||||
error[invalid-type-form]: List literals are not allowed in this context in a type expression
|
||||
--> src/mdtest_snippet.py:2:8
|
||||
|
|
||||
1 | def _(
|
||||
2 | x: [int], # error: [invalid-type-form]
|
||||
| ^^^^^ Did you mean `list[int]`?
|
||||
3 | ) -> [int]: # error: [invalid-type-form]
|
||||
4 | return x
|
||||
|
|
||||
info: See the following page for a reference on valid type expressions:
|
||||
info: https://typing.python.org/en/latest/spec/annotations.html#type-and-annotation-expressions
|
||||
info: rule `invalid-type-form` is enabled by default
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
error[invalid-type-form]: List literals are not allowed in this context in a type expression
|
||||
--> src/mdtest_snippet.py:3:6
|
||||
|
|
||||
1 | def _(
|
||||
2 | x: [int], # error: [invalid-type-form]
|
||||
3 | ) -> [int]: # error: [invalid-type-form]
|
||||
| ^^^^^ Did you mean `list[int]`?
|
||||
4 | return x
|
||||
5 | def _(
|
||||
|
|
||||
info: See the following page for a reference on valid type expressions:
|
||||
info: https://typing.python.org/en/latest/spec/annotations.html#type-and-annotation-expressions
|
||||
info: rule `invalid-type-form` is enabled by default
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
error[invalid-type-form]: List literals are not allowed in this context in a type expression
|
||||
--> src/mdtest_snippet.py:6:8
|
||||
|
|
||||
4 | return x
|
||||
5 | def _(
|
||||
6 | x: [int, str], # error: [invalid-type-form]
|
||||
| ^^^^^^^^^^ Did you mean `tuple[int, str]`?
|
||||
7 | ) -> [int, str]: # error: [invalid-type-form]
|
||||
8 | return x
|
||||
|
|
||||
info: See the following page for a reference on valid type expressions:
|
||||
info: https://typing.python.org/en/latest/spec/annotations.html#type-and-annotation-expressions
|
||||
info: rule `invalid-type-form` is enabled by default
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
error[invalid-type-form]: List literals are not allowed in this context in a type expression
|
||||
--> src/mdtest_snippet.py:7:6
|
||||
|
|
||||
5 | def _(
|
||||
6 | x: [int, str], # error: [invalid-type-form]
|
||||
7 | ) -> [int, str]: # error: [invalid-type-form]
|
||||
| ^^^^^^^^^^ Did you mean `tuple[int, str]`?
|
||||
8 | return x
|
||||
|
|
||||
info: See the following page for a reference on valid type expressions:
|
||||
info: https://typing.python.org/en/latest/spec/annotations.html#type-and-annotation-expressions
|
||||
info: rule `invalid-type-form` is enabled by default
|
||||
|
||||
```
|
|
@ -0,0 +1,129 @@
|
|||
---
|
||||
source: crates/ty_test/src/lib.rs
|
||||
expression: snapshot
|
||||
---
|
||||
---
|
||||
mdtest name: invalid.md - Tests for invalid types in type expressions - Diagnostics for common errors - Tuple-literal used when you meant to use a tuple
|
||||
mdtest path: crates/ty_python_semantic/resources/mdtest/annotations/invalid.md
|
||||
---
|
||||
|
||||
# Python source files
|
||||
|
||||
## mdtest_snippet.py
|
||||
|
||||
```
|
||||
1 | def _(
|
||||
2 | x: (), # error: [invalid-type-form]
|
||||
3 | ) -> (): # error: [invalid-type-form]
|
||||
4 | return x
|
||||
5 | def _(
|
||||
6 | x: (int,), # error: [invalid-type-form]
|
||||
7 | ) -> (int,): # error: [invalid-type-form]
|
||||
8 | return x
|
||||
9 | def _(
|
||||
10 | x: (int, str), # error: [invalid-type-form]
|
||||
11 | ) -> (int, str): # error: [invalid-type-form]
|
||||
12 | return x
|
||||
```
|
||||
|
||||
# Diagnostics
|
||||
|
||||
```
|
||||
error[invalid-type-form]: Tuple literals are not allowed in this context in a type expression
|
||||
--> src/mdtest_snippet.py:2:8
|
||||
|
|
||||
1 | def _(
|
||||
2 | x: (), # error: [invalid-type-form]
|
||||
| ^^ Did you mean `tuple[()]`?
|
||||
3 | ) -> (): # error: [invalid-type-form]
|
||||
4 | return x
|
||||
|
|
||||
info: See the following page for a reference on valid type expressions:
|
||||
info: https://typing.python.org/en/latest/spec/annotations.html#type-and-annotation-expressions
|
||||
info: rule `invalid-type-form` is enabled by default
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
error[invalid-type-form]: Tuple literals are not allowed in this context in a type expression
|
||||
--> src/mdtest_snippet.py:3:6
|
||||
|
|
||||
1 | def _(
|
||||
2 | x: (), # error: [invalid-type-form]
|
||||
3 | ) -> (): # error: [invalid-type-form]
|
||||
| ^^ Did you mean `tuple[()]`?
|
||||
4 | return x
|
||||
5 | def _(
|
||||
|
|
||||
info: See the following page for a reference on valid type expressions:
|
||||
info: https://typing.python.org/en/latest/spec/annotations.html#type-and-annotation-expressions
|
||||
info: rule `invalid-type-form` is enabled by default
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
error[invalid-type-form]: Tuple literals are not allowed in this context in a type expression
|
||||
--> src/mdtest_snippet.py:6:8
|
||||
|
|
||||
4 | return x
|
||||
5 | def _(
|
||||
6 | x: (int,), # error: [invalid-type-form]
|
||||
| ^^^^^^ Did you mean `tuple[int]`?
|
||||
7 | ) -> (int,): # error: [invalid-type-form]
|
||||
8 | return x
|
||||
|
|
||||
info: See the following page for a reference on valid type expressions:
|
||||
info: https://typing.python.org/en/latest/spec/annotations.html#type-and-annotation-expressions
|
||||
info: rule `invalid-type-form` is enabled by default
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
error[invalid-type-form]: Tuple literals are not allowed in this context in a type expression
|
||||
--> src/mdtest_snippet.py:7:6
|
||||
|
|
||||
5 | def _(
|
||||
6 | x: (int,), # error: [invalid-type-form]
|
||||
7 | ) -> (int,): # error: [invalid-type-form]
|
||||
| ^^^^^^ Did you mean `tuple[int]`?
|
||||
8 | return x
|
||||
9 | def _(
|
||||
|
|
||||
info: See the following page for a reference on valid type expressions:
|
||||
info: https://typing.python.org/en/latest/spec/annotations.html#type-and-annotation-expressions
|
||||
info: rule `invalid-type-form` is enabled by default
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
error[invalid-type-form]: Tuple literals are not allowed in this context in a type expression
|
||||
--> src/mdtest_snippet.py:10:8
|
||||
|
|
||||
8 | return x
|
||||
9 | def _(
|
||||
10 | x: (int, str), # error: [invalid-type-form]
|
||||
| ^^^^^^^^^^ Did you mean `tuple[int, str]`?
|
||||
11 | ) -> (int, str): # error: [invalid-type-form]
|
||||
12 | return x
|
||||
|
|
||||
info: See the following page for a reference on valid type expressions:
|
||||
info: https://typing.python.org/en/latest/spec/annotations.html#type-and-annotation-expressions
|
||||
info: rule `invalid-type-form` is enabled by default
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
error[invalid-type-form]: Tuple literals are not allowed in this context in a type expression
|
||||
--> src/mdtest_snippet.py:11:6
|
||||
|
|
||||
9 | def _(
|
||||
10 | x: (int, str), # error: [invalid-type-form]
|
||||
11 | ) -> (int, str): # error: [invalid-type-form]
|
||||
| ^^^^^^^^^^ Did you mean `tuple[int, str]`?
|
||||
12 | return x
|
||||
|
|
||||
info: See the following page for a reference on valid type expressions:
|
||||
info: https://typing.python.org/en/latest/spec/annotations.html#type-and-annotation-expressions
|
||||
info: rule `invalid-type-form` is enabled by default
|
||||
|
||||
```
|
|
@ -1878,11 +1878,14 @@ pub(crate) fn report_invalid_arguments_to_callable(
|
|||
));
|
||||
}
|
||||
|
||||
pub(crate) fn add_type_expression_reference_link(mut diag: LintDiagnosticGuard) {
|
||||
pub(crate) fn add_type_expression_reference_link<'db, 'ctx>(
|
||||
mut diag: LintDiagnosticGuard<'db, 'ctx>,
|
||||
) -> LintDiagnosticGuard<'db, 'ctx> {
|
||||
diag.info("See the following page for a reference on valid type expressions:");
|
||||
diag.info(
|
||||
"https://typing.python.org/en/latest/spec/annotations.html#type-and-annotation-expressions",
|
||||
);
|
||||
diag
|
||||
}
|
||||
|
||||
pub(crate) fn report_runtime_check_against_non_runtime_checkable_protocol(
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
//! the query cycle until a fixed-point is reached. Salsa has a built-in fixed limit on the number
|
||||
//! of iterations, so if we fail to converge, Salsa will eventually panic. (This should of course
|
||||
//! be considered a bug.)
|
||||
|
||||
use itertools::{Either, Itertools};
|
||||
use ruff_db::diagnostic::{Annotation, DiagnosticId, Severity};
|
||||
use ruff_db::files::File;
|
||||
|
@ -95,11 +96,11 @@ use crate::types::unpacker::{UnpackResult, Unpacker};
|
|||
use crate::types::{
|
||||
BareTypeAliasType, CallDunderError, CallableType, ClassLiteral, ClassType, DataclassParams,
|
||||
DynamicType, GenericAlias, IntersectionBuilder, IntersectionType, KnownClass,
|
||||
KnownInstanceType, MemberLookupPolicy, MetaclassCandidate, PEP695TypeAliasType, Parameter,
|
||||
ParameterForm, Parameters, SpecialFormType, StringLiteralType, SubclassOfType, Truthiness,
|
||||
TupleType, Type, TypeAliasType, TypeAndQualifiers, TypeArrayDisplay, TypeQualifiers,
|
||||
TypeVarBoundOrConstraints, TypeVarInstance, TypeVarKind, TypeVarVariance, UnionBuilder,
|
||||
UnionType, binding_type, todo_type,
|
||||
KnownInstanceType, LintDiagnosticGuard, MemberLookupPolicy, MetaclassCandidate,
|
||||
PEP695TypeAliasType, Parameter, ParameterForm, Parameters, SpecialFormType, StringLiteralType,
|
||||
SubclassOfType, Truthiness, TupleType, Type, TypeAliasType, TypeAndQualifiers,
|
||||
TypeArrayDisplay, TypeQualifiers, TypeVarBoundOrConstraints, TypeVarInstance, TypeVarKind,
|
||||
TypeVarVariance, UnionBuilder, UnionType, binding_type, todo_type,
|
||||
};
|
||||
use crate::unpack::{Unpack, UnpackPosition};
|
||||
use crate::util::subscript::{PyIndex, PySlice};
|
||||
|
@ -8308,7 +8309,10 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
self.store_expression_type(slice, inner_annotation_ty.inner_type());
|
||||
inner_annotation_ty
|
||||
} else {
|
||||
self.infer_type_expression(slice);
|
||||
for argument in arguments {
|
||||
self.infer_expression(argument);
|
||||
}
|
||||
self.store_expression_type(slice, Type::unknown());
|
||||
TypeAndQualifiers::unknown()
|
||||
}
|
||||
} else {
|
||||
|
@ -8416,15 +8420,15 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
}
|
||||
|
||||
fn report_invalid_type_expression(
|
||||
&mut self,
|
||||
&self,
|
||||
expression: &ast::Expr,
|
||||
message: std::fmt::Arguments,
|
||||
) -> Type<'db> {
|
||||
if let Some(builder) = self.context.report_lint(&INVALID_TYPE_FORM, expression) {
|
||||
let diag = builder.into_diagnostic(message);
|
||||
diagnostic::add_type_expression_reference_link(diag);
|
||||
}
|
||||
Type::unknown()
|
||||
) -> Option<LintDiagnosticGuard> {
|
||||
self.context
|
||||
.report_lint(&INVALID_TYPE_FORM, expression)
|
||||
.map(|builder| {
|
||||
diagnostic::add_type_expression_reference_link(builder.into_diagnostic(message))
|
||||
})
|
||||
}
|
||||
|
||||
/// Infer the type of a type expression without storing the result.
|
||||
|
@ -8511,56 +8515,126 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
|
||||
// TODO: add a subdiagnostic linking to type-expression grammar
|
||||
// and stating that it is only valid in `typing.Literal[]` or `typing.Annotated[]`
|
||||
ast::Expr::BytesLiteral(_) => self.report_invalid_type_expression(
|
||||
expression,
|
||||
format_args!("Bytes literals are not allowed in this context in a type expression"),
|
||||
),
|
||||
ast::Expr::BytesLiteral(_) => {
|
||||
self.report_invalid_type_expression(
|
||||
expression,
|
||||
format_args!(
|
||||
"Bytes literals are not allowed in this context in a type expression"
|
||||
),
|
||||
);
|
||||
Type::unknown()
|
||||
}
|
||||
|
||||
// TODO: add a subdiagnostic linking to type-expression grammar
|
||||
// and stating that it is only valid in `typing.Literal[]` or `typing.Annotated[]`
|
||||
ast::Expr::NumberLiteral(ast::ExprNumberLiteral {
|
||||
value: ast::Number::Int(_),
|
||||
..
|
||||
}) => self.report_invalid_type_expression(
|
||||
expression,
|
||||
format_args!("Int literals are not allowed in this context in a type expression"),
|
||||
),
|
||||
}) => {
|
||||
self.report_invalid_type_expression(
|
||||
expression,
|
||||
format_args!(
|
||||
"Int literals are not allowed in this context in a type expression"
|
||||
),
|
||||
);
|
||||
|
||||
Type::unknown()
|
||||
}
|
||||
|
||||
ast::Expr::NumberLiteral(ast::ExprNumberLiteral {
|
||||
value: ast::Number::Float(_),
|
||||
..
|
||||
}) => self.report_invalid_type_expression(
|
||||
expression,
|
||||
format_args!("Float literals are not allowed in type expressions"),
|
||||
),
|
||||
}) => {
|
||||
self.report_invalid_type_expression(
|
||||
expression,
|
||||
format_args!("Float literals are not allowed in type expressions"),
|
||||
);
|
||||
Type::unknown()
|
||||
}
|
||||
|
||||
ast::Expr::NumberLiteral(ast::ExprNumberLiteral {
|
||||
value: ast::Number::Complex { .. },
|
||||
..
|
||||
}) => self.report_invalid_type_expression(
|
||||
expression,
|
||||
format_args!("Complex literals are not allowed in type expressions"),
|
||||
),
|
||||
|
||||
// TODO: add a subdiagnostic linking to type-expression grammar
|
||||
// and stating that it is only valid in `typing.Literal[]` or `typing.Annotated[]`
|
||||
ast::Expr::BooleanLiteral(_) => self.report_invalid_type_expression(
|
||||
expression,
|
||||
format_args!(
|
||||
"Boolean literals are not allowed in this context in a type expression"
|
||||
),
|
||||
),
|
||||
|
||||
// TODO: add a subdiagnostic linking to type-expression grammar
|
||||
// and stating that it is only valid as first argument to `typing.Callable[]`
|
||||
ast::Expr::List(list) => {
|
||||
self.infer_list_expression(list);
|
||||
}) => {
|
||||
self.report_invalid_type_expression(
|
||||
expression,
|
||||
format_args!("Complex literals are not allowed in type expressions"),
|
||||
);
|
||||
Type::unknown()
|
||||
}
|
||||
|
||||
ast::Expr::BooleanLiteral(_) => {
|
||||
self.report_invalid_type_expression(
|
||||
expression,
|
||||
format_args!(
|
||||
"Boolean literals are not allowed in this context in a type expression"
|
||||
),
|
||||
);
|
||||
Type::unknown()
|
||||
}
|
||||
|
||||
ast::Expr::List(list) => {
|
||||
let db = self.db();
|
||||
|
||||
let inner_types: Vec<Type<'db>> = list
|
||||
.iter()
|
||||
.map(|element| self.infer_type_expression(element))
|
||||
.collect();
|
||||
|
||||
if let Some(mut diagnostic) = self.report_invalid_type_expression(
|
||||
expression,
|
||||
format_args!(
|
||||
"List literals are not allowed in this context in a type expression"
|
||||
),
|
||||
)
|
||||
) {
|
||||
if !inner_types.iter().any(|ty| {
|
||||
matches!(
|
||||
ty,
|
||||
Type::Dynamic(DynamicType::Todo(_) | DynamicType::Unknown)
|
||||
)
|
||||
}) {
|
||||
let hinted_type = if list.len() == 1 {
|
||||
KnownClass::List.to_specialized_instance(db, inner_types)
|
||||
} else {
|
||||
TupleType::from_elements(db, inner_types)
|
||||
};
|
||||
|
||||
diagnostic.set_primary_message(format_args!(
|
||||
"Did you mean `{}`?",
|
||||
hinted_type.display(self.db()),
|
||||
));
|
||||
}
|
||||
}
|
||||
Type::unknown()
|
||||
}
|
||||
|
||||
ast::Expr::Tuple(tuple) => {
|
||||
let inner_types: Vec<Type<'db>> = tuple
|
||||
.elts
|
||||
.iter()
|
||||
.map(|expr| self.infer_type_expression(expr))
|
||||
.collect();
|
||||
|
||||
if tuple.parenthesized {
|
||||
if let Some(mut diagnostic) = self.report_invalid_type_expression(
|
||||
expression,
|
||||
format_args!(
|
||||
"Tuple literals are not allowed in this context in a type expression"
|
||||
),
|
||||
) {
|
||||
if !inner_types.iter().any(|ty| {
|
||||
matches!(
|
||||
ty,
|
||||
Type::Dynamic(DynamicType::Todo(_) | DynamicType::Unknown)
|
||||
)
|
||||
}) {
|
||||
let hinted_type = TupleType::from_elements(self.db(), inner_types);
|
||||
diagnostic.set_primary_message(format_args!(
|
||||
"Did you mean `{}`?",
|
||||
hinted_type.display(self.db()),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
Type::unknown()
|
||||
}
|
||||
|
||||
ast::Expr::BoolOp(bool_op) => {
|
||||
|
@ -8568,7 +8642,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
self.report_invalid_type_expression(
|
||||
expression,
|
||||
format_args!("Boolean operations are not allowed in type expressions"),
|
||||
)
|
||||
);
|
||||
Type::unknown()
|
||||
}
|
||||
|
||||
ast::Expr::Named(named) => {
|
||||
|
@ -8576,7 +8651,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
self.report_invalid_type_expression(
|
||||
expression,
|
||||
format_args!("Named expressions are not allowed in type expressions"),
|
||||
)
|
||||
);
|
||||
Type::unknown()
|
||||
}
|
||||
|
||||
ast::Expr::UnaryOp(unary) => {
|
||||
|
@ -8584,7 +8660,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
self.report_invalid_type_expression(
|
||||
expression,
|
||||
format_args!("Unary operations are not allowed in type expressions"),
|
||||
)
|
||||
);
|
||||
Type::unknown()
|
||||
}
|
||||
|
||||
ast::Expr::Lambda(lambda_expression) => {
|
||||
|
@ -8592,7 +8669,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
self.report_invalid_type_expression(
|
||||
expression,
|
||||
format_args!("`lambda` expressions are not allowed in type expressions"),
|
||||
)
|
||||
);
|
||||
Type::unknown()
|
||||
}
|
||||
|
||||
ast::Expr::If(if_expression) => {
|
||||
|
@ -8600,7 +8678,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
self.report_invalid_type_expression(
|
||||
expression,
|
||||
format_args!("`if` expressions are not allowed in type expressions"),
|
||||
)
|
||||
);
|
||||
Type::unknown()
|
||||
}
|
||||
|
||||
ast::Expr::Dict(dict) => {
|
||||
|
@ -8608,7 +8687,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
self.report_invalid_type_expression(
|
||||
expression,
|
||||
format_args!("Dict literals are not allowed in type expressions"),
|
||||
)
|
||||
);
|
||||
Type::unknown()
|
||||
}
|
||||
|
||||
ast::Expr::Set(set) => {
|
||||
|
@ -8616,7 +8696,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
self.report_invalid_type_expression(
|
||||
expression,
|
||||
format_args!("Set literals are not allowed in type expressions"),
|
||||
)
|
||||
);
|
||||
Type::unknown()
|
||||
}
|
||||
|
||||
ast::Expr::DictComp(dictcomp) => {
|
||||
|
@ -8624,7 +8705,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
self.report_invalid_type_expression(
|
||||
expression,
|
||||
format_args!("Dict comprehensions are not allowed in type expressions"),
|
||||
)
|
||||
);
|
||||
Type::unknown()
|
||||
}
|
||||
|
||||
ast::Expr::ListComp(listcomp) => {
|
||||
|
@ -8632,7 +8714,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
self.report_invalid_type_expression(
|
||||
expression,
|
||||
format_args!("List comprehensions are not allowed in type expressions"),
|
||||
)
|
||||
);
|
||||
Type::unknown()
|
||||
}
|
||||
|
||||
ast::Expr::SetComp(setcomp) => {
|
||||
|
@ -8640,7 +8723,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
self.report_invalid_type_expression(
|
||||
expression,
|
||||
format_args!("Set comprehensions are not allowed in type expressions"),
|
||||
)
|
||||
);
|
||||
Type::unknown()
|
||||
}
|
||||
|
||||
ast::Expr::Generator(generator) => {
|
||||
|
@ -8648,7 +8732,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
self.report_invalid_type_expression(
|
||||
expression,
|
||||
format_args!("Generator expressions are not allowed in type expressions"),
|
||||
)
|
||||
);
|
||||
Type::unknown()
|
||||
}
|
||||
|
||||
ast::Expr::Await(await_expression) => {
|
||||
|
@ -8656,7 +8741,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
self.report_invalid_type_expression(
|
||||
expression,
|
||||
format_args!("`await` expressions are not allowed in type expressions"),
|
||||
)
|
||||
);
|
||||
Type::unknown()
|
||||
}
|
||||
|
||||
ast::Expr::Yield(yield_expression) => {
|
||||
|
@ -8664,7 +8750,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
self.report_invalid_type_expression(
|
||||
expression,
|
||||
format_args!("`yield` expressions are not allowed in type expressions"),
|
||||
)
|
||||
);
|
||||
Type::unknown()
|
||||
}
|
||||
|
||||
ast::Expr::YieldFrom(yield_from) => {
|
||||
|
@ -8672,7 +8759,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
self.report_invalid_type_expression(
|
||||
expression,
|
||||
format_args!("`yield from` expressions are not allowed in type expressions"),
|
||||
)
|
||||
);
|
||||
Type::unknown()
|
||||
}
|
||||
|
||||
ast::Expr::Compare(compare) => {
|
||||
|
@ -8680,7 +8768,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
self.report_invalid_type_expression(
|
||||
expression,
|
||||
format_args!("Comparison expressions are not allowed in type expressions"),
|
||||
)
|
||||
);
|
||||
Type::unknown()
|
||||
}
|
||||
|
||||
ast::Expr::Call(call_expr) => {
|
||||
|
@ -8688,7 +8777,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
self.report_invalid_type_expression(
|
||||
expression,
|
||||
format_args!("Function calls are not allowed in type expressions"),
|
||||
)
|
||||
);
|
||||
Type::unknown()
|
||||
}
|
||||
|
||||
ast::Expr::FString(fstring) => {
|
||||
|
@ -8696,7 +8786,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
self.report_invalid_type_expression(
|
||||
expression,
|
||||
format_args!("F-strings are not allowed in type expressions"),
|
||||
)
|
||||
);
|
||||
Type::unknown()
|
||||
}
|
||||
|
||||
ast::Expr::TString(tstring) => {
|
||||
|
@ -8704,7 +8795,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
self.report_invalid_type_expression(
|
||||
expression,
|
||||
format_args!("T-strings are not allowed in type expressions"),
|
||||
)
|
||||
);
|
||||
Type::unknown()
|
||||
}
|
||||
|
||||
ast::Expr::Slice(slice) => {
|
||||
|
@ -8712,7 +8804,8 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
self.report_invalid_type_expression(
|
||||
expression,
|
||||
format_args!("Slices are not allowed in type expressions"),
|
||||
)
|
||||
);
|
||||
Type::unknown()
|
||||
}
|
||||
|
||||
// =================================================================================
|
||||
|
@ -8724,11 +8817,6 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
todo_type!("ellipsis literal in type expression")
|
||||
}
|
||||
|
||||
ast::Expr::Tuple(tuple) => {
|
||||
self.infer_tuple_expression(tuple);
|
||||
Type::unknown()
|
||||
}
|
||||
|
||||
ast::Expr::Starred(starred) => {
|
||||
self.infer_starred_expression(starred);
|
||||
todo_type!("PEP 646")
|
||||
|
@ -9076,7 +9164,10 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
|||
}
|
||||
|
||||
let [type_expr, metadata @ ..] = &arguments[..] else {
|
||||
self.infer_type_expression(arguments_slice);
|
||||
for argument in arguments {
|
||||
self.infer_expression(argument);
|
||||
}
|
||||
self.store_expression_type(arguments_slice, Type::unknown());
|
||||
return Type::unknown();
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue