Skip to content

Commit d002bb8

Browse files
committed
WIP
1 parent daeb019 commit d002bb8

8 files changed

+72
-62
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3126,7 +3126,7 @@ NOTE(declared_protocol_conformance_here,none,
31263126

31273127
ERROR(witness_unavailable,none,
31283128
"unavailable %kind0 was used to satisfy a requirement of protocol %1%select{|: %2}2",
3129-
(const ValueDecl *, Identifier, StringRef))
3129+
(const ValueDecl *, const ProtocolDecl *, StringRef))
31303130

31313131
WARNING(witness_deprecated,none,
31323132
"deprecated default implementation is used to satisfy %kind0 required by "

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 4 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,10 @@ static bool computeContainedByDeploymentTarget(TypeRefinementContext *TRC,
348348
.isContainedIn(AvailabilityContext::forDeploymentTarget(ctx));
349349
}
350350

351+
AvailableAttr *ExportContext::isDeclAlwaysUnavailable(const Decl *decl) const {
352+
return nullptr; // ALLANXXX
353+
}
354+
351355
/// Returns true if the reference or any of its parents is an
352356
/// unconditional unavailable declaration for the same platform.
353357
static bool isInsideCompatibleUnavailableDeclaration(
@@ -4632,32 +4636,6 @@ static bool diagnoseExplicitUnavailabilityForTypeWitness(
46324636
return true;
46334637
}
46344638

4635-
static void diagnosePotentialUnavailabilityForTypeWitness(
4636-
SourceLoc loc, const TypeDecl *witness, const AssociatedTypeDecl *assocType,
4637-
const DeclContext *dc, const AvailabilityContext &requiredAvailability) {
4638-
auto &ctx = dc->getASTContext();
4639-
auto proto = assocType->getProtocol();
4640-
auto requiredRange = requiredAvailability.getOSVersion();
4641-
4642-
{
4643-
auto err = ctx.Diags.diagnose(
4644-
loc, diag::availability_protocol_requires_version, proto,
4645-
assocType, witness, prettyPlatformString(targetPlatform(ctx.LangOpts)),
4646-
requiredRange.getLowerEndpoint());
4647-
err.warnUntilSwiftVersion(7);
4648-
4649-
// Direct a fixit to the error if an existing guard is nearly-correct
4650-
if (fixAvailabilityByNarrowingNearbyVersionCheck(witness->getLoc(), dc,
4651-
requiredRange, ctx, err))
4652-
return;
4653-
}
4654-
4655-
fixAvailability(witness->getLoc(), dc, requiredRange, ctx);
4656-
4657-
if (loc != witness->getLoc())
4658-
ctx.Diags.diagnose(witness, diag::decl_declared_here, witness);
4659-
}
4660-
46614639
bool swift::diagnoseTypeWitnessAvailability(
46624640
SourceLoc loc, const TypeDecl *witness, const AssociatedTypeDecl *assocType,
46634641
const NormalProtocolConformance *conformance, const ExportContext &where) {
@@ -4671,14 +4649,6 @@ bool swift::diagnoseTypeWitnessAvailability(
46714649
where))
46724650
return true;
46734651

4674-
auto dc = conformance->getDeclContext();
4675-
auto requiredAvailability = AvailabilityContext::alwaysAvailable();
4676-
if (!TypeChecker::isAvailabilitySafeForConformance(conformance->getProtocol(), assocType, witness, dc, requiredAvailability)) {
4677-
diagnosePotentialUnavailabilityForTypeWitness(loc, witness, assocType, dc,
4678-
requiredAvailability);
4679-
return true;
4680-
}
4681-
46824652
return false;
46834653
}
46844654

lib/Sema/TypeCheckAvailability.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -153,11 +153,6 @@ class ExportContext {
153153
/// That is, this will perform a 'bitwise and' on the 'exported' bit.
154154
ExportContext withExported(bool exported) const;
155155

156-
/// Produce a new context with the same properties as this one, except the
157-
/// availability of the resulting context is constrained by \p availability
158-
/// if it is less available.
159-
ExportContext withRefinedAvailability(AvailabilityContext availability) const;
160-
161156
DeclContext *getDeclContext() const { return DC; }
162157

163158
AvailabilityContext getAvailabilityContext() const {
@@ -192,6 +187,10 @@ class ExportContext {
192187
/// Get the ExportabilityReason for diagnostics. If this is 'None', there
193188
/// are no restrictions on referencing unexported declarations.
194189
std::optional<ExportabilityReason> getExportabilityReason() const;
190+
191+
/// If \p decl is always unavailable in the context, returns the `@available`
192+
/// attribute that makes the decl unavailable. Otherwise, returns null.
193+
AvailableAttr *isDeclAlwaysUnavailable(const Decl *decl) const;
195194
};
196195

197196
/// Check if a declaration is exported as part of a module's external interface.

lib/Sema/TypeCheckDecl.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1689,8 +1689,9 @@ SelfAccessKindRequest::evaluate(Evaluator &evaluator, FuncDecl *FD) const {
16891689
}
16901690

16911691
bool TypeChecker::isAvailabilitySafeForConformance(
1692-
const ProtocolDecl *proto, const ValueDecl *requirement, const ValueDecl *witness,
1693-
const DeclContext *dc, AvailabilityContext &requirementInfo) {
1692+
const ProtocolDecl *proto, const ValueDecl *requirement,
1693+
const ValueDecl *witness, const DeclContext *dc,
1694+
AvailabilityContext &requirementInfo) {
16941695

16951696
// We assume conformances in
16961697
// non-SourceFiles have already been checked for availability.

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1842,6 +1842,7 @@ RequirementCheck WitnessChecker::checkWitness(ValueDecl *requirement,
18421842

18431843
if (match.Witness->getAttrs().isUnavailable(ctx) &&
18441844
!requirement->getAttrs().isUnavailable(ctx)) {
1845+
// ALLANXXX
18451846
auto nominalOrExtensionIsUnavailable = [&]() {
18461847
if (auto extension = dyn_cast<ExtensionDecl>(DC)) {
18471848
if (extension->getAttrs().isUnavailable(ctx))
@@ -4313,8 +4314,7 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
43134314
SourceLoc diagLoc = getLocForDiagnosingWitness(conformance, witness);
43144315
diags.diagnose(
43154316
diagLoc, diag::availability_protocol_requires_version,
4316-
conformance->getProtocol(),
4317-
witness,
4317+
conformance->getProtocol(), witness,
43184318
prettyPlatformString(targetPlatform(ctx.LangOpts)),
43194319
check.RequiredAvailability.getOSVersion().getLowerEndpoint());
43204320
emitDeclaredHereIfNeeded(diags, diagLoc, witness);
@@ -4385,9 +4385,8 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
43854385
SourceLoc diagLoc = getLocForDiagnosingWitness(conformance, witness);
43864386
auto *attr = AvailableAttr::isUnavailable(witness);
43874387
EncodedDiagnosticMessage EncodedMessage(attr->Message);
4388-
diags.diagnose(diagLoc, diag::witness_unavailable,
4389-
witness, conformance->getProtocol()->getName(),
4390-
EncodedMessage.Message);
4388+
diags.diagnose(diagLoc, diag::witness_unavailable, witness,
4389+
conformance->getProtocol(), EncodedMessage.Message);
43914390
emitDeclaredHereIfNeeded(diags, diagLoc, witness);
43924391
diags.diagnose(requirement, diag::kind_declname_declared_here,
43934392
DescriptiveDeclKind::Requirement,
@@ -4786,6 +4785,50 @@ static void diagnoseInvariantSelfRequirement(
47864785
.warnUntilSwiftVersion(6);
47874786
}
47884787

4788+
static bool diagnoseTypeWitnessAvailability(
4789+
NormalProtocolConformance *conformance, const TypeDecl *witness,
4790+
const AssociatedTypeDecl *assocType, const ExportContext &where) {
4791+
auto dc = conformance->getDeclContext();
4792+
auto &ctx = dc->getASTContext();
4793+
auto proto = conformance->getProtocol();
4794+
SourceLoc diagLoc =
4795+
getLocForDiagnosingWitness(conformance, witness); // ALLANXXX
4796+
// FIXME: If there's a language mode before 7, bump this up.
4797+
unsigned languageModeForErrors = 7;
4798+
bool shouldError = ctx.LangOpts.EffectiveLanguageVersion.isVersionAtLeast(
4799+
languageModeForErrors);
4800+
4801+
if (diagnoseTypeWitnessAvailability(diagLoc, witness, assocType, conformance,
4802+
where))
4803+
return true;
4804+
4805+
// ALLANXXX witness_unavailable diagnostic
4806+
4807+
auto requiredAvailability = AvailabilityContext::alwaysAvailable();
4808+
if (!TypeChecker::isAvailabilitySafeForConformance(
4809+
proto, assocType, witness, dc, requiredAvailability)) {
4810+
auto requiredRange = requiredAvailability.getOSVersion();
4811+
ctx.addDelayedConformanceDiag(
4812+
conformance, shouldError,
4813+
[witness, requiredRange](NormalProtocolConformance *conformance) {
4814+
SourceLoc loc = getLocForDiagnosingWitness(conformance, witness);
4815+
4816+
auto &ctx = conformance->getDeclContext()->getASTContext();
4817+
ctx.Diags
4818+
.diagnose(loc, diag::availability_protocol_requires_version,
4819+
conformance->getProtocol(), witness,
4820+
prettyPlatformString(targetPlatform(ctx.LangOpts)),
4821+
requiredRange.getLowerEndpoint())
4822+
.warnUntilSwiftVersion(languageModeForErrors);
4823+
4824+
emitDeclaredHereIfNeeded(ctx.Diags, loc, witness);
4825+
});
4826+
return true;
4827+
}
4828+
4829+
return false;
4830+
}
4831+
47894832
/// Check whether the type witnesses satisfy the protocol's requirement
47904833
/// signature. Also checks access level of type witnesses and availiability
47914834
/// of associated conformances.
@@ -4909,11 +4952,8 @@ static void ensureRequirementsAreSatisfied(ASTContext &ctx,
49094952
}
49104953

49114954
// The type witness must be as available as the associated type.
4912-
if (auto witness = type->getAnyNominal()) {
4913-
SourceLoc diagLoc = getLocForDiagnosingWitness(conformance, witness);
4914-
diagnoseTypeWitnessAvailability(diagLoc, witness, assocType,
4915-
conformance, where);
4916-
}
4955+
if (auto witness = type->getAnyNominal())
4956+
diagnoseTypeWitnessAvailability(conformance, witness, assocType, where);
49174957

49184958
// Make sure any associated type witnesses don't make reference to a
49194959
// type we can't emit metadata for, or we're going to have trouble at

lib/Sema/TypeChecker.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -990,10 +990,10 @@ bool diagnoseConformanceExportability(SourceLoc loc,
990990
/// is sufficient to safely conform to the requirement in the context
991991
/// the provided conformance. On return, requiredAvailability holds th
992992
/// availability levels required for conformance.
993-
bool
994-
isAvailabilitySafeForConformance(const ProtocolDecl *proto, const ValueDecl *requirement,
995-
const ValueDecl *witness, const DeclContext *dc,
996-
AvailabilityContext &requiredAvailability);
993+
bool isAvailabilitySafeForConformance(
994+
const ProtocolDecl *proto, const ValueDecl *requirement,
995+
const ValueDecl *witness, const DeclContext *dc,
996+
AvailabilityContext &requiredAvailability);
997997

998998
/// Returns an over-approximation of the range of operating system versions
999999
/// that could the passed-in location could be executing upon for

test/decl/protocol/associated_type_witness_availability.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ struct ConformsToProtoWithAssocType_WitnessSame: ProtoWithAssocType {
1717

1818
struct ConformsToProtoWithAssocType_WitnessTooNew: ProtoWithAssocType {
1919
@available(macOS 13, *)
20-
struct A {} // expected-warning {{struct witnessing requirement 'A' of 'ProtoWithAssocType' is only available in macOS 13 or newer; this will be an error in a future Swift language mode}}
20+
struct A {} // expected-warning {{protocol 'ProtoWithAssocType' requires 'A' to be available in macOS 12 and newer; this will be an error in a future Swift language mode}}
2121
}
2222

2323
struct ConformsToProtoWithAssocTypeInExtension_WitnessOld {}
@@ -38,7 +38,7 @@ struct ConformsToProtoWithAssocTypeInExtension_WitnessTooNew {}
3838

3939
extension ConformsToProtoWithAssocTypeInExtension_WitnessTooNew: ProtoWithAssocType {
4040
@available(macOS 13, *)
41-
struct A {} // expected-warning {{struct witnessing requirement 'A' of 'ProtoWithAssocType' is only available in macOS 13 or newer; this will be an error in a future Swift language mode}}
41+
struct A {} // expected-warning {{protocol 'ProtoWithAssocType' requires 'A' to be available in macOS 12 and newer; this will be an error in a future Swift language mode}}
4242
}
4343

4444
@available(macOS 13, *)
@@ -56,7 +56,7 @@ extension ConformsToProtoWithAssocTypeInExtension_NewerConformance: ProtoWithAss
5656
@available(macOS 13, *)
5757
struct ConformsToProtoWithAssocType_NewerAndWitnessTooNew: ProtoWithAssocType {
5858
@available(macOS 14, *)
59-
struct A {} // expected-warning {{struct witnessing requirement 'A' of 'ProtoWithAssocType' is only available in macOS 14 or newer; this will be an error in a future Swift language mode}}
59+
struct A {} // expected-warning {{protocol 'ProtoWithAssocType' requires 'A' to be available in macOS 13 and newer; this will be an error in a future Swift language mode}}
6060
}
6161

6262
struct ConformsToProtoWithAssocType_WitnessUnavailable: ProtoWithAssocType {
@@ -106,7 +106,7 @@ struct ConformsToProtoWithNewAssocType_WitnessSame: ProtoWithNewAssocType {
106106

107107
struct ConformsToProtoWithNewAssocType_WitnessTooNew: ProtoWithNewAssocType {
108108
@available(macOS 14, *)
109-
struct A {} // expected-warning {{struct witnessing requirement 'A' of 'ProtoWithNewAssocType' is only available in macOS 14 or newer; this will be an error in a future Swift language mode}}
109+
struct A {} // expected-warning {{protocol 'ProtoWithNewAssocType' requires 'A' to be available in macOS 13 and newer; this will be an error in a future Swift language mode}}
110110
}
111111

112112
protocol ProtoWithAssocTypeAndReq {
@@ -135,7 +135,7 @@ struct ConformsToProtoWithAssocTypeAndReq_InferredWitnessSame: ProtoWithAssocTyp
135135
struct InferredTooNew {} // expected-note {{'InferredTooNew' declared here}}
136136

137137
struct ConformsToProtoWithAssocTypeAndReq_InferredWitnessTooNew: ProtoWithAssocTypeAndReq {
138-
// expected-warning@-1 {{struct witnessing requirement 'A' of 'ProtoWithAssocTypeAndReq' is only available in macOS 13 or newer; this will be an error in a future Swift language mode}}
138+
// expected-warning@-1 {{protocol 'ProtoWithAssocTypeAndReq' requires 'InferredTooNew' to be available in macOS 12 and newer; this will be an error in a future Swift language mode}}
139139

140140
@available(macOS 13, *)
141141
func req(_ a: InferredTooNew) {}

test/decl/protocol/associated_type_witness_availability_swift7.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@ struct WitnessSame: ProtoWithAssocType {
1313

1414
struct WitnessTooNew: ProtoWithAssocType {
1515
@available(macOS 13, *)
16-
struct A {} // expected-error {{struct witnessing requirement 'A' of 'ProtoWithAssocType' is only available in macOS 13 or newer}}
16+
struct A {} // expected-error {{protocol 'ProtoWithAssocType' requires 'A' to be available in macOS 12 and newer}}
1717
}

0 commit comments

Comments
 (0)