Skip to content

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

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;
}

Copy link
Author

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.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I prefer returns over writing to a variable because they are generally more robust and help to streamline the flow. Do you find it counterintuitive to return true at the end here? You could invert the name of the function, but probably not worth it right now; we need to come up with a more descriptive name.

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.

Copy link
Author

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

Copy link
Collaborator

Choose a reason for hiding this comment

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

The comment: #73169 (comment)


So the goal is to relax the fall-through type alias criteria a little bit by allowing a mismatch in the number of generic parameters at the greatest depth, but only if that difference is due to some of those generic parameters being bound to fully concrete types. As for other depths, the current rules still apply. For example, <A><B,C>... vs. <A, B><C>... or <A, B, C>... vs. <A, B>... must not meet the criteria regardless of the nature of .... I.e., we should still return early if the size check or the std::equal check fail for what remains after we shave off max depth elements.

Could you rebase (I have renamed isGeneric to hasGenericParamList) and see if the test in test/decl and test/type pass with the current change? I would expect some of them to fail. If not, we should get this case covered.

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

Copy link
Author

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?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this passes now because you moved the std::equal check into the if. I don’t think there is anything inherently wrong with this case, but it belongs to a larger family of cases, and supporting it properly will require more work.

@xavgru12
Copy link
Author

xavgru12 commented Jun 5, 2025

@AnthonyLatsis
I iterated over it and added some comments unresolving threads. Please review again and I hope you are able to keep the overview over this, so let me know if something is unclear.

@xavgru12
Copy link
Author

@AnthonyLatsis reminder

@xavgru12
Copy link
Author

@AnthonyLatsis
another reminder, not sure if it was 2 weeks ago as Github suggests

@xavgru12
Copy link
Author

@AnthonyLatsis another reminder

@AnthonyLatsis
Copy link
Collaborator

@slavapestov Could you take a look at this too?

@xavgru12 xavgru12 requested a review from AnthonyLatsis July 31, 2025 19:56
@xavgru12
Copy link
Author

@AnthonyLatsis
It has been some time. I think this is close to a good solution

@xavgru12
Copy link
Author

@AnthonyLatsis could you have a look?

@xavgru12
Copy link
Author

xavgru12 commented Oct 4, 2025

@AnthonyLatsis @slavapestov
Could someone have a look at it, so I can iterate further on it if required?

@xavgru12
Copy link
Author

xavgru12 commented Nov 3, 2025

@AnthonyLatsis

@xavgru12 xavgru12 closed this Nov 14, 2025
@xavgru12 xavgru12 reopened this Nov 14, 2025
@xavgru12
Copy link
Author

swift typecheckdecl isGeneric seems to have changed since last time I worked on it. Can be reviewed either way though

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