-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[Sema] Fix compiler error when extending a typealias of a partially specialized generic type #73169
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?
Conversation
@swift-ci please smoke test Linux |
i was curious to see how this was solved and guess I was overcomplicating the issue 😭 |
This is far from solved, FWIW 🙂. I only triggered the tests to encourage the author to iterate on failures before any feedback arrives. |
Is it possible to make this PR as a draft? |
I was converting to draft but Anthony was faster |
For posterity, the convert to draft button is at the bottom of the Reviewers section. |
…red specialized nested types
@AnthonyLatsis |
@AnthonyLatsis reminder |
You once said a ping every two weeks is fine. So here I am pinging you @AnthonyLatsis |
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.
Thank you for the reminders and the patience. Another somewhat random test case I think worth having:
struct S1<T> {
struct Inner<U> {}
}
struct S2<T> {
typealias A1<U> = S1<T>.Inner<U>
typealias A2<U> = S1<T>.Inner<U> where T == Int
}
extension S2<Int>.A1 {
func foo1() {
let int: Int
let _: T = int // OK
}
}
extension S2.A2 {
func foo2() {
let int: Int
let _: T = int // OK
}
}
lib/Sema/TypeCheckDecl.cpp
Outdated
if (!typealiasBoundGenericType->hasTypeParameter()) { | ||
isInferredType = true; | ||
} else { | ||
isInferredType = false; | ||
break; | ||
} |
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.
If we remove isInferredType
, this can be
if (!typealiasBoundGenericType->hasTypeParameter()) { | |
isInferredType = true; | |
} else { | |
isInferredType = false; | |
break; | |
} | |
if (typealiasBoundGenericType->hasTypeParameter()) { | |
return false; | |
} |
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 removed isInferredType. I dislike the new solution because I have to write return true
at the end of the function and I would like to have return false
as default.
if (!std::equal(nominalGenericParams.begin(), nominalGenericParams.end(), | ||
typealiasGenericParams.begin(), | ||
[](GenericTypeParamType *gp1, GenericTypeParamType *gp2) { | ||
return gp1->isEqual(gp2); | ||
})) { | ||
return false; | ||
} |
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.
We need to perform this check regardless of whether the original number of generic params matched.
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.
Confused here, added a comment above about this
lib/Sema/TypeCheckDecl.cpp
Outdated
for (const auto &type : nominalGenericParams) { | ||
if (type->getDepth() == maxDepth) { | ||
nominalGenericParams = nominalGenericParams.drop_back(); | ||
} | ||
} |
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 like how this appears to be unsafe but is actually safe because we are trimming a non-owning view into the array. But this is probably better:
for (const auto &type : nominalGenericParams) { | |
if (type->getDepth() == maxDepth) { | |
nominalGenericParams = nominalGenericParams.drop_back(); | |
} | |
} | |
while (!nominalGenericParams.empty() && | |
nominalGenericParams.back().getDepth() == maxDepth) { | |
nominalGenericParams = nominalGenericParams.drop_back(); | |
} |
Test case for why we need !nominalGenericParams.empty()
:
struct S1<T> {
struct Inner<U> {}
}
struct S2 {
typealias A<T> = S1<T>.Inner<Int>
}
extension S2.A {
func test() {
let int: Int
let _: U = int // error
}
}
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 add the test case and changed it to while
.
The test does not produce an error.
So the nested struct parameter becomes Int. Then it checks for U which is Int now. Why is it supposed to produce an error?
…ypealiases.swift, decl/nested/type_in_type.swift, stdlib/Filter.swift, stdlib/Map.swift
@AnthonyLatsis |
@AnthonyLatsis reminder |
Resolves #68212.