Skip to content

Commit 39cbf6d

Browse files
committed
Sema: Request-ify WitnessChecker::getRequiredAccessScope()/isUsableFromInlineRequired()
1 parent a659b64 commit 39cbf6d

File tree

5 files changed

+69
-44
lines changed

5 files changed

+69
-44
lines changed

include/swift/AST/TypeCheckRequests.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2806,6 +2806,28 @@ class ResolveImplicitMemberRequest
28062806
bool isCached() const { return true; }
28072807
};
28082808

2809+
using ConformanceAccessScope =
2810+
std::pair<AccessScope, /*witnessesMustBeUsableFromInline=*/bool>;
2811+
2812+
class ConformanceAccessScopeRequest
2813+
: public SimpleRequest<ConformanceAccessScopeRequest,
2814+
ConformanceAccessScope(DeclContext *, ProtocolDecl *),
2815+
RequestFlags::Cached> {
2816+
public:
2817+
using SimpleRequest::SimpleRequest;
2818+
2819+
private:
2820+
friend SimpleRequest;
2821+
2822+
// Evaluation.
2823+
ConformanceAccessScope
2824+
evaluate(Evaluator &evaluator, DeclContext *dc, ProtocolDecl *proto) const;
2825+
2826+
public:
2827+
// Caching.
2828+
bool isCached() const { return true; }
2829+
};
2830+
28092831
class TypeWitnessRequest
28102832
: public SimpleRequest<TypeWitnessRequest,
28112833
TypeWitnessAndDecl(NormalProtocolConformance *,

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,9 @@ SWIFT_REQUEST(TypeChecker, SynthesizeDefaultInitRequest,
418418
ConstructorDecl *(NominalTypeDecl *), Cached, NoLocationInfo)
419419
SWIFT_REQUEST(TypeChecker, TypeCheckSourceFileRequest,
420420
bool(SouceFile *), SeparatelyCached, NoLocationInfo)
421+
SWIFT_REQUEST(TypeChecker, ConformanceAccessScopeRequest,
422+
ConformanceAccessScope(DeclContext *, ProtocolDecl *),
423+
Cached, NoLocationInfo)
421424
SWIFT_REQUEST(TypeChecker, TypeWitnessRequest,
422425
TypeWitnessAndDecl(NormalProtocolConformance *,
423426
AssociatedTypeDecl *),

lib/Sema/AssociatedTypeInference.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,9 @@ void ConformanceChecker::recordTypeWitness(AssociatedTypeDecl *assocType,
159159

160160
// Inject the typealias into the nominal decl that conforms to the protocol.
161161
auto nominal = DC->getSelfNominalTypeDecl();
162-
AccessScope requiredAccessScope = getRequiredAccessScope();
162+
auto requiredAccessScope = evaluateOrDefault(
163+
Context.evaluator, ConformanceAccessScopeRequest{DC, Proto},
164+
std::make_pair(AccessScope::getPublic(), false));
163165

164166
if (!getASTContext().isSwiftVersionAtLeast(5) &&
165167
!DC->getParentModule()->isResilient()) {
@@ -179,17 +181,17 @@ void ConformanceChecker::recordTypeWitness(AssociatedTypeDecl *assocType,
179181
underlyingTypeScope->intersectWith(nominalAccessScope);
180182
assert(widestPossibleScope.has_value() &&
181183
"we found the nominal and the type witness, didn't we?");
182-
requiredAccessScope = widestPossibleScope.value();
184+
requiredAccessScope.first = widestPossibleScope.value();
183185
}
184186

185187
// An associated type witness can never be less than fileprivate, since
186188
// it must always be at least as visible as the enclosing type.
187189
AccessLevel requiredAccess =
188-
std::max(requiredAccessScope.accessLevelForDiagnostics(),
190+
std::max(requiredAccessScope.first.accessLevelForDiagnostics(),
189191
AccessLevel::FilePrivate);
190192

191193
aliasDecl->setAccess(requiredAccess);
192-
if (isUsableFromInlineRequired()) {
194+
if (requiredAccessScope.second) {
193195
auto *attr =
194196
new (getASTContext()) UsableFromInlineAttr(/*implicit=*/true);
195197
aliasDecl->getAttrs().add(attr);

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1605,48 +1605,51 @@ bool WitnessChecker::findBestWitness(
16051605
return isReallyBest;
16061606
}
16071607

1608-
AccessScope WitnessChecker::getRequiredAccessScope() {
1609-
if (RequiredAccessScopeAndUsableFromInline.has_value())
1610-
return RequiredAccessScopeAndUsableFromInline.value().first;
1611-
1612-
AccessScope result = Proto->getFormalAccessScope(DC);
1613-
1608+
ConformanceAccessScope ConformanceAccessScopeRequest::evaluate(
1609+
Evaluator &evaluator, DeclContext *dc, ProtocolDecl *proto) const {
1610+
AccessScope result = proto->getFormalAccessScope(dc);
16141611
bool witnessesMustBeUsableFromInline = false;
1615-
if (Adoptee) {
1616-
const NominalTypeDecl *adoptingNominal = DC->getSelfNominalTypeDecl();
16171612

1613+
auto *nominal = dc->getSelfNominalTypeDecl();
1614+
1615+
// We're either looking at a concrete conformance, or the default witness
1616+
// table for a resilient protocol.
1617+
if (!isa<ProtocolDecl>(nominal)) {
16181618
// Compute the intersection of the conforming type's access scope
16191619
// and the protocol's access scope.
16201620
auto scopeIntersection =
1621-
result.intersectWith(adoptingNominal->getFormalAccessScope(DC));
1621+
result.intersectWith(nominal->getFormalAccessScope(dc));
16221622
assert(scopeIntersection.has_value());
16231623
result = scopeIntersection.value();
16241624

16251625
if (!result.isPublic()) {
16261626
witnessesMustBeUsableFromInline =
1627-
Proto->getFormalAccessScope(
1628-
DC, /*usableFromInlineAsPublic*/true).isPublic() &&
1629-
adoptingNominal->getFormalAccessScope(
1630-
DC, /*usableFromInlineAsPublic*/true).isPublic();
1627+
proto->getFormalAccessScope(
1628+
dc, /*usableFromInlineAsPublic*/true).isPublic() &&
1629+
nominal->getFormalAccessScope(
1630+
dc, /*usableFromInlineAsPublic*/true).isPublic();
16311631
}
16321632
} else {
16331633
if (!result.isPublic()) {
16341634
witnessesMustBeUsableFromInline =
1635-
Proto->getFormalAccessScope(
1636-
DC, /*usableFromInlineAsPublic*/true).isPublic();
1635+
proto->getFormalAccessScope(
1636+
dc, /*usableFromInlineAsPublic*/true).isPublic();
16371637
}
16381638
}
16391639

1640-
RequiredAccessScopeAndUsableFromInline =
1641-
std::make_pair(result, witnessesMustBeUsableFromInline);
1642-
return result;
1640+
return std::make_pair(result, witnessesMustBeUsableFromInline);
16431641
}
16441642

16451643
bool WitnessChecker::checkWitnessAccess(ValueDecl *requirement,
16461644
ValueDecl *witness,
16471645
bool *isSetter) {
16481646
*isSetter = false;
1649-
AccessScope actualScopeToCheck = getRequiredAccessScope();
1647+
1648+
auto requiredAccessScope = evaluateOrDefault(
1649+
Context.evaluator, ConformanceAccessScopeRequest{DC, Proto},
1650+
std::make_pair(AccessScope::getPublic(), false));
1651+
1652+
auto actualScopeToCheck = requiredAccessScope.first;
16501653

16511654
// Setting the 'forConformance' flag means that we admit witnesses in
16521655
// protocol extensions that we can see, but are not necessarily as
@@ -1669,7 +1672,7 @@ bool WitnessChecker::checkWitnessAccess(ValueDecl *requirement,
16691672
}
16701673
}
16711674

1672-
if (actualScopeToCheck.hasEqualDeclContextWith(getRequiredAccessScope()))
1675+
if (actualScopeToCheck.hasEqualDeclContextWith(requiredAccessScope.first))
16731676
return true;
16741677
}
16751678

@@ -1703,15 +1706,20 @@ RequirementCheck WitnessChecker::checkWitness(ValueDecl *requirement,
17031706
if (!match.OptionalAdjustments.empty())
17041707
return CheckKind::OptionalityConflict;
17051708

1709+
auto requiredAccessScope = evaluateOrDefault(
1710+
Context.evaluator, ConformanceAccessScopeRequest{DC, Proto},
1711+
std::make_pair(AccessScope::getPublic(), false));
1712+
17061713
bool isSetter = false;
17071714
if (checkWitnessAccess(requirement, match.Witness, &isSetter)) {
17081715
CheckKind kind = (isSetter
17091716
? CheckKind::AccessOfSetter
17101717
: CheckKind::Access);
1711-
return RequirementCheck(kind, getRequiredAccessScope());
1718+
1719+
return RequirementCheck(kind, requiredAccessScope.first);
17121720
}
17131721

1714-
if (isUsableFromInlineRequired()) {
1722+
if (requiredAccessScope.second) {
17151723
bool witnessIsUsableFromInline = match.Witness->getFormalAccessScope(
17161724
DC, /*usableFromInlineAsPublic*/true).isPublic();
17171725
if (!witnessIsUsableFromInline)
@@ -4655,24 +4663,27 @@ void ConformanceChecker::ensureRequirementsAreSatisfied() {
46554663
checkObjCTypeErasedGenerics(assocType, type, typeDecl);
46564664

46574665
if (typeDecl && !typeDecl->isImplicit()) {
4666+
auto requiredAccessScope = evaluateOrDefault(
4667+
Context.evaluator, ConformanceAccessScopeRequest{DC, Proto},
4668+
std::make_pair(AccessScope::getPublic(), false));
4669+
46584670
// Check access.
46594671
bool isSetter = false;
46604672
if (checkWitnessAccess(assocType, typeDecl, &isSetter)) {
46614673
assert(!isSetter);
46624674

46634675
// Note: you must not capture 'this' in the below closure.
4664-
const DeclContext *DC = this->DC;
4665-
auto requiredAccessScope = getRequiredAccessScope();
4676+
auto *DC = this->DC;
46664677

46674678
getASTContext().addDelayedConformanceDiag(Conformance, false,
46684679
[DC, requiredAccessScope, typeDecl](
46694680
NormalProtocolConformance *conformance) {
46704681
AccessLevel requiredAccess =
4671-
requiredAccessScope.requiredAccessForDiagnostics();
4682+
requiredAccessScope.first.requiredAccessForDiagnostics();
46724683
auto proto = conformance->getProtocol();
46734684
auto protoAccessScope = proto->getFormalAccessScope(DC);
46744685
bool protoForcesAccess =
4675-
requiredAccessScope.hasEqualDeclContextWith(protoAccessScope);
4686+
requiredAccessScope.first.hasEqualDeclContextWith(protoAccessScope);
46764687
auto diagKind = protoForcesAccess
46774688
? diag::type_witness_not_accessible_proto
46784689
: diag::type_witness_not_accessible_type;
@@ -4683,7 +4694,7 @@ void ConformanceChecker::ensureRequirementsAreSatisfied() {
46834694
});
46844695
}
46854696

4686-
if (isUsableFromInlineRequired()) {
4697+
if (requiredAccessScope.second) {
46874698
bool witnessIsUsableFromInline = typeDecl->getFormalAccessScope(
46884699
DC, /*usableFromInlineAsPublic*/true).isPublic();
46894700
if (!witnessIsUsableFromInline)

lib/Sema/TypeCheckProtocol.h

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -264,22 +264,9 @@ class WitnessChecker {
264264

265265
RequirementEnvironmentCache ReqEnvironmentCache;
266266

267-
llvm::Optional<std::pair<AccessScope, bool>>
268-
RequiredAccessScopeAndUsableFromInline;
269-
270267
WitnessChecker(ASTContext &ctx, ProtocolDecl *proto, Type adoptee,
271268
DeclContext *dc);
272269

273-
bool isMemberOperator(FuncDecl *decl, Type type);
274-
275-
AccessScope getRequiredAccessScope();
276-
277-
bool isUsableFromInlineRequired() {
278-
assert(RequiredAccessScopeAndUsableFromInline.has_value() &&
279-
"must check access first using getRequiredAccessScope");
280-
return RequiredAccessScopeAndUsableFromInline.value().second;
281-
}
282-
283270
void lookupValueWitnessesViaImplementsAttr(ValueDecl *req,
284271
SmallVector<ValueDecl *, 4>
285272
&witnesses);

0 commit comments

Comments
 (0)