Skip to content

Commit 26a8bf8

Browse files
committed
Merge remote-tracking branch 'origin/master' into master-rebranch
2 parents e901234 + ea81fdc commit 26a8bf8

File tree

9 files changed

+83
-29
lines changed

9 files changed

+83
-29
lines changed

include/swift/AST/Decl.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1678,7 +1678,11 @@ class ExtensionDecl final : public GenericContext, public Decl,
16781678
TypeRepr *ExtendedTypeRepr;
16791679

16801680
/// The nominal type being extended.
1681-
NominalTypeDecl *ExtendedNominal = nullptr;
1681+
///
1682+
/// The bit indicates whether binding has been attempted. The pointer can be
1683+
/// null if either no binding was attempted or if binding could not find the
1684+
/// extended nominal.
1685+
llvm::PointerIntPair<NominalTypeDecl *, 1, bool> ExtendedNominal;
16821686

16831687
MutableArrayRef<TypeLoc> Inherited;
16841688

@@ -1738,6 +1742,12 @@ class ExtensionDecl final : public GenericContext, public Decl,
17381742
SourceRange getBraces() const { return Braces; }
17391743
void setBraces(SourceRange braces) { Braces = braces; }
17401744

1745+
bool hasBeenBound() const { return ExtendedNominal.getInt(); }
1746+
1747+
void setExtendedNominal(NominalTypeDecl *n) {
1748+
ExtendedNominal.setPointerAndInt(n, true);
1749+
}
1750+
17411751
/// Retrieve the type being extended.
17421752
///
17431753
/// Only use this entry point when the complete type, as spelled in the source,
@@ -1746,8 +1756,21 @@ class ExtensionDecl final : public GenericContext, public Decl,
17461756
Type getExtendedType() const;
17471757

17481758
/// Retrieve the nominal type declaration that is being extended.
1759+
/// Will trip an assertion if the declaration has not already been computed.
1760+
/// In order to fail fast when type checking work is attempted
1761+
/// before extension binding has taken place.
1762+
17491763
NominalTypeDecl *getExtendedNominal() const;
17501764

1765+
/// Compute the nominal type declaration that is being extended.
1766+
NominalTypeDecl *computeExtendedNominal() const;
1767+
1768+
/// \c hasBeenBound means nothing if this extension can never been bound
1769+
/// because it is not at the top level.
1770+
bool canNeverBeBound() const;
1771+
1772+
bool hasValidParent() const;
1773+
17511774
/// Determine whether this extension has already been bound to a nominal
17521775
/// type declaration.
17531776
bool alreadyBoundToNominal() const { return NextExtension.getInt(); }

include/swift/AST/DeclContext.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,10 @@ class alignas(1 << DeclContextAlignInBits) DeclContext {
470470
/// AnyObject dynamic lookup.
471471
bool mayContainMembersAccessedByDynamicLookup() const;
472472

473+
/// Extensions are only allowed at the level in a file
474+
/// FIXME: do this for Protocols, too someday
475+
bool canBeParentOfExtension() const;
476+
473477
/// Returns true if lookups within this context could affect downstream files.
474478
///
475479
/// \param functionsAreNonCascading If true, functions are considered non-

lib/AST/ASTWalker.cpp

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -265,12 +265,8 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
265265
}
266266

267267
bool visitNominalTypeDecl(NominalTypeDecl *NTD) {
268-
bool WalkGenerics = NTD->getGenericParams() &&
269-
Walker.shouldWalkIntoGenericParams();
270268

271-
if (WalkGenerics) {
272-
visitGenericParamList(NTD->getGenericParams());
273-
}
269+
bool WalkGenerics = visitGenericParamListIfNeeded(NTD);
274270

275271
for (auto &Inherit : NTD->getInherited()) {
276272
if (doIt(Inherit))
@@ -329,11 +325,8 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
329325
}
330326

331327
bool visitSubscriptDecl(SubscriptDecl *SD) {
332-
bool WalkGenerics = SD->getGenericParams() &&
333-
Walker.shouldWalkIntoGenericParams();
334-
if (WalkGenerics) {
335-
visitGenericParamList(SD->getGenericParams());
336-
}
328+
bool WalkGenerics = visitGenericParamListIfNeeded(SD);
329+
337330
visit(SD->getIndices());
338331
if (doIt(SD->getElementTypeLoc()))
339332
return true;
@@ -364,14 +357,9 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
364357
PrettyStackTraceDecl debugStack("walking into body of", AFD);
365358
#endif
366359

367-
bool WalkGenerics = AFD->getGenericParams() &&
368-
Walker.shouldWalkIntoGenericParams() &&
360+
bool WalkGenerics =
369361
// accessor generics are visited from the storage decl
370-
!isa<AccessorDecl>(AFD);
371-
372-
if (WalkGenerics) {
373-
visitGenericParamList(AFD->getGenericParams());
374-
}
362+
!isa<AccessorDecl>(AFD) && visitGenericParamListIfNeeded(AFD);
375363

376364
if (auto *PD = AFD->getImplicitSelfDecl(/*createIfNeeded=*/false))
377365
visit(PD);
@@ -1345,6 +1333,18 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
13451333
}
13461334
return false;
13471335
}
1336+
1337+
private:
1338+
bool visitGenericParamListIfNeeded(GenericContext *gc) {
1339+
// Must check this first in case extensions have not been bound yet
1340+
if (Walker.shouldWalkIntoGenericParams()) {
1341+
if (auto *params = gc->getGenericParams()) {
1342+
visitGenericParamList(params);
1343+
return true;
1344+
}
1345+
}
1346+
return false;
1347+
}
13481348
};
13491349

