Skip to content

[TypeChecker] NFC: Unify logic in checkDeclarationAvailaibility and… #35343

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 9 additions & 31 deletions lib/Sema/ConstraintSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5085,42 +5085,20 @@ void ConstraintSystem::diagnoseFailureFor(SolutionApplicationTarget target) {

bool ConstraintSystem::isDeclUnavailable(const Decl *D,
ConstraintLocator *locator) const {
auto &ctx = getASTContext();

// First check whether this declaration is universally unavailable.
if (D->getAttrs().isUnavailable(ctx))
if (D->getAttrs().isUnavailable(getASTContext()))
return true;

if (ctx.LangOpts.DisableAvailabilityChecking)
return false;

if (!DC->getParentSourceFile()) {
// We only check availability if this reference is in a source file; we do
// not check in other kinds of FileUnits.
return false;
}

AvailabilityContext safeRangeUnderApprox{
AvailabilityInference::availableRange(D, ctx)};
if (safeRangeUnderApprox.isAlwaysAvailable())
return false;

SourceLoc loc;

if (locator) {
if (auto anchor = locator->getAnchor())
loc = getLoc(anchor);
}
return TypeChecker::isDeclarationUnavailable(D, DC, [&] {
SourceLoc loc;

AvailabilityContext runningOSOverApprox =
TypeChecker::overApproximateAvailabilityAtLocation(loc, DC);
if (locator) {
if (auto anchor = locator->getAnchor())
loc = getLoc(anchor);
}

// The reference is safe if an over-approximation of the running OS
// versions is fully contained within an under-approximation
// of the versions on which the declaration is available. If this
// containment cannot be guaranteed, we say the reference is
// not available.
return !runningOSOverApprox.isContainedIn(safeRangeUnderApprox);
return TypeChecker::overApproximateAvailabilityAtLocation(loc, DC);
});
}

bool ConstraintSystem::isConformanceUnavailable(ProtocolConformanceRef conformance,
Expand Down
40 changes: 27 additions & 13 deletions lib/Sema/TypeCheckAvailability.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -936,37 +936,51 @@ TypeChecker::overApproximateAvailabilityAtLocation(SourceLoc loc,
return OverApproximateContext;
}

Optional<UnavailabilityReason>
TypeChecker::checkDeclarationAvailability(const Decl *D,
const ExportContext &where) {
auto *referenceDC = where.getDeclContext();
bool TypeChecker::isDeclarationUnavailable(
const Decl *D, const DeclContext *referenceDC,
llvm::function_ref<AvailabilityContext()> getAvailabilityContext) {
ASTContext &Context = referenceDC->getASTContext();
if (Context.LangOpts.DisableAvailabilityChecking) {
return None;
return false;
}

if (!referenceDC->getParentSourceFile()) {
// We only check availability if this reference is in a source file; we do
// not check in other kinds of FileUnits.
return None;
return false;
}

AvailabilityContext runningOSOverApprox =
where.getAvailabilityContext();

AvailabilityContext safeRangeUnderApprox{
AvailabilityInference::availableRange(D, Context)};

if (safeRangeUnderApprox.isAlwaysAvailable())
return false;

AvailabilityContext runningOSOverApprox = getAvailabilityContext();

// The reference is safe if an over-approximation of the running OS
// versions is fully contained within an under-approximation
// of the versions on which the declaration is available. If this
// containment cannot be guaranteed, we say the reference is
// not available.
if (runningOSOverApprox.isContainedIn(safeRangeUnderApprox))
return None;
return !runningOSOverApprox.isContainedIn(safeRangeUnderApprox);
}

VersionRange version = safeRangeUnderApprox.getOSVersion();
return UnavailabilityReason::requiresVersionRange(version);
Optional<UnavailabilityReason>
TypeChecker::checkDeclarationAvailability(const Decl *D,
const ExportContext &Where) {
if (isDeclarationUnavailable(D, Where.getDeclContext(), [&Where] {
return Where.getAvailabilityContext();
})) {
auto &Context = Where.getDeclContext()->getASTContext();
AvailabilityContext safeRangeUnderApprox{
AvailabilityInference::availableRange(D, Context)};
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@slavapestov Is AvailabilityInference::availableRange(D, Context) an expensive operation? I could try and make sure that it's done only once is so.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it should be pretty cheap. I'll re-run my benchmark with your change.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me know how it goes then and I'll merge these changes if everything is fine.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can go ahead and merge it first

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, 🚀


VersionRange version = safeRangeUnderApprox.getOSVersion();
return UnavailabilityReason::requiresVersionRange(version);
}

return None;
}

Optional<UnavailabilityReason>
Expand Down
6 changes: 6 additions & 0 deletions lib/Sema/TypeChecker.h
Original file line number Diff line number Diff line change
Expand Up @@ -998,6 +998,12 @@ TypeRefinementContext *getOrBuildTypeRefinementContext(SourceFile *SF);
Optional<Diag<>>
diagnosticIfDeclCannotBePotentiallyUnavailable(const Decl *D);

/// Same as \c checkDeclarationAvailability but doesn't give a reason for
/// unavailability.
bool isDeclarationUnavailable(
const Decl *D, const DeclContext *referenceDC,
llvm::function_ref<AvailabilityContext()> getAvailabilityContext);

/// Checks whether a declaration should be considered unavailable when
/// referred to at the given location and, if so, returns the reason why the
/// declaration is unavailable. Returns None is the declaration is
Expand Down