[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:
Ben Bar-Or 2025-06-09 02:40:05 +03:00 committed by GitHub
parent 301b9f4135
commit 1dc8f8f903
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 462 additions and 74 deletions

View file

@ -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

View file

@ -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

View file

@ -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
```

View file

@ -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
```

View file

@ -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
```

View file

@ -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(

View file

@ -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();
};