Skip to content

Commit 0f1e301

Browse files
authored
Merge pull request #78775 from tshortli/replace-unavailability-diagnostic-info
Sema: Replace UnavailabilityDiagnosticInfo with AvailabilityConstraint
2 parents 59e07f1 + 31fa5fc commit 0f1e301

File tree

3 files changed

+91
-139
lines changed

3 files changed

+91
-139
lines changed

include/swift/AST/AvailabilityConstraint.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#ifndef SWIFT_AST_AVAILABILITY_CONSTRAINT_H
1818
#define SWIFT_AST_AVAILABILITY_CONSTRAINT_H
1919

20+
#include "swift/AST/AvailabilityDomain.h"
2021
#include "swift/AST/AvailabilityRange.h"
2122
#include "swift/AST/PlatformKind.h"
2223
#include "swift/Basic/LLVM.h"
@@ -88,6 +89,9 @@ class AvailabilityConstraint {
8889
return static_cast<SemanticAvailableAttr>(attrAndKind.getPointer());
8990
}
9091

92+
/// Returns the domain that the constraint applies to.
93+
AvailabilityDomain getDomain() const { return getAttr().getDomain(); }
94+
9195
/// Returns the platform that this constraint applies to, or
9296
/// `PlatformKind::none` if it is not platform specific.
9397
PlatformKind getPlatform() const;

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 86 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -55,17 +55,19 @@ concreteSyntaxDeclForAvailableAttribute(const Decl *AbstractSyntaxDecl);
5555
/// Emit a diagnostic for references to declarations that have been
5656
/// marked as unavailable, either through "unavailable" or "obsoleted:".
5757
static bool diagnoseExplicitUnavailability(
58-
SourceLoc loc, const RootProtocolConformance *rootConf,
59-
const ExtensionDecl *ext, const ExportContext &where,
58+
SourceLoc loc, const AvailabilityConstraint &constraint,
59+
const RootProtocolConformance *rootConf, const ExtensionDecl *ext,
60+
const ExportContext &where,
6061
bool warnIfConformanceUnavailablePreSwift6 = false,
6162
bool preconcurrency = false);
6263

6364
/// Emit a diagnostic for references to declarations that have been
6465
/// marked as unavailable, either through "unavailable" or "obsoleted:".
6566
static bool diagnoseExplicitUnavailability(
66-
const ValueDecl *D, SourceRange R, const ExportContext &Where,
67-
DeclAvailabilityFlags Flags,
68-
llvm::function_ref<void(InFlightDiagnostic &)> attachRenameFixIts);
67+
const ValueDecl *D, SourceRange R, const AvailabilityConstraint &constraint,
68+
const ExportContext &Where, DeclAvailabilityFlags Flags,
69+
llvm::function_ref<void(InFlightDiagnostic &, StringRef)>
70+
attachRenameFixIts);
6971

