-
Notifications
You must be signed in to change notification settings - Fork 10.5k
AST: Transition to storing substitution maps in bound generic type nodes #31895
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
base: main
Are you sure you want to change the base?
AST: Transition to storing substitution maps in bound generic type nodes #31895
Conversation
Moving out of draft status to be able to track conflicts. |
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.
Note that getContextSubstitutionMap() now becomes completely trivial. It can get the SubstitutionMap out of the type, instead of re-deriving it.
args.push_back(param->getDeclaredInterfaceType()); | ||
|
||
return BoundGenericType::get(decl, ParentTy, args); | ||
const auto sig = decl->getGenericSignature(); |
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.
This means calling getDeclaredInterfaceType() on a type will now compute it's generic signature. This may or may not be a problem. In any case, the above comment is out of date (it talks about "validation" which is no longer a thing).
lib/Sema/TypeCheckType.cpp
Outdated
assert(!resultType->hasTypeParameter()); | ||
return resultType; | ||
const auto resultTy = decl->getDeclaredInterfaceType(); | ||
assert(!resultTy->hasTypeParameter()); |
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.
This assertion will fail if decl is generic
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.
I wonder what this is trying to accomplish by ignoring the arguments. This is the code path for Foo.Alias<...>, where Foo is an unbound generic parent. I will see if I can reproduce this assertion failure once I get the Standard Library to build once again.
As for UnboundGenericType, I kind of wish it didn't exist at all. Instead, resolveType() should take some callback or other mechanism for filling in missing generic arguments. In expression context, we would move the logic from openUnboundGenericType() here; in type context, it would either take the arguments from context if you refer to a type inside its own body, or just diagnose. |
struct Foo<T, U> {}
extension Foo where T == Bool {} For example, asking for the substitutions of Edit: Forgot to mention the superclass context case. |
@AnthonyLatsis You're right about getContextSubstitutionMap(). However we should fast-path it in the case where the dc is the same as the nominal. |
Trying to figure out what's causing the following assertion failure:
|
It looks like you've got two BoundGenericTypes that print the same, but are not equal, because something is different with their substitution maps. |
Okay, here's what's going on.
with the semantic attribute
and attempts to specialize the latter using the substitutions from the apply site. Obviously, those substitutions are inadequate, because we need the conformance to @slavapestov I am not familiar with the expectations about functions referenced in |
To make this less cryptic, here is the method that requires prespecializing
|
412efb6
to
b0d26cb
Compare
Going to focus on cutting off @slavapestov Let me know whether that |
… in BoundGeneric*Type
b0d26cb
to
0d72b81
Compare
This change as it currently is will cause diagnostics regressions whenever a type appears within its own generic signature, because we now have to compute the generic signature just to form the declared interface type. Having discussed the latter with Slava, one idea we settled on was to define a
StructuralBoundGenericType
counterpart that stores an array of generic arguments -- just like we do today -- for use during the type-checking stage only. More importantly, this would ultimately enable us to unlock recursive generic signature validation altogether.There are still a few tests failing, in particular, I haven't figured yet how to deal with bound generic types with unbound generic parents. Representing unbound generic parameters as
T -> Type()
in the substitution map doesn't work right off the bat.@slavapestov I would greatly appreciate any feedback, especially on the performance-critical parts.