Skip to content

Commit 359de85

Browse files
committed
Sema: Relax associated conformance availability checking.
If an associated conformance comes from an associated type requirement, then the associated conformance only needs to be as available as that associated type. Resolves rdar://133544161.
1 parent 30b6cca commit 359de85

File tree

4 files changed

+88
-3
lines changed

4 files changed

+88
-3
lines changed

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,13 @@ ExportContext ExportContext::withExported(bool exported) const {
295295
return copy;
296296
}
297297

298+
ExportContext ExportContext::withRefinedAvailability(
299+
const AvailabilityContext &availability) const {
300+
auto copy = *this;
301+
copy.RunningOSVersion.intersectWith(availability);
302+
return copy;
303+
}
304+
298305
std::optional<PlatformKind> ExportContext::getUnavailablePlatformKind() const {
299306
if (Unavailable)
300307
return PlatformKind(Platform);

lib/Sema/TypeCheckAvailability.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,11 @@ 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 context is constrained by \p availability if necessary.
158+
ExportContext
159+
withRefinedAvailability(const AvailabilityContext &availability) const;
160+
156161
DeclContext *getDeclContext() const { return DC; }
157162

158163
AvailabilityContext getAvailabilityContext() const {

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4987,9 +4987,21 @@ static void ensureRequirementsAreSatisfied(ASTContext &ctx,
49874987
if (assocConf.isConcrete()) {
49884988
auto *concrete = assocConf.getConcrete();
49894989
auto replacementTy = dc->mapTypeIntoContext(concrete->getType());
4990-
diagnoseConformanceAvailability(conformance->getLoc(),
4991-
assocConf, where,
4992-
depTy, replacementTy);
4990+
4991+
// If this requirement has a dependent member type, only require the
4992+
// associated conformance to be as available as the requirement's
4993+
// associated type.
4994+
auto availability = AvailabilityContext::alwaysAvailable();
4995+
if (auto depMemberType = depTy->getAs<DependentMemberType>()) {
4996+
auto assocType = depMemberType->getAssocType();
4997+
availability.intersectWith(
4998+
TypeChecker::overApproximateAvailabilityAtLocation(
4999+
assocType->getLoc(), assocType->getDeclContext()));
5000+
}
5001+
5002+
diagnoseConformanceAvailability(
5003+
conformance->getLoc(), assocConf,
5004+
where.withRefinedAvailability(availability), depTy, replacementTy);
49935005
}
49945006

49955007
return false;

test/Sema/conformance_availability.swift

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,15 @@ func passAvailableConformance1a(x: HasAvailableConformance1) {
279279
_ = UsesHorse<HasAvailableConformance1>.self
280280
}
281281

282+
// Always available conformance
283+
struct HasAvailableConformance2: Horse {}
284+
285+
// Conformance available in macOS 200
286+
struct HasAvailableConformance3 {}
287+
288+
@available(macOS 200, *)
289+
extension HasAvailableConformance3: Horse {}
290+
282291
// Associated conformance with unavailability
283292
protocol Rider {
284293
associatedtype H : Horse
@@ -326,6 +335,58 @@ extension AssocConformanceAvailable4 : Rider {
326335
typealias H = HasAvailableConformance1
327336
}
328337

338+
@available(macOS 100, *)
339+
protocol Saddle {
340+
associatedtype H : Horse = HasAvailableConformance1
341+
}
342+
343+
struct ConformsToSaddle1 : Saddle {}
344+
345+
struct ConformsToSaddle2 : Saddle {
346+
typealias H = HasAvailableConformance2
347+
}
348+
349+
struct ConformsToSaddle3 : Saddle {
350+
// expected-error@-1 {{conformance of 'HasAvailableConformance3' to 'Horse' is only available in macOS 200 or newer}}
351+
// expected-note@-2 {{add @available attribute to enclosing struct}}
352+
// expected-note@-3 {{in associated type 'Self.H' (inferred as 'HasAvailableConformance3'}}
353+
typealias H = HasAvailableConformance3
354+
}
355+
356+
struct ConformsToSaddle4 : Saddle {
357+
// expected-error@-1 {{conformance of 'HasAvailableConformance3' to 'Horse' is only available in macOS 200 or newer}}
358+
// expected-note@-2 {{add @available attribute to enclosing struct}}
359+
// expected-note@-3 {{in associated type 'Self.H' (inferred as 'HasAvailableConformance3'}}
360+
@available(macOS 200, *)
361+
typealias H = HasAvailableConformance3
362+
}
363+
364+
protocol Barn {
365+
@available(macOS 100, *)
366+
associatedtype H : Horse = HasAvailableConformance1
367+
}
368+
369+
struct ConformsToBarn1 : Barn {}
370+
371+
struct ConformsToBarn2 : Barn {
372+
typealias H = HasAvailableConformance2
373+
}
374+
375+
struct ConformsToBarn3 : Barn {
376+
// expected-error@-1 {{conformance of 'HasAvailableConformance3' to 'Horse' is only available in macOS 200 or newer}}
377+
// expected-note@-2 {{add @available attribute to enclosing struct}}
378+
// expected-note@-3 {{in associated type 'Self.H' (inferred as 'HasAvailableConformance3'}}
379+
typealias H = HasAvailableConformance3
380+
}
381+
382+
struct ConformsToBarn4 : Barn {
383+
// expected-error@-1 {{conformance of 'HasAvailableConformance3' to 'Horse' is only available in macOS 200 or newer}}
384+
// expected-note@-2 {{add @available attribute to enclosing struct}}
385+
// expected-note@-3 {{in associated type 'Self.H' (inferred as 'HasAvailableConformance3'}}
386+
@available(macOS 200, *)
387+
typealias H = HasAvailableConformance3
388+
}
389+
329390
// Solution ranking should down-rank solutions involving unavailable conformances
330391
protocol First {}
331392
extension First {

0 commit comments

Comments
 (0)