Skip to content

Commit 44c8052

Browse files
authored
Merge pull request swiftlang#34123 from DougGregor/circular-inheritance-decl
Teach SuperclassDeclRequest to always diagnose circularity.
2 parents 4e633b6 + 2dc8a13 commit 44c8052

15 files changed

+71
-117
lines changed

include/swift/AST/Decl.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3920,9 +3920,6 @@ class ClassDecl final : public NominalTypeDecl {
39203920
/// Set the superclass of this class.
39213921
void setSuperclass(Type superclass);
39223922

3923-
/// Whether this class has a circular reference in its inheritance hierarchy.
3924-
bool hasCircularInheritance() const;
3925-
39263923
/// Walk this class and all of the superclasses of this class, transitively,
39273924
/// invoking the callback function for each class.
39283925
///

include/swift/AST/NameLookupRequests.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,10 @@ class SuperclassDeclRequest :
160160
evaluate(Evaluator &evaluator, NominalTypeDecl *subject) const;
161161

162162
public:
163+
// Cycle handling
164+
void diagnoseCycle(DiagnosticEngine &diags) const;
165+
void noteCycleStep(DiagnosticEngine &diags) const;
166+
163167
// Caching
164168
bool isCached() const { return true; }
165169
Optional<ClassDecl *> getCachedResult() const;

include/swift/AST/TypeCheckRequests.h

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1986,29 +1986,6 @@ class PreCheckFunctionBuilderRequest
19861986
bool isCached() const { return true; }
19871987
};
19881988

