Skip to content

Commit e5cd36e

Browse files
authored
Merge pull request #79656 from tshortli/defer-availability-domain-resolution
AST/Parse: Always delay AvailabilityDomain lookup to type-checking
2 parents 69302f9 + b0afd07 commit e5cd36e

12 files changed

+98
-148
lines changed

include/swift/AST/ASTBridging.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -691,13 +691,6 @@ struct BridgedAvailabilityMacroDefinition {
691691
BridgedArrayRef specs;
692692
};
693693

694-
enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedAvailabilitySpecKind {
695-
BridgedAvailabilitySpecKindPlatformVersionConstraint,
696-
BridgedAvailabilitySpecKindWildcard,
697-
BridgedAvailabilitySpecKindLanguageVersionConstraint,
698-
BridgedAvailabilitySpecKindPackageDescriptionVersionConstraint,
699-
};
700-
701694
struct BridgedAvailabilityDomain;
702695

703696
SWIFT_NAME("BridgedAvailabilitySpec.createWildcard(_:loc:)")

include/swift/AST/AvailabilitySpec.h

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,12 @@ class AvailabilitySpec : public ASTAllocated<AvailabilitySpec> {
7474
createForDomain(ASTContext &ctx, AvailabilityDomain domain, SourceLoc loc,
7575
llvm::VersionTuple version, SourceRange versionRange);
7676

77-
/// Creates an availability specification for an unknown availability domain.
78-
static AvailabilitySpec *createForUnknownDomain(ASTContext &ctx,
79-
Identifier domainIdentifier,
80-
SourceLoc loc,
81-
llvm::VersionTuple version,
82-
SourceRange versionRange);
77+
/// Creates an availability specification that requires a minimum version of
78+
/// some availability domain which has not yet been resolved.
79+
static AvailabilitySpec *
80+
createForDomainIdentifier(ASTContext &ctx, Identifier domainIdentifier,
81+
SourceLoc loc, llvm::VersionTuple version,
82+
SourceRange versionRange);
8383

8484
AvailabilitySpec *clone(ASTContext &ctx) const;
8585

@@ -91,24 +91,14 @@ class AvailabilitySpec : public ASTAllocated<AvailabilitySpec> {
9191
SourceRange getSourceRange() const { return SrcRange; }
9292
SourceLoc getStartLoc() const { return SrcRange.Start; }
9393

94-
bool isWildcard() const {
95-
if (auto domain = getDomain())
96-
return domain->isUniversal();
97-
return false;
98-
}
99-
10094
AvailabilityDomainOrIdentifier getDomainOrIdentifier() const {
10195
return DomainOrIdentifier;
10296
}
10397

104-
std::optional<AvailabilityDomain> getDomain() const {
105-
return getDomainOrIdentifier().getAsDomain();
106-
}
107-
108-
PlatformKind getPlatform() const {
109-
if (auto domain = getDomain())
110-
return domain->getPlatformKind();
111-
return PlatformKind::none;
98+
bool isWildcard() const {
99+
if (auto domain = getDomainOrIdentifier().getAsDomain())
100+
return domain->isUniversal();
101+
return false;
112102
}
113103

114104
// The version tuple that was written in source.
@@ -140,15 +130,14 @@ class SemanticAvailabilitySpec {
140130
public:
141131
SemanticAvailabilitySpec(const AvailabilitySpec *spec) : spec(spec) {
142132
// The domain must be resolved in order to wrap it in a semantic spec.
143-
ASSERT(spec->isWildcard() || spec->getDomain());
133+
bool hasDomain = spec->getDomainOrIdentifier().isDomain();
134+
ASSERT(hasDomain);
144135
}
145136

146137
const AvailabilitySpec *getParsedSpec() const { return spec; }
147138

148139
AvailabilityDomain getDomain() const {
149-
if (isWildcard())
150-
return AvailabilityDomain::forUniversal();
151-
return spec->getDomain().value();
140+
return spec->getDomainOrIdentifier().getAsDomain().value();
152141
}
153142

154143
bool isWildcard() const { return spec->isWildcard(); }

include/swift/AST/DiagnosticsParse.def

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1972,13 +1972,6 @@ ERROR(avail_query_expected_version_number,PointsToFirstBadToken,
19721972
ERROR(avail_query_expected_rparen,PointsToFirstBadToken,
19731973
"expected ')' in availability query", ())
19741974

1975-
WARNING(avail_query_unrecognized_platform_name,
1976-
PointsToFirstBadToken, "unrecognized platform name %0", (Identifier))
1977-
WARNING(avail_query_suggest_platform_name,
1978-
PointsToFirstBadToken, "unrecognized platform name %0;"
1979-
" did you mean '%1'?",
1980-
(Identifier, StringRef))
1981-
19821975
ERROR(avail_query_disallowed_operator, PointsToFirstBadToken,
19831976
"'%0' cannot be used in an availability condition", (StringRef))
19841977

include/swift/AST/DiagnosticsSema.def

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6753,6 +6753,16 @@ NOTE(type_eraser_init_spi,none,
67536753
// MARK: @available
67546754
//------------------------------------------------------------------------------
67556755

6756+
ERROR(availability_must_occur_alone, none,
6757+
"'%0' version-availability must be specified alone", (StringRef))
6758+
6759+
WARNING(availability_unrecognized_platform_name,
6760+
PointsToFirstBadToken, "unrecognized platform name %0", (Identifier))
6761+
WARNING(availability_suggest_platform_name,
6762+
PointsToFirstBadToken, "unrecognized platform name %0;"
6763+
" did you mean '%1'?",
6764+
(Identifier, StringRef))
6765+
67566766
WARNING(attr_availability_expected_deprecated_version, none,
67576767
"expected version number with 'deprecated' in '%0' attribute for "
67586768
"platform '%1'", (StringRef, StringRef))
@@ -6988,9 +6998,6 @@ ERROR(conformance_availability_only_version_newer, none,
69886998
"conformance of %0 to %1 is only available in %2 %3 or newer",
69896999
(Type, Type, StringRef, llvm::VersionTuple))
69907000

6991-
ERROR(availability_must_occur_alone, none,
6992-
"'%0' version-availability must be specified alone", (StringRef))
6993-
69947001
//------------------------------------------------------------------------------
69957002
// MARK: if #available(...)
69967003
//------------------------------------------------------------------------------

include/swift/Parse/Parser.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2035,8 +2035,6 @@ class Parser {
20352035
SmallVectorImpl<AvailabilitySpec *> &Specs);
20362036

20372037
ParserResult<AvailabilitySpec> parseAvailabilitySpec();
2038-
ParserResult<AvailabilitySpec> parsePlatformVersionConstraintSpec();
2039-
ParserResult<AvailabilitySpec> parsePlatformAgnosticVersionConstraintSpec();
20402038
bool
20412039
parseAvailability(bool parseAsPartOfSpecializeAttr, StringRef AttrName,
20422040
bool &DiscardAttribute, SourceRange &attrRange,

lib/AST/AvailabilityDomain.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
#include "swift/AST/AvailabilityDomain.h"
1414
#include "swift/AST/ASTContext.h"
1515
#include "swift/AST/Decl.h"
16-
#include "swift/AST/DiagnosticsParse.h"
1716
#include "swift/AST/DiagnosticsSema.h"
1817
#include "swift/AST/TypeCheckRequests.h"
1918
#include "swift/Basic/Assertions.h"
@@ -234,11 +233,11 @@ AvailabilityDomainOrIdentifier::lookUpInDeclContext(
234233
auto domainString = identifier.str();
235234
if (auto suggestion = closestCorrectedPlatformString(domainString)) {
236235
diags
237-
.diagnose(loc, diag::avail_query_suggest_platform_name, identifier,
236+
.diagnose(loc, diag::availability_suggest_platform_name, identifier,
238237
*suggestion)
239238
.fixItReplace(SourceRange(loc), *suggestion);
240239
} else {
241-
diags.diagnose(loc, diag::avail_query_unrecognized_platform_name,
240+
diags.diagnose(loc, diag::availability_unrecognized_platform_name,
242241
identifier);
243242
}
244243
return std::nullopt;

lib/AST/AvailabilitySpec.cpp

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "swift/AST/AvailabilitySpec.h"
1818
#include "swift/AST/ASTContext.h"
1919
#include "swift/AST/AvailabilityDomain.h"
20+
#include "swift/AST/DiagnosticsParse.h"
2021
#include "llvm/Support/raw_ostream.h"
2122

2223
using namespace swift;
@@ -38,7 +39,7 @@ AvailabilitySpec *AvailabilitySpec::createForDomain(ASTContext &ctx,
3839
version, versionRange.Start);
3940
}
4041

41-
AvailabilitySpec *AvailabilitySpec::createForUnknownDomain(
42+
AvailabilitySpec *AvailabilitySpec::createForDomainIdentifier(
4243
ASTContext &ctx, Identifier domainIdentifier, SourceLoc loc,
4344
llvm::VersionTuple version, SourceRange versionRange) {
4445
DEBUG_ASSERT(!version.empty());
@@ -59,6 +60,18 @@ void AvailabilitySpec::print(llvm::raw_ostream &os) const {
5960
os << " " << getRawVersion().getAsString();
6061
}
6162

63+
std::optional<SemanticAvailabilitySpec>
64+
AvailabilitySpec::getSemanticAvailabilitySpec(
65+
const DeclContext *declContext) const {
66+
AvailabilitySpec *mutableThis = const_cast<AvailabilitySpec *>(this);
67+
auto domain = mutableThis->DomainOrIdentifier.resolveInDeclContext(
68+
getStartLoc(), declContext);
69+
70+
if (domain)
71+
return SemanticAvailabilitySpec(this);
72+
return std::nullopt;
73+
}
74+
6275
llvm::VersionTuple SemanticAvailabilitySpec::getVersion() const {
6376
// For macOS Big Sur, we canonicalize 10.16 to 11.0 for compile-time
6477
// checking since clang canonicalizes availability markup. However, to
@@ -75,14 +88,6 @@ llvm::VersionTuple SemanticAvailabilitySpec::getVersion() const {
7588
spec->getRawVersion());
7689
}
7790

78-
std::optional<SemanticAvailabilitySpec>
79-
AvailabilitySpec::getSemanticAvailabilitySpec(
80-
const DeclContext *declContext) const {
81-
if (isWildcard() || getDomain())
82-
return SemanticAvailabilitySpec(this);
83-
return std::nullopt;
84-
}
85-
8691
std::optional<SemanticAvailabilitySpec>
8792
SemanticAvailabilitySpecs::Filter::operator()(
8893
const AvailabilitySpec *spec) const {

lib/AST/Bridging/AvailabilityBridging.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,17 +111,22 @@ bool BridgedAvailabilitySpec_isWildcard(BridgedAvailabilitySpec spec) {
111111
return spec.unbridged()->isWildcard();
112112
}
113113

114+
// FIXME: [availability] Remove this (re-implement ASTGen to match ParseDecl)
114115
BridgedAvailabilityDomain
115116
BridgedAvailabilitySpec_getDomain(BridgedAvailabilitySpec spec) {
116-
auto domain = spec.unbridged()->getDomain();
117+
auto domain = spec.unbridged()->getDomainOrIdentifier().getAsDomain();
117118
if (domain)
118119
return *domain;
119120
return BridgedAvailabilityDomain();
120121
}
121122

123+
// FIXME: [availability] Remove this (re-implement ASTGen to match ParseDecl)
122124
BridgedPlatformKind
123125
BridgedAvailabilitySpec_getPlatform(BridgedAvailabilitySpec spec) {
124-
return bridge(spec.unbridged()->getPlatform());
126+
auto domain = spec.unbridged()->getDomainOrIdentifier().getAsDomain();
127+
if (domain)
128+
return bridge(domain->getPlatformKind());
129+
return bridge(PlatformKind::none);
125130
}
126131

127132
BridgedVersionTuple

lib/Parse/ParseDecl.cpp

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -798,22 +798,27 @@ bool Parser::parseAvailability(
798798
if (Spec->isWildcard())
799799
continue;
800800

801-
std::optional<AvailabilityDomain> Domain = Spec->getDomain();
802-
if (!Domain)
801+
auto DomainOrIdentifier = Spec->getDomainOrIdentifier();
802+
803+
// The domain should not be resolved during parsing.
804+
DEBUG_ASSERT(!DomainOrIdentifier.isDomain());
805+
806+
auto DomainIdentifier = DomainOrIdentifier.getAsIdentifier();
807+
if (!DomainIdentifier)
803808
continue;
804809

805-
auto Attr = new (Context)
806-
AvailableAttr(AtLoc, attrRange, *Domain, Spec->getSourceRange().Start,
807-
AvailableAttr::Kind::Default,
808-
/*Message=*/StringRef(),
809-
/*Rename=*/StringRef(),
810-
/*Introduced=*/Spec->getRawVersion(),
811-
/*IntroducedRange=*/Spec->getVersionSrcRange(),
812-
/*Deprecated=*/llvm::VersionTuple(),
813-
/*DeprecatedRange=*/SourceRange(),
814-
/*Obsoleted=*/llvm::VersionTuple(),
815-
/*ObsoletedRange=*/SourceRange(),
816-
/*Implicit=*/false, AttrName == SPI_AVAILABLE_ATTRNAME);
810+
auto Attr = new (Context) AvailableAttr(
811+
AtLoc, attrRange, *DomainIdentifier, Spec->getSourceRange().Start,
812+
AvailableAttr::Kind::Default,
813+
/*Message=*/StringRef(),
814+
/*Rename=*/StringRef(),
815+
/*Introduced=*/Spec->getRawVersion(),
816+
/*IntroducedRange=*/Spec->getVersionSrcRange(),
817+
/*Deprecated=*/llvm::VersionTuple(),
818+
/*DeprecatedRange=*/SourceRange(),
819+
/*Obsoleted=*/llvm::VersionTuple(),
820+
/*ObsoletedRange=*/SourceRange(),
821+
/*Implicit=*/false, AttrName == SPI_AVAILABLE_ATTRNAME);
817822
addAttribute(Attr);
818823

819824
Attr->setIsGroupMember();
@@ -1875,6 +1880,18 @@ Parser::parseAvailabilityMacro(SmallVectorImpl<AvailabilitySpec *> &Specs) {
18751880
return makeParserSuccess();
18761881
}
18771882

1883+
static PlatformKind getPlatformFromDomainOrIdentifier(
1884+
const AvailabilityDomainOrIdentifier &domainOrIdentifier) {
1885+
if (auto domain = domainOrIdentifier.getAsDomain())
1886+
return domain->getPlatformKind();
1887+
1888+
if (auto platform =
1889+
platformFromString(domainOrIdentifier.getAsIdentifier()->str()))
1890+
return *platform;
1891+
1892+
return PlatformKind::none;
1893+
}
1894+
18781895
ParserStatus Parser::parsePlatformVersionInList(StringRef AttrName,
18791896
llvm::SmallVector<PlatformAndVersion, 4> &PlatformAndVersions,
18801897
bool &ParsedUnrecognizedPlatformName) {
@@ -1886,10 +1903,10 @@ ParserStatus Parser::parsePlatformVersionInList(StringRef AttrName,
18861903
return MacroStatus;
18871904

18881905
for (auto *Spec : Specs) {
1889-
auto Platform = Spec->getPlatform();
1890-
// Since peekAvailabilityMacroName() only matches defined availability
1891-
// macros, we only expect platform specific constraints here.
1892-
DEBUG_ASSERT(Platform != PlatformKind::none);
1906+
auto Platform =
1907+
getPlatformFromDomainOrIdentifier(Spec->getDomainOrIdentifier());
1908+
if (Platform == PlatformKind::none)
1909+
continue;
18931910

18941911
auto Version = Spec->getRawVersion();
18951912
if (Version.getSubminor().has_value() || Version.getBuild().has_value()) {

lib/Parse/ParseExpr.cpp

Lines changed: 2 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -3675,8 +3675,6 @@ void Parser::validateCollectionElement(ParserResult<Expr> element) {
36753675
}
36763676
}
36773677

3678-
3679-
36803678
/// Parse availability query specification.
36813679
///
36823680
/// availability-spec:
@@ -3691,51 +3689,7 @@ ParserResult<AvailabilitySpec> Parser::parseAvailabilitySpec() {
36913689

36923690
return makeParserResult(AvailabilitySpec::createWildcard(Context, StarLoc));
36933691
}
3694-
if (Tok.isIdentifierOrUnderscore() &&
3695-
(Tok.getText() == "swift" || Tok.getText() == "_PackageDescription"))
3696-
return parsePlatformAgnosticVersionConstraintSpec();
3697-
3698-
return parsePlatformVersionConstraintSpec();
3699-
}
37003692

3701-
/// Parse platform-agnostic version constraint specification.
3702-
///
3703-
/// language-version-constraint-spec:
3704-
/// "swift" version-tuple
3705-
/// package-description-version-constraint-spec:
3706-
/// "_PackageDescription" version-tuple
3707-
ParserResult<AvailabilitySpec>
3708-
Parser::parsePlatformAgnosticVersionConstraintSpec() {
3709-
SourceLoc PlatformAgnosticNameLoc;
3710-
llvm::VersionTuple Version;
3711-
std::optional<AvailabilityDomain> Domain;
3712-
SourceRange VersionRange;
3713-
3714-
if (Tok.isIdentifierOrUnderscore()) {
3715-
if (Tok.getText() == "swift")
3716-
Domain = AvailabilityDomain::forSwiftLanguage();
3717-
else if (Tok.getText() == "_PackageDescription")
3718-
Domain = AvailabilityDomain::forPackageDescription();
3719-
}
3720-
3721-
if (!Domain.has_value())
3722-
return nullptr;
3723-
3724-
PlatformAgnosticNameLoc = Tok.getLoc();
3725-
consumeToken();
3726-
if (parseVersionTuple(Version, VersionRange,
3727-
diag::avail_query_expected_version_number)) {
3728-
return nullptr;
3729-
}
3730-
return makeParserResult(AvailabilitySpec::createForDomain(
3731-
Context, Domain.value(), PlatformAgnosticNameLoc, Version, VersionRange));
3732-
}
3733-
3734-
/// Parse platform-version constraint specification.
3735-
///
3736-
/// platform-version-constraint-spec:
3737-
/// identifier version-comparison version-tuple
3738-
ParserResult<AvailabilitySpec> Parser::parsePlatformVersionConstraintSpec() {
37393693
Identifier PlatformIdentifier;
37403694
SourceLoc PlatformLoc;
37413695
if (Tok.is(tok::code_complete)) {
@@ -3766,24 +3720,6 @@ ParserResult<AvailabilitySpec> Parser::parsePlatformVersionConstraintSpec() {
37663720
return nullptr;
37673721
}
37683722

3769-
std::optional<PlatformKind> Platform =
3770-
platformFromString(PlatformIdentifier.str());
3771-
3772-
if (!Platform.has_value() || Platform.value() == PlatformKind::none) {
3773-
if (auto CorrectedPlatform =
3774-
closestCorrectedPlatformString(PlatformIdentifier.str())) {
3775-
diagnose(PlatformLoc, diag::avail_query_suggest_platform_name,
3776-
PlatformIdentifier, *CorrectedPlatform)
3777-
.fixItReplace(PlatformLoc, *CorrectedPlatform);
3778-
} else {
3779-
diagnose(PlatformLoc, diag::avail_query_unrecognized_platform_name,
3780-
PlatformIdentifier);
3781-
}
3782-
return makeParserResult(AvailabilitySpec::createForUnknownDomain(
3783-
Context, PlatformIdentifier, PlatformLoc, Version, VersionRange));
3784-
}
3785-
3786-
return makeParserResult(AvailabilitySpec::createForDomain(
3787-
Context, AvailabilityDomain::forPlatform(Platform.value()), PlatformLoc,
3788-
Version, VersionRange));
3723+
return makeParserResult(AvailabilitySpec::createForDomainIdentifier(
3724+
Context, PlatformIdentifier, PlatformLoc, Version, VersionRange));
37893725
}

0 commit comments

Comments
 (0)