Skip to content

Commit 300d04a

Browse files
authored
Merge pull request #67642 from DougGregor/lazy-type-refinement-context
Eliminate Observable circular reference errors via lazier TypeRefinementContext building
2 parents c0e2d5e + 37959de commit 300d04a

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
@@ -377,6 +377,13 @@ class AvailabilityInference {
377377
annotatedAvailableRangeForAttr(const SpecializeAttr *attr, ASTContext &ctx);
378378
};
379379

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

382389
#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;
@@ -4433,6 +4434,25 @@ class InitAccessorReferencedVariablesRequest
44334434
bool isCached() const { return true; }
44344435
};
44354436

4437+
/// Expand the children of the type refinement context for the given
4438+
/// declaration.
4439+
class ExpandChildTypeRefinementContextsRequest
4440+
: public SimpleRequest<ExpandChildTypeRefinementContextsRequest,
4441+
bool(Decl *, TypeRefinementContext *),
4442+
RequestFlags::Cached> {
4443+
public:
4444+
using SimpleRequest::SimpleRequest;
4445+
4446+
private:
4447+
friend SimpleRequest;
4448+
4449+
bool evaluate(Evaluator &evaluator, Decl *decl,
4450+
TypeRefinementContext *parentTRC) const;
4451+
4452+
public:
4453+
bool isCached() const { return true; }
4454+
};
4455+
44364456
#define SWIFT_TYPEID_ZONE TypeChecker
44374457
#define SWIFT_TYPEID_HEADER "swift/AST/TypeCheckerTypeIDZone.def"
44384458
#include "swift/Basic/DefineTypeIDZone.h"

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,3 +506,6 @@ SWIFT_REQUEST(TypeChecker, InitAccessorReferencedVariablesRequest,
506506
ArrayRef<VarDecl *>(DeclAttribute *, AccessorDecl *,
507507
ArrayRef<Identifier>),
508508
Cached, NoLocationInfo)
509+
SWIFT_REQUEST(TypeChecker, ExpandChildTypeRefinementContextsRequest,
510+
bool(Decl *, TypeRefinementContext *),
511+
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
@@ -225,6 +225,8 @@ AvailabilityInference::attrForAnnotatedAvailableRange(const Decl *D,
225225
ASTContext &Ctx) {
226226
const AvailableAttr *bestAvailAttr = nullptr;
227227

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

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)