Skip to content

Commit 1864f6f

Browse files
committed
AST: Introduce ClassDecl::isSuperclassOf()
1 parent cece98b commit 1864f6f

File tree

7 files changed

+37
-57
lines changed

7 files changed

+37
-57
lines changed

include/swift/AST/Decl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3631,6 +3631,9 @@ class ClassDecl final : public NominalTypeDecl {
36313631
/// is no superclass.
36323632
ClassDecl *getSuperclassDecl() const;
36333633

3634+
/// Check if this class is a superclass or equal to the given class.
3635+
bool isSuperclassOf(ClassDecl *other) const;
3636+
36343637
/// Set the superclass of this class.
36353638
void setSuperclass(Type superclass);
36363639

lib/AST/Decl.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3680,6 +3680,22 @@ AncestryOptions ClassDecl::checkAncestry() const {
36803680
return result;
36813681
}
36823682

3683+
bool ClassDecl::isSuperclassOf(ClassDecl *other) const {
3684+
llvm::SmallPtrSet<const ClassDecl *, 8> visited;
3685+
3686+
do {
3687+
if (!visited.insert(other).second)
3688+
break;
3689+
3690+
if (this == other)
3691+
return true;
3692+
3693+
other = other->getSuperclassDecl();
3694+
} while (other != nullptr);
3695+
3696+
return false;
3697+
}
3698+
36833699
ClassDecl::MetaclassKind ClassDecl::getMetaclassKind() const {
36843700
assert(getASTContext().LangOpts.EnableObjCInterop &&
36853701
"querying metaclass kind without objc interop");
@@ -3773,8 +3789,6 @@ ClassDecl::findImplementingMethod(const AbstractFunctionDecl *Method) const {
37733789
}
37743790
}
37753791
// Check the superclass
3776-
if (!C->hasSuperclass())
3777-
break;
37783792
C = C->getSuperclassDecl();
37793793
}
37803794
return nullptr;

