Skip to content

AST/Parse: Always delay AvailabilityDomain lookup to type-checking #79656

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
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
7 changes: 0 additions & 7 deletions include/swift/AST/ASTBridging.h
Original file line number Diff line number Diff line change
Expand Up @@ -691,13 +691,6 @@ struct BridgedAvailabilityMacroDefinition {
BridgedArrayRef specs;
};

enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedAvailabilitySpecKind {
BridgedAvailabilitySpecKindPlatformVersionConstraint,
BridgedAvailabilitySpecKindWildcard,
BridgedAvailabilitySpecKindLanguageVersionConstraint,
BridgedAvailabilitySpecKindPackageDescriptionVersionConstraint,
};

struct BridgedAvailabilityDomain;

SWIFT_NAME("BridgedAvailabilitySpec.createWildcard(_:loc:)")
Expand Down
37 changes: 13 additions & 24 deletions include/swift/AST/AvailabilitySpec.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,12 @@ class AvailabilitySpec : public ASTAllocated<AvailabilitySpec> {
createForDomain(ASTContext &ctx, AvailabilityDomain domain, SourceLoc loc,
llvm::VersionTuple version, SourceRange versionRange);

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

AvailabilitySpec *clone(ASTContext &ctx) const;

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

bool isWildcard() const {
if (auto domain = getDomain())
return domain->isUniversal();
return false;
}

AvailabilityDomainOrIdentifier getDomainOrIdentifier() const {
return DomainOrIdentifier;
}

std::optional<AvailabilityDomain> getDomain() const {
return getDomainOrIdentifier().getAsDomain();
}

PlatformKind getPlatform() const {
if (auto domain = getDomain())
return domain->getPlatformKind();
return PlatformKind::none;
bool isWildcard() const {
if (auto domain = getDomainOrIdentifier().getAsDomain())
return domain->isUniversal();
return false;
}

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

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

AvailabilityDomain getDomain() const {
if (isWildcard())
return AvailabilityDomain::forUniversal();
return spec->getDomain().value();
return spec->getDomainOrIdentifier().getAsDomain().value();
}

bool isWildcard() const { return spec->isWildcard(); }
Expand Down
7 changes: 0 additions & 7 deletions include/swift/AST/DiagnosticsParse.def
Original file line number Diff line number Diff line change
Expand Up @@ -1972,13 +1972,6 @@ ERROR(avail_query_expected_version_number,PointsToFirstBadToken,
ERROR(avail_query_expected_rparen,PointsToFirstBadToken,
"expected ')' in availability query", ())

WARNING(avail_query_unrecognized_platform_name,
PointsToFirstBadToken, "unrecognized platform name %0", (Identifier))
WARNING(avail_query_suggest_platform_name,
PointsToFirstBadToken, "unrecognized platform name %0;"
" did you mean '%1'?",
(Identifier, StringRef))

ERROR(avail_query_disallowed_operator, PointsToFirstBadToken,
"'%0' cannot be used in an availability condition", (StringRef))

Expand Down
13 changes: 10 additions & 3 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -6738,6 +6738,16 @@ NOTE(type_eraser_init_spi,none,
// MARK: @available
//------------------------------------------------------------------------------

ERROR(availability_must_occur_alone, none,
"'%0' version-availability must be specified alone", (StringRef))

WARNING(availability_unrecognized_platform_name,
PointsToFirstBadToken, "unrecognized platform name %0", (Identifier))
WARNING(availability_suggest_platform_name,
PointsToFirstBadToken, "unrecognized platform name %0;"
" did you mean '%1'?",
(Identifier, StringRef))

WARNING(attr_availability_expected_deprecated_version, none,
"expected version number with 'deprecated' in '%0' attribute for "
"platform '%1'", (StringRef, StringRef))
Expand Down Expand Up @@ -6973,9 +6983,6 @@ ERROR(conformance_availability_only_version_newer, none,
"conformance of %0 to %1 is only available in %2 %3 or newer",
(Type, Type, StringRef, llvm::VersionTuple))

ERROR(availability_must_occur_alone, none,
"'%0' version-availability must be specified alone", (StringRef))

//------------------------------------------------------------------------------
// MARK: if #available(...)
//------------------------------------------------------------------------------
Expand Down
2 changes: 0 additions & 2 deletions include/swift/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -2035,8 +2035,6 @@ class Parser {
SmallVectorImpl<AvailabilitySpec *> &Specs);

ParserResult<AvailabilitySpec> parseAvailabilitySpec();
ParserResult<AvailabilitySpec> parsePlatformVersionConstraintSpec();
ParserResult<AvailabilitySpec> parsePlatformAgnosticVersionConstraintSpec();
bool
parseAvailability(bool parseAsPartOfSpecializeAttr, StringRef AttrName,
bool &DiscardAttribute, SourceRange &attrRange,
Expand Down
5 changes: 2 additions & 3 deletions lib/AST/AvailabilityDomain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
#include "swift/AST/AvailabilityDomain.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Decl.h"
#include "swift/AST/DiagnosticsParse.h"
#include "swift/AST/DiagnosticsSema.h"
#include "swift/AST/TypeCheckRequests.h"
#include "swift/Basic/Assertions.h"
Expand Down Expand Up @@ -234,11 +233,11 @@ AvailabilityDomainOrIdentifier::lookUpInDeclContext(
auto domainString = identifier.str();
if (auto suggestion = closestCorrectedPlatformString(domainString)) {
diags
.diagnose(loc, diag::avail_query_suggest_platform_name, identifier,
.diagnose(loc, diag::availability_suggest_platform_name, identifier,
*suggestion)
.fixItReplace(SourceRange(loc), *suggestion);
} else {
diags.diagnose(loc, diag::avail_query_unrecognized_platform_name,
diags.diagnose(loc, diag::availability_unrecognized_platform_name,
identifier);
}
return std::nullopt;
Expand Down
23 changes: 14 additions & 9 deletions lib/AST/AvailabilitySpec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "swift/AST/AvailabilitySpec.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/AvailabilityDomain.h"
#include "swift/AST/DiagnosticsParse.h"
#include "llvm/Support/raw_ostream.h"

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

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

std::optional<SemanticAvailabilitySpec>
AvailabilitySpec::getSemanticAvailabilitySpec(
const DeclContext *declContext) const {
AvailabilitySpec *mutableThis = const_cast<AvailabilitySpec *>(this);
auto domain = mutableThis->DomainOrIdentifier.resolveInDeclContext(
getStartLoc(), declContext);

if (domain)
return SemanticAvailabilitySpec(this);
return std::nullopt;
}

llvm::VersionTuple SemanticAvailabilitySpec::getVersion() const {
// For macOS Big Sur, we canonicalize 10.16 to 11.0 for compile-time
// checking since clang canonicalizes availability markup. However, to
Expand All @@ -75,14 +88,6 @@ llvm::VersionTuple SemanticAvailabilitySpec::getVersion() const {
spec->getRawVersion());
}

std::optional<SemanticAvailabilitySpec>
AvailabilitySpec::getSemanticAvailabilitySpec(
const DeclContext *declContext) const {
if (isWildcard() || getDomain())
return SemanticAvailabilitySpec(this);
return std::nullopt;
}

std::optional<SemanticAvailabilitySpec>
SemanticAvailabilitySpecs::Filter::operator()(
const AvailabilitySpec *spec) const {
Expand Down
9 changes: 7 additions & 2 deletions lib/AST/Bridging/AvailabilityBridging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,17 +111,22 @@ bool BridgedAvailabilitySpec_isWildcard(BridgedAvailabilitySpec spec) {
return spec.unbridged()->isWildcard();
}

// FIXME: [availability] Remove this (re-implement ASTGen to match ParseDecl)
BridgedAvailabilityDomain
BridgedAvailabilitySpec_getDomain(BridgedAvailabilitySpec spec) {
auto domain = spec.unbridged()->getDomain();
auto domain = spec.unbridged()->getDomainOrIdentifier().getAsDomain();
if (domain)
return *domain;
return BridgedAvailabilityDomain();
}

// FIXME: [availability] Remove this (re-implement ASTGen to match ParseDecl)
BridgedPlatformKind
BridgedAvailabilitySpec_getPlatform(BridgedAvailabilitySpec spec) {
return bridge(spec.unbridged()->getPlatform());
auto domain = spec.unbridged()->getDomainOrIdentifier().getAsDomain();
if (domain)
return bridge(domain->getPlatformKind());
return bridge(PlatformKind::none);
}

BridgedVersionTuple
Expand Down
2 changes: 0 additions & 2 deletions lib/IDE/SyntaxModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1170,8 +1170,6 @@ bool ModelASTWalker::handleSpecialDeclAttribute(const DeclAttribute *D,
assert(Next.Range.getStart() == D->getRange().Start &&
"Attribute's TokenNodes already consumed?");
}
} else {
assert(0 && "No TokenNodes?");
}
if (!passTokenNodesUntil(D->getRange().End,
IncludeNodeAtLocation).shouldContinue)
Expand Down
53 changes: 35 additions & 18 deletions lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -798,22 +798,27 @@ bool Parser::parseAvailability(
if (Spec->isWildcard())
continue;

std::optional<AvailabilityDomain> Domain = Spec->getDomain();
if (!Domain)
auto DomainOrIdentifier = Spec->getDomainOrIdentifier();

// The domain should not be resolved during parsing.
DEBUG_ASSERT(!DomainOrIdentifier.isDomain());

auto DomainIdentifier = DomainOrIdentifier.getAsIdentifier();
if (!DomainIdentifier)
continue;

auto Attr = new (Context)
AvailableAttr(AtLoc, attrRange, *Domain, Spec->getSourceRange().Start,
AvailableAttr::Kind::Default,
/*Message=*/StringRef(),
/*Rename=*/StringRef(),
/*Introduced=*/Spec->getRawVersion(),
/*IntroducedRange=*/Spec->getVersionSrcRange(),
/*Deprecated=*/llvm::VersionTuple(),
/*DeprecatedRange=*/SourceRange(),
/*Obsoleted=*/llvm::VersionTuple(),
/*ObsoletedRange=*/SourceRange(),
/*Implicit=*/false, AttrName == SPI_AVAILABLE_ATTRNAME);
auto Attr = new (Context) AvailableAttr(
AtLoc, attrRange, *DomainIdentifier, Spec->getSourceRange().Start,
AvailableAttr::Kind::Default,
/*Message=*/StringRef(),
/*Rename=*/StringRef(),
/*Introduced=*/Spec->getRawVersion(),
/*IntroducedRange=*/Spec->getVersionSrcRange(),
/*Deprecated=*/llvm::VersionTuple(),
/*DeprecatedRange=*/SourceRange(),
/*Obsoleted=*/llvm::VersionTuple(),
/*ObsoletedRange=*/SourceRange(),
/*Implicit=*/false, AttrName == SPI_AVAILABLE_ATTRNAME);
addAttribute(Attr);

Attr->setIsGroupMember();
Expand Down Expand Up @@ -1875,6 +1880,18 @@ Parser::parseAvailabilityMacro(SmallVectorImpl<AvailabilitySpec *> &Specs) {
return makeParserSuccess();
}

static PlatformKind getPlatformFromDomainOrIdentifier(
const AvailabilityDomainOrIdentifier &domainOrIdentifier) {
if (auto domain = domainOrIdentifier.getAsDomain())
return domain->getPlatformKind();

if (auto platform =
platformFromString(domainOrIdentifier.getAsIdentifier()->str()))
return *platform;

return PlatformKind::none;
}

ParserStatus Parser::parsePlatformVersionInList(StringRef AttrName,
llvm::SmallVector<PlatformAndVersion, 4> &PlatformAndVersions,
bool &ParsedUnrecognizedPlatformName) {
Expand All @@ -1886,10 +1903,10 @@ ParserStatus Parser::parsePlatformVersionInList(StringRef AttrName,
return MacroStatus;

for (auto *Spec : Specs) {
auto Platform = Spec->getPlatform();
// Since peekAvailabilityMacroName() only matches defined availability
// macros, we only expect platform specific constraints here.
DEBUG_ASSERT(Platform != PlatformKind::none);
auto Platform =
getPlatformFromDomainOrIdentifier(Spec->getDomainOrIdentifier());
if (Platform == PlatformKind::none)
continue;

auto Version = Spec->getRawVersion();
if (Version.getSubminor().has_value() || Version.getBuild().has_value()) {
Expand Down
Loading