AST: Update TypeBase::getSuperclassForDecl() for subclass existentials

This function takes a member of a class and a base type, and returns
the correct 'self' type to substitute into the member's type.

When accessing a member of a subclass existential, if the member
was found via the superclass constraint, we have to erase the
existential down to the class type to calculate the member's
substituted type.

We already had special logic to handle class-constrained archetypes
in the callers of getSuperclassForDecl(); move this check into the
method, and add a similar check for subclass existentials, which
now support the getSuperclass() method.
This commit is contained in:
Slava Pestov
2017-04-07 21:56:03 -07:00
parent 30cd0a9268
commit 473faf1eed
2 changed files with 12 additions and 14 deletions

View File

@@ -3105,10 +3105,19 @@ Type TypeBase::getSuperclassForDecl(const ClassDecl *baseClass,
LazyResolver *resolver) { LazyResolver *resolver) {
Type t(this); Type t(this);
while (t) { while (t) {
auto *derivedClass = dyn_cast_or_null<ClassDecl>(t->getAnyNominal()); // If we have a class-constrained archetype or class-constrained
assert(derivedClass && "expected a class here"); // existential, get the underlying superclass constraint.
auto *nominalDecl = t->getAnyNominal();
if (!nominalDecl) {
assert(t->is<ArchetypeType>() || t->isExistentialType() &&
"expected a class, archetype or existentiall");
t = t->getSuperclass(resolver);
assert(t && "archetype or existential is not class constrained");
continue;
}
assert(isa<ClassDecl>(nominalDecl) && "expected a class here");
if (derivedClass == baseClass) if (nominalDecl == baseClass)
return t; return t;
t = t->getSuperclass(resolver); t = t->getSuperclass(resolver);
@@ -3139,19 +3148,10 @@ TypeBase::getContextSubstitutions(const DeclContext *dc,
return substitutions; return substitutions;
} }
// If we found a member of a concrete type from a protocol extension,
// get the superclass out of the archetype.
if (auto *archetypeTy = baseTy->getAs<ArchetypeType>())
baseTy = archetypeTy->getSuperclass();
// Extract the lazy resolver. // Extract the lazy resolver.
LazyResolver *resolver = dc->getASTContext().getLazyResolver(); LazyResolver *resolver = dc->getASTContext().getLazyResolver();
// Find the superclass type with the context matching that of the member. // Find the superclass type with the context matching that of the member.
//
// FIXME: Do this in the caller?
assert(baseTy->getAnyNominal());
auto *ownerNominal = dc->getAsNominalTypeOrNominalTypeExtensionContext(); auto *ownerNominal = dc->getAsNominalTypeOrNominalTypeExtensionContext();
if (auto *ownerClass = dyn_cast<ClassDecl>(ownerNominal)) if (auto *ownerClass = dyn_cast<ClassDecl>(ownerNominal))
baseTy = baseTy->getSuperclassForDecl(ownerClass, resolver); baseTy = baseTy->getSuperclassForDecl(ownerClass, resolver);

View File

@@ -3030,8 +3030,6 @@ Type TypeChecker::substMemberTypeWithBase(ModuleDecl *module,
// derived class as the parent type. // derived class as the parent type.
if (auto *ownerClass = member->getDeclContext() if (auto *ownerClass = member->getDeclContext()
->getAsClassOrClassExtensionContext()) { ->getAsClassOrClassExtensionContext()) {
if (auto *archetypeTy = baseTy->getAs<ArchetypeType>())
baseTy = archetypeTy->getSuperclass();
baseTy = baseTy->getSuperclassForDecl(ownerClass, this); baseTy = baseTy->getSuperclassForDecl(ownerClass, this);
} }