diff --git a/crates/ty_python_semantic/resources/mdtest/typed_dict.md b/crates/ty_python_semantic/resources/mdtest/typed_dict.md index 042d6317a2..8be6de4ef3 100644 --- a/crates/ty_python_semantic/resources/mdtest/typed_dict.md +++ b/crates/ty_python_semantic/resources/mdtest/typed_dict.md @@ -99,15 +99,24 @@ eve1a: Person = {"name": b"Eve", "age": None} # error: [invalid-argument-type] "Invalid argument to key "name" with declared type `str` on TypedDict `Person`" eve1b = Person(name=b"Eve", age=None) +reveal_type(eve1a) # revealed: Person +reveal_type(eve1b) # revealed: Person + # error: [missing-typed-dict-key] "Missing required key 'name' in TypedDict `Person` constructor" eve2a: Person = {"age": 22} # error: [missing-typed-dict-key] "Missing required key 'name' in TypedDict `Person` constructor" eve2b = Person(age=22) +reveal_type(eve2a) # revealed: Person +reveal_type(eve2b) # revealed: Person + # error: [invalid-key] "Invalid key for TypedDict `Person`: Unknown key "extra"" eve3a: Person = {"name": "Eve", "age": 25, "extra": True} # error: [invalid-key] "Invalid key for TypedDict `Person`: Unknown key "extra"" eve3b = Person(name="Eve", age=25, extra=True) + +reveal_type(eve3a) # revealed: Person +reveal_type(eve3b) # revealed: Person ``` Also, the value types ​​declared in a `TypedDict` affect generic call inference: diff --git a/crates/ty_python_semantic/src/types/infer/builder.rs b/crates/ty_python_semantic/src/types/infer/builder.rs index edf8581bcd..ea3f739f22 100644 --- a/crates/ty_python_semantic/src/types/infer/builder.rs +++ b/crates/ty_python_semantic/src/types/infer/builder.rs @@ -6103,9 +6103,9 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { && let Some(typed_dict) = tcx .filter_union(self.db(), Type::is_typed_dict) .as_typed_dict() - && let Some(ty) = self.infer_typed_dict_expression(dict, typed_dict) { - return ty; + self.infer_typed_dict_expression(dict, typed_dict); + return Type::TypedDict(typed_dict); } // Avoid false positives for the functional `TypedDict` form, which is currently @@ -6130,7 +6130,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { &mut self, dict: &ast::ExprDict, typed_dict: TypedDictType<'db>, - ) -> Option> { + ) { let ast::ExprDict { range: _, node_index: _, @@ -6153,9 +6153,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { validate_typed_dict_dict_literal(&self.context, typed_dict, dict, dict.into(), |expr| { self.expression_type(expr) - }) - .ok() - .map(|_| Type::TypedDict(typed_dict)) + }); } // Infer the type of a collection literal expression. diff --git a/crates/ty_python_semantic/src/types/typed_dict.rs b/crates/ty_python_semantic/src/types/typed_dict.rs index e29b836d8a..632d2a2933 100644 --- a/crates/ty_python_semantic/src/types/typed_dict.rs +++ b/crates/ty_python_semantic/src/types/typed_dict.rs @@ -389,7 +389,7 @@ fn validate_from_keywords<'db, 'ast>( provided_keys } -/// Validates a `TypedDict` dictionary literal assignment, +/// Validates a `TypedDict` dictionary literal assignment, emitting any needed diagnostics. /// e.g. `person: Person = {"name": "Alice", "age": 30}` pub(super) fn validate_typed_dict_dict_literal<'db>( context: &InferContext<'db, '_>, @@ -397,8 +397,7 @@ pub(super) fn validate_typed_dict_dict_literal<'db>( dict_expr: &ast::ExprDict, error_node: AnyNodeRef, expression_type_fn: impl Fn(&ast::Expr) -> Type<'db>, -) -> Result, OrderSet<&'db str>> { - let mut valid = true; +) { let mut provided_keys = OrderSet::new(); // Validate each key-value pair in the dictionary literal @@ -411,7 +410,7 @@ pub(super) fn validate_typed_dict_dict_literal<'db>( let value_type = expression_type_fn(&item.value); - valid &= validate_typed_dict_key_assignment( + validate_typed_dict_key_assignment( context, typed_dict, key_str, @@ -424,11 +423,5 @@ pub(super) fn validate_typed_dict_dict_literal<'db>( } } - valid &= validate_typed_dict_required_keys(context, typed_dict, &provided_keys, error_node); - - if valid { - Ok(provided_keys) - } else { - Err(provided_keys) - } + validate_typed_dict_required_keys(context, typed_dict, &provided_keys, error_node); }