Skip to content

Commit 744e4a6

Browse files
authored
Merge pull request swiftlang#6043 from slavapestov/circularity
Consolidate circularity checks for recursive validateDecl() calls
2 parents e9dede7 + bb839c5 commit 744e4a6

33 files changed

+473
-493
lines changed

include/swift/AST/Decl.h

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ bool conflicting(const OverloadSignature& sig1, const OverloadSignature& sig2);
215215
class alignas(1 << DeclAlignInBits) Decl {
216216
class DeclBitfields {
217217
friend class Decl;
218-
unsigned Kind : 8;
218+
unsigned Kind : 6;
219219

220220
/// \brief Whether this declaration is invalid.
221221
unsigned Invalid : 1;
@@ -233,10 +233,10 @@ class alignas(1 << DeclAlignInBits) Decl {
233233
/// FIXME: This is ugly.
234234
unsigned EarlyAttrValidation : 1;
235235

236-
/// \brief Whether or not this declaration is currently being type-checked.
237-
unsigned BeingTypeChecked : 1;
236+
/// \brief Whether this declaration is currently being validated.
237+
unsigned BeingValidated : 1;
238238
};
239-
enum { NumDeclBits = 13 };
239+
enum { NumDeclBits = 11 };
240240
static_assert(NumDeclBits <= 32, "fits in an unsigned");
241241

242242
class PatternBindingDeclBitfields {
@@ -632,7 +632,7 @@ class alignas(1 << DeclAlignInBits) Decl {
632632
DeclBits.Implicit = false;
633633
DeclBits.FromClang = false;
634634
DeclBits.EarlyAttrValidation = false;
635-
DeclBits.BeingTypeChecked = false;
635+
DeclBits.BeingValidated = false;
636636
}
637637

638638
ClangNode getClangNodeImpl() const {
@@ -778,12 +778,16 @@ class alignas(1 << DeclAlignInBits) Decl {
778778
DeclBits.EarlyAttrValidation = validated;
779779
}
780780

781-
/// Whether the declaration is currently being validated.
782-
bool isBeingTypeChecked();
783-
781+
/// Whether the declaration has a valid interface type and
782+
/// generic signature.
783+
bool isBeingValidated() const {
784+
return DeclBits.BeingValidated;
785+
}
786+
784787
/// Toggle whether or not the declaration is being validated.
785-
void setIsBeingTypeChecked(bool ibt = true) {
786-
DeclBits.BeingTypeChecked = ibt;
788+
void setIsBeingValidated(bool ibv = true) {
789+
assert(DeclBits.BeingValidated != ibv);
790+
DeclBits.BeingValidated = ibv;
787791
}
788792

789793
/// \returns the unparsed comment attached to this declaration.
@@ -1522,7 +1526,7 @@ class ExtensionDecl final : public Decl, public DeclContext,
15221526

15231527
void setInherited(MutableArrayRef<TypeLoc> i) { Inherited = i; }
15241528

1525-
/// Whether we already validated this extension.
1529+
/// Whether we started validating this extension.
15261530
bool validated() const {
15271531
return ExtensionDeclBits.Validated;
15281532
}
@@ -1532,6 +1536,11 @@ class ExtensionDecl final : public Decl, public DeclContext,
15321536
ExtensionDeclBits.Validated = validated;
15331537
}
15341538

1539+
/// Whether we have fully checked the extension.
1540+
bool hasValidSignature() const {
1541+
return validated() && !isBeingValidated();
1542+
}
1543+
15351544
/// Whether we already type-checked the inheritance clause.
15361545
bool checkedInheritanceClause() const {
15371546
return ExtensionDeclBits.CheckedInheritanceClause;
@@ -2111,7 +2120,11 @@ class ValueDecl : public Decl {
21112120

21122121
/// Set the interface type for the given value.
21132122
void setInterfaceType(Type type);
2114-
2123+
2124+
bool hasValidSignature() const {
2125+
return hasInterfaceType() && !isBeingValidated();
2126+
}
2127+
21152128
/// isSettable - Determine whether references to this decl may appear
21162129
/// on the left-hand side of an assignment or as the operand of a
21172130
/// `&` or 'inout' operator.
@@ -2257,11 +2270,6 @@ class GenericTypeDecl : public TypeDecl, public DeclContext {
22572270
mutable llvm::PointerUnion<GenericSignature *, GenericEnvironment *>
22582271
GenericSigOrEnv;
22592272

2260-
/// \brief Whether or not the generic signature of the type declaration is
2261-
/// currently being validated.
2262-
// TODO: Merge into GenericSig bits.
2263-
unsigned ValidatingGenericSignature = false;
2264-
22652273
/// Lazily populate the generic environment.
22662274
GenericEnvironment *getLazyGenericEnvironmentSlow() const;
22672275

@@ -2299,14 +2307,6 @@ class GenericTypeDecl : public TypeDecl, public DeclContext {
22992307
/// Retrieve the generic context for this type.
23002308
GenericEnvironment *getGenericEnvironment() const;
23012309

2302-
void setIsValidatingGenericSignature(bool validating=true) {
2303-
ValidatingGenericSignature = validating;
2304-
}
2305-
2306-
bool isValidatingGenericSignature() const {
2307-
return ValidatingGenericSignature;
2308-
}
2309-
23102310
/// Set a lazy generic environment.
23112311
void setLazyGenericEnvironment(LazyMemberLoader *lazyLoader,
23122312
GenericSignature *genericSig,

include/swift/AST/DiagnosticsSema.def

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1173,8 +1173,6 @@ ERROR(unsupported_nested_protocol,none,
11731173
(Identifier))
11741174

11751175
// Type aliases
1176-
ERROR(circular_type_alias,none,
1177-
"type alias %0 circularly references itself", (Identifier))
11781176
ERROR(type_alias_underlying_type_access,none,
11791177
"type alias %select{must be declared %select{"
11801178
"%select{private|fileprivate|internal|PUBLIC}2|private or fileprivate}3"
@@ -1548,7 +1546,7 @@ ERROR(requires_superclass_conflict,none,
15481546
"generic parameter %0 cannot be a subclass of both %1 and %2",
15491547
(Identifier, Type, Type))
15501548
ERROR(recursive_type_reference,none,
1551-
"type %0 references itself", (Identifier))
1549+
"%0 %1 references itself", (DescriptiveDeclKind, Identifier))
15521550
ERROR(recursive_requirement_reference,none,
15531551
"type may not reference itself as a requirement",())
15541552
ERROR(recursive_same_type_constraint,none,

lib/AST/Decl.cpp

Lines changed: 11 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -375,24 +375,6 @@ bool AbstractFunctionDecl::isTransparent() const {
375375
return false;
376376
}
377377

378-
bool Decl::isBeingTypeChecked() {
379-
auto decl = this;
380-
while (true) {
381-
if (decl->DeclBits.BeingTypeChecked)
382-
return true;
383-
384-
auto dc = decl->getDeclContext();
385-
if (auto nominal = dyn_cast<NominalTypeDecl>(dc))
386-
decl = nominal;
387-
else if (auto ext = dyn_cast<ExtensionDecl>(dc))
388-
decl = ext;
389-
else
390-
break;
391-
}
392-
393-
return false;
394-
}
395-
396378
bool Decl::isPrivateStdlibDecl(bool whitelistProtocols) const {
397379
const Decl *D = this;
398380
if (auto ExtD = dyn_cast<ExtensionDecl>(D))
@@ -1937,6 +1919,15 @@ Type TypeDecl::getDeclaredInterfaceType() const {
19371919
if (auto *NTD = dyn_cast<NominalTypeDecl>(this))
19381920
return NTD->getDeclaredInterfaceType();
19391921

1922+
if (auto *ATD = dyn_cast<AssociatedTypeDecl>(this)) {
1923+
auto &ctx = getASTContext();
1924+
auto selfTy = getDeclContext()->getSelfInterfaceType();
1925+
if (!selfTy)
1926+
return ErrorType::get(ctx);
1927+
return DependentMemberType::get(
1928+
selfTy, const_cast<AssociatedTypeDecl *>(ATD));
1929+
}
1930+
19401931
Type interfaceType = getInterfaceType();
19411932
if (interfaceType.isNull() || interfaceType->is<ErrorType>())
19421933
return interfaceType;
@@ -2363,11 +2354,7 @@ AssociatedTypeDecl::AssociatedTypeDecl(DeclContext *dc, SourceLoc keywordLoc,
23632354

23642355
void AssociatedTypeDecl::computeType() {
23652356
auto &ctx = getASTContext();
2366-
auto proto = cast<ProtocolDecl>(getDeclContext());
2367-
auto selfTy = proto->getSelfInterfaceType();
2368-
if (!selfTy)
2369-
selfTy = ErrorType::get(ctx);
2370-
auto interfaceTy = DependentMemberType::get(selfTy, this);
2357+
auto interfaceTy = getDeclaredInterfaceType();
23712358
setInterfaceType(MetatypeType::get(interfaceTy, ctx));
23722359
}
23732360

@@ -2719,7 +2706,7 @@ bool ProtocolDecl::requiresClassSlow() {
27192706
ProtocolDeclBits.RequiresClass = false;
27202707

27212708
// Ensure that the result cannot change in future.
2722-
assert(isInheritedProtocolsValid() || isBeingTypeChecked());
2709+
assert(isInheritedProtocolsValid());
27232710

27242711
if (getAttrs().hasAttribute<ObjCAttr>() || isObjC()) {
27252712
ProtocolDeclBits.RequiresClass = true;

lib/AST/GenericEnvironment.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,8 @@ Type GenericEnvironment::mapTypeIntoContext(ModuleDecl *M, Type type) const {
305305
Type GenericEnvironment::mapTypeIntoContext(GenericTypeParamType *type) const {
306306
auto self = const_cast<GenericEnvironment *>(this);
307307
Type result = QueryInterfaceTypeSubstitutions(self)(type);
308-
assert(result && "Missing context type for generic parameter");
308+
if (!result)
309+
return ErrorType::get(type);
309310
return result;
310311
}
311312

lib/AST/NameLookup.cpp

Lines changed: 12 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -149,33 +149,20 @@ bool swift::removeShadowedDecls(SmallVectorImpl<ValueDecl*> &decls,
149149
ObjCCollidingConstructors;
150150
bool anyCollisions = false;
151151
for (auto decl : decls) {
152-
// Determine the signature of this declaration.
153-
// FIXME: the canonical type makes a poor signature, because we don't
154-
// canonicalize away default arguments and don't canonicalize polymorphic
155-
// types well.
156-
CanType signature;
157-
158152
// FIXME: Egregious hack to avoid failing when there are no declared types.
159-
if (!decl->hasInterfaceType() ||
160-
isa<TypeAliasDecl>(decl) ||
161-
isa<AbstractTypeParamDecl>(decl)) {
162-
// FIXME: Pass this down instead of getting it from the ASTContext.
163-
if (typeResolver && !decl->isBeingTypeChecked())
164-
typeResolver->resolveDeclSignature(decl);
165-
if (!decl->hasInterfaceType())
166-
continue;
167-
if (auto assocType = dyn_cast<AssociatedTypeDecl>(decl))
168-
if (!assocType->getProtocol()->isValidGenericContext())
169-
continue;
170-
}
153+
// FIXME: Pass this down instead of getting it from the ASTContext.
154+
if (typeResolver)
155+
typeResolver->resolveDeclSignature(decl);
171156

172157
// If the decl is currently being validated, this is likely a recursive
173158
// reference and we'll want to skip ahead so as to avoid having its type
174159
// attempt to desugar itself.
175-
if (decl->isBeingTypeChecked())
160+
if (!decl->hasValidSignature())
176161
continue;
177162

178-
signature = decl->getInterfaceType()->getCanonicalType();
163+
// FIXME: the canonical type makes a poor signature, because we don't
164+
// canonicalize away default arguments.
165+
auto signature = decl->getInterfaceType()->getCanonicalType();
179166

180167
// FIXME: The type of a variable or subscript doesn't include
181168
// enough context to distinguish entities from different
@@ -1497,12 +1484,12 @@ bool DeclContext::lookupQualified(Type type,
14971484
// Allow filtering of the visible declarations based on various
14981485
// criteria.
14991486
bool onlyCompleteObjectInits = false;
1500-
auto isAcceptableDecl = [&](NominalTypeDecl *current, Decl *decl) -> bool {
1487+
auto isAcceptableDecl = [&](NominalTypeDecl *current, ValueDecl *decl) -> bool {
15011488
// If the decl is currently being type checked, then we have something
15021489
// cyclic going on. Instead of poking at parts that are potentially not
15031490
// set up, just assume it is acceptable. This will make sure we produce an
15041491
// error later.
1505-
if (decl->isBeingTypeChecked())
1492+
if (!decl->hasValidSignature())
15061493
return true;
15071494

15081495
// Filter out designated initializers, if requested.
@@ -1523,8 +1510,7 @@ bool DeclContext::lookupQualified(Type type,
15231510

15241511
// Check access.
15251512
if (!(options & NL_IgnoreAccessibility))
1526-
if (auto VD = dyn_cast<ValueDecl>(decl))
1527-
return VD->isAccessibleFrom(this);
1513+
return decl->isAccessibleFrom(this);
15281514

15291515
return true;
15301516
};
@@ -1564,13 +1550,9 @@ bool DeclContext::lookupQualified(Type type,
15641550

15651551
// Resolve the declaration signature when we find the
15661552
// declaration.
1567-
if (typeResolver && !decl->isBeingTypeChecked()) {
1553+
if (typeResolver)
15681554
typeResolver->resolveDeclSignature(decl);
15691555

1570-
if (!decl->hasInterfaceType())
1571-
continue;
1572-
}
1573-
15741556
if (isAcceptableDecl(current, decl))
15751557
decls.push_back(decl);
15761558
}
@@ -1635,11 +1617,8 @@ bool DeclContext::lookupQualified(Type type,
16351617
if ((options & NL_OnlyTypes) && !isa<TypeDecl>(decl))
16361618
continue;
16371619

1638-
if (typeResolver && !decl->isBeingTypeChecked()) {
1620+
if (typeResolver)
16391621
typeResolver->resolveDeclSignature(decl);
1640-
if (!decl->hasInterfaceType())
1641-
continue;
1642-
}
16431622

16441623
// If the declaration has an override, name lookup will also have
16451624
// found the overridden method. Skip this declaration, because we

lib/Sema/CSGen.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1021,7 +1021,7 @@ namespace {
10211021
if (!decl)
10221022
return nullptr;
10231023

1024-
CS.getTypeChecker().validateDecl(decl, true);
1024+
CS.getTypeChecker().validateDecl(decl);
10251025
if (decl->isInvalid())
10261026
return nullptr;
10271027

@@ -1312,7 +1312,7 @@ namespace {
13121312
// FIXME: If the decl is in error, we get no information from this.
13131313
// We may, alternatively, want to use a type variable in that case,
13141314
// and possibly infer the type of the variable that way.
1315-
CS.getTypeChecker().validateDecl(E->getDecl(), true);
1315+
CS.getTypeChecker().validateDecl(E->getDecl());
13161316
if (E->getDecl()->isInvalid())
13171317
return nullptr;
13181318

@@ -1390,7 +1390,7 @@ namespace {
13901390
// If the result is invalid, skip it.
13911391
// FIXME: Note this as invalid, in case we don't find a solution,
13921392
// so we don't let errors cascade further.
1393-
CS.getTypeChecker().validateDecl(decls[i], true);
1393+
CS.getTypeChecker().validateDecl(decls[i]);
13941394
if (decls[i]->isInvalid())
13951395
continue;
13961396

lib/Sema/CSSimplify.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2942,7 +2942,7 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName,
29422942
bool labelMismatch = false;
29432943
for (auto ctor : ctors) {
29442944
// If the constructor is invalid, we fail entirely to avoid error cascade.
2945-
TC.validateDecl(ctor, true);
2945+
TC.validateDecl(ctor);
29462946
if (ctor->isInvalid())
29472947
return result.markErrorAlreadyDiagnosed();
29482948

@@ -3038,7 +3038,7 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName,
30383038
return;
30393039
}
30403040
// If the result is invalid, skip it.
3041-
TC.validateDecl(cand, true);
3041+
TC.validateDecl(cand);
30423042
if (cand->isInvalid()) {
30433043
result.markErrorAlreadyDiagnosed();
30443044
return;
@@ -3228,7 +3228,7 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName,
32283228
memberName, lookupOptions);
32293229
for (auto cand : lookup) {
32303230
// If the result is invalid, skip it.
3231-
TC.validateDecl(cand, true);
3231+
TC.validateDecl(cand);
32323232
if (cand->isInvalid()) {
32333233
result.markErrorAlreadyDiagnosed();
32343234
return result;

0 commit comments

Comments
 (0)