Skip to content

SR-2709: @available(swift, ...) #4985

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 13 commits into from
Oct 12, 2016
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
62 changes: 35 additions & 27 deletions include/swift/AST/Attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "swift/Basic/UUID.h"
#include "swift/Basic/STLExtras.h"
#include "swift/Basic/Range.h"
#include "swift/Basic/Version.h"
#include "swift/AST/Identifier.h"
#include "swift/AST/AttrKind.h"
#include "swift/AST/ConcreteDeclRef.h"
Expand Down Expand Up @@ -542,33 +543,33 @@ class SwiftNativeObjCRuntimeBaseAttr : public DeclAttribute {
};

/// Determine the result of comparing an availability attribute to a specific
/// minimum platform version.
enum class MinVersionComparison {
/// platform or language version.
enum class AvailableVersionComparison {
/// The entity is guaranteed to be available.
Available,

/// The entity is never available.
Unavailable,

/// The entity might be unavailable, because it was introduced after
/// the minimum version.
/// The entity might be unavailable at runtime, because it was introduced
/// after the requested minimum platform version.
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: You say "platform or language" version above but "platform" here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's correct; potential-availability only applies to platform, not language.

PotentiallyUnavailable,

/// The entity has been obsoleted.
Obsoleted,
};

/// Describes the unconditional availability of a declaration.
enum class UnconditionalAvailabilityKind {
/// The declaration is not unconditionally unavailable.
/// Describes the platform-agnostic availability of a declaration.
enum class PlatformAgnosticAvailabilityKind {
/// The associated availability attribute is not platform-agnostic.
None,
/// The declaration is deprecated, but can still be used.
Deprecated,
/// The declaration is unavailable in Swift, specifically
UnavailableInSwift,
/// The declaration is unavailable in the current version of Swift,
/// but was available in previous Swift versions.
UnavailableInCurrentSwift,
/// The declaration is available in some but not all versions
/// of Swift, as specified by the VersionTuple members.
SwiftVersionSpecific,
/// The declaration is unavailable for other reasons.
Unavailable,
};
Expand All @@ -585,14 +586,14 @@ class AvailableAttr : public DeclAttribute {
const clang::VersionTuple &Introduced,
const clang::VersionTuple &Deprecated,
const clang::VersionTuple &Obsoleted,
UnconditionalAvailabilityKind Unconditional,
PlatformAgnosticAvailabilityKind PlatformAgnostic,
bool Implicit)
: DeclAttribute(DAK_Available, AtLoc, Range, Implicit),
Message(Message), Rename(Rename),
INIT_VER_TUPLE(Introduced),
INIT_VER_TUPLE(Deprecated),
INIT_VER_TUPLE(Obsoleted),
Unconditional(Unconditional),
PlatformAgnostic(PlatformAgnostic),
Platform(Platform)
{}

Expand All @@ -618,21 +619,24 @@ class AvailableAttr : public DeclAttribute {
/// Indicates when the symbol was obsoleted.
const Optional<clang::VersionTuple> Obsoleted;

/// Indicates if the declaration has unconditional availability.
const UnconditionalAvailabilityKind Unconditional;
/// Indicates if the declaration has platform-agnostic availability.
const PlatformAgnosticAvailabilityKind PlatformAgnostic;

/// The platform of the availability.
const PlatformKind Platform;

/// Whether this is a language-version-specific entity.
bool isLanguageVersionSpecific() const;

/// Whether this is an unconditionally unavailable entity.
bool isUnconditionallyUnavailable() const;

/// Whether this is an unconditionally deprecated entity.
bool isUnconditionallyDeprecated() const;

/// Returns the unconditional unavailability.
UnconditionalAvailabilityKind getUnconditionalAvailability() const {
return Unconditional;
/// Returns the platform-agnostic availability.
PlatformAgnosticAvailabilityKind getPlatformAgnosticAvailability() const {
return PlatformAgnostic;
}

/// Determine if a given declaration should be considered unavailable given
Expand Down Expand Up @@ -660,17 +664,19 @@ class AvailableAttr : public DeclAttribute {
/// Returns true if this attribute is active given the current platform.
bool isActivePlatform(const ASTContext &ctx) const;

/// Compare this attribute's version information against the minimum platform
/// version (assuming the this attribute pertains to the active platform).
MinVersionComparison getMinVersionAvailability(
clang::VersionTuple minVersion) const;
/// Compare this attribute's version information against the platform or
/// language version (assuming the this attribute pertains to the active
/// platform).
AvailableVersionComparison getVersionAvailability(const ASTContext &ctx) const;

/// Create an AvailableAttr that indicates specific availability
/// for all platforms.
static AvailableAttr *
createUnconditional(ASTContext &C, StringRef Message, StringRef Rename = "",
UnconditionalAvailabilityKind Reason
= UnconditionalAvailabilityKind::Unavailable);
createPlatformAgnostic(ASTContext &C, StringRef Message, StringRef Rename = "",
PlatformAgnosticAvailabilityKind Reason
= PlatformAgnosticAvailabilityKind::Unavailable,
clang::VersionTuple Obsoleted
= clang::VersionTuple());

static bool classof(const DeclAttribute *DA) {
return DA->getKind() == DAK_Available;
Expand Down Expand Up @@ -1081,9 +1087,11 @@ class DeclAttributes {
return getUnavailable(ctx) != nullptr;
}

/// Determine whether there is an "unavailable in current Swift"
/// attribute.
bool isUnavailableInCurrentSwift() const;
/// Determine whether there is a swiftVersionSpecific attribute that's
/// unavailable relative to the provided language version (defaulting to
/// current language version).
bool isUnavailableInSwiftVersion(const version::Version &effectiveVersion =
version::Version::getCurrentLanguageVersion()) const;

/// Returns the first @available attribute that indicates
/// a declaration is unavailable, or null otherwise.
Expand Down
68 changes: 54 additions & 14 deletions include/swift/AST/AvailabilitySpec.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,15 @@ class ASTContext;
enum class VersionComparison { GreaterThanEqual };

enum class AvailabilitySpecKind {
/// A version constraint of the form PlatformName X.Y.Z
VersionConstraint,
/// A platform-version constraint of the form "PlatformName X.Y.Z"
PlatformVersionConstraint,

/// A wildcard constraint, spelled '*', that is be equivalent
/// to CurrentPlatformName >= MinimumDeploymentTargetVersion
OtherPlatform
OtherPlatform,

/// A language-version constraint of the form "swift X.Y.Z"
LanguageVersionConstraint,
};

/// The root class for specifications of API availability in availability
Expand All @@ -57,22 +60,22 @@ class AvailabilitySpec {

/// \brief An availability specification that guards execution based on the
/// run-time platform and version, e.g., OS X >= 10.10.
class VersionConstraintAvailabilitySpec : public AvailabilitySpec {
class PlatformVersionConstraintAvailabilitySpec : public AvailabilitySpec {
PlatformKind Platform;
SourceLoc PlatformLoc;

clang::VersionTuple Version;
SourceRange VersionSrcRange;

public:
VersionConstraintAvailabilitySpec(PlatformKind Platform,
SourceLoc PlatformLoc,
clang::VersionTuple Version,
SourceRange VersionSrcRange)
: AvailabilitySpec(AvailabilitySpecKind::VersionConstraint),
Platform(Platform),
PlatformLoc(PlatformLoc), Version(Version),
VersionSrcRange(VersionSrcRange) {}
PlatformVersionConstraintAvailabilitySpec(PlatformKind Platform,
SourceLoc PlatformLoc,
clang::VersionTuple Version,
SourceRange VersionSrcRange)
: AvailabilitySpec(AvailabilitySpecKind::PlatformVersionConstraint),
Platform(Platform),
PlatformLoc(PlatformLoc), Version(Version),
VersionSrcRange(VersionSrcRange) {}

/// The required platform.
PlatformKind getPlatform() const { return Platform; }
Expand All @@ -87,12 +90,49 @@ class VersionConstraintAvailabilitySpec : public AvailabilitySpec {
void print(raw_ostream &OS, unsigned Indent) const;

static bool classof(const AvailabilitySpec *Spec) {
return Spec->getKind() == AvailabilitySpecKind::VersionConstraint;
return Spec->getKind() == AvailabilitySpecKind::PlatformVersionConstraint;
}

void *
operator new(size_t Bytes, ASTContext &C,
unsigned Alignment = alignof(PlatformVersionConstraintAvailabilitySpec)){
return AvailabilitySpec::operator new(Bytes, C, Alignment);
}
};

/// \brief An availability specification that guards execution based on the
/// compile-time language version, e.g., swift >= 3.0.1.
class LanguageVersionConstraintAvailabilitySpec : public AvailabilitySpec {
SourceLoc SwiftLoc;

clang::VersionTuple Version;
SourceRange VersionSrcRange;

public:
LanguageVersionConstraintAvailabilitySpec(SourceLoc SwiftLoc,
clang::VersionTuple Version,
SourceRange VersionSrcRange)
: AvailabilitySpec(AvailabilitySpecKind::LanguageVersionConstraint),
SwiftLoc(SwiftLoc), Version(Version),
VersionSrcRange(VersionSrcRange) {}

SourceLoc getSwiftLoc() const { return SwiftLoc; }

// The platform version to compare against.
clang::VersionTuple getVersion() const { return Version; }
SourceRange getVersionSrcRange() const { return VersionSrcRange; }

SourceRange getSourceRange() const;

void print(raw_ostream &OS, unsigned Indent) const;

static bool classof(const AvailabilitySpec *Spec) {
return Spec->getKind() == AvailabilitySpecKind::LanguageVersionConstraint;
}

void *
operator new(size_t Bytes, ASTContext &C,
unsigned Alignment = alignof(VersionConstraintAvailabilitySpec)){
unsigned Alignment = alignof(LanguageVersionConstraintAvailabilitySpec)){
return AvailabilitySpec::operator new(Bytes, C, Alignment);
}
};
Expand Down
6 changes: 6 additions & 0 deletions include/swift/AST/DiagnosticsParse.def
Original file line number Diff line number Diff line change
Expand Up @@ -1380,6 +1380,12 @@ ERROR(avail_query_version_comparison_not_needed,
ERROR(availability_query_wildcard_required, none,
"must handle potential future platforms with '*'", ())

ERROR(availability_swift_must_occur_alone, none,
"'swift' version-availability must be specified alone", ())

ERROR(pound_available_swift_not_allowed, none,
"Swift language version checks not allowed in #available(...)", ())
Copy link
Contributor

Choose a reason for hiding this comment

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

Please add tests for these diagnostics!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed


ERROR(availability_query_repeated_platform, none,
"version for '%0' already specified", (StringRef))

Expand Down
4 changes: 4 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -3108,6 +3108,10 @@ ERROR(availability_decl_unavailable_in_swift_msg, none,
NOTE(availability_marked_unavailable, none,
"%0 has been explicitly marked unavailable here", (DeclName))

NOTE(availability_introduced_in_swift, none,
"%0 was introduced in Swift %1",
(DeclName, clang::VersionTuple))

NOTE(availability_obsoleted, none,
"%0 was obsoleted in %1 %2",
(DeclName, StringRef, clang::VersionTuple))
Expand Down
5 changes: 5 additions & 0 deletions include/swift/Basic/Version.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "clang/Basic/VersionTuple.h"
#include <string>

namespace swift {
Expand Down Expand Up @@ -89,6 +90,10 @@ class Version {
return Components.empty();
}

/// Convert to a (maximum-4-element) clang::VersionTuple, truncating
/// away any 5th component that might be in this version.
operator clang::VersionTuple() const;

/// Return whether this version is a valid Swift language version number
/// to set the compiler to using -swift-version; this is not the same as
/// the set of Swift versions that have ever existed, just those that we
Expand Down
5 changes: 4 additions & 1 deletion include/swift/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -1245,7 +1245,10 @@ class Parser {
parseAvailabilitySpecList(SmallVectorImpl<AvailabilitySpec *> &Specs);

ParserResult<AvailabilitySpec> parseAvailabilitySpec();
ParserResult<VersionConstraintAvailabilitySpec> parseVersionConstraintSpec();
ParserResult<PlatformVersionConstraintAvailabilitySpec>
parsePlatformVersionConstraintSpec();
ParserResult<LanguageVersionConstraintAvailabilitySpec>
parseLanguageVersionConstraintSpec();
};

/// Describes a parsed declaration name.
Expand Down
7 changes: 5 additions & 2 deletions lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1215,8 +1215,11 @@ class PrintStmt : public StmtVisitor<PrintStmt> {
for (auto *Query : C.getAvailability()->getQueries()) {
OS << '\n';
switch (Query->getKind()) {
case AvailabilitySpecKind::VersionConstraint:
cast<VersionConstraintAvailabilitySpec>(Query)->print(OS, Indent + 2);
case AvailabilitySpecKind::PlatformVersionConstraint:
cast<PlatformVersionConstraintAvailabilitySpec>(Query)->print(OS, Indent + 2);
break;
case AvailabilitySpecKind::LanguageVersionConstraint:
cast<LanguageVersionConstraintAvailabilitySpec>(Query)->print(OS, Indent + 2);
break;
case AvailabilitySpecKind::OtherPlatform:
cast<OtherPlatformAvailabilitySpec>(Query)->print(OS, Indent + 2);
Expand Down
4 changes: 2 additions & 2 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1448,8 +1448,8 @@ bool swift::shouldPrint(const Decl *D, PrintOptions &Options) {
D->getAttrs().isUnavailable(D->getASTContext()))
return false;

// Skip stub declarations used for prior variants of Swift.
if (D->getAttrs().isUnavailableInCurrentSwift())
// Skip stub declarations used for prior or later variants of Swift.
if (D->getAttrs().isUnavailableInSwiftVersion())
return false;

if (Options.ExplodeEnumCaseDecls) {
Expand Down
Loading