Skip to content

Commit bf2e5ac

Browse files
authored
Merge pull request #67689 from DougGregor/lazy-type-refinement-context-5.9
[5.9] Eliminate Observable circular reference errors via lazier TypeRefinementContext building
2 parents ae5efe8 + 29f1022 commit bf2e5ac

11 files changed

+261
-186
lines changed

include/swift/AST/Availability.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,13 @@ class AvailabilityInference {
380380

381381
};
382382

383+
/// Given a declaration upon which an availability attribute would appear in
384+
/// concrete syntax, return a declaration to which the parser
385+
/// actually attaches the attribute in the abstract syntax tree. We use this
386+
/// function to determine whether the concrete syntax already has an
387+
/// availability attribute.
388+
const Decl *abstractSyntaxDeclForAvailableAttribute(const Decl *D);
389+
383390
} // end namespace swift
384391

385392
#endif

include/swift/AST/TypeCheckRequests.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ class TypeAliasDecl;
6363
class TypeLoc;
6464
class Witness;
6565
class TypeResolution;
66+
class TypeRefinementContext;
6667
struct TypeWitnessAndDecl;
6768
class ValueDecl;
6869
enum class OpaqueReadOwnership: uint8_t;
@@ -4387,6 +4388,25 @@ class InitAccessorReferencedVariablesRequest
43874388
bool isCached() const { return true; }
43884389
};
43894390

4391+
/// Expand the children of the type refinement context for the given
4392+
/// declaration.
4393+
class ExpandChildTypeRefinementContextsRequest
4394+
: public SimpleRequest<ExpandChildTypeRefinementContextsRequest,
4395+
bool(Decl *, TypeRefinementContext *),
4396+
RequestFlags::Cached> {
4397+
public:
4398+
using SimpleRequest::SimpleRequest;
4399+
4400+
private:
4401+
friend SimpleRequest;
4402+
4403+
bool evaluate(Evaluator &evaluator, Decl *decl,
4404+
TypeRefinementContext *parentTRC) const;
4405+
4406+
public:
4407+
bool isCached() const { return true; }
4408+
};
4409+
43904410
#define SWIFT_TYPEID_ZONE TypeChecker
43914411
#define SWIFT_TYPEID_HEADER "swift/AST/TypeCheckerTypeIDZone.def"
43924412
#include "swift/Basic/DefineTypeIDZone.h"

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,3 +500,6 @@ SWIFT_REQUEST(TypeChecker, InitAccessorReferencedVariablesRequest,
500500
ArrayRef<VarDecl *>(DeclAttribute *, AccessorDecl *,
501501
ArrayRef<Identifier>),
502502
Cached, NoLocationInfo)
503+
SWIFT_REQUEST(TypeChecker, ExpandChildTypeRefinementContextsRequest,
504+
bool(Decl *, TypeRefinementContext *),
505+
Cached, NoLocationInfo)

include/swift/AST/TypeRefinementContext.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,9 @@ class TypeRefinementContext : public ASTAllocated<TypeRefinementContext> {
297297
static StringRef getReasonName(Reason R);
298298
};
299299

300+
void simple_display(llvm::raw_ostream &out,
301+
const TypeRefinementContext *trc);
302+
300303
} // end namespace swift
301304

302305
#endif