1989-
/// Computes whether a class has a circular reference in its inheritance
1990-
/// hierarchy.
1991-
class HasCircularInheritanceRequest
1992-
: public SimpleRequest<HasCircularInheritanceRequest, bool(ClassDecl *),
1993-
RequestFlags::Cached> {
1994-
public:
1995-
using SimpleRequest::SimpleRequest;
1996-
1997-
private:
1998-
friend SimpleRequest;
1999-
2000-
// Evaluation.
2001-
bool evaluate(Evaluator &evaluator, ClassDecl *decl) const;
2002-
2003-
public:
2004-
// Cycle handling.
2005-
void diagnoseCycle(DiagnosticEngine &diags) const;
2006-
void noteCycleStep(DiagnosticEngine &diags) const;
2007-
2008-
// Cached.
2009-
bool isCached() const { return true; }
2010-
};
2011-
20121989
/// Computes whether a protocol has a circular reference in its list of
20131990
/// inherited protocols.
20141991
class HasCircularInheritedProtocolsRequest

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,6 @@ SWIFT_REQUEST(TypeChecker, FunctionOperatorRequest, OperatorDecl *(FuncDecl *),
9595
SWIFT_REQUEST(NameLookup, GenericSignatureRequest,
9696
GenericSignature (GenericContext *),
9797
SeparatelyCached, NoLocationInfo)
98-
SWIFT_REQUEST(TypeChecker, HasCircularInheritanceRequest,
99-
bool(ClassDecl *), Cached, NoLocationInfo)
10098
SWIFT_REQUEST(TypeChecker, HasCircularInheritedProtocolsRequest,
10199
bool(ProtocolDecl *), Cached, NoLocationInfo)
102100
SWIFT_REQUEST(TypeChecker, HasCircularRawValueRequest,

lib/AST/Decl.cpp

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4148,13 +4148,6 @@ void NominalTypeDecl::synthesizeSemanticMembersIfNeeded(DeclName member) {
41484148
}
41494149
}
41504150

4151-
bool ClassDecl::hasCircularInheritance() const {
4152-
auto &ctx = getASTContext();
4153-
auto *mutableThis = const_cast<ClassDecl *>(this);
4154-
return evaluateOrDefault(ctx.evaluator,
4155-
HasCircularInheritanceRequest{mutableThis}, true);
4156-
}
4157-
41584151
ClassDecl::ClassDecl(SourceLoc ClassLoc, Identifier Name, SourceLoc NameLoc,
41594152
MutableArrayRef<TypeLoc> Inherited,
41604153
GenericParamList *GenericParams, DeclContext *Parent)
@@ -4276,7 +4269,7 @@ bool ClassDecl::isIncompatibleWithWeakReferences() const {
42764269

42774270
bool ClassDecl::inheritsSuperclassInitializers() const {
42784271
// If there's no superclass, there's nothing to inherit.
4279-
if (!getSuperclass())
4272+
if (!getSuperclassDecl())
42804273
return false;
42814274

42824275
auto &ctx = getASTContext();
@@ -4294,19 +4287,11 @@ AncestryOptions ClassDecl::checkAncestry() const {
42944287
AncestryFlags
42954288
ClassAncestryFlagsRequest::evaluate(Evaluator &evaluator,
42964289
ClassDecl *value) const {
4297-
llvm::SmallPtrSet<const ClassDecl *, 8> visited;
4298-
42994290
AncestryOptions result;
43004291
const ClassDecl *CD = value;
43014292
auto *M = value->getParentModule();
43024293

43034294
do {
4304-
// If we hit circularity, we will diagnose at some point in typeCheckDecl().
4305-
// However we have to explicitly guard against that here because we get
4306-
// called as part of the interface type request.
4307-
if (!visited.insert(CD).second)
4308-
break;
4309-
43104295
if (CD->isGenericContext())
43114296
result |= AncestryFlags::Generic;
43124297

@@ -4496,10 +4481,9 @@ ClassDecl::findImplementingMethod(const AbstractFunctionDecl *Method) const {
44964481
bool ClassDecl::walkSuperclasses(
44974482
llvm::function_ref<TypeWalker::Action(ClassDecl *)> fn) const {
44984483

4499-
SmallPtrSet<ClassDecl *, 8> seen;
45004484
auto *cls = const_cast<ClassDecl *>(this);
45014485

4502-
while (cls && seen.insert(cls).second) {
4486+
while (cls) {
45034487
switch (fn(cls)) {
45044488
case TypeWalker::Action::Stop:
45054489
return true;

lib/AST/NameLookup.cpp

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2290,12 +2290,33 @@ SuperclassDeclRequest::evaluate(Evaluator &evaluator,
22902290
inheritedTypes, modulesFound, anyObject);
22912291

22922292
// Look for a class declaration.
2293+
ClassDecl *superclass = nullptr;
22932294
for (auto inheritedNominal : inheritedNominalTypes) {
2294-
if (auto classDecl = dyn_cast<ClassDecl>(inheritedNominal))
2295-
return classDecl;
2295+
if (auto classDecl = dyn_cast<ClassDecl>(inheritedNominal)) {
2296+
superclass = classDecl;
2297+
break;
2298+
}
22962299
}
2297-
}
22982300

2301+
// If we found a superclass, ensure that we don't have a circular
2302+
// inheritance hierarchy by evaluating its superclass. This forces the
2303+
// diagnostic at this point and then suppresses the superclass failure.
2304+
if (superclass) {
2305+
auto result = Ctx.evaluator(SuperclassDeclRequest{superclass});
2306+
bool hadCycle = false;
2307+
if (auto err = result.takeError()) {
2308+
llvm::handleAllErrors(std::move(err),
2309+
[&hadCycle](const CyclicalRequestError<SuperclassDeclRequest> &E) {
2310+
hadCycle = true;
2311+
});
2312+
2313+
if (hadCycle)
2314+
return nullptr;
2315+
}
2316+
2317+
return superclass;
2318+
}
2319+
}
22992320

23002321
return nullptr;
23012322
}

lib/AST/NameLookupRequests.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,19 @@ SourceLoc InheritedDeclsReferencedRequest::getNearestLoc() const {
4545
//----------------------------------------------------------------------------//
4646
// Superclass declaration computation.
4747
//----------------------------------------------------------------------------//
48+
void SuperclassDeclRequest::diagnoseCycle(DiagnosticEngine &diags) const {
49+
// FIXME: Improve this diagnostic.
50+
auto nominalDecl = std::get<0>(getStorage());
51+
diags.diagnose(nominalDecl, diag::circular_class_inheritance,
52+
nominalDecl->getName());
53+
}
54+
55+
void SuperclassDeclRequest::noteCycleStep(DiagnosticEngine &diags) const {
56+
auto decl = std::get<0>(getStorage());
57+
diags.diagnose(decl, diag::kind_declname_declared_here,
58+
decl->getDescriptiveKind(), decl->getName());
59+
}
60+
4861
Optional<ClassDecl *> SuperclassDeclRequest::getCachedResult() const {
4962
auto nominalDecl = std::get<0>(getStorage());
5063

lib/AST/TypeCheckRequests.cpp

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1136,23 +1136,6 @@ void swift::simple_display(llvm::raw_ostream &out,
11361136
}
11371137
}
11381138

1139-
//----------------------------------------------------------------------------//
1140-
// HasCircularInheritanceRequest computation.
1141-
//----------------------------------------------------------------------------//
1142-
1143-
void HasCircularInheritanceRequest::diagnoseCycle(
1144-
DiagnosticEngine &diags) const {
1145-
auto *decl = std::get<0>(getStorage());
1146-
diags.diagnose(decl, diag::circular_class_inheritance, decl->getName());
1147-
}
1148-
1149-
void HasCircularInheritanceRequest::noteCycleStep(
1150-
DiagnosticEngine &diags) const {
1151-
auto *decl = std::get<0>(getStorage());
1152-
diags.diagnose(decl, diag::kind_declname_declared_here,
1153-
decl->getDescriptiveKind(), decl->getName());
1154-
}
1155-
11561139
//----------------------------------------------------------------------------//
11571140
// HasCircularInheritedProtocolsRequest computation.
11581141
//----------------------------------------------------------------------------//

lib/SILGen/SILGen.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1288,8 +1288,8 @@ bool SILGenModule::requiresIVarDestroyer(ClassDecl *cd) {
12881288
// Only needed if we have non-trivial ivars, we're not a root class, and
12891289
// the superclass is not @objc.
12901290
return (hasNonTrivialIVars(cd) &&
1291-
cd->getSuperclass() &&
1292-
!cd->getSuperclass()->getClassOrBoundGenericClass()->hasClangNode());
1291+
cd->getSuperclassDecl() &&
1292+
!cd->getSuperclassDecl()->hasClangNode());
12931293
}
12941294

12951295
/// TODO: This needs a better name.

lib/Sema/CodeSynthesis.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1076,12 +1076,11 @@ InheritsSuperclassInitializersRequest::evaluate(Evaluator &eval,
10761076
if (decl->getAttrs().hasAttribute<InheritsConvenienceInitializersAttr>())
10771077
return true;
10781078

1079-
auto superclass = decl->getSuperclass();
1080-
assert(superclass);
1079+
auto superclassDecl = decl->getSuperclassDecl();
1080+
assert(superclassDecl);
10811081

10821082
// If the superclass has known-missing designated initializers, inheriting
10831083
// is unsafe.
1084-
auto *superclassDecl = superclass->getClassOrBoundGenericClass();
10851084
if (superclassDecl->getModuleContext() != decl->getParentModule() &&
10861085
superclassDecl->hasMissingDesignatedInitializers())
10871086
return false;
@@ -1357,7 +1356,7 @@ HasDefaultInitRequest::evaluate(Evaluator &evaluator,
13571356
// Don't synthesize a default for a subclass, it will attempt to inherit its
13581357
// initializers from its superclass.
13591358
if (auto *cd = dyn_cast<ClassDecl>(decl))
1360-
if (cd->getSuperclass())
1359+
if (cd->getSuperclassDecl())
13611360
return false;
13621361

13631362
// If the user has already defined a designated initializer, then don't

0 commit comments

Comments
 (0)