Skip to content

Commit ae9d450

Browse files
carljmlipefree
andauthored
[ty] Fallback to Unknown if no type is stored for an expression (#19517)
## Summary See discussion at https://github.com/astral-sh/ruff/pull/19478/files#r2223870292 Fixes astral-sh/ty#865 ## Test Plan Added one mdtest for invalid Callable annotation; removed `pull-types: skip` from that test file. Co-authored-by: lipefree <[email protected]>
1 parent c8c80e0 commit ae9d450

File tree

3 files changed

+28
-35
lines changed

3 files changed

+28
-35
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from typing import Callable
2+
3+
def a(x: Callable[.., None]): ...
4+
5+
def b(x: Callable[..

crates/ty_python_semantic/resources/mdtest/annotations/callable.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,6 @@ def _(c: Callable[[int, 42, str, False], None]):
5858

5959
### Missing return type
6060

61-
<!-- pull-types:skip -->
62-
6361
Using a parameter list:
6462

6563
```py
@@ -90,6 +88,21 @@ def _(c: Callable[ # error: [invalid-type-form] "Special form `typing.Callable`
9088
reveal_type(c) # revealed: (...) -> Unknown
9189
```
9290

91+
### Invalid parameters and return type
92+
93+
```py
94+
from typing import Callable
95+
96+
# fmt: off
97+
98+
def _(c: Callable[
99+
# error: [invalid-type-form] "Int literals are not allowed in this context in a type expression"
100+
{1, 2}, 2 # error: [invalid-type-form] "The first argument to `Callable` must be either a list of types, ParamSpec, Concatenate, or `...`"
101+
]
102+
):
103+
reveal_type(c) # revealed: (...) -> Unknown
104+
```
105+
93106
### More than two arguments
94107

95108
We can't reliably infer the callable type if there are more then 2 arguments because we don't know

crates/ty_python_semantic/src/types/infer.rs

Lines changed: 8 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -452,14 +452,9 @@ impl<'db> ScopeInference<'db> {
452452
self.extra.as_deref().map(|extra| &extra.diagnostics)
453453
}
454454

455-
#[track_caller]
456455
pub(crate) fn expression_type(&self, expression: impl Into<ExpressionNodeKey>) -> Type<'db> {
457-
self.try_expression_type(expression).expect(
458-
"Failed to retrieve the inferred type for an `ast::Expr` node \
459-
passed to `TypeInference::expression_type()`. The `TypeInferenceBuilder` \
460-
should infer and store types for all `ast::Expr` nodes in any `TypeInference` \
461-
region it analyzes.",
462-
)
456+
self.try_expression_type(expression)
457+
.unwrap_or_else(Type::unknown)
463458
}
464459

465460
pub(crate) fn try_expression_type(
@@ -541,14 +536,9 @@ impl<'db> DefinitionInference<'db> {
541536
}
542537
}
543538

544-
#[track_caller]
545539
pub(crate) fn expression_type(&self, expression: impl Into<ExpressionNodeKey>) -> Type<'db> {
546-
self.try_expression_type(expression).expect(
547-
"Failed to retrieve the inferred type for an `ast::Expr` node \
548-
passed to `TypeInference::expression_type()`. The `TypeInferenceBuilder` \
549-
should infer and store types for all `ast::Expr` nodes in any `TypeInference` \
550-
region it analyzes.",
551-
)
540+
self.try_expression_type(expression)
541+
.unwrap_or_else(Type::unknown)
552542
}
553543

554544
pub(crate) fn try_expression_type(
@@ -675,14 +665,9 @@ impl<'db> ExpressionInference<'db> {
675665
.or_else(|| self.fallback_type())
676666
}
677667

678-
#[track_caller]
679668
pub(crate) fn expression_type(&self, expression: impl Into<ExpressionNodeKey>) -> Type<'db> {
680-
self.try_expression_type(expression).expect(
681-
"Failed to retrieve the inferred type for an `ast::Expr` node \
682-
passed to `TypeInference::expression_type()`. The `TypeInferenceBuilder` \
683-
should infer and store types for all `ast::Expr` nodes in any `TypeInference` \
684-
region it analyzes.",
685-
)
669+
self.try_expression_type(expression)
670+
.unwrap_or_else(Type::unknown)
686671
}
687672

688673
fn is_cycle_callback(&self) -> bool {
@@ -959,19 +944,9 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
959944
self.context.in_stub()
960945
}
961946

962-
/// Get the already-inferred type of an expression node.
963-
///
964-
/// ## Panics
965-
/// If the expression is not within this region, or if no type has yet been inferred for
966-
/// this node.
967-
#[track_caller]
947+
/// Get the already-inferred type of an expression node, or Unknown.
968948
fn expression_type(&self, expr: &ast::Expr) -> Type<'db> {
969-
self.try_expression_type(expr).expect(
970-
"Failed to retrieve the inferred type for an `ast::Expr` node \
971-
passed to `TypeInference::expression_type()`. The `TypeInferenceBuilder` \
972-
should infer and store types for all `ast::Expr` nodes in any `TypeInference` \
973-
region it analyzes.",
974-
)
949+
self.try_expression_type(expr).unwrap_or_else(Type::unknown)
975950
}
976951

977952
fn try_expression_type(&self, expr: &ast::Expr) -> Option<Type<'db>> {

0 commit comments

Comments
 (0)