7072
static bool diagnoseSubstitutionMapAvailability(
7173
SourceLoc loc, SubstitutionMap subs, const ExportContext &where,
@@ -2950,11 +2952,19 @@ void swift::diagnoseOverrideOfUnavailableDecl(ValueDecl *override,
29502952
return;
29512953
}
29522954

2955+
// FIXME: [availability] Take an unsatisfied constraint as input instead of
2956+
// recomputing it.
29532957
ExportContext where = ExportContext::forDeclSignature(override, nullptr);
2958+
auto constraint =
2959+
getUnsatisfiedAvailabilityConstraint(base, where.getAvailability());
2960+
if (!constraint)
2961+
return;
2962+
29542963
diagnoseExplicitUnavailability(
2955-
base, override->getLoc(), where,
2956-
/*Flags*/ std::nullopt, [&](InFlightDiagnostic &diag) {
2957-
ParsedDeclName parsedName = parseDeclName(attr.getRename());
2964+
base, override->getLoc(), *constraint, where,
2965+
/*Flags*/ std::nullopt,
2966+
[&override, &ctx](InFlightDiagnostic &diag, StringRef rename) {
2967+
ParsedDeclName parsedName = parseDeclName(rename);
29582968
if (!parsedName || parsedName.isPropertyAccessor() ||
29592969
parsedName.isMember() || parsedName.isOperator()) {
29602970
return;
@@ -2981,127 +2991,63 @@ void swift::diagnoseOverrideOfUnavailableDecl(ValueDecl *override,
29812991

29822992
/// Emit a diagnostic for references to declarations that have been
29832993
/// marked as unavailable, either through "unavailable" or "obsoleted:".
2984-
static bool diagnoseExplicitUnavailability(const ValueDecl *D, SourceRange R,
2985-
const ExportContext &Where,
2986-
const Expr *call,
2987-
DeclAvailabilityFlags Flags) {
2994+
static bool diagnoseExplicitUnavailability(
2995+
const ValueDecl *D, SourceRange R, const AvailabilityConstraint &constraint,
2996+
const ExportContext &Where, const Expr *call, DeclAvailabilityFlags Flags) {
29882997
return diagnoseExplicitUnavailability(
2989-
D, R, Where, Flags, [=](InFlightDiagnostic &diag) {
2990-
auto attr = D->getUnavailableAttr();
2991-
assert(attr);
2992-
fixItAvailableAttrRename(diag, R, D, attr->getRename(), call);
2998+
D, R, constraint, Where, Flags,
2999+
[=](InFlightDiagnostic &diag, StringRef rename) {
3000+
fixItAvailableAttrRename(diag, R, D, rename, call);
29933001
});
29943002
}
29953003

2996-
/// Represents common information needed to emit diagnostics about explicitly
2997-
/// unavailable declarations.
2998-
class UnavailabilityDiagnosticInfo {
2999-
public:
3000-
enum class Status {
3001-
/// The declaration is marked `unavailable`, potentially on a specific
3002-
/// platform.
3003-
AlwaysUnavailable,
3004-
3005-
/// The declaration is not available until, for example, a later Swift
3006-
/// language mode.
3007-
IntroducedInVersion,
3008-
3009-
/// The declaration was obsoleted in a previous version.
3010-
Obsoleted,
3011-
};
3012-
3013-
private:
3014-
Status DiagnosticStatus;
3015-
SemanticAvailableAttr Attr;
3016-
3017-
public:
3018-
UnavailabilityDiagnosticInfo(Status status, const SemanticAvailableAttr &attr)
3019-
: DiagnosticStatus(status), Attr(attr) {};
3020-
3021-
Status getStatus() const { return DiagnosticStatus; }
3022-
SemanticAvailableAttr getAttr() const { return Attr; }
3023-
AvailabilityDomain getDomain() const { return Attr.getDomain(); }
3024-
StringRef getDomainName() const {
3025-
return getDomain().getNameForDiagnostics();
3026-
}
3004+
bool shouldHideDomainNameForConstraintDiagnostic(
3005+
const AvailabilityConstraint &constraint) {
3006+
switch (constraint.getDomain().getKind()) {
3007+
case AvailabilityDomain::Kind::Universal:
3008+
case AvailabilityDomain::Kind::Embedded:
3009+
return true;
3010+
case AvailabilityDomain::Kind::Platform:
3011+
return false;
30273012

3028-
bool shouldHideDomainNameInUnversionedDiagnostics() const {
3029-
switch (getDomain().getKind()) {
3030-
case AvailabilityDomain::Kind::Universal:
3031-
case AvailabilityDomain::Kind::Embedded:
3032-
return true;
3033-
case AvailabilityDomain::Kind::Platform:
3013+
case AvailabilityDomain::Kind::PackageDescription:
3014+
case AvailabilityDomain::Kind::SwiftLanguage:
3015+
switch (constraint.getKind()) {
3016+
case AvailabilityConstraint::Kind::AlwaysUnavailable:
3017+
case AvailabilityConstraint::Kind::IntroducedInNewerVersion:
30343018
return false;
3035-
3036-
case AvailabilityDomain::Kind::PackageDescription:
3037-
case AvailabilityDomain::Kind::SwiftLanguage:
3038-
switch (DiagnosticStatus) {
3039-
case Status::AlwaysUnavailable:
3040-
return false;
3041-
case Status::IntroducedInVersion:
3042-
case Status::Obsoleted:
3043-
return true;
3044-
}
3045-
}
3046-
}
3047-
};
3048-
3049-
static std::optional<UnavailabilityDiagnosticInfo>
3050-
getExplicitUnavailabilityDiagnosticInfo(const Decl *decl,
3051-
const ExportContext &where) {
3052-
auto attr = where.shouldDiagnoseDeclAsUnavailable(decl);
3053-
if (!attr)
3054-
return std::nullopt;
3055-
3056-
ASTContext &ctx = decl->getASTContext();
3057-
3058-
switch (attr->getVersionAvailability(ctx)) {
3059-
case AvailableVersionComparison::Available:
3060-
case AvailableVersionComparison::PotentiallyUnavailable:
3061-
llvm_unreachable("These aren't considered unavailable");
3062-
3063-
case AvailableVersionComparison::Unavailable:
3064-
if ((attr->isSwiftLanguageModeSpecific() ||
3065-
attr->isPackageDescriptionVersionSpecific()) &&
3066-
attr->getIntroduced()) {
3067-
return UnavailabilityDiagnosticInfo(
3068-
UnavailabilityDiagnosticInfo::Status::IntroducedInVersion, *attr);
3069-
} else {
3070-
return UnavailabilityDiagnosticInfo(
3071-
UnavailabilityDiagnosticInfo::Status::AlwaysUnavailable, *attr);
3019+
case AvailabilityConstraint::Kind::RequiresVersion:
3020+
case AvailabilityConstraint::Kind::Obsoleted:
3021+
return true;
30723022
}
3073-
break;
3074-
3075-
case AvailableVersionComparison::Obsoleted:
3076-
return UnavailabilityDiagnosticInfo(
3077-
UnavailabilityDiagnosticInfo::Status::Obsoleted, *attr);
30783023
}
30793024
}
30803025

3081-
bool diagnoseExplicitUnavailability(
3082-
SourceLoc loc, const RootProtocolConformance *rootConf,
3083-
const ExtensionDecl *ext, const ExportContext &where,
3084-
bool warnIfConformanceUnavailablePreSwift6,
3085-
bool preconcurrency) {
3086-
// Invertible protocols are never unavailable.
3087-
if (rootConf->getProtocol()->getInvertibleProtocolKind())
3026+
bool diagnoseExplicitUnavailability(SourceLoc loc,
3027+
const AvailabilityConstraint &constraint,
3028+
const RootProtocolConformance *rootConf,
3029+
const ExtensionDecl *ext,
3030+
const ExportContext &where,
3031+
bool warnIfConformanceUnavailablePreSwift6,
3032+
bool preconcurrency) {
3033+
if (constraint.isConditionallySatisfiable())
30883034
return false;
30893035

3090-
auto diagnosticInfo = getExplicitUnavailabilityDiagnosticInfo(ext, where);
3091-
if (!diagnosticInfo)
3036+
// Invertible protocols are never unavailable.
3037+
if (rootConf->getProtocol()->getInvertibleProtocolKind())
30923038
return false;
30933039

30943040
ASTContext &ctx = ext->getASTContext();
30953041
auto &diags = ctx.Diags;
30963042

30973043
auto type = rootConf->getType();
30983044
auto proto = rootConf->getProtocol()->getDeclaredInterfaceType();
3099-
StringRef versionedPlatform = diagnosticInfo->getDomainName();
3100-
StringRef platform =
3101-
diagnosticInfo->shouldHideDomainNameInUnversionedDiagnostics()
3102-
? ""
3103-
: versionedPlatform;
3104-
auto attr = diagnosticInfo->getAttr();
3045+
auto domain = constraint.getDomain();
3046+
StringRef versionedPlatform = domain.getNameForDiagnostics();
3047+
StringRef platform = shouldHideDomainNameForConstraintDiagnostic(constraint)
3048+
? ""
3049+
: versionedPlatform;
3050+
auto attr = constraint.getAttr();
31053051

31063052
// Downgrade unavailable Sendable conformance diagnostics where
31073053
// appropriate.
@@ -3115,23 +3061,25 @@ bool diagnoseExplicitUnavailability(
31153061
.limitBehaviorWithPreconcurrency(behavior, preconcurrency)
31163062
.warnUntilSwiftVersionIf(warnIfConformanceUnavailablePreSwift6, 6);
31173063

3118-
switch (diagnosticInfo->getStatus()) {
3119-
case UnavailabilityDiagnosticInfo::Status::AlwaysUnavailable:
3064+
switch (constraint.getKind()) {
3065+
case AvailabilityConstraint::Kind::AlwaysUnavailable:
31203066
diags
31213067
.diagnose(ext, diag::conformance_availability_marked_unavailable, type,
31223068
proto)
31233069
.highlight(attr.getParsedAttr()->getRange());
31243070
break;
3125-
case UnavailabilityDiagnosticInfo::Status::IntroducedInVersion:
3071+
case AvailabilityConstraint::Kind::RequiresVersion:
31263072
diags.diagnose(ext, diag::conformance_availability_introduced_in_version,
31273073
type, proto, versionedPlatform, *attr.getIntroduced());
31283074
break;
3129-
case UnavailabilityDiagnosticInfo::Status::Obsoleted:
3075+
case AvailabilityConstraint::Kind::Obsoleted:
31303076
diags
31313077
.diagnose(ext, diag::conformance_availability_obsoleted, type, proto,
31323078
versionedPlatform, *attr.getObsoleted())
31333079
.highlight(attr.getParsedAttr()->getRange());
31343080
break;
3081+
case AvailabilityConstraint::Kind::IntroducedInNewerVersion:
3082+
llvm_unreachable("unexpected constraint");
31353083
}
31363084
return true;
31373085
}
@@ -3510,14 +3458,14 @@ static void checkFunctionConversionAvailability(Type srcType, Type destType,
35103458
}
35113459

35123460
bool diagnoseExplicitUnavailability(
3513-
const ValueDecl *D, SourceRange R, const ExportContext &Where,
3514-
DeclAvailabilityFlags Flags,
3515-
llvm::function_ref<void(InFlightDiagnostic &)> attachRenameFixIts) {
3516-
auto diagnosticInfo = getExplicitUnavailabilityDiagnosticInfo(D, Where);
3517-
if (!diagnosticInfo)
3461+
const ValueDecl *D, SourceRange R, const AvailabilityConstraint &constraint,
3462+
const ExportContext &Where, DeclAvailabilityFlags Flags,
3463+
llvm::function_ref<void(InFlightDiagnostic &, StringRef)>
3464+
attachRenameFixIts) {
3465+
if (constraint.isConditionallySatisfiable())
35183466
return false;
35193467

3520-
auto Attr = diagnosticInfo->getAttr();
3468+
auto Attr = constraint.getAttr();
35213469
if (Attr.getDomain().isSwiftLanguage() && !Attr.isVersionSpecific()) {
35223470
if (shouldAllowReferenceToUnavailableInSwiftDeclaration(D, Where))
35233471
return false;
@@ -3526,11 +3474,11 @@ bool diagnoseExplicitUnavailability(
35263474
SourceLoc Loc = R.Start;
35273475
ASTContext &ctx = D->getASTContext();
35283476
auto &diags = ctx.Diags;
3529-
StringRef versionedPlatform = diagnosticInfo->getDomainName();
3530-
StringRef platform =
3531-
diagnosticInfo->shouldHideDomainNameInUnversionedDiagnostics()
3532-
? ""
3533-
: versionedPlatform;
3477+
auto domain = constraint.getDomain();
3478+
StringRef versionedPlatform = domain.getNameForDiagnostics();
3479+
StringRef platform = shouldHideDomainNameForConstraintDiagnostic(constraint)
3480+
? ""
3481+
: versionedPlatform;
35343482

35353483
// TODO: Consider removing this.
35363484
// ObjC keypaths components weren't checked previously, so errors are demoted
@@ -3556,7 +3504,7 @@ bool diagnoseExplicitUnavailability(
35563504
D, replaceKind.has_value(), rawReplaceKind,
35573505
newName, EncodedMessage.Message);
35583506
diag.limitBehavior(limit);
3559-
attachRenameFixIts(diag);
3507+
attachRenameFixIts(diag, rename);
35603508
} else if (isSubscriptReturningString(D, ctx)) {
35613509
diags.diagnose(Loc, diag::availability_string_subscript_migration)
35623510
.highlight(R)
@@ -3578,23 +3526,26 @@ bool diagnoseExplicitUnavailability(
35783526
}
35793527

35803528
auto sourceRange = Attr.getParsedAttr()->getRange();
3581-
switch (diagnosticInfo->getStatus()) {
3582-
case UnavailabilityDiagnosticInfo::Status::AlwaysUnavailable:
3529+
switch (constraint.getKind()) {
3530+
case AvailabilityConstraint::Kind::AlwaysUnavailable:
35833531
diags.diagnose(D, diag::availability_marked_unavailable, D)
35843532
.highlight(sourceRange);
35853533
break;
3586-
case UnavailabilityDiagnosticInfo::Status::IntroducedInVersion:
3534+
case AvailabilityConstraint::Kind::RequiresVersion:
35873535
diags
35883536
.diagnose(D, diag::availability_introduced_in_version, D,
35893537
versionedPlatform, *Attr.getIntroduced())
35903538
.highlight(sourceRange);
35913539
break;
3592-
case UnavailabilityDiagnosticInfo::Status::Obsoleted:
3540+
case AvailabilityConstraint::Kind::Obsoleted:
35933541
diags
35943542
.diagnose(D, diag::availability_obsoleted, D, versionedPlatform,
35953543
*Attr.getObsoleted())
35963544
.highlight(sourceRange);
35973545
break;
3546+
case AvailabilityConstraint::Kind::IntroducedInNewerVersion:
3547+
llvm_unreachable("unexpected constraint");
3548+
break;
35983549
}
35993550
return true;
36003551
}
@@ -4216,9 +4167,8 @@ bool swift::diagnoseDeclAvailability(const ValueDecl *D, SourceRange R,
42164167
auto constraint =
42174168
getUnsatisfiedAvailabilityConstraint(D, Where.getAvailability());
42184169

4219-
if (constraint && !constraint->isConditionallySatisfiable()) {
4220-
// FIXME: diagnoseExplicitUnavailability should take an unmet requirement
4221-
if (diagnoseExplicitUnavailability(D, R, Where, call, Flags))
4170+
if (constraint) {
4171+
if (diagnoseExplicitUnavailability(D, R, *constraint, Where, call, Flags))
42224172
return true;
42234173
}
42244174

@@ -4738,11 +4688,9 @@ swift::diagnoseConformanceAvailability(SourceLoc loc,
47384688
auto constraint =
47394689
getUnsatisfiedAvailabilityConstraint(ext, where.getAvailability());
47404690
if (constraint) {
4741-
// FIXME: diagnoseExplicitUnavailability() should take unmet requirement
4742-
if (diagnoseExplicitUnavailability(
4743-
loc, rootConf, ext, where,
4744-
warnIfConformanceUnavailablePreSwift6,
4745-
preconcurrency)) {
4691+
if (diagnoseExplicitUnavailability(loc, *constraint, rootConf, ext, where,
4692+
warnIfConformanceUnavailablePreSwift6,
4693+
preconcurrency)) {
47464694
maybeEmitAssociatedTypeNote();
47474695
return true;
47484696
}

lib/Sema/TypeCheckDeclOverride.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2223,7 +2223,7 @@ static bool checkSingleOverride(ValueDecl *override, ValueDecl *base) {
22232223
return true;
22242224
}
22252225

2226-
// FIXME: Possibly should extend to more availability checking.
2226+
// FIXME: [availability] Possibly should extend to more availability checking.
22272227
auto unavailabilityStatusAndAttr =
22282228
checkOverrideUnavailability(override, base);
22292229
auto unavailableAttr = unavailabilityStatusAndAttr.second;

0 commit comments

Comments
 (0)