lib/AST/Type.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3110,9 +3110,7 @@ Type TypeBase::getSuperclassForDecl(const ClassDecl *baseClass,
31103110
#ifndef NDEBUG
31113111
auto *currentClass = getConcreteTypeForSuperclassTraversing(this)
31123112
->getClassOrBoundGenericClass();
3113-
while (currentClass && currentClass != baseClass)
3114-
currentClass = currentClass->getSuperclassDecl();
3115-
assert(currentClass == baseClass &&
3113+
assert(baseClass->isSuperclassOf(currentClass) &&
31163114
"no inheritance relationship between given classes");
31173115
#endif
31183116

lib/SIL/DynamicCasts.cpp

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,14 @@ mustBridgeToSwiftValueBox(ModuleDecl *M, CanType T) {
5656
return !M->getASTContext().getBridgedToObjC(M, T);
5757
}
5858

59-
static bool canClassOrSuperclassesHaveExtensions(ClassDecl *CD,
60-
bool isWholeModuleOpts) {
59+
static bool canClassOrSuperclassesHaveUnknownSubclasses(ClassDecl *CD,
60+
bool isWholeModuleOpts) {
6161
while (CD) {
62-
// Open classes can always be extended
62+
// Open classes can always have unknown subclasses.
6363
if (CD->getEffectiveAccess() == AccessLevel::Open)
6464
return true;
6565

66-
// Internal and public classes can be extended, if we are not in
66+
// Internal and public classes may have unknown subclasses if we are not in
6767
// whole-module-optimization mode.
6868
if (CD->getEffectiveAccess() >= AccessLevel::Internal &&
6969
!isWholeModuleOpts)
@@ -110,11 +110,9 @@ classifyDynamicCastToProtocol(ModuleDecl *M, CanType source, CanType target,
110110
}
111111

112112
// If it is a class and it can be proven that this class and its
113-
// superclasses cannot be extended, then it is safe to proceed.
114-
// No need to check this for structs, as they do not have any
115-
// superclasses.
113+
// superclasses cannot have unknown subclasses, then it is safe to proceed.
116114
if (auto *CD = source.getClassOrBoundGenericClass()) {
117-
if (canClassOrSuperclassesHaveExtensions(CD, isWholeModuleOpts))
115+
if (canClassOrSuperclassesHaveUnknownSubclasses(CD, isWholeModuleOpts))
118116
return DynamicCastFeasibility::MaySucceed;
119117
// Derived types may conform to the protocol.
120118
if (!CD->isFinal()) {
@@ -555,22 +553,13 @@ swift::classifyDynamicCast(ModuleDecl *M,
555553
if (targetClass->usesObjCGenericsModel()) {
556554
// If both classes are ObjC generics, the cast may succeed if the
557555
// classes are related, irrespective of their generic parameters.
558-
auto isDeclSuperclass = [&](ClassDecl *proposedSuper,
559-
ClassDecl *proposedSub) -> bool {
560-
do {
561-
if (proposedSuper == proposedSub)
562-
return true;
563-
} while ((proposedSub = proposedSub->getSuperclassDecl()));
564-
565-
return false;
566-
};
567-
568-
if (isDeclSuperclass(sourceClass, targetClass))
556+
557+
if (sourceClass->isSuperclassOf(targetClass))
569558
return DynamicCastFeasibility::MaySucceed;
570559

571-
if (isDeclSuperclass(targetClass, sourceClass)) {
560+
if (targetClass->isSuperclassOf(sourceClass))
572561
return DynamicCastFeasibility::WillSucceed;
573-
}
562+
574563
return DynamicCastFeasibility::WillFail;
575564
}
576565
}

lib/SIL/SILVerifier.cpp

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2291,10 +2291,8 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
22912291
->getInstanceType()->getClassOrBoundGenericClass();
22922292
require(class2,
22932293
"Second operand of dealloc_partial_ref must be a class metatype");
2294-
while (class1 != class2) {
2295-
class1 = class1->getSuperclassDecl();
2296-
require(class1, "First operand not superclass of second instance type");
2297-
}
2294+
require(class2->isSuperclassOf(class1),
2295+
"First operand not superclass of second instance type");
22982296
}
22992297

23002298
void checkAllocBoxInst(AllocBoxInst *AI) {
@@ -4981,13 +4979,8 @@ void SILVTable::verify(const SILModule &M) const {
49814979
assert(theClass && "vtable entry must refer to a class member");
49824980

49834981
// The class context must be the vtable's class, or a superclass thereof.
4984-
auto c = getClass();
4985-
do {
4986-
if (c == theClass)
4987-
break;
4988-
c = c->getSuperclassDecl();
4989-
} while (c);
4990-
assert(c && "vtable entry must refer to a member of the vtable's class");
4982+
assert(theClass->isSuperclassOf(getClass()) &&
4983+
"vtable entry must refer to a member of the vtable's class");
49914984

49924985
// All function vtable entries must be at their natural uncurry level.
49934986
assert(!entry.Method.isCurried && "vtable entry must not be curried");

lib/SILOptimizer/IPO/DeadFunctionElimination.cpp

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -255,18 +255,6 @@ class FunctionLivenessComputation {
255255
makeAlive(WT);
256256
}
257257

258-
/// Returns true if \a Derived is the same as \p Base or derived from it.
259-
static bool isDerivedOrEqual(ClassDecl *Derived, ClassDecl *Base) {
260-
for (;;) {
261-
if (Derived == Base)
262-
return true;
263-
if (!Derived->hasSuperclass())
264-
break;
265-
Derived = Derived->getSuperclassDecl();
266-
}
267-
return false;
268-
}
269-
270258
/// Returns true if the implementation of method \p FD in class \p ImplCl
271259
/// may be called when the type of the class_method's operand is \p MethodCl.
272260
/// Both, \p MethodCl and \p ImplCl, may by null if not known or if it's a
@@ -277,7 +265,7 @@ class FunctionLivenessComputation {
277265
return true;
278266

279267
// All implementations of derived classes may be called.
280-
if (isDerivedOrEqual(ImplCl, MethodCl))
268+
if (MethodCl->isSuperclassOf(ImplCl))
281269
return true;
282270

283271
// Check if the method implementation is the same in a super class, i.e.

lib/Sema/MiscDiagnostics.cpp

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3335,13 +3335,8 @@ class ObjCSelectorWalker : public ASTWalker {
33353335

33363336
// If the best method was from a subclass of the place where
33373337
// this method was declared, we have a new best.
3338-
while (auto superclassDecl = bestClassDecl->getSuperclassDecl()) {
3339-
if (classDecl == superclassDecl) {
3340-
bestMethod = method;
3341-
break;
3342-
}
3343-
3344-
bestClassDecl = superclassDecl;
3338+
if (classDecl->isSuperclassOf(bestClassDecl)) {
3339+
bestMethod = method;
33453340
}
33463341
}
33473342

0 commit comments

Comments
 (0)