AST: Cleanups for TypeBase::getSuperclass()

First, enforce that the superclass of a class is an interface type.
Previously, Swift classes used interface types but imported
Objective-C generics used archetypes.

When the superclass type is always an interface type, we
can use the recently-added gatherAllSubstitutions() instead of
rolling our own parent type walk.

Also, this exposed an issue in name lookup where we would call
getSuperclass() on a type whose parent was an unbound generic.
This doesn't make sense, so generalize the existing check there.
This commit is contained in:
Slava Pestov
2016-06-25 04:42:23 -07:00
parent 68c6b1a14b
commit 680688cbf5
5 changed files with 32 additions and 65 deletions

View File

@@ -3212,9 +3212,7 @@ public:
ClassDecl *getSuperclassDecl() const; ClassDecl *getSuperclassDecl() const;
/// Set the superclass of this class. /// Set the superclass of this class.
void setSuperclass(Type superclass) { void setSuperclass(Type superclass);
LazySemanticInfo.Superclass.setPointerAndInt(superclass, true);
}
/// Retrieve the status of circularity checking for class inheritance. /// Retrieve the status of circularity checking for class inheritance.
CircularityCheck getCircularityCheck() const { CircularityCheck getCircularityCheck() const {

View File

@@ -4762,3 +4762,9 @@ ClassDecl *ClassDecl::getSuperclassDecl() const {
return superclass->getClassOrBoundGenericClass(); return superclass->getClassOrBoundGenericClass();
return nullptr; return nullptr;
} }
void ClassDecl::setSuperclass(Type superclass) {
assert((!superclass || !superclass->hasArchetype())
&& "superclass must be interface type");
LazySemanticInfo.Superclass.setPointerAndInt(superclass, true);
}

View File

@@ -716,7 +716,7 @@ public:
} }
// Does it make sense to substitute types? // Does it make sense to substitute types?
bool shouldSubst = !isa<UnboundGenericType>(BaseTy.getPointer()) && bool shouldSubst = !BaseTy->hasUnboundGenericType() &&
!isa<AnyMetatypeType>(BaseTy.getPointer()) && !isa<AnyMetatypeType>(BaseTy.getPointer()) &&
!BaseTy->isAnyExistentialType(); !BaseTy->isAnyExistentialType();
ModuleDecl *M = DC->getParentModule(); ModuleDecl *M = DC->getParentModule();

View File

@@ -1597,76 +1597,37 @@ bool TypeBase::isSpelledLike(Type other) {
} }
Type TypeBase::getSuperclass(LazyResolver *resolver) { Type TypeBase::getSuperclass(LazyResolver *resolver) {
// If this type is either a bound generic type, or a nested type inside a ClassDecl *classDecl = getClassOrBoundGenericClass();
// bound generic type, we will need to fish out the generic parameters.
Type specializedTy;
ClassDecl *classDecl; // Handle some special non-class types here.
if (auto classTy = getAs<ClassType>()) { if (!classDecl) {
classDecl = classTy->getDecl(); if (auto archetype = getAs<ArchetypeType>())
if (auto parentTy = classTy->getParent()) {
if (parentTy->isSpecialized())
specializedTy = parentTy;
}
} else if (auto boundTy = getAs<BoundGenericType>()) {
classDecl = dyn_cast<ClassDecl>(boundTy->getDecl());
specializedTy = this;
} else if (auto archetype = getAs<ArchetypeType>()) {
return archetype->getSuperclass(); return archetype->getSuperclass();
} else if (auto dynamicSelfTy = getAs<DynamicSelfType>()) {
if (auto dynamicSelfTy = getAs<DynamicSelfType>())
return dynamicSelfTy->getSelfType(); return dynamicSelfTy->getSelfType();
} else {
// No other types have superclasses. // No other types have superclasses.
return nullptr; return nullptr;
} }
// Get the superclass type. If the class is generic, the superclass type may // We have a class, so get the superclass type.
// contain generic type parameters from the signature of the class. //
Type superclassTy; // If the derived class is generic, the superclass type may contain
if (classDecl) // generic type parameters from the signature of the derived class.
superclassTy = classDecl->getSuperclass(); Type superclassTy = classDecl->getSuperclass();
// If there's no superclass, return a null type. If the class is not in a // If there's no superclass, or it is fully concrete, we're done.
// generic context, return the original superclass type. if (!superclassTy || !superclassTy->hasTypeParameter())
if (!superclassTy || !classDecl->isGenericContext())
return superclassTy; return superclassTy;
// The class is defined in a generic context, so its superclass type may refer // Gather substitutions from the self type, and apply them to the original
// to generic parameters of the class or some parent type of the class. Map // superclass type to form the substituted superclass type.
// it to a contextual type.
// FIXME: Lame to rely on archetypes in the substitution below.
superclassTy = ArchetypeBuilder::mapTypeIntoContext(classDecl, superclassTy);
// If the type does not bind any generic parameters, return the superclass
// type as-is.
if (!specializedTy)
return superclassTy;
// If the type is specialized, we need to gather all of the substitutions
// for the type and any parent types.
TypeSubstitutionMap substitutions;
while (specializedTy) {
if (auto nominalTy = specializedTy->getAs<NominalType>()) {
specializedTy = nominalTy->getParent();
continue;
}
// Introduce substitutions for each of the generic parameters/arguments.
auto boundTy = specializedTy->castTo<BoundGenericType>();
auto gp = boundTy->getDecl()->getGenericParams()->getParams();
for (unsigned i = 0, n = boundTy->getGenericArgs().size(); i != n; ++i) {
auto archetype = gp[i]->getArchetype();
substitutions[archetype] = boundTy->getGenericArgs()[i];
}
specializedTy = boundTy->getParent();
}
// Perform substitutions into the superclass type to yield the
// substituted superclass type.
Module *module = classDecl->getModuleContext(); Module *module = classDecl->getModuleContext();
return superclassTy.subst(module, substitutions, None); auto *sig = classDecl->getGenericSignatureOfContext();
auto subs = sig->getSubstitutionMap(gatherAllSubstitutions(module, resolver));
return superclassTy.subst(module, subs, None);
} }
bool TypeBase::isExactSuperclassOf(Type ty, LazyResolver *resolver) { bool TypeBase::isExactSuperclassOf(Type ty, LazyResolver *resolver) {

View File

@@ -5740,6 +5740,8 @@ namespace {
isInSystemModule(dc), isInSystemModule(dc),
/*isFullyBridgeable*/false); /*isFullyBridgeable*/false);
if (superclassType) { if (superclassType) {
superclassType =
ArchetypeBuilder::mapTypeOutOfContext(result, superclassType);
assert(superclassType->is<ClassType>() || assert(superclassType->is<ClassType>() ||
superclassType->is<BoundGenericClassType>()); superclassType->is<BoundGenericClassType>());
inheritedTypes.push_back(TypeLoc::withoutLoc(superclassType)); inheritedTypes.push_back(TypeLoc::withoutLoc(superclassType));