Skip to content

Commit bc11683

Browse files
committed
Sema: Relax the availability requirements for @_spi protocol witnesses.
Now that the public declarations in API libraries are checked according to the minimum possible deployment target of their clients this relaxation is needed for source compatibility with some existing code. Resolves rdar://100904631
1 parent e550944 commit bc11683

File tree

2 files changed

+83
-0
lines changed

2 files changed

+83
-0
lines changed

lib/Sema/TypeCheckDecl.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1707,6 +1707,20 @@ bool TypeChecker::isAvailabilitySafeForConformance(
17071707
AvailabilityContext infoForConformingDecl =
17081708
overApproximateAvailabilityAtLocation(dc->getAsDecl()->getLoc(), dc);
17091709

1710+
// Relax the requirements for @_spi witnesses by treating the requirement as
1711+
// if it were introduced at the deployment target. This is not strictly sound
1712+
// since clients of SPI do not necessarily have the same deployment target as
1713+
// the module declaring the requirement. However, now that the public
1714+
// declarations in API libraries are checked according to the minimum possible
1715+
// deployment target of their clients this relaxation is needed for source
1716+
// compatibility with some existing code and is reasonably safe for the
1717+
// majority of cases.
1718+
if (witness->isSPI()) {
1719+
AvailabilityContext deploymentTarget =
1720+
AvailabilityContext::forDeploymentTarget(Context);
1721+
requirementInfo.constrainWith(deploymentTarget);
1722+
}
1723+
17101724
// Constrain over-approximates intersection of version ranges.
17111725
witnessInfo.constrainWith(infoForConformingDecl);
17121726
requirementInfo.constrainWith(infoForConformingDecl);
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// RUN: %target-run-simple-swift(-target %target-cpu-macos10.15) | \
2+
// RUN: %FileCheck %s --check-prefix=CHECK-CONFORMANCES-NOT-AVAILABLE
3+
// RUN: %target-run-simple-swift(-target %target-cpu-macos10.15.4) | \
4+
// RUN: %FileCheck %s --check-prefix=CHECK-CONFORMANCES-AVAILABLE
5+
// RUN: %target-run-simple-swift(-target %target-cpu-macos10.15.4 -library-level api) | \
6+
// RUN: %FileCheck %s --check-prefix=CHECK-CONFORMANCES-AVAILABLE-API
7+
8+
// REQUIRES: executable_test
9+
// REQUIRES: OS=macosx
10+
11+
@available(macOS 10.15, *)
12+
public protocol BaseProto {
13+
static var foo: String { get }
14+
}
15+
16+
@available(macOS 10.15, *)
17+
extension BaseProto {
18+
public static var foo: String { return "Base" }
19+
}
20+
21+
@available(macOS 10.15.4, *)
22+
public protocol DerivedProto: BaseProto {}
23+
24+
@available(macOS 10.15.4, *)
25+
extension DerivedProto {
26+
public static var foo: String { return "Derived" }
27+
}
28+
29+
@_spi(Private)
30+
@available(macOS 10.15.4, *)
31+
public protocol SecretDerivedProto: BaseProto {
32+
}
33+
34+
@_spi(Private)
35+
@available(macOS 10.15.4, *)
36+
extension SecretDerivedProto {
37+
public static var foo: String { return "Secret" }
38+
}
39+
40+
@available(macOS 10.15, *)
41+
public struct NoSecrets: BaseProto {
42+
public init() {}
43+
}
44+
45+
@available(macOS 10.15.4, *)
46+
extension NoSecrets: DerivedProto {}
47+
48+
@available(macOS 10.15, *)
49+
public struct HasSecrets: BaseProto {
50+
public init() {}
51+
}
52+
53+
@_spi(Private)
54+
@available(macOS 10.15.4, *)
55+
extension HasSecrets: SecretDerivedProto {}
56+
57+
@available(macOS 10.15, *)
58+
func doIt<T: BaseProto>(_: T) {
59+
print(T.foo)
60+
}
61+
62+
// CHECK-CONFORMANCES-NOT-AVAILABLE: Base
63+
// CHECK-CONFORMANCES-AVAILABLE: Derived
64+
// CHECK-CONFORMANCES-AVAILABLE-API: Base
65+
doIt(NoSecrets())
66+
// CHECK-CONFORMANCES-NOT-AVAILABLE: Base
67+
// CHECK-CONFORMANCES-AVAILABLE: Secret
68+
// CHECK-CONFORMANCES-AVAILABLE-API: Secret
69+
doIt(HasSecrets())

0 commit comments

Comments
 (0)