Skip to content

Commit f4f9d85

Browse files
committed
AST/Sema: Sink SemanticAvailableAttrRequest from Sema into AST.
Unblocks some work on the `@abi` attribute.
1 parent 6e4f711 commit f4f9d85

File tree

2 files changed

+140
-137
lines changed

2 files changed

+140
-137
lines changed

lib/AST/Availability.cpp

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
#include "swift/AST/AvailabilityInference.h"
2323
#include "swift/AST/AvailabilityRange.h"
2424
#include "swift/AST/Decl.h"
25+
// FIXME: [availability] Remove this when possible
26+
#include "swift/AST/DiagnosticsParse.h"
27+
#include "swift/AST/DiagnosticsSema.h"
2528
#include "swift/AST/PlatformKind.h"
2629
#include "swift/AST/TypeCheckRequests.h"
2730
#include "swift/AST/TypeWalker.h"
@@ -794,6 +797,143 @@ bool AvailabilityInference::isAvailableAsSPI(const Decl *D) {
794797
return false;
795798
}
796799

800+
static std::optional<AvailabilityDomain>
801+
getAvailabilityDomainForName(Identifier identifier,
802+
const DeclContext *declContext) {
803+
if (auto builtinDomain = AvailabilityDomain::builtinDomainForString(
804+
identifier.str(), declContext))
805+
return builtinDomain;
806+
807+
auto &ctx = declContext->getASTContext();
808+
if (auto customDomain =
809+
ctx.MainModule->getAvailabilityDomainForIdentifier(identifier))
810+
return customDomain;
811+
812+
return std::nullopt;
813+
}
814+
815+
std::optional<SemanticAvailableAttr>
816+
SemanticAvailableAttrRequest::evaluate(swift::Evaluator &evaluator,
817+
const AvailableAttr *attr,
818+
const Decl *decl) const {
819+
if (attr->hasCachedDomain())
820+
return SemanticAvailableAttr(attr);
821+
822+
auto &ctx = decl->getASTContext();
823+
auto &diags = ctx.Diags;
824+
auto attrLoc = attr->getLocation();
825+
auto attrName = attr->getAttrName();
826+
auto domainLoc = attr->getDomainLoc();
827+
auto introducedVersion = attr->getRawIntroduced();
828+
auto deprecatedVersion = attr->getRawDeprecated();
829+
auto obsoletedVersion = attr->getRawObsoleted();
830+
auto mutableAttr = const_cast<AvailableAttr *>(attr);
831+
auto domain = attr->getCachedDomain();
832+
833+
if (!domain) {
834+
auto domainIdentifier = attr->getDomainIdentifier();
835+
ASSERT(domainIdentifier);
836+
837+
// Attempt to resolve the domain specified for the attribute and diagnose
838+
// if no domain is found.
839+
auto declContext = decl->getInnermostDeclContext();
840+
domain = getAvailabilityDomainForName(*domainIdentifier, declContext);
841+
if (!domain) {
842+
auto domainString = domainIdentifier->str();
843+
if (auto suggestion = closestCorrectedPlatformString(domainString)) {
844+
diags
845+
.diagnose(domainLoc, diag::attr_availability_suggest_platform,
846+
domainString, attrName, *suggestion)
847+
.fixItReplace(SourceRange(domainLoc), *suggestion);
848+
} else {
849+
diags.diagnose(attrLoc, diag::attr_availability_unknown_platform,
850+
domainString, attrName);
851+
}
852+
return std::nullopt;
853+
}
854+
855+
if (domain->isCustom() &&
856+
!ctx.LangOpts.hasFeature(Feature::CustomAvailability) &&
857+
!declContext->isInSwiftinterface()) {
858+
diags.diagnose(domainLoc,
859+
diag::attr_availability_requires_custom_availability,
860+
domain->getNameForAttributePrinting(), attr);
861+
return std::nullopt;
862+
}
863+
864+
mutableAttr->setCachedDomain(*domain);
865+
}
866+
867+
auto domainName = domain->getNameForAttributePrinting();
868+
auto semanticAttr = SemanticAvailableAttr(attr);
869+
870+
bool hasVersionSpec =
871+
(introducedVersion || deprecatedVersion || obsoletedVersion);
872+
873+
if (!domain->isVersioned() && hasVersionSpec) {
874+
SourceRange versionSourceRange;
875+
if (introducedVersion)
876+
versionSourceRange = semanticAttr.getIntroducedSourceRange();
877+
else if (deprecatedVersion)
878+
versionSourceRange = semanticAttr.getDeprecatedSourceRange();
879+
else if (obsoletedVersion)
880+
versionSourceRange = semanticAttr.getObsoletedSourceRange();
881+
882+
diags
883+
.diagnose(attrLoc, diag::attr_availability_unexpected_version, attr,
884+
domainName)
885+
.highlight(versionSourceRange);
886+
return std::nullopt;
887+
}
888+
889+
if (domain->isSwiftLanguage() || domain->isPackageDescription()) {
890+
switch (attr->getKind()) {
891+
case AvailableAttr::Kind::Deprecated:
892+
diags.diagnose(attrLoc,
893+
diag::attr_availability_expected_deprecated_version,
894+
attrName, domainName);
895+
return std::nullopt;
896+
897+
case AvailableAttr::Kind::Unavailable:
898+
diags.diagnose(attrLoc, diag::attr_availability_cannot_be_used_for_domain,
899+
"unavailable", attrName, domainName);
900+
return std::nullopt;
901+
902+
case AvailableAttr::Kind::NoAsync:
903+
diags.diagnose(attrLoc, diag::attr_availability_cannot_be_used_for_domain,
904+
"noasync", attrName, domainName);
905+
return std::nullopt;
906+
907+
case AvailableAttr::Kind::Default:
908+
break;
909+
}
910+
911+
if (!hasVersionSpec) {
912+
diags.diagnose(attrLoc, diag::attr_availability_expected_version_spec,
913+
attrName, domainName);
914+
return std::nullopt;
915+
}
916+
}
917+
918+
// Canonicalize platform versions.
919+
// FIXME: [availability] This should be done when remapping versions instead.
920+
if (domain->isPlatform()) {
921+
auto canonicalizeVersion = [&](llvm::VersionTuple version) {
922+
return canonicalizePlatformVersion(domain->getPlatformKind(), version);
923+
};
924+
if (introducedVersion)
925+
mutableAttr->setRawIntroduced(canonicalizeVersion(*introducedVersion));
926+
927+
if (deprecatedVersion)
928+
mutableAttr->setRawDeprecated(canonicalizeVersion(*deprecatedVersion));
929+
930+
if (obsoletedVersion)
931+
mutableAttr->setRawObsoleted(canonicalizeVersion(*obsoletedVersion));
932+
}
933+
934+
return semanticAttr;
935+
}
936+
797937
AvailabilityRange
798938
SemanticAvailableAttr::getIntroducedRange(const ASTContext &Ctx) const {
799939
assert(getDomain().isActive(Ctx));

lib/Sema/TypeCheckAttr.cpp

Lines changed: 0 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -8387,143 +8387,6 @@ ValueDecl *RenamedDeclRequest::evaluate(Evaluator &evaluator,
83878387
return renamedDecl;
83888388
}
83898389

8390-
static std::optional<AvailabilityDomain>
8391-
getAvailabilityDomainForName(Identifier identifier,
8392-
const DeclContext *declContext) {
8393-
if (auto builtinDomain = AvailabilityDomain::builtinDomainForString(
8394-
identifier.str(), declContext))
8395-
return builtinDomain;
8396-
8397-
auto &ctx = declContext->getASTContext();
8398-
if (auto customDomain =
8399-
ctx.MainModule->getAvailabilityDomainForIdentifier(identifier))
8400-
return customDomain;
8401-
8402-
return std::nullopt;
8403-
}
8404-
8405-
std::optional<SemanticAvailableAttr>
8406-
SemanticAvailableAttrRequest::evaluate(swift::Evaluator &evaluator,
8407-
const AvailableAttr *attr,
8408-
const Decl *decl) const {
8409-
if (attr->hasCachedDomain())
8410-
return SemanticAvailableAttr(attr);
8411-
8412-
auto &ctx = decl->getASTContext();
8413-
auto &diags = ctx.Diags;
8414-
auto attrLoc = attr->getLocation();
8415-
auto attrName = attr->getAttrName();
8416-
auto domainLoc = attr->getDomainLoc();
8417-
auto introducedVersion = attr->getRawIntroduced();
8418-
auto deprecatedVersion = attr->getRawDeprecated();
8419-
auto obsoletedVersion = attr->getRawObsoleted();
8420-
auto mutableAttr = const_cast<AvailableAttr *>(attr);
8421-
auto domain = attr->getCachedDomain();
8422-
8423-
if (!domain) {
8424-
auto domainIdentifier = attr->getDomainIdentifier();
8425-
ASSERT(domainIdentifier);
8426-
8427-
// Attempt to resolve the domain specified for the attribute and diagnose
8428-
// if no domain is found.
8429-
auto declContext = decl->getInnermostDeclContext();
8430-
domain = getAvailabilityDomainForName(*domainIdentifier, declContext);
8431-
if (!domain) {
8432-
auto domainString = domainIdentifier->str();
8433-
if (auto suggestion = closestCorrectedPlatformString(domainString)) {
8434-
diags
8435-
.diagnose(domainLoc, diag::attr_availability_suggest_platform,
8436-
domainString, attrName, *suggestion)
8437-
.fixItReplace(SourceRange(domainLoc), *suggestion);
8438-
} else {
8439-
diags.diagnose(attrLoc, diag::attr_availability_unknown_platform,
8440-
domainString, attrName);
8441-
}
8442-
return std::nullopt;
8443-
}
8444-
8445-
if (domain->isCustom() &&
8446-
!ctx.LangOpts.hasFeature(Feature::CustomAvailability) &&
8447-
!declContext->isInSwiftinterface()) {
8448-
diags.diagnose(domainLoc,
8449-
diag::attr_availability_requires_custom_availability,
8450-
domain->getNameForAttributePrinting(), attr);
8451-
return std::nullopt;
8452-
}
8453-
8454-
mutableAttr->setCachedDomain(*domain);
8455-
}
8456-
8457-
auto domainName = domain->getNameForAttributePrinting();
8458-
auto semanticAttr = SemanticAvailableAttr(attr);
8459-
8460-
bool hasVersionSpec =
8461-
(introducedVersion || deprecatedVersion || obsoletedVersion);
8462-
8463-
if (!domain->isVersioned() && hasVersionSpec) {
8464-
SourceRange versionSourceRange;
8465-
if (introducedVersion)
8466-
versionSourceRange = semanticAttr.getIntroducedSourceRange();
8467-
else if (deprecatedVersion)
8468-
versionSourceRange = semanticAttr.getDeprecatedSourceRange();
8469-
else if (obsoletedVersion)
8470-
versionSourceRange = semanticAttr.getObsoletedSourceRange();
8471-
8472-
diags
8473-
.diagnose(attrLoc, diag::attr_availability_unexpected_version, attr,
8474-
domainName)
8475-
.highlight(versionSourceRange);
8476-
return std::nullopt;
8477-
}
8478-
8479-
if (domain->isSwiftLanguage() || domain->isPackageDescription()) {
8480-
switch (attr->getKind()) {
8481-
case AvailableAttr::Kind::Deprecated:
8482-
diags.diagnose(attrLoc,
8483-
diag::attr_availability_expected_deprecated_version,
8484-
attrName, domainName);
8485-
return std::nullopt;
8486-
8487-
case AvailableAttr::Kind::Unavailable:
8488-
diags.diagnose(attrLoc, diag::attr_availability_cannot_be_used_for_domain,
8489-
"unavailable", attrName, domainName);
8490-
return std::nullopt;
8491-
8492-
case AvailableAttr::Kind::NoAsync:
8493-
diags.diagnose(attrLoc, diag::attr_availability_cannot_be_used_for_domain,
8494-
"noasync", attrName, domainName);
8495-
return std::nullopt;
8496-
8497-
case AvailableAttr::Kind::Default:
8498-
break;
8499-
}
8500-
8501-
if (!hasVersionSpec) {
8502-
diags.diagnose(attrLoc, diag::attr_availability_expected_version_spec,
8503-
attrName, domainName);
8504-
return std::nullopt;
8505-
}
8506-
}
8507-
8508-
// Canonicalize platform versions.
8509-
// FIXME: [availability] This should be done when remapping versions instead.
8510-
if (domain->isPlatform()) {
8511-
auto canonicalizeVersion = [&](llvm::VersionTuple version) {
8512-
return canonicalizePlatformVersion(domain->getPlatformKind(), version);
8513-
};
8514-
if (introducedVersion)
8515-
mutableAttr->setRawIntroduced(canonicalizeVersion(*introducedVersion));
8516-
8517-
if (deprecatedVersion)
8518-
mutableAttr->setRawDeprecated(canonicalizeVersion(*deprecatedVersion));
8519-
8520-
if (obsoletedVersion)
8521-
mutableAttr->setRawObsoleted(canonicalizeVersion(*obsoletedVersion));
8522-
}
8523-
8524-
return semanticAttr;
8525-
}
8526-
85278390
template <typename ATTR>
85288391
static void forEachCustomAttribute(
85298392
Decl *decl,

0 commit comments

Comments
 (0)