Skip to content

Commit 536e666

Browse files
committed
Sema: Introduce TypeChecker::availabilityAtLocation().
Implement a query that returns the `AvailabilityContext` for a given `SourceLoc` and `DeclContext`. Re-implement the existing type checker query that just returns an `AvailabilityRange` on top of the new query.
1 parent f0a5a5e commit 536e666

File tree

5 files changed

+69
-28
lines changed

5 files changed

+69
-28
lines changed

include/swift/AST/AvailabilityContext.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,12 @@ class AvailabilityContext {
7171
/// Returns true if this context is deprecated on the current platform.
7272
bool isDeprecated() const;
7373

74+
/// Constrain with another `AvailabilityContext`.
75+
void constrainWithContext(const AvailabilityContext &other, ASTContext &ctx);
76+
77+
/// Constrain with the availability attributes of `decl`.
78+
void constrainWithDecl(const Decl *decl);
79+
7480
/// Constrain the platform availability range with `platformRange`.
7581
void constrainWithPlatformRange(const AvailabilityRange &platformRange,
7682
ASTContext &ctx);

include/swift/AST/AvailabilityContextStorage.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,13 @@ struct AvailabilityContext::PlatformInfo {
4040
/// platform.
4141
unsigned IsDeprecated : 1;
4242

43-
/// Sets `Range` to `other` if `other` is more restrictive. Returns true if
44-
/// any property changed as a result of adding this constraint.
43+
/// Sets each field to the value of the corresponding field in `other` if the
44+
/// other is more restrictive. Returns true if any field changed as a result
45+
/// of adding this constraint.
46+
bool constrainWith(const PlatformInfo &other);
47+
4548
/// Updates each field to reflect the availability of `decl`, if that
46-
/// availability is more restrictive. Return true if any field was updated.
49+
/// availability is more restrictive. Returns true if any field was updated.
4750
bool constrainWith(const Decl *decl);
4851

4952
bool constrainRange(const AvailabilityRange &other) {

lib/AST/AvailabilityContext.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,18 @@
1818

1919
using namespace swift;
2020

21+
bool AvailabilityContext::PlatformInfo::constrainWith(
22+
const PlatformInfo &other) {
23+
bool isConstrained = false;
24+
isConstrained |= constrainRange(other.Range);
25+
if (other.IsUnavailable) {
26+
isConstrained |= constrainUnavailability(other.UnavailablePlatform);
27+
}
28+
isConstrained |= constrainDeprecated(other.IsDeprecated);
29+
30+
return isConstrained;
31+
}
32+
2133
bool AvailabilityContext::PlatformInfo::constrainWith(const Decl *decl) {
2234
bool isConstrained = false;
2335
auto &ctx = decl->getASTContext();
@@ -129,6 +141,18 @@ bool AvailabilityContext::isDeprecated() const {
129141
return Info->Platform.IsDeprecated;
130142
}
131143

144+
void AvailabilityContext::constrainWithContext(const AvailabilityContext &other,
145+
ASTContext &ctx) {
146+
PlatformInfo platformAvailability{Info->Platform};
147+
if (platformAvailability.constrainWith(other.Info->Platform)) {
148+
Info = Storage::get(platformAvailability, ctx);
149+
}
150+
}
151+
152+
void AvailabilityContext::constrainWithDecl(const Decl *decl) {
153+
constrainWithDeclAndPlatformRange(decl, AvailabilityRange::alwaysAvailable());
154+
}
155+
132156
void AvailabilityContext::constrainWithPlatformRange(
133157
const AvailabilityRange &platformRange, ASTContext &ctx) {
134158
PlatformInfo platformAvailability{Info->Platform};

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1411,9 +1411,9 @@ evaluator::SideEffect ExpandChildTypeRefinementContextsRequest::evaluate(
14111411
return evaluator::SideEffect();
14121412
}
14131413

1414-
AvailabilityRange TypeChecker::overApproximateAvailabilityAtLocation(
1415-
SourceLoc loc, const DeclContext *DC,
1416-
const TypeRefinementContext **MostRefined) {
1414+
AvailabilityContext
1415+
TypeChecker::availabilityAtLocation(SourceLoc loc, const DeclContext *DC,
1416+
const TypeRefinementContext **MostRefined) {
14171417
SourceFile *SF;
14181418
if (loc.isValid())
14191419
SF = DC->getParentModule()->getSourceFileContainingLocation(loc);
@@ -1436,7 +1436,7 @@ AvailabilityRange TypeChecker::overApproximateAvailabilityAtLocation(
14361436
// this will be a real problem.
14371437

14381438
// We can assume we are running on at least the minimum inlining target.
1439-
auto OverApproximateContext = AvailabilityRange::forInliningTarget(Context);
1439+
auto baseAvailability = AvailabilityContext::getDefault(Context);
14401440
auto isInvalidLoc = [SF](SourceLoc loc) {
14411441
return SF ? loc.isInvalid() : true;
14421442
};
@@ -1445,34 +1445,35 @@ AvailabilityRange TypeChecker::overApproximateAvailabilityAtLocation(
14451445
if (!D)
14461446
break;
14471447

1448+
baseAvailability.constrainWithDecl(D);
14481449
loc = D->getLoc();
1450+
DC = D->getDeclContext();
1451+
}
14491452

1450-
std::optional<AvailabilityRange> Info =
1451-
AvailabilityInference::annotatedAvailableRange(D);
1453+
if (!SF || loc.isInvalid())
1454+
return baseAvailability;
14521455

1453-
if (Info.has_value()) {
1454-
OverApproximateContext.constrainWith(Info.value());
1455-
}
1456+
TypeRefinementContext *rootTRC = getOrBuildTypeRefinementContext(SF);
1457+
if (!rootTRC)
1458+
return baseAvailability;
14561459

1457-
DC = D->getDeclContext();
1458-
}
1460+
TypeRefinementContext *TRC = rootTRC->findMostRefinedSubContext(loc, Context);
1461+
if (!TRC)
1462+
return baseAvailability;
14591463

1460-
if (SF && loc.isValid()) {
1461-
TypeRefinementContext *rootTRC = getOrBuildTypeRefinementContext(SF);
1462-
if (rootTRC) {
1463-
TypeRefinementContext *TRC =
1464-
rootTRC->findMostRefinedSubContext(loc, Context);
1465-
if (TRC) {
1466-
OverApproximateContext.constrainWith(
1467-
TRC->getPlatformAvailabilityRange());
1468-
if (MostRefined) {
1469-
*MostRefined = TRC;
1470-
}
1471-
}
1472-
}
1464+
if (MostRefined) {
1465+
*MostRefined = TRC;
14731466
}
14741467

1475-
return OverApproximateContext;
1468+
auto availability = TRC->getAvailabilityContext();
1469+
availability.constrainWithContext(baseAvailability, Context);
1470+
return availability;
1471+
}
1472+
1473+
AvailabilityRange TypeChecker::overApproximateAvailabilityAtLocation(
1474+
SourceLoc loc, const DeclContext *DC,
1475+
const TypeRefinementContext **MostRefined) {
1476+
return availabilityAtLocation(loc, DC, MostRefined).getPlatformRange();
14761477
}
14771478

14781479
bool TypeChecker::isDeclarationUnavailable(

lib/Sema/TypeChecker.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -998,6 +998,13 @@ bool isAvailabilitySafeForConformance(
998998
const ValueDecl *witness, const DeclContext *dc,
999999
AvailabilityRange &requiredAvailability);
10001000

1001+
/// Returns the most refined `AvailabilityContext` for the given location.
1002+
/// If `MostRefined` is not `nullptr`, it will be set to the most refined TRC
1003+
/// that contains the given location.
1004+
AvailabilityContext
1005+
availabilityAtLocation(SourceLoc loc, const DeclContext *DC,
1006+
const TypeRefinementContext **MostRefined = nullptr);
1007+
10011008
/// Returns an over-approximation of the range of operating system versions
10021009
/// that could the passed-in location could be executing upon for
10031010
/// the target platform. If MostRefined != nullptr, set to the most-refined

0 commit comments

Comments
 (0)