[ty] Add support for dict(...) calls in typed dict contexts (#22113)
## Summary fixes https://github.com/astral-sh/ty/issues/2127 - handle `dict(...)` calls in TypedDict context with bidirectional inference - validate keys/values using the existing TypedDict constructor implem - mdtest: add 1 positive test, 1 negative test for invalid coverage ## Test Plan ```sh cargo clippy --workspace --all-targets --all-features -- -D warnings # Rust linting cargo test # Rust testing uvx pre-commit run --all-files --show-diff-on-failure # Rust and Python formatting, Markdown and Python linting, etc. ``` fully green
This commit is contained in:
@@ -8448,6 +8448,43 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
arguments,
|
||||
} = call_expression;
|
||||
|
||||
// Fast-path dict(...) in TypedDict context: infer keyword values against fields,
|
||||
// then validate and return the TypedDict type.
|
||||
if let Some(tcx) = tcx.annotation
|
||||
&& let Some(typed_dict) = tcx
|
||||
.filter_union(self.db(), Type::is_typed_dict)
|
||||
.as_typed_dict()
|
||||
&& callable_type
|
||||
.as_class_literal()
|
||||
.is_some_and(|class_literal| class_literal.is_known(self.db(), KnownClass::Dict))
|
||||
&& arguments.args.is_empty()
|
||||
&& arguments
|
||||
.keywords
|
||||
.iter()
|
||||
.all(|keyword| keyword.arg.is_some())
|
||||
{
|
||||
let items = typed_dict.items(self.db());
|
||||
for keyword in &arguments.keywords {
|
||||
if let Some(arg_name) = &keyword.arg {
|
||||
let value_tcx = items
|
||||
.get(arg_name.id.as_str())
|
||||
.map(|field| TypeContext::new(Some(field.declared_ty)))
|
||||
.unwrap_or_default();
|
||||
self.infer_expression(&keyword.value, value_tcx);
|
||||
}
|
||||
}
|
||||
|
||||
validate_typed_dict_constructor(
|
||||
&self.context,
|
||||
typed_dict,
|
||||
arguments,
|
||||
func.as_ref().into(),
|
||||
|expr| self.expression_type(expr),
|
||||
);
|
||||
|
||||
return Type::TypedDict(typed_dict);
|
||||
}
|
||||
|
||||
// We don't call `Type::try_call`, because we want to perform type inference on the
|
||||
// arguments after matching them to parameters, but before checking that the argument types
|
||||
// are assignable to any parameter annotations.
|
||||
|
||||
Reference in New Issue
Block a user