Skip to content

Commit aa16ff5

Browse files
authored
Merge pull request #83354 from tshortli/check-custom-domain-availability-for-overrides
Sema: Check custom domain availability for overrides
2 parents 7abff71 + da7a215 commit aa16ff5

File tree

7 files changed

+316
-157
lines changed

7 files changed

+316
-157
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3519,13 +3519,17 @@ ERROR(multiple_override,none,
35193519
NOTE(multiple_override_prev,none,
35203520
"%0 previously overridden here", (DeclName))
35213521

3522-
ERROR(override_unavailable, none,
3523-
"cannot override %0 which has been marked unavailable%select{|: %1}1",
3524-
(DeclBaseName, StringRef))
3522+
ERROR(cannot_override_unavailable, none,
3523+
"cannot override %base0 which has been marked unavailable%select{|: %1}1",
3524+
(ValueDecl *, StringRef))
35253525
NOTE(suggest_removing_override, none,
35263526
"remove 'override' modifier to declare a new %0",
35273527
(DeclBaseName))
35283528

3529+
ERROR(override_unavailable, none,
3530+
"cannot override %base0 with a declaration that is marked unavailable",
3531+
(ValueDecl *))
3532+
35293533
ERROR(override_less_available,none,
35303534
"overriding %base0 must be as available as declaration it overrides",
35313535
(ValueDecl *))

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1630,8 +1630,8 @@ void swift::diagnoseOverrideOfUnavailableDecl(ValueDecl *override,
16301630
auto &diags = ctx.Diags;
16311631
if (attr.getRename().empty()) {
16321632
EncodedDiagnosticMessage EncodedMessage(attr.getMessage());
1633-
diags.diagnose(override, diag::override_unavailable,
1634-
override->getBaseName(), EncodedMessage.Message);
1633+
diags.diagnose(override, diag::cannot_override_unavailable,
1634+
override, EncodedMessage.Message);
16351635

16361636
diags.diagnose(base, diag::availability_marked_unavailable, base);
16371637
return;

lib/Sema/TypeCheckDeclOverride.cpp

Lines changed: 103 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
#include "TypeCheckUnsafe.h"
2323
#include "TypeChecker.h"
2424
#include "swift/AST/ASTVisitor.h"
25-
#include "swift/AST/AvailabilityInference.h"
25+
#include "swift/AST/AvailabilityConstraint.h"
2626
#include "swift/AST/AvailabilityRange.h"
2727
#include "swift/AST/Decl.h"
2828
#include "swift/AST/GenericEnvironment.h"
@@ -1810,159 +1810,97 @@ OverrideRequiresKeyword swift::overrideRequiresKeyword(ValueDecl *overridden) {
18101810
return OverrideRequiresKeyword::Always;
18111811
}
18121812

1813-
/// Returns true if the availability of the overriding declaration
1814-
/// makes it a safe override, given the availability of the base declaration.
1815-
static bool isAvailabilitySafeForOverride(ValueDecl *override,
1816-
ValueDecl *base) {
1817-
// API availability ranges are contravariant: make sure the version range
1818-
// of an overridden declaration is fully contained in the range of the
1819-
// overriding declaration.
1820-
AvailabilityRange overrideInfo =
1821-
AvailabilityInference::availableRange(override);
1822-
AvailabilityRange baseInfo = AvailabilityInference::availableRange(base);
1823-
1824-
if (baseInfo.isContainedIn(overrideInfo))
1825-
return true;
1813+
enum class OverrideAvailability {
1814+
/// The unavailability of the base decl and override decl are compatible.
1815+
Compatible,
1816+
/// The base decl is unavailable but the override decl is not.
1817+
BaseUnavailable,
1818+
/// The override decl is unavailable but the base decl is not.
1819+
OverrideUnavailable,
1820+
/// The override decl is less available than the base decl.
1821+
OverrideLessAvailable,
1822+
/// Do not diagnose the unavailability of these decls.
1823+
Ignored,
1824+
};
18261825

1827-
// Allow overrides that are not as available as the base decl as long as the
1828-
// override is as available as its context.
1829-
auto availabilityContext = AvailabilityContext::forDeclSignature(
1830-
override->getDeclContext()->getSelfNominalTypeDecl());
1826+
static std::pair<OverrideAvailability, std::optional<AvailabilityConstraint>>
1827+
getOverrideAvailability(ValueDecl *override, ValueDecl *base) {
1828+
auto &ctx = override->getASTContext();
18311829

1832-
return availabilityContext.getPlatformRange().isContainedIn(overrideInfo);
1833-
}
1830+
// Availability is contravariant so make sure the availability of of an
1831+
// overridden declaration is fully contained in the availability of the
1832+
// overriding declaration.
1833+
auto baseAvailability = AvailabilityContext::forDeclSignature(base);
18341834

1835-
/// Returns true if a diagnostic about an accessor being less available
1836-
/// than the accessor it overrides would be redundant because we will
1837-
/// already emit another diagnostic.
1838-
static bool
1839-
isRedundantAccessorOverrideAvailabilityDiagnostic(ValueDecl *override,
1840-
ValueDecl *base) {
1835+
// The override is allowed to be less available than the base decl as long as
1836+
// it is as available as its containing nominal decl.
1837+
auto nominalAvailability = AvailabilityContext::forDeclSignature(
1838+
override->getDeclContext()->getSelfNominalTypeDecl());
1839+
baseAvailability.constrainWithContext(nominalAvailability, ctx);
18411840

1842-
auto *overrideFn = dyn_cast<AccessorDecl>(override);
1843-
auto *baseFn = dyn_cast<AccessorDecl>(base);
1844-
if (!overrideFn || !baseFn)
1845-
return false;
1841+
// In order to maintain source compatibility, universally unavailable decls
1842+
// are allowed to override universally unavailable bases.
1843+
AvailabilityConstraintFlags flags;
1844+
flags |= AvailabilityConstraintFlag::
1845+
AllowUniversallyUnavailableInCompatibleContexts;
18461846

1847-
AbstractStorageDecl *overrideASD = overrideFn->getStorage();
1848-
AbstractStorageDecl *baseASD = baseFn->getStorage();
1849-
if (overrideASD->getOverriddenDecl() != baseASD)
1850-
return false;
1847+
if (auto constraint =
1848+
getAvailabilityConstraintsForDecl(override, baseAvailability, flags)
1849+
.getPrimaryConstraint()) {
1850+
if (constraint->isUnavailable())
1851+
return {OverrideAvailability::OverrideUnavailable, constraint};
18511852

1852-
// If we have already emitted a diagnostic about an unsafe override
1853-
// for the property, don't complain about the accessor.
1854-
if (!isAvailabilitySafeForOverride(overrideASD, baseASD)) {
1855-
return true;
1853+
return {OverrideAvailability::OverrideLessAvailable, constraint};
18561854
}
18571855

1858-
// Returns true if we will already diagnose a bad override
1859-
// on the property's accessor of the given kind.
1860-
auto accessorOverrideAlreadyDiagnosed = [&](AccessorKind kind) {
1861-
FuncDecl *overrideAccessor = overrideASD->getOpaqueAccessor(kind);
1862-
FuncDecl *baseAccessor = baseASD->getOpaqueAccessor(kind);
1863-
if (overrideAccessor && baseAccessor &&
1864-
!isAvailabilitySafeForOverride(overrideAccessor, baseAccessor)) {
1865-
return true;
1866-
}
1867-
return false;
1868-
};
1869-
1870-
// If we have already emitted a diagnostic about an unsafe override
1871-
// for a getter or a setter, no need to complain about the read or
1872-
// modify coroutines, which are synthesized to be as available as either
1873-
// the getter and the setter.
1874-
switch (overrideFn->getAccessorKind()) {
1875-
case AccessorKind::Get:
1876-
case AccessorKind::DistributedGet:
1877-
case AccessorKind::Set:
1878-
break;
1879-
1880-
case AccessorKind::Read:
1881-
case AccessorKind::Read2:
1882-
if (accessorOverrideAlreadyDiagnosed(AccessorKind::Get))
1883-
return true;
1884-
break;
1885-
1886-
case AccessorKind::Modify:
1887-
case AccessorKind::Modify2:
1888-
if (accessorOverrideAlreadyDiagnosed(AccessorKind::Get) ||
1889-
accessorOverrideAlreadyDiagnosed(AccessorKind::Set)) {
1890-
return true;
1891-
}
1892-
break;
1893-
1894-
#define OPAQUE_ACCESSOR(ID, KEYWORD)
1895-
#define ACCESSOR(ID, KEYWORD) case AccessorKind::ID:
1896-
#include "swift/AST/AccessorKinds.def"
1897-
llvm_unreachable("checking override for non-opaque accessor");
1856+
// Check whether the base is unavailable from the perspective of the override.
1857+
auto overrideAvailability = AvailabilityContext::forDeclSignature(override);
1858+
if (auto baseConstraint =
1859+
getAvailabilityConstraintsForDecl(base, overrideAvailability, flags)
1860+
.getPrimaryConstraint()) {
1861+
if (baseConstraint->isUnavailable())
1862+
return {OverrideAvailability::BaseUnavailable, baseConstraint};
18981863
}
18991864

1900-
return false;
1865+
return {OverrideAvailability::Compatible, std::nullopt};
19011866
}
19021867

1903-
/// Diagnose an override for potential availability. Returns true if
1904-
/// a diagnostic was emitted and false otherwise.
1905-
static bool diagnoseOverrideForAvailability(ValueDecl *override,
1906-
ValueDecl *base) {
1907-
if (isAvailabilitySafeForOverride(override, base))
1908-
return false;
1909-
1910-
// Suppress diagnostics about availability overrides for accessors
1911-
// if they would be redundant with other diagnostics.
1912-
if (isRedundantAccessorOverrideAvailabilityDiagnostic(override, base))
1913-
return false;
1914-
1915-
auto &diags = override->getASTContext().Diags;
1916-
diags.diagnose(override, diag::override_less_available, override);
1917-
diags.diagnose(base, diag::overridden_here);
1918-
1919-
return true;
1920-
}
1921-
1922-
enum class OverrideUnavailabilityStatus {
1923-
/// The unavailability of the base decl and override decl are compatible.
1924-
Compatible,
1925-
/// The base decl is unavailable but the override decl is not.
1926-
BaseUnavailable,
1927-
/// Do not diagnose the unavailability of these decls.
1928-
Ignored,
1929-
};
1930-
1931-
static std::pair<OverrideUnavailabilityStatus,
1932-
std::optional<SemanticAvailableAttr>>
1933-
checkOverrideUnavailability(ValueDecl *override, ValueDecl *base) {
1934-
if (auto *overrideParent = override->getDeclContext()->getAsDecl()) {
1935-
// If the parent of the override is unavailable, then the unavailability of
1936-
// the override decl is irrelevant.
1937-
if (AvailabilityContext::forDeclSignature(overrideParent).isUnavailable())
1938-
return {OverrideUnavailabilityStatus::Ignored, std::nullopt};
1868+
static std::pair<OverrideAvailability, std::optional<AvailabilityConstraint>>
1869+
checkOverrideAvailability(ValueDecl *override, ValueDecl *base) {
1870+
auto &ctx = override->getASTContext();
1871+
if (ctx.LangOpts.DisableAvailabilityChecking)
1872+
return {OverrideAvailability::Ignored, std::nullopt};
1873+
1874+
auto result = getOverrideAvailability(override, base);
1875+
switch (result.first) {
1876+
case OverrideAvailability::Ignored:
1877+
case OverrideAvailability::Compatible:
1878+
return result;
1879+
case OverrideAvailability::BaseUnavailable:
1880+
case OverrideAvailability::OverrideUnavailable:
1881+
case OverrideAvailability::OverrideLessAvailable:
1882+
break;
19391883
}
19401884

1941-
if (auto *baseAccessor = dyn_cast<AccessorDecl>(base)) {
1942-
// Ignore implicit accessors since the diagnostics are likely to duplicate
1943-
// the diagnostics for the explicit accessors that availability was inferred
1944-
// from.
1885+
auto *overrideAccessor = dyn_cast<AccessorDecl>(override);
1886+
auto *baseAccessor = dyn_cast<AccessorDecl>(base);
1887+
if (baseAccessor && overrideAccessor) {
1888+
// Skip implicit accessors since they're synthesized with availability that
1889+
// matches the accessors that they were derived from and therefore
1890+
// diagnostics for them will be redundant.
19451891
if (baseAccessor->isImplicit())
1946-
return {OverrideUnavailabilityStatus::Ignored, std::nullopt};
1892+
return {OverrideAvailability::Ignored, std::nullopt};
19471893

1948-
if (auto *overrideAccessor = dyn_cast<AccessorDecl>(override)) {
1949-
// If base and override are accessors, check whether the unavailability of
1950-
// their storage matches. Diagnosing accessors with invalid storage
1951-
// produces redundant diagnostics.
1952-
if (checkOverrideUnavailability(overrideAccessor->getStorage(),
1953-
baseAccessor->getStorage())
1954-
.first != OverrideUnavailabilityStatus::Compatible)
1955-
return {OverrideUnavailabilityStatus::Ignored, std::nullopt};
1956-
}
1894+
// If we're checking an accessor that's overriding another accessor, ignore
1895+
// the result if we get the same result for the underlying storage
1896+
// (otherwise we'll emit redundant diagnostics).
1897+
if (checkOverrideAvailability(overrideAccessor->getStorage(),
1898+
baseAccessor->getStorage())
1899+
.first != OverrideAvailability::Compatible)
1900+
return {OverrideAvailability::Ignored, std::nullopt};
19571901
}
19581902

1959-
auto baseUnavailableAttr = base->getUnavailableAttr();
1960-
auto overrideUnavailableAttr = override->getUnavailableAttr();
1961-
1962-
if (baseUnavailableAttr && !overrideUnavailableAttr)
1963-
return {OverrideUnavailabilityStatus::BaseUnavailable, baseUnavailableAttr};
1964-
1965-
return {OverrideUnavailabilityStatus::Compatible, std::nullopt};
1903+
return result;
19661904
}
19671905

19681906
static bool checkSingleOverride(ValueDecl *override, ValueDecl *base) {
@@ -2231,14 +2169,11 @@ static bool checkSingleOverride(ValueDecl *override, ValueDecl *base) {
22312169
return true;
22322170
}
22332171

2234-
// FIXME: [availability] Possibly should extend to more availability checking.
2235-
auto unavailabilityStatusAndAttr =
2236-
checkOverrideUnavailability(override, base);
2237-
auto unavailableAttr = unavailabilityStatusAndAttr.second;
2238-
2239-
switch (unavailabilityStatusAndAttr.first) {
2240-
case OverrideUnavailabilityStatus::BaseUnavailable: {
2241-
diagnoseOverrideOfUnavailableDecl(override, base, unavailableAttr.value());
2172+
auto [status, constraint] = checkOverrideAvailability(override, base);
2173+
switch (status) {
2174+
case OverrideAvailability::BaseUnavailable: {
2175+
auto unavailableAttr = constraint->getAttr();
2176+
diagnoseOverrideOfUnavailableDecl(override, base, unavailableAttr);
22422177

22432178
if (isUnavailableInAllVersions(base)) {
22442179
auto modifier = override->getAttrs().getAttribute<OverrideAttr>();
@@ -2251,13 +2186,32 @@ static bool checkSingleOverride(ValueDecl *override, ValueDecl *base) {
22512186
}
22522187
break;
22532188
}
2254-
case OverrideUnavailabilityStatus::Compatible:
2255-
case OverrideUnavailabilityStatus::Ignored:
2189+
case OverrideAvailability::OverrideUnavailable: {
2190+
auto unavailableAttr = constraint->getAttr();
2191+
auto domain = unavailableAttr.getDomain();
2192+
auto parsedAttr = unavailableAttr.getParsedAttr();
2193+
2194+
if (domain.isPlatform() || domain.isUniversal()) {
2195+
// FIXME: [availability] Diagnose as an error in a future Swift version.
2196+
break;
2197+
}
2198+
2199+
if (parsedAttr->getLocation().isValid())
2200+
ctx.Diags.diagnose(override, diag::override_unavailable, override)
2201+
.fixItRemove(parsedAttr->getRangeWithAt());
2202+
else
2203+
ctx.Diags.diagnose(override, diag::override_unavailable, override);
2204+
ctx.Diags.diagnose(base, diag::overridden_here);
2205+
break;
2206+
}
2207+
case OverrideAvailability::OverrideLessAvailable: {
2208+
ctx.Diags.diagnose(override, diag::override_less_available, override);
2209+
ctx.Diags.diagnose(base, diag::overridden_here);
22562210
break;
22572211
}
2258-
2259-
if (!ctx.LangOpts.DisableAvailabilityChecking) {
2260-
diagnoseOverrideForAvailability(override, base);
2212+
case OverrideAvailability::Compatible:
2213+
case OverrideAvailability::Ignored:
2214+
break;
22612215
}
22622216

22632217
if (ctx.LangOpts.hasFeature(Feature::StrictMemorySafety, /*allowMigration=*/true)) {

0 commit comments

Comments
 (0)