@@ -315,6 +315,19 @@ ExportContext::getExportabilityReason() const {
315315 return std::nullopt ;
316316}
317317
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+
318331// / Returns the first availability attribute on the declaration that is active
319332// / on the target platform.
320333static const AvailableAttr *getActiveAvailableAttribute (const Decl *D,
@@ -345,8 +358,9 @@ static bool computeContainedByDeploymentTarget(TypeRefinementContext *TRC,
345358// / Returns true if the reference or any of its parents is an
346359// / unconditional unavailable declaration for the same platform.
347360static 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 ();
350364 if (!referencedPlatform)
351365 return false ;
352366
@@ -374,7 +388,7 @@ ExportContext::shouldDiagnoseDeclAsUnavailable(const Decl *D) const {
374388 if (!attr)
375389 return nullptr ;
376390
377- if (isInsideCompatibleUnavailableDeclaration (D, * this , attr))
391+ if (isInsideCompatibleUnavailableDeclaration (D, Availability , attr))
378392 return nullptr ;
379393
380394 return attr;
@@ -1496,7 +1510,8 @@ TypeChecker::checkDeclarationAvailability(const Decl *D,
14961510 // Skip computing potential unavailability if the declaration is explicitly
14971511 // unavailable and the context is also unavailable.
14981512 if (const AvailableAttr *Attr = AvailableAttr::isUnavailable (D))
1499- if (isInsideCompatibleUnavailableDeclaration (D, Where, Attr))
1513+ if (isInsideCompatibleUnavailableDeclaration (D, Where.getAvailability (),
1514+ Attr))
15001515 return std::nullopt ;
15011516
15021517 if (isDeclarationUnavailable (D, Where.getDeclContext (), [&Where] {
@@ -3063,6 +3078,51 @@ bool diagnoseExplicitUnavailability(
30633078 return true ;
30643079}
30653080
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+
30663126// / Check if this is a subscript declaration inside String or
30673127// / Substring that returns String, and if so return true.
30683128bool isSubscriptReturningString (const ValueDecl *D, ASTContext &Context) {
@@ -4055,8 +4115,20 @@ bool swift::diagnoseDeclAvailability(const ValueDecl *D, SourceRange R,
40554115 return false ;
40564116 }
40574117
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+ }
40604132
40614133 if (diagnoseDeclAsyncAvailability (D, R, call, Where))
40624134 return true ;
@@ -4077,25 +4149,21 @@ bool swift::diagnoseDeclAvailability(const ValueDecl *D, SourceRange R,
40774149 return false ;
40784150
40794151 // Diagnose (and possibly signal) for potential unavailability
4080- auto maybeUnavail = TypeChecker::checkDeclarationAvailability (D, Where);
4081- if (!maybeUnavail.has_value ())
4152+ if (!requiredRange)
40824153 return false ;
40834154
4084- auto requiredAvailability = maybeUnavail.value ();
4085- auto *DC = Where.getDeclContext ();
4086- auto &ctx = DC->getASTContext ();
40874155 if (Flags.contains (
40884156 DeclAvailabilityFlag::
40894157 AllowPotentiallyUnavailableAtOrBelowDeploymentTarget) &&
4090- requiresDeploymentTargetOrEarlier (requiredAvailability , ctx))
4158+ requiresDeploymentTargetOrEarlier (*requiredRange , ctx))
40914159 return false ;
40924160
40934161 if (accessor) {
40944162 bool forInout = Flags.contains (DeclAvailabilityFlag::ForInout);
4095- diagnosePotentialAccessorUnavailability (accessor, R, DC,
4096- requiredAvailability, forInout);
4163+ diagnosePotentialAccessorUnavailability (accessor, R, DC, *requiredRange,
4164+ forInout);
40974165 } else {
4098- if (!diagnosePotentialUnavailability (D, R, DC, requiredAvailability ))
4166+ if (!diagnosePotentialUnavailability (D, R, DC, *requiredRange ))
40994167 return false ;
41004168 }
41014169
0 commit comments