Skip to content

Commit 0fabfa3

Browse files
committed
Sema: Check custom domain availability during conformance checking.
Protocol requirement witnesses cannot only be available in a custom availability domain if the requirement does not have the same availability constraint. Resolves rdar://156462516.
1 parent b45d278 commit 0fabfa3

File tree

7 files changed

+263
-163
lines changed

7 files changed

+263
-163
lines changed

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/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)