lib/AST/Availability.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,8 @@ AvailabilityInference::attrForAnnotatedAvailableRange(const Decl *D,
224224
ASTContext &Ctx) {
225225
const AvailableAttr *bestAvailAttr = nullptr;
226226

227+
D = abstractSyntaxDeclForAvailableAttribute(D);
228+
227229
for (auto Attr : D->getAttrs()) {
228230
auto *AvailAttr = dyn_cast<AvailableAttr>(Attr);
229231
if (AvailAttr == nullptr || !AvailAttr->Introduced.has_value() ||
@@ -744,3 +746,31 @@ ASTContext::getSwift5PlusAvailability(llvm::VersionTuple swiftVersion) {
744746
Twine("Missing call to getSwiftXYAvailability for Swift ") +
745747
swiftVersion.getAsString());
746748
}
749+
750+
const Decl *
751+
swift::abstractSyntaxDeclForAvailableAttribute(const Decl *ConcreteSyntaxDecl) {
752+
// This function needs to be kept in sync with its counterpart,
753+
// concreteSyntaxDeclForAvailableAttribute().
754+
755+
if (auto *PBD = dyn_cast<PatternBindingDecl>(ConcreteSyntaxDecl)) {
756+
// Existing @available attributes in the AST are attached to VarDecls
757+
// rather than PatternBindingDecls, so we return the first VarDecl for
758+
// the pattern binding declaration.
759+
// This is safe, even though there may be multiple VarDecls, because
760+
// all parsed attribute that appear in the concrete syntax upon on the
761+
// PatternBindingDecl are added to all of the VarDecls for the pattern
762+
// binding.
763+
for (auto index : range(PBD->getNumPatternEntries())) {
764+
if (auto VD = PBD->getAnchoringVarDecl(index))
765+
return VD;
766+
}
767+
} else if (auto *ECD = dyn_cast<EnumCaseDecl>(ConcreteSyntaxDecl)) {
768+
// Similar to the PatternBindingDecl case above, we return the
769+
// first EnumElementDecl.
770+
if (auto *Elem = ECD->getFirstElement()) {
771+
return Elem;
772+
}
773+
}
774+
775+
return ConcreteSyntaxDecl;
776+
}

lib/AST/Decl.cpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2079,19 +2079,23 @@ bool VarDecl::isLayoutExposedToClients() const {
20792079
if (!parent) return false;
20802080
if (isStatic()) return false;
20812081

2082-
if (!hasStorage() &&
2083-
!getAttrs().hasAttribute<LazyAttr>() &&
2084-
!hasAttachedPropertyWrapper()) {
2085-
return false;
2086-
}
20872082

20882083
auto nominalAccess =
20892084
parent->getFormalAccessScope(/*useDC=*/nullptr,
20902085
/*treatUsableFromInlineAsPublic=*/true);
20912086
if (!nominalAccess.isPublic()) return false;
20922087

2093-
return (parent->getAttrs().hasAttribute<FrozenAttr>() ||
2094-
parent->getAttrs().hasAttribute<FixedLayoutAttr>());
2088+
if (!parent->getAttrs().hasAttribute<FrozenAttr>() &&
2089+
!parent->getAttrs().hasAttribute<FixedLayoutAttr>())
2090+
return false;
2091+
2092+
if (!hasStorage() &&
2093+
!getAttrs().hasAttribute<LazyAttr>() &&
2094+
!hasAttachedPropertyWrapper()) {
2095+
return false;
2096+
}
2097+
2098+
return true;
20952099
}
20962100

20972101
/// Check whether the given type representation will be

lib/AST/TypeRefinementContext.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "swift/AST/Stmt.h"
2121
#include "swift/AST/Expr.h"
2222
#include "swift/AST/SourceFile.h"
23+
#include "swift/AST/TypeCheckRequests.h"
2324
#include "swift/AST/TypeRefinementContext.h"
2425
#include "swift/Basic/SourceManager.h"
2526

@@ -192,6 +193,18 @@ TypeRefinementContext::findMostRefinedSubContext(SourceLoc Loc,
192193
!rangeContainsTokenLocWithGeneratedSource(SM, SrcRange, Loc))
193194
return nullptr;
194195

196+
// If this context is for a declaration, ensure that we've expanded the
197+
// children of the declaration.
198+
if (Node.getReason() == Reason::Decl ||
199+
Node.getReason() == Reason::DeclImplicit) {
200+
if (auto decl = Node.getAsDecl()) {
201+
ASTContext &ctx = decl->getASTContext();
202+
(void)evaluateOrDefault(
203+
ctx.evaluator, ExpandChildTypeRefinementContextsRequest{decl, this},
204+
false);
205+
}
206+
}
207+
195208
// For the moment, we perform a linear search here, but we can and should
196209
// do something more efficient.
197210
for (TypeRefinementContext *Child : Children) {
@@ -354,6 +367,10 @@ void TypeRefinementContext::print(raw_ostream &OS, SourceManager &SrcMgr,
354367
OS << "extension." << ED->getExtendedType().getString();
355368
} else if (isa<TopLevelCodeDecl>(D)) {
356369
OS << "<top-level-code>";
370+
} else if (auto PBD = dyn_cast<PatternBindingDecl>(D)) {
371+
if (auto VD = PBD->getAnchoringVarDecl(0)) {
372+
OS << VD->getName();
373+
}
357374
}
358375
}
359376

@@ -411,3 +428,8 @@ StringRef TypeRefinementContext::getReasonName(Reason R) {
411428

412429
llvm_unreachable("Unhandled Reason in switch.");
413430
}
431+
432+
void swift::simple_display(
433+
llvm::raw_ostream &out, const TypeRefinementContext *trc) {
434+
out << "TRC @" << trc;
435+
}

0 commit comments

Comments
 (0)