Skip to content

[GSB] Eliminate concrete potential archetypes by early substitution #14965

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 1 commit into from
Mar 7, 2018

Conversation

xedin
Copy link
Contributor

@xedin xedin commented Mar 4, 2018

To make generic signature builder more robust it's imperative to
eliminate possibility of out-of-order typealias substitution.

These changes try to make it so potential archetypes could only be
constructed with associated types by doing early concrete type (typealias)
subsitution while trying to resolve equivalence class.

@xedin xedin requested a review from DougGregor March 4, 2018 12:20
@xedin
Copy link
Contributor Author

xedin commented Mar 4, 2018

/cc @DougGregor could you please take a look? Spent some time working on this over the weekend to remove the hack for typealias we have in place now...

It seems like it can detect more situations where typealias makes generic parameters 'non-generic' e.g.

protocol P {
  typealias A = Int
}

func foo<T: P, U>(_ a: T, _ b: U) where T.A == U {}

is going to produce error: same-type requirement makes generic parameter 'U' non-generic as this code does without my changes:

func foo<U>(_ a: U) where U == Int {}

@xedin xedin force-pushed the potential-archetype-only-assoc branch from bfa046a to a1fb120 Compare March 4, 2018 12:42
Copy link
Member

@DougGregor DougGregor left a comment

Choose a reason for hiding this comment

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

This is looking really promising! I'd like us to think about that loop over the "other" declarations found with the same name (in maybeResolvedEquivalenceClass), and will comment on the new error separately.

if (!concreteDecl->hasInterfaceType())
builder.getLazyResolver()->resolveDeclSignature(concreteDecl);

if (concreteDecl->hasInterfaceType()) {
Copy link
Member

Choose a reason for hiding this comment

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

Nit: I suggest doing an early return if !concreteDecl->hasInterfaceType() to de-nest the main code path.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure! I confess that I have a habit of moving the code around without really refactoring it all the way...

static Type substituteConcreteType(GenericSignatureBuilder &builder,
PotentialArchetype *basePA,
TypeDecl *concreteDecl) {
if (!concreteDecl)
Copy link
Member

Choose a reason for hiding this comment

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

Will we ever call it with a null concreteDecl? It seems like this should be an assert.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, makes sense!

// introduce various same-type constraints.
for (auto concreteDecl : concreteDecls) {
(void)basePA->updateNestedTypeForConformance(*this, concreteDecl,
resolutionKind);
Copy link
Member

Choose a reason for hiding this comment

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

Huh. I'm surprised we can get rid of this. It's supposed to establish equivalences between same-named nested types.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

To be honest I'm just not sure what it's going to do now because we substitute early which means that we'd end up with new potential archetype that has associated type so we don't really need to add new same-type requirement like before where we had potential archetype with concrete decl and substituted typealias type. But I might be totally missing something here, could you please provide an example?

Copy link
Member

Choose a reason for hiding this comment

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

Huh. I had convinced myself that this mattered due to #14974, but my change there didn't fix the problem at all. Maybe this is indeed dead code!

Copy link
Member

Choose a reason for hiding this comment

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

I suspect the deletion of this loop is the cause of the regression in ./validation-test/compiler_crashers_2_fixed/0075-rdar30248571.swift.

target->getParent() &&
sourceDepMemTy->getAssocType() &&
sourceDepMemTy->getAssocType() == target->getResolvedAssociatedType()){
target->getParent() && sourceDepMemTy->getAssocType() &&
Copy link
Member

Choose a reason for hiding this comment

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

Oh, I don't think you need to check for a null sourceDepMemTy->getAssocType(), because the "subject" of any constraint should (now) always be a well-formed type. I bet there are other places where we have such null checks that could go away with your PR!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right, good catch! Thanks!

@DougGregor
Copy link
Member

That same-type requirement makes generic parameter 'U' non-generic error might cause us some source-compatibility trouble (particularly with IndexDistance recently changing to Int), but we can assess the impact before we make any changes.

@DougGregor
Copy link
Member

Here's an assertion I have lying around that I think we can introduce into your PR, which would ensure that unresolved dependent types never slip into a generic function type. It's worth a shot!

diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp
index 5763586508..7c93d90f0c 100644
--- a/lib/Sema/TypeCheckGeneric.cpp
+++ b/lib/Sema/TypeCheckGeneric.cpp
@@ -866,7 +866,15 @@ TypeChecker::validateGenericFuncSignature(AbstractFunctionDecl *func) {
   }
 
   configureInterfaceType(func, sig);
-  return sig;
+
+  assert(func->getInterfaceType()->hasError() ||
+         !func->getInterfaceType().findIf([](Type type) {
+    if (auto depMemTy = type->getAs<DependentMemberType>()) {
+      return depMemTy->getAssocType() == nullptr;
+    }
+    return false;
+  }));
+return sig;
 }
 
 void TypeChecker::configureInterfaceType(AbstractFunctionDecl *func,

@xedin xedin force-pushed the potential-archetype-only-assoc branch from a1fb120 to 2be67ef Compare March 5, 2018 08:43
@xedin
Copy link
Contributor Author

xedin commented Mar 5, 2018

@DougGregor You've already added findUnresolvedDependentMemberType as a method on TypeBase so I'm just going to use that in the assert :)

@xedin xedin force-pushed the potential-archetype-only-assoc branch from 2be67ef to d0c533f Compare March 5, 2018 08:57
@xedin
Copy link
Contributor Author

xedin commented Mar 6, 2018

@swift-ci please smoke test

@xedin
Copy link
Contributor Author

xedin commented Mar 6, 2018

@DougGregor Could you please take a look at the failures - especially new error message in ./validation-test/compiler_crashers_2_fixed/0075-rdar30248571.swift and see that makes sense?

@xedin
Copy link
Contributor Author

xedin commented Mar 6, 2018

@DougGregor Thanks! I'll take a look, maybe I should get it back and substitute all of them the same way as typealiases, will try that later today.

@xedin
Copy link
Contributor Author

xedin commented Mar 7, 2018

@swift-ci please smoke test macOS platform

@xedin
Copy link
Contributor Author

xedin commented Mar 7, 2018

@DougGregor looks like your changes for nested typealiases have fixed validation test, I am going to fix up code completion one and run source compatibility suite.

@xedin xedin force-pushed the potential-archetype-only-assoc branch from d0c533f to 76fc9f7 Compare March 7, 2018 07:08
To make generic signature builder more robust it's imperative to
eliminate possibility of out-of-order typealias substitution.

These changes try to make it so potential archetypes could only be
constructed with associated types by doing early concrete type (typealias)
subsitution while trying to resolve equivalence class.
@xedin xedin force-pushed the potential-archetype-only-assoc branch from 76fc9f7 to 4b05449 Compare March 7, 2018 07:34
@xedin
Copy link
Contributor Author

xedin commented Mar 7, 2018

@swift-ci please smoke test

@xedin
Copy link
Contributor Author

xedin commented Mar 7, 2018

@swift-ci please test source compatibility

@xedin
Copy link
Contributor Author

xedin commented Mar 7, 2018

@swift-ci please test

@xedin
Copy link
Contributor Author

xedin commented Mar 7, 2018

@DougGregor Looks like everything is green, going to merge in the morning.

@DougGregor
Copy link
Member

Fantastic!


// Make sure that there are no unresolved
// dependent types in the generic signature.
assert(func->getInterfaceType()->hasError() ||
Copy link
Member

Choose a reason for hiding this comment

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

Very excited that this assertion is here now!

@xedin xedin merged commit e226c20 into swiftlang:master Mar 7, 2018
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.

2 participants