From 8d98aea6c41f4f8c71ab2727f46b5319392b91bd Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Tue, 29 Oct 2024 11:06:44 +0000 Subject: [PATCH] [red-knot] Infer attribute expressions in type annotations (#13967) --- .../resources/mdtest/assignment/annotations.md | 17 +++++++++++++++++ .../src/types/infer.rs | 18 +++++++----------- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/crates/red_knot_python_semantic/resources/mdtest/assignment/annotations.md b/crates/red_knot_python_semantic/resources/mdtest/assignment/annotations.md index 84d9ab943f..30ea843523 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/assignment/annotations.md +++ b/crates/red_knot_python_semantic/resources/mdtest/assignment/annotations.md @@ -91,3 +91,20 @@ def baz() -> str | str: reveal_type(baz()) # revealed: str ``` + +## Attribute expressions in type annotations are understood + +```py +import builtins + +int = "foo" +a: builtins.int = 42 + +# error: [invalid-assignment] "Object of type `Literal["bar"]` is not assignable to `int`" +b: builtins.int = "bar" + +c: builtins.tuple[builtins.tuple[builtins.int, builtins.int], builtins.int] = ((42, 42), 42) + +# error: [invalid-assignment] "Object of type `Literal["foo"]` is not assignable to `tuple[tuple[int, int], int]`" +c: builtins.tuple[builtins.tuple[builtins.int, builtins.int], builtins.int] = "foo" +``` diff --git a/crates/red_knot_python_semantic/src/types/infer.rs b/crates/red_knot_python_semantic/src/types/infer.rs index 30429850a4..19a97f71c9 100644 --- a/crates/red_knot_python_semantic/src/types/infer.rs +++ b/crates/red_knot_python_semantic/src/types/infer.rs @@ -3542,15 +3542,16 @@ impl<'db> TypeInferenceBuilder<'db> { let ty = match expression { ast::Expr::Name(name) => { - debug_assert!( - name.ctx.is_load(), - "name in a type expression is always 'load' but got: '{:?}'", - name.ctx - ); - + debug_assert_eq!(name.ctx, ast::ExprContext::Load); self.infer_name_expression(name).to_instance(self.db) } + ast::Expr::Attribute(attribute_expression) => { + debug_assert_eq!(attribute_expression.ctx, ast::ExprContext::Load); + self.infer_attribute_expression(attribute_expression) + .to_instance(self.db) + } + ast::Expr::NoneLiteral(_literal) => Type::None, // TODO: parse the expression and check whether it is a string annotation. @@ -3684,11 +3685,6 @@ impl<'db> TypeInferenceBuilder<'db> { self.infer_fstring_expression(fstring); Type::Unknown } - // - ast::Expr::Attribute(attribute) => { - self.infer_attribute_expression(attribute); - Type::Unknown - } ast::Expr::List(list) => { self.infer_list_expression(list); Type::Unknown