Skip to content

Commit f7ed8a7

Browse files
authored
Requestify circularity checking (swiftlang#28185)
Requestify circularity checking
2 parents 5602b54 + eacca4e commit f7ed8a7

File tree

10 files changed

+229
-173
lines changed

10 files changed

+229
-173
lines changed

include/swift/AST/Decl.h

Lines changed: 11 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -176,16 +176,6 @@ enum class DescriptiveDeclKind : uint8_t {
176176
OpaqueVarType
177177
};
178178

179-
/// Keeps track of stage of circularity checking for the given protocol.
180-
enum class CircularityCheck {
181-
/// Circularity has not yet been checked.
182-
Unchecked,
183-
/// We're currently checking circularity.
184-
Checking,
185-
/// Circularity has already been checked.
186-
Checked
187-
};
188-
189179
/// Describes which spelling was used in the source for the 'static' or 'class'
190180
/// keyword.
191181
enum class StaticSpellingKind : uint8_t {
@@ -489,7 +479,7 @@ class alignas(1 << DeclAlignInBits) Decl {
489479
IsComputingSemanticMembers : 1
490480
);
491481

492-
SWIFT_INLINE_BITFIELD_FULL(ProtocolDecl, NominalTypeDecl, 1+1+1+1+1+1+1+2+1+1+8+16,
482+
SWIFT_INLINE_BITFIELD_FULL(ProtocolDecl, NominalTypeDecl, 1+1+1+1+1+1+1+1+1+8+16,
493483
/// Whether the \c RequiresClass bit is valid.
494484
RequiresClassValid : 1,
495485

@@ -512,9 +502,6 @@ class alignas(1 << DeclAlignInBits) Decl {
512502
/// because they could not be imported from Objective-C).
513503
HasMissingRequirements : 1,
514504

515-
/// The stage of the circularity check for this protocol.
516-
Circularity : 2,
517-
518505
/// Whether we've computed the inherited protocols list yet.
519506
InheritedProtocolsValid : 1,
520507

@@ -531,10 +518,7 @@ class alignas(1 << DeclAlignInBits) Decl {
531518
NumRequirementsInSignature : 16
532519
);
533520

534-
SWIFT_INLINE_BITFIELD(ClassDecl, NominalTypeDecl, 2+1+1+2+1+7+1+1+1+1+1+1,
535-
/// The stage of the inheritance circularity check for this class.
536-
Circularity : 2,
537-
521+
SWIFT_INLINE_BITFIELD(ClassDecl, NominalTypeDecl, 1+1+2+1+1+1+1+1+1,
538522
/// Whether this class inherits its superclass's convenience initializers.
539523
InheritsSuperclassInits : 1,
540524
ComputedInheritsSuperclassInits : 1,
@@ -562,10 +546,7 @@ class alignas(1 << DeclAlignInBits) Decl {
562546
HasUnreferenceableStorage : 1
563547
);
564548

565-
SWIFT_INLINE_BITFIELD(EnumDecl, NominalTypeDecl, 2+2+1,
566-
/// The stage of the raw type circularity check for this class.
567-
Circularity : 2,
568-
549+
SWIFT_INLINE_BITFIELD(EnumDecl, NominalTypeDecl, 2+1,
569550
/// True if the enum has cases and at least one case has associated values.
570551
HasAssociatedValues : 2,
571552
/// True if the enum has at least one case that has some availability
@@ -3601,16 +3582,9 @@ class EnumDecl final : public NominalTypeDecl {
36013582
for (auto elt : getAllElements())
36023583
elements.insert(elt);
36033584
}
3604-
3605-
/// Retrieve the status of circularity checking for class inheritance.
3606-
CircularityCheck getCircularityCheck() const {
3607-
return static_cast<CircularityCheck>(Bits.EnumDecl.Circularity);
3608-
}
3609-
3610-
/// Record the current stage of circularity checking.
3611-
void setCircularityCheck(CircularityCheck circularity) {
3612-
Bits.EnumDecl.Circularity = static_cast<unsigned>(circularity);
3613-
}
3585+
3586+
/// Whether this enum has a raw value type that recursively references itself.
3587+
bool hasCircularRawValue() const;
36143588

36153589
/// Record that this enum has had all of its raw values computed.
36163590
void setHasFixedRawValues();
@@ -3869,15 +3843,8 @@ class ClassDecl final : public NominalTypeDecl {
38693843
/// Set the superclass of this class.
38703844
void setSuperclass(Type superclass);
38713845

3872-
/// Retrieve the status of circularity checking for class inheritance.
3873-
CircularityCheck getCircularityCheck() const {
3874-
return static_cast<CircularityCheck>(Bits.ClassDecl.Circularity);
3875-
}
3876-
3877-
/// Record the current stage of circularity checking.
3878-
void setCircularityCheck(CircularityCheck circularity) {
3879-
Bits.ClassDecl.Circularity = static_cast<unsigned>(circularity);
3880-
}
3846+
/// Whether this class has a circular reference in its inheritance hierarchy.
3847+
bool hasCircularInheritance() const;
38813848

38823849
/// Walk this class and all of the superclasses of this class, transitively,
38833850
/// invoking the callback function for each class.
@@ -4348,15 +4315,9 @@ class ProtocolDecl final : public NominalTypeDecl {
43484315
return false;
43494316
}
43504317

4351-
/// Retrieve the status of circularity checking for protocol inheritance.
4352-
CircularityCheck getCircularityCheck() const {
4353-
return static_cast<CircularityCheck>(Bits.ProtocolDecl.Circularity);
4354-
}
4355-
4356-
/// Record the current stage of circularity checking.
4357-
void setCircularityCheck(CircularityCheck circularity) {
4358-
Bits.ProtocolDecl.Circularity = static_cast<unsigned>(circularity);
4359-
}
4318+
/// Whether this protocol has a circular reference in its list of inherited
4319+
/// protocols.
4320+
bool hasCircularInheritedProtocols() const;
43604321

43614322
/// Returns true if the protocol has requirements that are not listed in its
43624323
/// members.

include/swift/AST/TypeCheckRequests.h

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1775,6 +1775,74 @@ class PreCheckFunctionBuilderRequest
17751775
bool isCached() const { return true; }
17761776
};
17771777

1778+
/// Computes whether a class has a circular reference in its inheritance
1779+
/// hierarchy.
1780+
class HasCircularInheritanceRequest
1781+
: public SimpleRequest<HasCircularInheritanceRequest, bool(ClassDecl *),
1782+
CacheKind::Cached> {
1783+
public:
1784+
using SimpleRequest::SimpleRequest;
1785+
1786+
private:
1787+
friend SimpleRequest;
1788+
1789+
// Evaluation.
1790+
llvm::Expected<bool> evaluate(Evaluator &evaluator, ClassDecl *decl) const;
1791+
1792+
public:
1793+
// Cycle handling.
1794+
void diagnoseCycle(DiagnosticEngine &diags) const;
1795+
void noteCycleStep(DiagnosticEngine &diags) const;
1796+
1797+
// Cached.
1798+
bool isCached() const { return true; }
1799+
};
1800+
1801+
/// Computes whether a protocol has a circular reference in its list of
1802+
/// inherited protocols.
1803+
class HasCircularInheritedProtocolsRequest
1804+
: public SimpleRequest<HasCircularInheritedProtocolsRequest,
1805+
bool(ProtocolDecl *), CacheKind::Cached> {
1806+
public:
1807+
using SimpleRequest::SimpleRequest;
1808+
1809+
private:
1810+
friend SimpleRequest;
1811+
1812+
// Evaluation.
1813+
llvm::Expected<bool> evaluate(Evaluator &evaluator, ProtocolDecl *decl) const;
1814+
1815+
public:
1816+
// Cycle handling.
1817+
void diagnoseCycle(DiagnosticEngine &diags) const;
1818+
void noteCycleStep(DiagnosticEngine &diags) const;
1819+
1820+
// Cached.
1821+
bool isCached() const { return true; }
1822+
};
1823+
1824+
/// Computes whether an enum's raw value has a circular reference.
1825+
class HasCircularRawValueRequest
1826+
: public SimpleRequest<HasCircularRawValueRequest, bool(EnumDecl *),
1827+
CacheKind::Cached> {
1828+
public:
1829+
using SimpleRequest::SimpleRequest;
1830+
1831+
private:
1832+
friend SimpleRequest;
1833+
1834+
// Evaluation.
1835+
llvm::Expected<bool> evaluate(Evaluator &evaluator, EnumDecl *decl) const;
1836+
1837+
public:
1838+
// Cycle handling.
1839+
void diagnoseCycle(DiagnosticEngine &diags) const;
1840+
void noteCycleStep(DiagnosticEngine &diags) const;
1841+
1842+
// Cached.
1843+
bool isCached() const { return true; }
1844+
};
1845+
17781846
// Allow AnyValue to compare two Type values, even though Type doesn't
17791847
// support ==.
17801848
template<>

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ SWIFT_REQUEST(TypeChecker, FunctionOperatorRequest, OperatorDecl *(FuncDecl *),
5858
SWIFT_REQUEST(NameLookup, GenericSignatureRequest,
5959
GenericSignature (GenericContext *),
6060
SeparatelyCached, NoLocationInfo)
61+
SWIFT_REQUEST(TypeChecker, HasCircularInheritanceRequest,
62+
bool(ClassDecl *), Cached, NoLocationInfo)
63+
SWIFT_REQUEST(TypeChecker, HasCircularInheritedProtocolsRequest,
64+
bool(ProtocolDecl *), Cached, NoLocationInfo)
65+
SWIFT_REQUEST(TypeChecker, HasCircularRawValueRequest,
66+
bool(EnumDecl *), Cached, NoLocationInfo)
6167
SWIFT_REQUEST(TypeChecker, InferredGenericSignatureRequest,
6268
GenericSignature (ModuleDecl *, GenericSignatureImpl *,
6369
GenericParamList *,

lib/AST/Decl.cpp

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3888,8 +3888,6 @@ EnumDecl::EnumDecl(SourceLoc EnumLoc,
38883888
GenericParams),
38893889
EnumLoc(EnumLoc)
38903890
{
3891-
Bits.EnumDecl.Circularity
3892-
= static_cast<unsigned>(CircularityCheck::Unchecked);
38933891
Bits.EnumDecl.HasAssociatedValues
38943892
= static_cast<unsigned>(AssociatedValueCheck::Unchecked);
38953893
Bits.EnumDecl.HasAnyUnavailableValues
@@ -3997,14 +3995,19 @@ void NominalTypeDecl::synthesizeSemanticMembersIfNeeded(DeclName member) {
39973995
}
39983996
}
39993997

3998+
bool ClassDecl::hasCircularInheritance() const {
3999+
auto &ctx = getASTContext();
4000+
auto *mutableThis = const_cast<ClassDecl *>(this);
4001+
return evaluateOrDefault(ctx.evaluator,
4002+
HasCircularInheritanceRequest{mutableThis}, true);
4003+
}
4004+
40004005
ClassDecl::ClassDecl(SourceLoc ClassLoc, Identifier Name, SourceLoc NameLoc,
40014006
MutableArrayRef<TypeLoc> Inherited,
40024007
GenericParamList *GenericParams, DeclContext *Parent)
40034008
: NominalTypeDecl(DeclKind::Class, Parent, Name, NameLoc, Inherited,
40044009
GenericParams),
40054010
ClassLoc(ClassLoc) {
4006-
Bits.ClassDecl.Circularity
4007-
= static_cast<unsigned>(CircularityCheck::Unchecked);
40084011
Bits.ClassDecl.InheritsSuperclassInits = 0;
40094012
Bits.ClassDecl.ComputedInheritsSuperclassInits = 0;
40104013
Bits.ClassDecl.RawForeignKind = 0;
@@ -4477,6 +4480,13 @@ void EnumDecl::setHasFixedRawValues() {
44774480
LazySemanticInfo.RawTypeAndFlags.setInt(flags);
44784481
}
44794482

4483+
bool EnumDecl::hasCircularRawValue() const {
4484+
auto &ctx = getASTContext();
4485+
auto *mutableThis = const_cast<EnumDecl *>(this);
4486+
return evaluateOrDefault(ctx.evaluator,
4487+
HasCircularRawValueRequest{mutableThis}, true);
4488+
}
4489+
44804490
ProtocolDecl::ProtocolDecl(DeclContext *DC, SourceLoc ProtocolLoc,
44814491
SourceLoc NameLoc, Identifier Name,
44824492
MutableArrayRef<TypeLoc> Inherited,
@@ -4488,8 +4498,6 @@ ProtocolDecl::ProtocolDecl(DeclContext *DC, SourceLoc ProtocolLoc,
44884498
Bits.ProtocolDecl.RequiresClass = false;
44894499
Bits.ProtocolDecl.ExistentialConformsToSelfValid = false;
44904500
Bits.ProtocolDecl.ExistentialConformsToSelf = false;
4491-
Bits.ProtocolDecl.Circularity
4492-
= static_cast<unsigned>(CircularityCheck::Unchecked);
44934501
Bits.ProtocolDecl.InheritedProtocolsValid = 0;
44944502
Bits.ProtocolDecl.NumRequirementsInSignature = 0;
44954503
Bits.ProtocolDecl.HasMissingRequirements = false;
@@ -4916,6 +4924,12 @@ void ProtocolDecl::computeKnownProtocolKind() const {
49164924
const_cast<ProtocolDecl *>(this)->Bits.ProtocolDecl.KnownProtocol = value;
49174925
}
49184926

4927+
bool ProtocolDecl::hasCircularInheritedProtocols() const {
4928+
auto &ctx = getASTContext();
4929+
auto *mutableThis = const_cast<ProtocolDecl *>(this);
4930+
return evaluateOrDefault(
4931+
ctx.evaluator, HasCircularInheritedProtocolsRequest{mutableThis}, true);
4932+
}
49194933

49204934
StorageImplInfo AbstractStorageDecl::getImplInfo() const {
49214935
ASTContext &ctx = getASTContext();

lib/AST/TypeCheckRequests.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,3 +1132,52 @@ void swift::simple_display(llvm::raw_ostream &out,
11321132
break;
11331133
}
11341134
}
1135+
1136+
//----------------------------------------------------------------------------//
1137+
// HasCircularInheritanceRequest computation.
1138+
//----------------------------------------------------------------------------//
1139+
1140+
void HasCircularInheritanceRequest::diagnoseCycle(
1141+
DiagnosticEngine &diags) const {
1142+
auto *decl = std::get<0>(getStorage());
1143+
diags.diagnose(decl, diag::circular_class_inheritance, decl->getName());
1144+
}
1145+
1146+
void HasCircularInheritanceRequest::noteCycleStep(
1147+
DiagnosticEngine &diags) const {
1148+
auto *decl = std::get<0>(getStorage());
1149+
diags.diagnose(decl, diag::kind_declname_declared_here,
1150+
decl->getDescriptiveKind(), decl->getName());
1151+
}
1152+
1153+
//----------------------------------------------------------------------------//
1154+
// HasCircularInheritedProtocolsRequest computation.
1155+
//----------------------------------------------------------------------------//
1156+
1157+
void HasCircularInheritedProtocolsRequest::diagnoseCycle(
1158+
DiagnosticEngine &diags) const {
1159+
auto *decl = std::get<0>(getStorage());
1160+
diags.diagnose(decl, diag::circular_protocol_def, decl->getName());
1161+
}
1162+
1163+
void HasCircularInheritedProtocolsRequest::noteCycleStep(
1164+
DiagnosticEngine &diags) const {
1165+
auto *decl = std::get<0>(getStorage());
1166+
diags.diagnose(decl, diag::kind_declname_declared_here,
1167+
decl->getDescriptiveKind(), decl->getName());
1168+
}
1169+
1170+
//----------------------------------------------------------------------------//
1171+
// HasCircularRawValueRequest computation.
1172+
//----------------------------------------------------------------------------//
1173+
1174+
void HasCircularRawValueRequest::diagnoseCycle(DiagnosticEngine &diags) const {
1175+
auto *decl = std::get<0>(getStorage());
1176+
diags.diagnose(decl, diag::circular_enum_inheritance, decl->getName());
1177+
}
1178+
1179+
void HasCircularRawValueRequest::noteCycleStep(DiagnosticEngine &diags) const {
1180+
auto *decl = std::get<0>(getStorage());
1181+
diags.diagnose(decl, diag::kind_declname_declared_here,
1182+
decl->getDescriptiveKind(), decl->getName());
1183+
}

lib/ClangImporter/ImportDecl.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4699,8 +4699,6 @@ namespace {
46994699

47004700
Impl.ImportedDecls[{decl->getCanonicalDecl(), getVersion()}] = result;
47014701

4702-
result->setCircularityCheck(CircularityCheck::Checked);
4703-
47044702
// Import protocols this protocol conforms to.
47054703
SmallVector<TypeLoc, 4> inheritedTypes;
47064704
importObjCProtocols(result, decl->getReferencedProtocols(),
@@ -4736,7 +4734,6 @@ namespace {
47364734
SourceLoc(), None,
47374735
nullptr, dc);
47384736
Impl.ImportedDecls[{decl->getCanonicalDecl(), getVersion()}] = result;
4739-
result->setCircularityCheck(CircularityCheck::Checked);
47404737
result->setSuperclass(Type());
47414738
result->setAddedImplicitInitializers(); // suppress all initializers
47424739
result->setHasMissingVTableEntries(false);
@@ -4842,7 +4839,6 @@ namespace {
48424839
}
48434840

48444841
Impl.ImportedDecls[{decl->getCanonicalDecl(), getVersion()}] = result;
4845-
result->setCircularityCheck(CircularityCheck::Checked);
48464842
addObjCAttribute(result, Impl.importIdentifier(decl->getIdentifier()));
48474843

48484844
if (declaredNative)
@@ -5319,7 +5315,6 @@ SwiftDeclConverter::importCFClassType(const clang::TypedefNameDecl *decl,
53195315
auto theClass = Impl.createDeclWithClangNode<ClassDecl>(
53205316
decl, AccessLevel::Public, SourceLoc(), className, SourceLoc(), None,
53215317
nullptr, dc);
5322-
theClass->setCircularityCheck(CircularityCheck::Checked);
53235318
theClass->setSuperclass(superclass);
53245319
theClass->setAddedImplicitInitializers(); // suppress all initializers
53255320
theClass->setHasMissingVTableEntries(false);

0 commit comments

Comments
 (0)