Skip to content

Commit c4e242e

Browse files
authored
Merge pull request swiftlang#83349 from tshortli/check-custom-domain-availability-for-conformances
Sema: Check custom domain availability during conformance checking
2 parents da1f8b2 + 0fabfa3 commit c4e242e

12 files changed

+306
-193
lines changed

include/swift/AST/ASTContext.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -909,7 +909,7 @@ class ASTContext final {
909909
AvailabilityRange getSwiftAvailability(unsigned major, unsigned minor) const;
910910

911911
// For each feature defined in FeatureAvailability, define two functions;
912-
// the latter, with the suffix RuntimeAvailabilty, is for use with
912+
// the latter, with the suffix RuntimeAvailability, is for use with
913913
// AvailabilityRange::forRuntimeTarget(), and only looks at the Swift
914914
// runtime version.
915915
#define FEATURE(N, V) \

include/swift/AST/DiagnosticsSema.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7123,6 +7123,11 @@ ERROR(availability_protocol_requires_version,
71237123
(const ProtocolDecl *, const ValueDecl *, AvailabilityDomain,
71247124
AvailabilityRange))
71257125

7126+
ERROR(availability_protocol_requirement_only_available_in,
7127+
none, "protocol %0 requirement %1 cannot be satisfied by %kindonly1 that "
7128+
"is only available in %2",
7129+
(const ProtocolDecl *, const ValueDecl *, AvailabilityDomain))
7130+
71267131
NOTE(availability_protocol_requirement_here, none,
71277132
"protocol requirement here", ())
71287133

include/swift/AST/RequirementMatch.h

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#ifndef SWIFT_AST_REQUIREMENTMATCH_H
1313
#define SWIFT_AST_REQUIREMENTMATCH_H
1414

15+
#include "swift/AST/AvailabilityConstraint.h"
1516
#include "swift/AST/RequirementEnvironment.h"
1617
#include "swift/AST/Type.h"
1718
#include "swift/AST/Types.h"
@@ -252,7 +253,8 @@ class RequirementCheck {
252253

253254
/// Storage for `CheckKind::Availability`.
254255
struct {
255-
AvailabilityRange requiredRange;
256+
AvailabilityConstraint constraint;
257+
AvailabilityContext requiredContext;
256258
} Availability;
257259
};
258260

@@ -266,8 +268,10 @@ class RequirementCheck {
266268
RequirementCheck(AccessScope requiredAccessScope, bool forSetter)
267269
: Kind(CheckKind::Access), Access{requiredAccessScope, forSetter} {}
268270

269-
RequirementCheck(AvailabilityRange requiredRange)
270-
: Kind(CheckKind::Availability), Availability{requiredRange} {}
271+
RequirementCheck(AvailabilityConstraint constraint,
272+
AvailabilityContext requiredContext)
273+
: Kind(CheckKind::Availability),
274+
Availability{constraint, requiredContext} {}
271275

272276
CheckKind getKind() const { return Kind; }
273277

@@ -280,7 +284,7 @@ class RequirementCheck {
280284
/// True if the witness is less available than the requirement.
281285
bool isLessAvailable() const {
282286
return (Kind == CheckKind::Availability)
283-
? !Availability.requiredRange.isKnownUnreachable()
287+
? !Availability.constraint.isUnavailable()
284288
: false;
285289
}
286290

@@ -291,11 +295,18 @@ class RequirementCheck {
291295
return Access.requiredScope;
292296
}
293297

298+
/// The availability constraint that would fail if the witness were accessed
299+
/// from contexts in which the requirement is available.
300+
AvailabilityConstraint getAvailabilityConstraint() const {
301+
ASSERT(Kind == CheckKind::Availability);
302+
return Availability.constraint;
303+
}
304+
294305
/// The required availability range for checks that failed due to the witness
295306
/// being less available than the requirement.
296-
AvailabilityRange getRequiredAvailabilityRange() const {
307+
AvailabilityContext getRequiredAvailabilityContext() const {
297308
ASSERT(Kind == CheckKind::Availability);
298-
return Availability.requiredRange;
309+
return Availability.requiredContext;
299310
}
300311
};
301312

lib/AST/AvailabilityContext.cpp

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "swift/AST/AvailabilityScope.h"
1919
#include "swift/AST/Decl.h"
2020
#include "swift/AST/Module.h"
21+
#include "swift/AST/SourceFile.h"
2122
#include "swift/Basic/Assertions.h"
2223

2324
using namespace swift;
@@ -155,6 +156,30 @@ AvailabilityContext::forDeploymentTarget(const ASTContext &ctx) {
155156
AvailabilityRange::forDeploymentTarget(ctx), ctx);
156157
}
157158

159+
static AvailabilityContext
160+
contextForLocationInSourceFile(SourceLoc loc, SourceFile *sf,
161+
AvailabilityContext baseAvailability,
162+
const AvailabilityScope **refinedScope) {
163+
if (!sf || loc.isInvalid())
164+
return baseAvailability;
165+
166+
auto &ctx = sf->getASTContext();
167+
auto *rootScope = AvailabilityScope::getOrBuildForSourceFile(*sf);
168+
if (!rootScope)
169+
return baseAvailability;
170+
171+
auto *scope = rootScope->findMostRefinedSubContext(loc, ctx);
172+
if (!scope)
173+
return baseAvailability;
174+
175+
if (refinedScope)
176+
*refinedScope = scope;
177+
178+
auto availability = scope->getAvailabilityContext();
179+
availability.constrainWithContext(baseAvailability, ctx);
180+
return availability;
181+
}
182+
158183
AvailabilityContext
159184
AvailabilityContext::forLocation(SourceLoc loc, const DeclContext *declContext,
160185
const AvailabilityScope **refinedScope) {
@@ -191,37 +216,25 @@ AvailabilityContext::forLocation(SourceLoc loc, const DeclContext *declContext,
191216
declContext = decl->getDeclContext();
192217
}
193218

194-
if (!sf || loc.isInvalid())
195-
return baseAvailability;
196-
197-
auto *rootScope = AvailabilityScope::getOrBuildForSourceFile(*sf);
198-
if (!rootScope)
199-
return baseAvailability;
200-
201-
auto *scope = rootScope->findMostRefinedSubContext(loc, ctx);
202-
if (!scope)
203-
return baseAvailability;
204-
205-
if (refinedScope)
206-
*refinedScope = scope;
207-
208-
auto availability = scope->getAvailabilityContext();
209-
availability.constrainWithContext(baseAvailability, ctx);
210-
return availability;
219+
return contextForLocationInSourceFile(loc, sf, baseAvailability,
220+
refinedScope);
211221
}
212222

213223
AvailabilityContext AvailabilityContext::forDeclSignature(const Decl *decl) {
214-
// For decls with valid source locations, query the availability scope tree.
224+
// For decls with valid source locations in source files, we can query the
225+
// availability scope tree.
215226
auto loc = decl->getLoc();
216-
if (loc.isValid())
217-
return forLocation(loc, decl->getInnermostDeclContext());
218-
219-
// Otherwise, walk the decl hierarchy to compute availability. This can't be
220-
// delegated to `AvailabilityContext::forLocation()` since it walks up the
221-
// `DeclContext` hierachy for invalid source locations and that may skip
222-
// some declarations with availability attributes.
223227
auto &ctx = decl->getASTContext();
224228
auto availability = forInliningTarget(ctx);
229+
230+
if (loc.isValid()) {
231+
if (auto sf = decl->getDeclContext()
232+
->getParentModule()
233+
->getSourceFileContainingLocation(loc))
234+
return contextForLocationInSourceFile(loc, sf, availability, nullptr);
235+
}
236+
237+
// Otherwise, just walk the decl hierarchy to compute availability.
225238
while (decl) {
226239
availability.constrainWithDecl(decl);
227240
decl = decl->parentDeclForAvailability();

lib/AST/AvailabilityScopeBuilder.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ class AvailabilityScopeBuilder : private ASTWalker {
126126
}
127127

128128
const char *stackTraceAction() const {
129-
return "building availabilty scope for";
129+
return "building availability scope for";
130130
}
131131

132132
friend class swift::ExpandChildAvailabilityScopesRequest;
@@ -415,7 +415,7 @@ class AvailabilityScopeBuilder : private ASTWalker {
415415
// As a special case, extension decls are treated as effectively as
416416
// available as the nominal type they extend, up to the deployment target.
417417
// This rule is a convenience for library authors who have written
418-
// extensions without specifying platform availabilty on the extension
418+
// extensions without specifying platform availability on the extension
419419
// itself.
420420
if (auto *extension = dyn_cast<ExtensionDecl>(decl)) {
421421
auto extendedType = extension->getExtendedType();

lib/ClangImporter/ImportDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9750,7 +9750,7 @@ void ClangImporter::Implementation::importAttributes(
97509750
declContext->lookupAvailabilityDomains(domainIdentifier, results);
97519751

97529752
if (results.size() > 0) {
9753-
// FIXME: [availability] Diagnose ambiguous availabilty domain name?
9753+
// FIXME: [availability] Diagnose ambiguous availability domain name?
97549754
auto AttrKind = avail->getUnavailable()
97559755
? AvailableAttr::Kind::Unavailable
97569756
: AvailableAttr::Kind::Default;

lib/SILGen/SILGenAvailability.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ SILGenFunction::emitIfAvailableQuery(SILLocation loc,
267267

268268
// The query may not have been computed by Sema under the following
269269
// conditions:
270-
// - Availability checking was disabled (-disable-availabilty-checking).
270+
// - Availability checking was disabled (-disable-availability-checking).
271271
// - The query was marked invalid in the AST for a non-fatal reason.
272272
//
273273
// Otherwise, there's a bug in Sema.

lib/Sema/TypeCheckDecl.cpp

Lines changed: 0 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1670,72 +1670,6 @@ SelfAccessKindRequest::evaluate(Evaluator &evaluator, FuncDecl *FD) const {
16701670
return SelfAccessKind::NonMutating;
16711671
}
16721672

1673-
bool TypeChecker::isAvailabilitySafeForConformance(
1674-
const ProtocolDecl *proto, const ValueDecl *requirement,
1675-
const ValueDecl *witness, const DeclContext *dc,
1676-
AvailabilityRange &requirementInfo) {
1677-
1678-
// We assume conformances in
1679-
// non-SourceFiles have already been checked for availability.
1680-
if (!dc->getParentSourceFile())
1681-
return true;
1682-
1683-
auto &Context = proto->getASTContext();
1684-
assert(dc->getSelfNominalTypeDecl() &&
1685-
"Must have a nominal or extension context");
1686-
1687-
auto contextForConformingDecl =
1688-
AvailabilityContext::forDeclSignature(dc->getAsDecl());
1689-
1690-
// If the conformance is unavailable then it's irrelevant whether the witness
1691-
// is potentially unavailable.
1692-
if (contextForConformingDecl.isUnavailable())
1693-
return true;
1694-
1695-
// Make sure that any access of the witness through the protocol
1696-
// can only occur when the witness is available. That is, make sure that
1697-
// on every version where the conforming declaration is available, if the
1698-
// requirement is available then the witness is available as well.
1699-
// We do this by checking that (an over-approximation of) the intersection of
1700-
// the requirement's available range with both the conforming declaration's
1701-
// available range and the protocol's available range is fully contained in
1702-
// (an over-approximation of) the intersection of the witnesses's available
1703-
// range with both the conforming type's available range and the protocol
1704-
// declaration's available range.
1705-
AvailabilityRange witnessInfo =
1706-
AvailabilityInference::availableRange(witness);
1707-
requirementInfo = AvailabilityInference::availableRange(requirement);
1708-
1709-
AvailabilityRange infoForConformingDecl =
1710-
contextForConformingDecl.getPlatformRange();
1711-
1712-
// Relax the requirements for @_spi witnesses by treating the requirement as
1713-
// if it were introduced at the deployment target. This is not strictly sound
1714-
// since clients of SPI do not necessarily have the same deployment target as
1715-
// the module declaring the requirement. However, now that the public
1716-
// declarations in API libraries are checked according to the minimum possible
1717-
// deployment target of their clients this relaxation is needed for source
1718-
// compatibility with some existing code and is reasonably safe for the
1719-
// majority of cases.
1720-
if (witness->isSPI()) {
1721-
AvailabilityRange deploymentTarget =
1722-
AvailabilityRange::forDeploymentTarget(Context);
1723-
requirementInfo.constrainWith(deploymentTarget);
1724-
}
1725-
1726-
// Constrain over-approximates intersection of version ranges.
1727-
witnessInfo.constrainWith(infoForConformingDecl);
1728-
requirementInfo.constrainWith(infoForConformingDecl);
1729-
1730-
AvailabilityRange infoForProtocolDecl =
1731-
AvailabilityContext::forDeclSignature(proto).getPlatformRange();
1732-
1733-
witnessInfo.constrainWith(infoForProtocolDecl);
1734-
requirementInfo.constrainWith(infoForProtocolDecl);
1735-
1736-
return requirementInfo.isContainedIn(witnessInfo);
1737-
}
1738-
17391673
// Returns 'nullptr' if this is the 'newValue' or 'oldValue' parameter;
17401674
// otherwise, returns the corresponding parameter of the subscript
17411675
// declaration.

0 commit comments

Comments
 (0)