@@ -315,6 +315,19 @@ ExportContext::getExportabilityReason() const {
315
315
return std::nullopt;
316
316
}
317
317
318
+ std::optional<AvailabilityRange>
319
+ UnmetAvailabilityRequirement::getRequiredNewerAvailabilityRange (
320
+ ASTContext &ctx) const {
321
+ switch (kind) {
322
+ case Kind::AlwaysUnavailable:
323
+ case Kind::RequiresVersion:
324
+ case Kind::Obsoleted:
325
+ return std::nullopt;
326
+ case Kind::IntroducedInNewerVersion:
327
+ return AvailabilityInference::availableRange (attr, ctx);
328
+ }
329
+ }
330
+
318
331
// / Returns the first availability attribute on the declaration that is active
319
332
// / on the target platform.
320
333
static const AvailableAttr *getActiveAvailableAttribute (const Decl *D,
@@ -345,8 +358,9 @@ static bool computeContainedByDeploymentTarget(TypeRefinementContext *TRC,
345
358
// / Returns true if the reference or any of its parents is an
346
359
// / unconditional unavailable declaration for the same platform.
347
360
static bool isInsideCompatibleUnavailableDeclaration (
348
- const Decl *D, const ExportContext &where, const AvailableAttr *attr) {
349
- auto referencedPlatform = where.getUnavailablePlatformKind ();
361
+ const Decl *D, AvailabilityContext availabilityContext,
362
+ const AvailableAttr *attr) {
363
+ auto referencedPlatform = availabilityContext.getUnavailablePlatformKind ();
350
364
if (!referencedPlatform)
351
365
return false ;
352
366
@@ -374,7 +388,7 @@ ExportContext::shouldDiagnoseDeclAsUnavailable(const Decl *D) const {
374
388
if (!attr)
375
389
return nullptr ;
376
390
377
- if (isInsideCompatibleUnavailableDeclaration (D, * this , attr))
391
+ if (isInsideCompatibleUnavailableDeclaration (D, Availability , attr))
378
392
return nullptr ;
379
393
380
394
return attr;
@@ -1496,7 +1510,8 @@ TypeChecker::checkDeclarationAvailability(const Decl *D,
1496
1510
// Skip computing potential unavailability if the declaration is explicitly
1497
1511
// unavailable and the context is also unavailable.
1498
1512
if (const AvailableAttr *Attr = AvailableAttr::isUnavailable (D))
1499
- if (isInsideCompatibleUnavailableDeclaration (D, Where, Attr))
1513
+ if (isInsideCompatibleUnavailableDeclaration (D, Where.getAvailability (),
1514
+ Attr))
1500
1515
return std::nullopt;
1501
1516
1502
1517
if (isDeclarationUnavailable (D, Where.getDeclContext (), [&Where] {
@@ -3063,6 +3078,51 @@ bool diagnoseExplicitUnavailability(
3063
3078
return true ;
3064
3079
}
3065
3080
3081
+ std::optional<UnmetAvailabilityRequirement>
3082
+ swift::checkDeclarationAvailability (const Decl *decl,
3083
+ const DeclContext *declContext,
3084
+ AvailabilityContext availabilityContext) {
3085
+ auto &ctx = declContext->getASTContext ();
3086
+ if (ctx.LangOpts .DisableAvailabilityChecking )
3087
+ return std::nullopt;
3088
+
3089
+ // Generic parameters are always available.
3090
+ if (isa<GenericTypeParamDecl>(decl))
3091
+ return std::nullopt;
3092
+
3093
+ if (auto attr = AvailableAttr::isUnavailable (decl)) {
3094
+ if (isInsideCompatibleUnavailableDeclaration (decl, availabilityContext,
3095
+ attr))
3096
+ return std::nullopt;
3097
+
3098
+ switch (attr->getVersionAvailability (ctx)) {
3099
+ case AvailableVersionComparison::Available:
3100
+ case AvailableVersionComparison::PotentiallyUnavailable:
3101
+ llvm_unreachable (" Decl should be unavailable" );
3102
+
3103
+ case AvailableVersionComparison::Unavailable:
3104
+ if ((attr->isLanguageVersionSpecific () ||
3105
+ attr->isPackageDescriptionVersionSpecific ()) &&
3106
+ attr->Introduced .has_value ())
3107
+ return UnmetAvailabilityRequirement::forRequiresVersion (attr);
3108
+
3109
+ return UnmetAvailabilityRequirement::forAlwaysUnavailable (attr);
3110
+
3111
+ case AvailableVersionComparison::Obsoleted:
3112
+ return UnmetAvailabilityRequirement::forObsoleted (attr);
3113
+ }
3114
+ }
3115
+
3116
+ // Check whether the declaration is available in a newer platform version.
3117
+ auto rangeAndAttr = AvailabilityInference::availableRangeAndAttr (decl);
3118
+ if (!availabilityContext.getPlatformRange ().isContainedIn (rangeAndAttr.first ))
3119
+ return UnmetAvailabilityRequirement::forIntroducedInNewerVersion (
3120
+ rangeAndAttr.second );
3121
+
3122
+ return std::nullopt;
3123
+ }
3124
+
3125
+
3066
3126
// / Check if this is a subscript declaration inside String or
3067
3127
// / Substring that returns String, and if so return true.
3068
3128
bool isSubscriptReturningString (const ValueDecl *D, ASTContext &Context) {
@@ -4055,8 +4115,20 @@ bool swift::diagnoseDeclAvailability(const ValueDecl *D, SourceRange R,
4055
4115
return false ;
4056
4116
}
4057
4117
4058
- if (diagnoseExplicitUnavailability (D, R, Where, call, Flags))
4059
- return true ;
4118
+ auto *DC = Where.getDeclContext ();
4119
+ auto &ctx = DC->getASTContext ();
4120
+ auto unmetRequirement =
4121
+ checkDeclarationAvailability (D, DC, Where.getAvailability ());
4122
+ auto requiredRange =
4123
+ unmetRequirement
4124
+ ? unmetRequirement->getRequiredNewerAvailabilityRange (ctx)
4125
+ : std::nullopt;
4126
+
4127
+ if (unmetRequirement && !requiredRange) {
4128
+ // FIXME: diagnoseExplicitUnavailability should take an unmet requirement
4129
+ if (diagnoseExplicitUnavailability (D, R, Where, call, Flags))
4130
+ return true ;
4131
+ }
4060
4132
4061
4133
if (diagnoseDeclAsyncAvailability (D, R, call, Where))
4062
4134
return true ;
@@ -4077,25 +4149,21 @@ bool swift::diagnoseDeclAvailability(const ValueDecl *D, SourceRange R,
4077
4149
return false ;
4078
4150
4079
4151
// Diagnose (and possibly signal) for potential unavailability
4080
- auto maybeUnavail = TypeChecker::checkDeclarationAvailability (D, Where);
4081
- if (!maybeUnavail.has_value ())
4152
+ if (!requiredRange)
4082
4153
return false ;
4083
4154
4084
- auto requiredAvailability = maybeUnavail.value ();
4085
- auto *DC = Where.getDeclContext ();
4086
- auto &ctx = DC->getASTContext ();
4087
4155
if (Flags.contains (
4088
4156
DeclAvailabilityFlag::
4089
4157
AllowPotentiallyUnavailableAtOrBelowDeploymentTarget) &&
4090
- requiresDeploymentTargetOrEarlier (requiredAvailability , ctx))
4158
+ requiresDeploymentTargetOrEarlier (*requiredRange , ctx))
4091
4159
return false ;
4092
4160
4093
4161
if (accessor) {
4094
4162
bool forInout = Flags.contains (DeclAvailabilityFlag::ForInout);
4095
- diagnosePotentialAccessorUnavailability (accessor, R, DC,
4096
- requiredAvailability, forInout);
4163
+ diagnosePotentialAccessorUnavailability (accessor, R, DC, *requiredRange,
4164
+ forInout);
4097
4165
} else {
4098
- if (!diagnosePotentialUnavailability (D, R, DC, requiredAvailability ))
4166
+ if (!diagnosePotentialUnavailability (D, R, DC, *requiredRange ))
4099
4167
return false ;
4100
4168
}
4101
4169
0 commit comments