-
Notifications
You must be signed in to change notification settings - Fork 1.8k
[ty] Promote literals in invariant return position #21320
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -30,7 +30,8 @@ use crate::types::function::{ | |
| OverloadLiteral, | ||
| }; | ||
| use crate::types::generics::{ | ||
| InferableTypeVars, Specialization, SpecializationBuilder, SpecializationError, | ||
| GenericContextTypeVar, InferableTypeVars, Specialization, SpecializationBuilder, | ||
| SpecializationError, | ||
| }; | ||
| use crate::types::signatures::{Parameter, ParameterForm, ParameterKind, Parameters}; | ||
| use crate::types::tuple::{TupleLength, TupleType}; | ||
|
|
@@ -2762,6 +2763,51 @@ impl<'a, 'db> ArgumentTypeChecker<'a, 'db> { | |
| .or(self.signature.return_ty) | ||
| .zip(self.call_expression_tcx.annotation); | ||
|
|
||
| let tcx_specialization = self | ||
| .call_expression_tcx | ||
| .annotation | ||
| .and_then(|annotation| annotation.class_specialization(self.db)); | ||
|
|
||
| let promote_literals = |typevar: GenericContextTypeVar<'db>, ty: Type<'db>| -> Type<'db> { | ||
| let bound_typevar = typevar.bound_typevar(); | ||
|
|
||
| if typevar.is_inherited() && bound_typevar.variance(self.db).is_invariant() { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What does (It would be great if
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, I think I see -- you're using the term to mean that the typevar is associated with a class's generic context rather than the generic context of a function or method? So it doesn't have any thing to do with the generic context of a class's base classes etc.?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's right, though I didn't invent that terminology. Ideally we wouldn't need to special case inherited type variables, but we don't currently have a robust way to get access to the bound type of a constructor method (the |
||
| return ty.promote_literals( | ||
| self.db, | ||
| TypeContext::new( | ||
| tcx_specialization | ||
| .and_then(|specialization| specialization.get(self.db, bound_typevar)), | ||
| ), | ||
| ); | ||
| } | ||
|
|
||
| let Some(return_specialization) = self | ||
| .signature | ||
| .return_ty | ||
| .and_then(|return_ty| return_ty.class_specialization(self.db)) | ||
| else { | ||
| return ty; | ||
| }; | ||
|
|
||
| if let Some((typevar, _)) = return_specialization | ||
| .generic_context(self.db) | ||
| .variables(self.db) | ||
| .zip(return_specialization.types(self.db)) | ||
| .find(|(_, ty)| **ty == Type::TypeVar(bound_typevar)) | ||
| .filter(|(typevar, _)| typevar.variance(self.db).is_invariant()) | ||
| { | ||
| return ty.promote_literals( | ||
| self.db, | ||
| TypeContext::new( | ||
| tcx_specialization | ||
| .and_then(|specialization| specialization.get(self.db, typevar)), | ||
| ), | ||
| ); | ||
| } | ||
|
|
||
| ty | ||
| }; | ||
|
|
||
| self.inferable_typevars = generic_context.inferable_typevars(self.db); | ||
| let mut builder = SpecializationBuilder::new(self.db, self.inferable_typevars); | ||
|
|
||
|
|
@@ -2811,7 +2857,9 @@ impl<'a, 'db> ArgumentTypeChecker<'a, 'db> { | |
| } | ||
|
|
||
| // Build the specialization first without inferring the complete type context. | ||
| let isolated_specialization = builder.build(generic_context, self.call_expression_tcx); | ||
| let isolated_specialization = builder | ||
| .mapped(generic_context, promote_literals) | ||
| .build(generic_context); | ||
| let isolated_return_ty = self | ||
| .return_ty | ||
| .apply_specialization(self.db, isolated_specialization); | ||
|
|
@@ -2836,7 +2884,9 @@ impl<'a, 'db> ArgumentTypeChecker<'a, 'db> { | |
| builder.infer(return_ty, call_expression_tcx).ok()?; | ||
|
|
||
| // Otherwise, build the specialization again after inferring the complete type context. | ||
| let specialization = builder.build(generic_context, self.call_expression_tcx); | ||
| let specialization = builder | ||
| .mapped(generic_context, promote_literals) | ||
| .build(generic_context); | ||
| let return_ty = return_ty.apply_specialization(self.db, specialization); | ||
|
|
||
| Some((Some(specialization), return_ty)) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wonderful!