8000 [Sema] Fix compiler error when extending a typealias of a partially specialized generic type by xavgru12 · Pull Request #73169 · swiftlang/swift · GitHub
[go: up one dir, main page]

Skip to content

[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

Open
wants to merge 50 commits into
base: main
Choose a base branch
from

Conversation

xavgru12
Copy link
@xavgru12 xavgru12 commented Apr 21, 2024

Resolves #68212.

@AnthonyLatsis
Copy link
Collaborator

@swift-ci please smoke test Linux

@saehejkang
Copy link
Contributor
saehejkang commented Apr 21, 2024

i was curious to see how this was solved and guess I was overcomplicating the issue 😭

@AnthonyLatsis
Copy link
Collaborator

This is far from solved, FWIW 🙂. I only triggered the tests to encourage the author to iterate on failures before any feedback arrives.

@xedin
Copy link
Contributor
xedin commented Apr 24, 2024

Is it possible to make this PR as a draft?

@AnthonyLatsis AnthonyLatsis marked this pull request as draft April 24, 2024 20:59
@xavgru12
Copy link
Author

I was converting to draft but Anthony was faster

@AnthonyLatsis
Copy link
Collaborator

For posterity, the convert to draft button is at the bottom of the Reviewers section.

@AnthonyLatsis AnthonyLatsis self-requested a review April 26, 2024 21:19
@AnthonyLatsis AnthonyLatsis self-assigned this Jan 27, 2025
@xavgru12 xavgru12 closed this Mar 10, 2025
@xavgru12 xavgru12 deleted the genericTypealias branch March 10, 2025 17:26
@xavgru12 xavgru12 reopened this Mar 10, 2025
@xavgru12 xavgru12 restored the genericTypealias branch March 31, 2025 18:32
@xavgru12 xavgru12 reopened this Mar 31, 2025
@xavgru12
Copy link
Author

deleted and pushed branch in order to trigger CI

@xavgru12
Copy link
Author
xavgru12 commented Apr 2, 2025

@AnthonyLatsis check this out

@xavgru12
Copy link
Author
xavgru12 commented Apr 3, 2025

merged main again, smoke test Linux was green already

@xavgru12
Copy link
Author
xavgru12 commented Apr 9, 2025

@AnthonyLatsis I see you have been quite busy with 6.1 these days. Could you review this?

@xavgru12 xavgru12 changed the title Compiler error when extending a typealias of a partially specialized generic type #68212 Fix compiler error when extending a typealias of a partially specialized generic type #68212 Apr 11, 2025
@xavgru12 xavgru12 changed the title Fix compiler error when extending a typealias of a partially specialized generic type #68212 Fix compiler error when extending a typealias of a partially specialized generic type Apr 11, 2025
@xavgru12 xavgru12 changed the title Fix compiler error when extending a typealias of a partially specialized generic type [Sema] Fix compiler error when extending a typealias of a partially specialized generic type Apr 12, 2025
@AnthonyLatsis
Copy link
Collaborator

@swift-ci please smoke test macOS

@AnthonyLatsis
Copy link
Collaborator

Will have a review ready by Monday.

Copy link
Collaborator
@AnthonyLatsis AnthonyLatsis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall direction is looking great!


Please add regression tests with extensions for all the type alias examples from my comments as you go.

@xavgru12
Copy link
Author
xavgru12 commented May 4, 2025

@AnthonyLatsis
I changed the code according review and added test cases. Let me know what you think about this.

@xavgru12 xavgru12 requested a review from AnthonyLatsis May 4, 2025 20:42
@xavgru12
Copy link
Author

@AnthonyLatsis reminder

@xavgru12
Copy link
Author

You once said a ping every two weeks is fine. So here I am pinging you @AnthonyLatsis

Copy link
Collaborator
@AnthonyLatsis AnthonyLatsis left a 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
  }
}

}

auto nominalGenericArguments = nominal->getDeclaredInterfaceType()
.getPointer()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.getPointer() is superfluous.

->getGenericArgs();
auto typealiasGenericArguments = typealias->getUnderlyingType()
.getPointer()
->getAs<BoundGenericType>()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.getPointer() is superfluous.

Comment on lines +3035 to +3036
if (nominalBoundGenericType.getPointer()->isEqual(
typealiasBoundGenericType.getPointer())) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.getPointer() is superfluous.

Comment on lines +3040 to +3045
if (!typealiasBoundGenericType->hasTypeParameter()) {
isInferredType = true;
} else {
isInferredType = false;
break;
}
Copy link
Collaborator

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

Suggested change
if (!typealiasBoundGenericType->hasTypeParameter()) {
isInferredType = true;
} else {
isInferredType = false;
break;
}
if (typealiasBoundGenericType->hasTypeParameter()) {
return false;
}

Comment on lines +3097 to +3103
if (!std::equal(nominalGenericParams.begin(), nominalGenericParams.end(),
typealiasGenericParams.begin(),
[](GenericTypeParamType *gp1, GenericTypeParamType *gp2) {
return gp1->isEqual(gp2);
})) {
return false;
}
Copy link
Collaborator

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.

Comment on lines +66 to +70
extension A2 {
func adding(_ x: Int) -> Self {
S2(x: self.x + x, y: y, z: z) // expected-error {{binary operator '+' cannot be applied to operands of type 'X' and 'Int'}} expected-note {{overloads for '+' exist with these partially matching parameter lists: (Int, Int)}}
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can simplify these specialization checks and minimize diagnostic noise like so:

Suggested change
extension A2 {
func adding(_ x: Int) -> Self {
S2(x: self.x + x, y: y, z: z) // expected-error {{binary operator '+' cannot be applied to operands of type 'X' and 'Int'}} expected-note {{overloads for '+' exist with these partially matching parameter lists: (Int, Int)}}
}
}
extension A2 {
func test() {
let int: Int
let _: X = int // Is X == Int in this extension?
}
}

Then you also remove the properties.

Comment on lines +3081 to +3085
for (const auto &type : nominalGenericParams) {
if (type->getDepth() == maxDepth) {
nominalGenericParams = nominalGenericParams.drop_back();
}
}
Copy link
Collaborator

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:

Suggested change
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
  }
}

Comment on lines +73 to +92
struct S4<A, B> {
// Generic parameters: <A, B, C>
// Depth: 0 0 1
struct Nested<C> {
let c: C
}
}

struct S5<A> {
// Generic parameters: <A, B, C>
// Depth: 0 1 1
typealias Alias<B, C> = S4<A, B>.Nested<C>

}

extension S5.Alias{
func adding(_ c: Int) -> Self {
S4.Nested(c: self.c + c) //expected-error {{binary operator '+' cannot be applied to operands of type 'C' and 'Int'}} expected-note {{overloads for '+' exist with these partially matching parameter lists: (Int, Int)}}
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need a different way to verify that Alias is not passthrough in this case. The error you are verifying is legit even if Alias was passthrough, since nothing is specialized. One way would be

struct S5<A> {
  // Generic parameters: <A, B, C>
  // Depth:               0  1  1
  typealias Alias<B, C> = S4<A, B>.Nested<C> where A == Int
}

And check that A != Int in the extension. The extension will not pick up the constraint if Alias is not passthrough:

// If we have a passthrough typealias, add the requirements from its
// generic signature.
if (typealias && TypeChecker::isPassThroughTypealias(typealias, nominal)) {
for (auto req : typealias->getGenericSignature().getRequirements())
extraReqs.push_back(req);
}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Compiler error when extending a typealias of a partially specialized generic type
4 participants
0