13501350
} // end anonymous namespace

lib/AST/Decl.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,9 +1084,25 @@ ExtensionDecl::takeConformanceLoaderSlow() {
10841084
}
10851085

10861086
NominalTypeDecl *ExtensionDecl::getExtendedNominal() const {
1087+
assert((hasBeenBound() || canNeverBeBound()) &&
1088+
"Extension must have already been bound (by bindExtensions)");
1089+
return ExtendedNominal.getPointer();
1090+
}
1091+
1092+
NominalTypeDecl *ExtensionDecl::computeExtendedNominal() const {
10871093
ASTContext &ctx = getASTContext();
1088-
return evaluateOrDefault(ctx.evaluator,
1089-
ExtendedNominalRequest{const_cast<ExtensionDecl *>(this)}, nullptr);
1094+
return evaluateOrDefault(
1095+
ctx.evaluator, ExtendedNominalRequest{const_cast<ExtensionDecl *>(this)},
1096+
nullptr);
1097+
}
1098+
1099+
bool ExtensionDecl::canNeverBeBound() const {
1100+
// \c bindExtensions() only looks at valid parents for extensions.
1101+
return !hasValidParent();
1102+
}
1103+
1104+
bool ExtensionDecl::hasValidParent() const {
1105+
return getDeclContext()->canBeParentOfExtension();
10901106
}
10911107

10921108
bool ExtensionDecl::isConstrainedExtension() const {

lib/AST/DeclContext.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,10 @@ bool DeclContext::mayContainMembersAccessedByDynamicLookup() const {
489489
return false;
490490
}
491491

492+
bool DeclContext::canBeParentOfExtension() const {
493+
return isa<SourceFile>(this);
494+
}
495+
492496
bool DeclContext::walkContext(ASTWalker &Walker) {
493497
switch (getContextKind()) {
494498
case DeclContextKind::Module:

lib/AST/NameLookupRequests.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,17 +74,19 @@ Optional<NominalTypeDecl *> ExtendedNominalRequest::getCachedResult() const {
7474
// Note: if we fail to compute any nominal declaration, it's considered
7575
// a cache miss. This allows us to recompute the extended nominal types
7676
// during extension binding.
77+
// This recomputation is also what allows you to extend types defined inside
78+
// other extensions, regardless of source file order. See \c bindExtensions(),
79+
// which uses a worklist algorithm that attempts to bind everything until
80+
// fixed point.
7781
auto ext = std::get<0>(getStorage());
78-
if (ext->ExtendedNominal)
79-
return ext->ExtendedNominal;
80-
81-
return None;
82+
if (!ext->hasBeenBound() || !ext->getExtendedNominal())
83+
return None;
84+
return ext->getExtendedNominal();
8285
}
8386

8487
void ExtendedNominalRequest::cacheResult(NominalTypeDecl *value) const {
8588
auto ext = std::get<0>(getStorage());
86-
if (value)
87-
ext->ExtendedNominal = value;
89+
ext->setExtendedNominal(value);
8890
}
8991

9092
//----------------------------------------------------------------------------//

lib/IDE/SyntaxModel.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -786,6 +786,9 @@ bool ModelASTWalker::walkToDeclPre(Decl *D) {
786786
pushStructureNode(SN, NTD);
787787

788788
} else if (auto *ED = dyn_cast<ExtensionDecl>(D)) {
789+
// Normally bindExtension() would take care of computing the extended
790+
// nominal. It must be done before asking for generic parameters.
791+
ED->computeExtendedNominal();
789792
SyntaxStructureNode SN;
790793
setDecl(SN, D);
791794
SN.Kind = SyntaxStructureKind::Extension;

lib/Sema/TypeCheckDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3130,7 +3130,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
31303130
// Produce any diagnostics for the extended type.
31313131
auto extType = ED->getExtendedType();
31323132

3133-
auto nominal = ED->getExtendedNominal();
3133+
auto nominal = ED->computeExtendedNominal();
31343134
if (nominal == nullptr) {
31353135
const bool wasAlreadyInvalid = ED->isInvalid();
31363136
ED->setInvalid();

lib/Sema/TypeChecker.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,9 @@ static void bindExtensions(SourceFile &SF) {
229229
// Utility function to try and resolve the extended type without diagnosing.
230230
// If we succeed, we go ahead and bind the extension. Otherwise, return false.
231231
auto tryBindExtension = [&](ExtensionDecl *ext) -> bool {
232-
if (auto nominal = ext->getExtendedNominal()) {
232+
assert(!ext->canNeverBeBound() &&
233+
"Only extensions that can ever be bound get here.");
234+
if (auto nominal = ext->computeExtendedNominal()) {
233235
bindExtensionToNominal(ext, nominal);
234236
return true;
235237
}
@@ -622,7 +624,7 @@ void swift::typeCheckCompletionDecl(Decl *D) {
622624
DiagnosticSuppression suppression(Ctx.Diags);
623625
(void)createTypeChecker(Ctx);
624626
if (auto ext = dyn_cast<ExtensionDecl>(D)) {
625-
if (auto *nominal = ext->getExtendedNominal()) {
627+
if (auto *nominal = ext->computeExtendedNominal()) {
626628
// FIXME(InterfaceTypeRequest): Remove this.
627629
(void)nominal->getInterfaceType();
628630
}

0 commit comments

Comments
 (0)