Skip to content

Remove duplicate signatures in intersections #32049

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

Merged
merged 5 commits into from
Jul 1, 2019

Conversation

ahejlsberg
Copy link
Member

Fixes #32038.

@ahejlsberg ahejlsberg added this to the TypeScript 3.6.0 milestone Jun 23, 2019
@ahejlsberg
Copy link
Member Author

@typescript-bot run dt

@typescript-bot
Copy link
Collaborator

typescript-bot commented Jun 23, 2019

Heya @ahejlsberg, I've started to run the parallelized Definitely Typed test suite on this PR at be4147d. You can monitor the build here. It should now contribute to this PR's status checks.

@ahejlsberg
Copy link
Member Author

DT run is clean (error is unrelated and exists with master branch as well).


function appendSignatures(signatures: Signature[] | undefined, newSignatures: readonly Signature[]) {
for (const sig of newSignatures) {
if (!signatures || every(signatures, s => !compareSignaturesIdentical(s, sig, /*partialMatch*/ false, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ false, compareTypesIdentical))) {
Copy link
Member

Choose a reason for hiding this comment

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

Uhhhh, it's probably worth noting that compareSignaturesIdentical needs some TLC - it currently erases constraints to any like compareSignatures used to, which causes spurious false positives. Concretely, that means that if I have a:

type Foo = (<T extends number>(x: T) => T) & (<T extends string>(x: T) => T)

I don't think we'll be happy with the result here... (I looked into this around #31023 )

@ahejlsberg
Copy link
Member Author

With latest commits we now properly compare type parameters, constraints, and defaults when checking signature identity. Baseline changes nicely reflect cases that should fail but previously didn't because we just erased type parameters.

@ahejlsberg ahejlsberg requested a review from weswigham June 27, 2019 04:15
@ahejlsberg
Copy link
Member Author

@typescript-bot run dt

@typescript-bot
Copy link
Collaborator

typescript-bot commented Jun 27, 2019

Heya @ahejlsberg, I've started to run the parallelized Definitely Typed test suite on this PR at 10c9fbc. You can monitor the build here. It should now contribute to this PR's status checks.

const s = source.typeParameters![i];
const t = target.typeParameters[i];
if (!(s === t || compareTypes(instantiateType(getConstraintFromTypeParameter(s), mapper) || unknownType, getConstraintFromTypeParameter(t) || unknownType) &&
compareTypes(instantiateType(getDefaultFromTypeParameter(s), mapper) || unknownType, getDefaultFromTypeParameter(t) || unknownType))) {
Copy link
Member

Choose a reason for hiding this comment

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

Yeah, I don't think we can consider defaults when checking identity - if we do, then two conditional extends clauses that only differ in a local type parameter default (which doesn't affect relationship checking) will fail to be seen as identical.

Copy link
Member

Choose a reason for hiding this comment

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

Eg, (A extends <T = {}>() => T ? 1 : 0) extends (A extends <T = unknown>() => T ? 1 : 0) ? true : false should resolve to true, I think, not false.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not sure I understand how that example is relevant. Best I can tell at no point will we compare signatures for identity in the example.

Copy link
Member

Choose a reason for hiding this comment

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

Conditional extends clauses are compared using isTypeIdenticalTo when checking if one conditional extends the other in the above example. Apparently this is already in use in the wild as a way to observe type "identity" in complex type toolbelt libraries.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ok, I see that logic in structuredTypeRelatedTo. Still, as far as I'm concerned, those two types aren't identical and I can't think of a meaningful definition of "identical" that would make it true for them, but not for the other cases we care about. It would just seem really odd to make an exception for local type parameter defaults, but nothing else.

Copy link
Member

Choose a reason for hiding this comment

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

I mean, we let you assign a function with a default to a function with a different default and vice-versa - it's just the typesystem equivalent of aliasing. Generally defaults aren't observable up until the point where inference fails - this exposes them into relationship checking before inference is ever invoked, success or no.

Copy link
Member Author

Choose a reason for hiding this comment

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

I still don't think that merits a special exception to identity checking. The identity relation should be concerned with accurately identifying semantically identical types, and it does a better job of that now. I think we need to get this merged.

@ahejlsberg
Copy link
Member Author

@weswigham I don't see a compelling reason for why defaults shouldn't be included in identity checking. After all, we're checking whether the signatures are semantically identical, meaning that you get identical results no matter which one you pick. With different defaults that isn't the case.

@ahejlsberg
Copy link
Member Author

The DT test run looks clean (the one failure appears completely unrelated).

Copy link
Member

@weswigham weswigham left a comment

Choose a reason for hiding this comment

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

I still think we shouldn't be considering defaults when comparing conditional extends. 🤷‍♂️

@ahejlsberg ahejlsberg merged commit f89165d into master Jul 1, 2019
@ahejlsberg ahejlsberg deleted the noDuplicateIntersectionSignatures branch July 1, 2019 02:38
@weswigham
Copy link
Member

DT is clean, but RWC is strange. A bunch of errors were eliminated in fp-ts (unsure why), while in glimmer we got a bunch of new errors.

amcasey added a commit to amcasey/TypeScript that referenced this pull request Nov 13, 2019
…IntersectionSignatures"

This reverts commit f89165d, reversing
changes made to 410b717.
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.

3.5 regression: union type as property accessor break function parameter inference
3 participants