Skip to content

Retain type sugar for extension declarations that name generic typealiases #15450

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 4 commits into from
Mar 25, 2018

Conversation

DougGregor
Copy link
Member

When extending a type via a generic typealias, where the type parameters of
the underlying nominal type line up precisely with those of the
generic typealias and its specialization of the underlying nominal
type (a so-called "pass-through" typealias in the new code), maintain
type sugar in the extension declaration.

This new type sugar enables inference of type requirements from the
generic typealias, which is both useful by itself (it lets the type
requirements on generic typealiases be meaningful for extensions like
they are elsewhere), and also addresses a source-compatability
regression where an extension of CountableRange will now infer the
requirement Bound: Comparable.

Fixes SR-6907 / rdar://problem/29066394.

…iases.

When extending a type via a generic typealias, where the type parameters of
the underlying nominal type line up precisely with those of the
generic typealias and its specialization of the underlying nominal
type (a so-called "pass-through" typealias in the new code), maintain
type sugar in the extension declaration.

This new type sugar enables inference of type requirements from the
generic typealias, which is both useful by itself (it lets the type
requirements on generic typealiases be meaningful for extensions like
they are elsewhere), and also addresses a source-compatability
regression where an extension of `CountableRange` will now infer the
requirement `Bound: Comparable`.

Fixes SR-6907 / rdar://problem/29066394.
@DougGregor
Copy link
Member Author

@swift-ci please smoke test

@DougGregor
Copy link
Member Author

@swift-ci please test source compatibility


struct RequiresComparable<T: Comparable> { }

extension CountableRange { // expected-warning{{'CountableRange' is deprecated: renamed to 'Range'}}
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you test 'extension DictionaryIndex' too?

Copy link
Member Author

Choose a reason for hiding this comment

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

Sure!

This function was unable to "look through" an unbound generic typealias to
find the underlying nominal type that was getting extended, which can occur
if we end up performing a name lookup into this context before the extension
itself has been fully-checked.

Also, test that extending DictionaryIndex works.
@DougGregor
Copy link
Member Author

@swift-ci please smoke test

@DougGregor
Copy link
Member Author

@swift-ci please test source compatibility

The optimization that avoided forming new generic signatures for extensions
of nominal types was kicking in too eagerly, preventing us from inferring
requirements from the typealias.
@DougGregor
Copy link
Member Author

@swift-ci please smoke test

2 similar comments
@DougGregor
Copy link
Member Author

@swift-ci please smoke test

@DougGregor
Copy link
Member Author

@swift-ci please smoke test

@DougGregor
Copy link
Member Author

@swift-ci please test source compatibility

1 similar comment
@DougGregor
Copy link
Member Author

@swift-ci please test source compatibility

@DougGregor
Copy link
Member Author

@swift-ci please smoke test

2 similar comments
@DougGregor
Copy link
Member Author

@swift-ci please smoke test

@DougGregor
Copy link
Member Author

@swift-ci please smoke test

@DougGregor
Copy link
Member Author

Linux failure is weird:

15:17:41 CMake Error at CMakeLists.txt:90 (message):
15:17:41   LLDB test compilers not specified.  Tests will not run
15:17:41 
15:17:41 
15:17:41 -- Configuring incomplete, errors occurred!

Copy link
Contributor

@lattner lattner left a comment

Choose a reason for hiding this comment

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

LGTM, but I don't have this stuff paged into my head anymore.

auto type = ext->getExtendedType();
if (!type) return nullptr;

do {
Copy link
Contributor

Choose a reason for hiding this comment

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

Trivial style point, but a while(true) is arguably better than do/while(true) because you can know that it is an infinite loop reading the code top to bottom.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, sure.

// Check that the type parameters are the same the whole way through.
auto nominalGenericParams = nominalSig->getGenericParams();
auto typealiasGenericParams = typealiasSig->getGenericParams();
if (nominalGenericParams.size() != typealiasGenericParams.size())
Copy link
Contributor

Choose a reason for hiding this comment

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

Checking the sizes match is redundant with the subsequent std::equal call.

Copy link
Member Author

Choose a reason for hiding this comment

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

Unfortunately, it isn't, because std::equal is terrible API that only takes the "first" iterator to the second sequence, assuming that one has already performed the size check ahead of time!

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh man. 🙄🙄

Copy link
Contributor

Choose a reason for hiding this comment

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

Well, there's the variant that takes the second end-iterator too…

// a passthrough typealias.
auto innermostGenericParams = typealiasSig->getInnermostGenericParams();
auto boundArgs = boundGenericType->getGenericArgs();
if (boundArgs.size() != innermostGenericParams.size())
Copy link
Contributor

Choose a reason for hiding this comment

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

likewise.

auto nominal = dyn_cast<NominalTypeDecl>(genericDecl);
auto typealias = dyn_cast<TypeAliasDecl>(genericDecl);
if (!nominal) {
Type underlyingType = typealias->getUnderlyingTypeLoc().getType();
Copy link
Contributor

Choose a reason for hiding this comment

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

Are you sure that genericDecl is either a typealias or a nominaltype decl? If it is possible for it to be neither of those, then this code will crash with a null dereference.

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 am, because the only forms of type declaration we have in the language are "nominal" and "alias". I suspect that distinction will last "forever", because any new kind of type we invent will either have a name and a runtime presence (nominal) or be some form of alias.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ok, sounds good. please add an assertion :)

@DougGregor
Copy link
Member Author

Okay, this one is actually good to go. The GRDB source-compatibility failure can't be addressed in a meaningful way. @lattner , I have another commit coming to fix the while(true) issue, but it's in a follow-on PR.

@DougGregor DougGregor merged commit 82ea1dc into swiftlang:master Mar 25, 2018
@DougGregor DougGregor deleted the infer-ext-generic-typealias branch March 25, 2018 06:57
@groue
Copy link

groue commented Mar 26, 2018

The GRDB source-compatibility failure can't be addressed in a meaningful way.

I feel sorry (GRDB author here). Is there anything I can do to help?

@DougGregor
Copy link
Member Author

@groue actually, my comment was incorrect and I was confused! GRDB has provided a fantastic example here, and I'd missed that I needed to update the standard library to take advance of the compiler work in this pull request. The standard library change at #15513 gets GRDB passing again!

@groue
Copy link

groue commented Mar 26, 2018

That's a relief, thank you Doug! Because the work that had to be done to make it pass was everything but trivial :-)

@DougGregor
Copy link
Member Author

You gave me an excuse to refactor something that I've felt is wrong/broken for ~2 years, so thanks!

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.

5 participants