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;
/// Set the superclass of this class.
void setSuperclass(Type superclass) {
LazySemanticInfo.Superclass.setPointerAndInt(superclass, true);
}
void setSuperclass(Type superclass);
/// Retrieve the status of circularity checking for class inheritance.
CircularityCheck getCircularityCheck() const {

View File

@@ -4762,3 +4762,9 @@ ClassDecl *ClassDecl::getSuperclassDecl() const {
return superclass->getClassOrBoundGenericClass();
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?
bool shouldSubst = !isa<UnboundGenericType>(BaseTy.getPointer()) &&
bool shouldSubst = !BaseTy->hasUnboundGenericType() &&
!isa<AnyMetatypeType>(BaseTy.getPointer()) &&
!BaseTy->isAnyExistentialType();
ModuleDecl *M = DC->getParentModule();

View File

@@ -1597,76 +1597,37 @@ bool TypeBase::isSpelledLike(Type other) {
}
Type TypeBase::getSuperclass(LazyResolver *resolver) {
// If this type is either a bound generic type, or a nested type inside a
// bound generic type, we will need to fish out the generic parameters.
Type specializedTy;
ClassDecl *classDecl = getClassOrBoundGenericClass();
ClassDecl *classDecl;
if (auto classTy = getAs<ClassType>()) {
classDecl = classTy->getDecl();
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>()) {
// Handle some special non-class types here.
if (!classDecl) {
if (auto archetype = getAs<ArchetypeType>())
return archetype->getSuperclass();
} else if (auto dynamicSelfTy = getAs<DynamicSelfType>()) {
if (auto dynamicSelfTy = getAs<DynamicSelfType>())
return dynamicSelfTy->getSelfType();
} else {
// No other types have superclasses.
return nullptr;
}
// Get the superclass type. If the class is generic, the superclass type may
// contain generic type parameters from the signature of the class.
Type superclassTy;
if (classDecl)
superclassTy = classDecl->getSuperclass();
// We have a class, so get the superclass type.
//
// If the derived class is generic, the superclass type may contain
// generic type parameters from the signature of the derived class.
Type superclassTy = classDecl->getSuperclass();
// If there's no superclass, return a null type. If the class is not in a
// generic context, return the original superclass type.
if (!superclassTy || !classDecl->isGenericContext())
// If there's no superclass, or it is fully concrete, we're done.
if (!superclassTy || !superclassTy->hasTypeParameter())
return superclassTy;
// The class is defined in a generic context, so its superclass type may refer
// to generic parameters of the class or some parent type of the class. Map
// 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.
// Gather substitutions from the self type, and apply them to the original
// superclass type to form the substituted superclass type.
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) {

View File

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