mirror of
https://github.com/astral-sh/ruff.git
synced 2025-07-19 11:05:24 +00:00
[ty] Don't require default typevars when specializing (#17872)
If a typevar is declared as having a default, we shouldn't require a type to be specified for that typevar when explicitly specializing a generic class: ```py class WithDefault[T, U = int]: ... reveal_type(WithDefault[str]()) # revealed: WithDefault[str, int] ``` --------- Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
This commit is contained in:
parent
bb6c7cad07
commit
ada4c4cb1f
5 changed files with 46 additions and 12 deletions
|
@ -1316,10 +1316,27 @@ impl<'db> Binding<'db> {
|
|||
self.inherited_specialization
|
||||
}
|
||||
|
||||
/// Returns the bound types for each parameter, in parameter source order, or `None` if no
|
||||
/// argument was matched to that parameter.
|
||||
pub(crate) fn parameter_types(&self) -> &[Option<Type<'db>>] {
|
||||
&self.parameter_tys
|
||||
}
|
||||
|
||||
/// Returns the bound types for each parameter, in parameter source order, with default values
|
||||
/// applied for arguments that weren't matched to a parameter. Returns `None` if there are any
|
||||
/// non-default arguments that weren't matched to a parameter.
|
||||
pub(crate) fn parameter_types_with_defaults(
|
||||
&self,
|
||||
signature: &Signature<'db>,
|
||||
) -> Option<Box<[Type<'db>]>> {
|
||||
signature
|
||||
.parameters()
|
||||
.iter()
|
||||
.zip(&self.parameter_tys)
|
||||
.map(|(parameter, parameter_ty)| parameter_ty.or(parameter.default_type()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn arguments_for_parameter<'a>(
|
||||
&'a self,
|
||||
argument_types: &'a CallArgumentTypes<'a, 'db>,
|
||||
|
|
|
@ -123,6 +123,9 @@ impl<'db> GenericContext<'db> {
|
|||
}
|
||||
None => {}
|
||||
}
|
||||
if let Some(default_ty) = typevar.default_ty(db) {
|
||||
parameter = parameter.with_default_type(default_ty);
|
||||
}
|
||||
parameter
|
||||
}
|
||||
|
||||
|
|
|
@ -6711,10 +6711,8 @@ impl<'db> TypeInferenceBuilder<'db> {
|
|||
}
|
||||
_ => CallArgumentTypes::positional([self.infer_type_expression(slice_node)]),
|
||||
};
|
||||
let signatures = Signatures::single(CallableSignature::single(
|
||||
value_ty,
|
||||
generic_context.signature(self.db()),
|
||||
));
|
||||
let signature = generic_context.signature(self.db());
|
||||
let signatures = Signatures::single(CallableSignature::single(value_ty, signature.clone()));
|
||||
let bindings = match Bindings::match_parameters(signatures, &call_argument_types)
|
||||
.check_types(self.db(), &call_argument_types)
|
||||
{
|
||||
|
@ -6732,14 +6730,10 @@ impl<'db> TypeInferenceBuilder<'db> {
|
|||
.matching_overloads()
|
||||
.next()
|
||||
.expect("valid bindings should have matching overload");
|
||||
let specialization = generic_context.specialize(
|
||||
self.db(),
|
||||
overload
|
||||
.parameter_types()
|
||||
.iter()
|
||||
.map(|ty| ty.unwrap_or(Type::unknown()))
|
||||
.collect(),
|
||||
);
|
||||
let parameters = overload
|
||||
.parameter_types_with_defaults(&signature)
|
||||
.expect("matching overload should not have missing arguments");
|
||||
let specialization = generic_context.specialize(self.db(), parameters);
|
||||
Type::from(GenericAlias::new(self.db(), generic_class, specialization))
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue