Sema: Fix a couple of crash-on-invalid problems with class inheritance

It is possible for ClassDecl::getSuperclassDecl() to succeed but for
ClassDecl::getSuperclass() to fail. This happens if the superclass is
a generic type and one of the generic arguments could not be resolved,
or does not satisfy the generic requirements, for example; in that
case, a BoundGenericType cannot be formed.

In a couple of places we were not prepared for this possibility.
Let's recover by making judicious use of ErrorType.

Fixes <rdar://problem/73169149>.
This commit is contained in:
Slava Pestov
2021-01-17 18:00:32 -05:00
parent 0ee3b22384
commit c8aee4180e
4 changed files with 48 additions and 10 deletions

View File

@@ -62,6 +62,12 @@ Expr *swift::buildSelfReference(VarDecl *selfDecl,
selfTy = metaTy->getInstanceType(); selfTy = metaTy->getInstanceType();
} }
selfTy = selfTy->getSuperclass(); selfTy = selfTy->getSuperclass();
if (!selfTy) {
// Error recovery path. We end up here if getSuperclassDecl() succeeds
// but getSuperclass() fails (because, for instance, a generic parameter
// of a generic nominal type cannot be resolved).
selfTy = ErrorType::get(ctx);
}
if (isMetatype) if (isMetatype)
selfTy = MetatypeType::get(selfTy); selfTy = MetatypeType::get(selfTy);
@@ -70,7 +76,7 @@ Expr *swift::buildSelfReference(VarDecl *selfDecl,
// If no conversion type was specified, or we're already at that type, we're // If no conversion type was specified, or we're already at that type, we're
// done. // done.
if (!convertTy || convertTy->isEqual(selfTy)) if (!convertTy || convertTy->isEqual(selfTy) || selfTy->is<ErrorType>())
return superRef; return superRef;
// Insert the appropriate expr to handle the upcast. // Insert the appropriate expr to handle the upcast.

View File

@@ -151,12 +151,12 @@ namespace {
auto conformance = DC->getParentModule()->lookupConformance( auto conformance = DC->getParentModule()->lookupConformance(
conformingType, foundProto); conformingType, foundProto);
if (conformance.isInvalid()) { if (conformance.isInvalid()) {
// If there's no conformance, we have an existential if (foundInType->isExistentialType()) {
// and we found a member from one of the protocols, and // If there's no conformance, we have an existential
// not a class constraint if any. // and we found a member from one of the protocols, and
assert(foundInType->isExistentialType() || foundInType->hasError()); // not a class constraint if any.
if (foundInType->isExistentialType())
addResult(found); addResult(found);
}
return; return;
} }

View File

@@ -717,10 +717,16 @@ static Expr *buildStorageReference(AccessorDecl *accessor,
// Adjust the self type of the access to refer to the relevant superclass. // Adjust the self type of the access to refer to the relevant superclass.
auto *baseClass = override->getDeclContext()->getSelfClassDecl(); auto *baseClass = override->getDeclContext()->getSelfClassDecl();
selfTypeForAccess = selfTypeForAccess->getSuperclassForDecl(baseClass); selfTypeForAccess = selfTypeForAccess->getSuperclassForDecl(baseClass);
subs =
selfTypeForAccess->getContextSubstitutionMap( // Error recovery path. We get an ErrorType here if getSuperclassForDecl()
accessor->getParentModule(), // fails (because, for instance, a generic parameter of a generic nominal
baseClass); // type cannot be resolved).
if (!selfTypeForAccess->is<ErrorType>()) {
subs =
selfTypeForAccess->getContextSubstitutionMap(
accessor->getParentModule(),
baseClass);
}
storage = override; storage = override;

View File

@@ -0,0 +1,26 @@
// RUN: not %target-swift-frontend -emit-ir %s
public protocol Ungulate {
func eat()
}
public class Horse<T> : Ungulate {
public var saddle: AnyObject? = nil
public func eat() {}
}
public struct Hay {}
// Here, ClassDecl::getSuperclassDecl() will find the 'Horse' class, but
// ClassDecl::getSuperclass() will return ErrorType because the generic
// argument 'DoesNotExist' cannot be resolved.
public class Pony : Horse<DoesNotExist> {
public override var saddle: AnyObject? {
didSet {}
}
public func eat(_: Hay) {
eat()
}
}