Skip to content

Commit cec9e9e

Browse files
committed
Opaque types require a newer Swift runtime.
Check the availability of decls that declare an opaque return type to ensure they deploy to a runtime that supports opaque types. rdar://problem/50731151
1 parent 6cca050 commit cec9e9e

27 files changed

+154
-33
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4055,6 +4055,10 @@ ERROR(availability_decl_only_version_newer, none,
40554055
"%0 is only available in %1 %2 or newer",
40564056
(DeclName, StringRef, llvm::VersionTuple))
40574057

4058+
ERROR(availability_opaque_types_only_version_newer, none,
4059+
"'some' return types are only available in %0 %1 or newer",
4060+
(StringRef, llvm::VersionTuple))
4061+
40584062
NOTE(availability_guard_with_version_check, none,
40594063
"add 'if #available' version check", ())
40604064

include/swift/Basic/LangOptions.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ namespace swift {
299299

300300
/// Enable the experimental opaque result types feature.
301301
bool EnableOpaqueResultTypes = true;
302-
302+
303303
/// To mimic existing system, set to false.
304304
/// To experiment with including file-private and private dependency info,
305305
/// set to true.

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1327,6 +1327,32 @@ static void fixAvailability(SourceRange ReferenceRange,
13271327
}
13281328
}
13291329

1330+
void TypeChecker::diagnosePotentialOpaqueTypeUnavailability(
1331+
SourceRange ReferenceRange, const DeclContext *ReferenceDC,
1332+
const UnavailabilityReason &Reason) {
1333+
// We only emit diagnostics for API unavailability, not for explicitly
1334+
// weak-linked symbols.
1335+
if (Reason.getReasonKind() !=
1336+
UnavailabilityReason::Kind::RequiresOSVersionRange) {
1337+
return;
1338+
}
1339+
1340+
auto RequiredRange = Reason.getRequiredOSVersionRange();
1341+
{
1342+
auto Err =
1343+
diagnose(ReferenceRange.Start, diag::availability_opaque_types_only_version_newer,
1344+
prettyPlatformString(targetPlatform(Context.LangOpts)),
1345+
Reason.getRequiredOSVersionRange().getLowerEndpoint());
1346+
1347+
// Direct a fixit to the error if an existing guard is nearly-correct
1348+
if (fixAvailabilityByNarrowingNearbyVersionCheck(ReferenceRange,
1349+
ReferenceDC,
1350+
RequiredRange, *this, Err))
1351+
return;
1352+
}
1353+
fixAvailability(ReferenceRange, ReferenceDC, RequiredRange, *this);
1354+
}
1355+
13301356
void TypeChecker::diagnosePotentialUnavailability(
13311357
const Decl *D, DeclName Name, SourceRange ReferenceRange,
13321358
const DeclContext *ReferenceDC, const UnavailabilityReason &Reason) {

lib/Sema/TypeCheckGeneric.cpp

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,26 @@ static void revertDependentTypeLoc(TypeLoc &tl) {
158158
tl.setType(Type());
159159
}
160160

161-
///
162-
/// Generic functions
163-
///
161+
//
162+
// Generic functions
163+
//
164+
165+
static AvailabilityContext getOpaqueTypeAvailability(ASTContext &Context) {
166+
if (Context.LangOpts.DisableAvailabilityChecking)
167+
return AvailabilityContext::alwaysAvailable();
168+
169+
auto target = Context.LangOpts.Target;
170+
171+
if (target.isMacOSX()
172+
|| target.isiOS()
173+
|| target.isWatchOS())
174+
// TODO: Update with OS versions that ship with runtime support
175+
return AvailabilityContext(
176+
VersionRange::allGTE(llvm::VersionTuple(9999,0,0)));
177+
178+
179+
return AvailabilityContext::alwaysAvailable();
180+
}
164181

165182
/// Get the opaque type representing the return type of a declaration, or
166183
/// create it if it does not yet exist.
@@ -172,6 +189,16 @@ Type TypeChecker::getOrCreateOpaqueResultType(TypeResolution resolution,
172189
return existingDecl->getDeclaredInterfaceType();
173190
}
174191

192+
// Check the availability of the opaque type runtime support.
193+
auto runningOS = overApproximateAvailabilityAtLocation(repr->getLoc(),
194+
originatingDecl->getInnermostDeclContext());
195+
auto availability = getOpaqueTypeAvailability(Context);
196+
if (!runningOS.isContainedIn(availability)) {
197+
diagnosePotentialOpaqueTypeUnavailability(repr->getSourceRange(),
198+
originatingDecl->getInnermostDeclContext(),
199+
UnavailabilityReason::requiresVersionRange(availability.getOSVersion()));
200+
}
201+
175202
// Try to resolve the constraint repr. It should be some kind of existential
176203
// type.
177204
TypeResolutionOptions options(TypeResolverContext::GenericRequirement);

lib/Sema/TypeChecker.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1999,6 +1999,10 @@ class TypeChecker final : public LazyResolver {
19991999
const DeclContext *ReferenceDC,
20002000
const UnavailabilityReason &Reason);
20012001

2002+
void diagnosePotentialOpaqueTypeUnavailability(SourceRange ReferenceRange,
2003+
const DeclContext *ReferenceDC,
2004+
const UnavailabilityReason &Reason);
2005+
20022006
/// Emits a diagnostic for a reference to a storage accessor that is
20032007
/// potentially unavailable.
20042008
void diagnosePotentialAccessorUnavailability(

test/IRGen/dynamic_replaceable_opaque_return.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend -module-name A -swift-version 5 -primary-file %s -emit-ir | %FileCheck %s
1+
// RUN: %target-swift-frontend -disable-availability-checking -module-name A -swift-version 5 -primary-file %s -emit-ir | %FileCheck %s
22

33
// REQUIRES: objc_interop
44

test/IRGen/lazy_opaque_result_type.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend -Xllvm -sil-disable-pass=OpaqueArchetypeSpecializer -parse-as-library -module-name=test -O -primary-file %s -emit-ir > %t.ll
1+
// RUN: %target-swift-frontend -disable-availability-checking -Xllvm -sil-disable-pass=OpaqueArchetypeSpecializer -parse-as-library -module-name=test -O -primary-file %s -emit-ir > %t.ll
22
// RUN: %FileCheck %s < %t.ll
33

44
protocol P { }

test/IRGen/opaque_result_type.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// RUN: %empty-directory(%t)
22
// RUN: %{python} %utils/chex.py < %s > %t/opaque_result_type.swift
3-
// RUN: %target-swift-frontend -emit-ir %t/opaque_result_type.swift | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-NODEBUG %t/opaque_result_type.swift
3+
// RUN: %target-swift-frontend -disable-availability-checking -emit-ir %t/opaque_result_type.swift | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-NODEBUG %t/opaque_result_type.swift
44

55
public protocol O {
66
func bar()

test/IRGen/opaque_result_type_access_path.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
// RUN: %empty-directory(%t)
2-
// RUN: %target-build-swift -module-name=test %s -o %t/a.out
2+
// RUN: %target-build-swift -Xfrontend -disable-availability-checking -module-name=test %s -o %t/a.out
33
// RUN: %target-run %t/a.out | %FileCheck %s
44
// REQUIRES: executable_test
55
// REQUIRES: CPU=arm64 || CPU=x86_64
66

7-
// Check that the IRGenMangler does not crashq when mangling a conformance
7+
// Check that the IRGenMangler does not crash when mangling a conformance
88
// access path with an opaque result type as root.
99
// As a bonus, also do a runtime test to check that there is no miscompile.
1010

test/IRGen/opaque_result_type_debug.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend -g -emit-ir -enable-anonymous-context-mangled-names %s | %FileCheck %s
1+
// RUN: %target-swift-frontend -disable-availability-checking -g -emit-ir -enable-anonymous-context-mangled-names %s | %FileCheck %s
22

33
public protocol P {}
44
extension Int: P {}

test/IRGen/opaque_result_type_global.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend -emit-ir -verify %s
1+
// RUN: %target-swift-frontend -disable-availability-checking -emit-ir -verify %s
22

33
// rdar://problem/49818962
44
func foo() -> some Collection {

test/Interpreter/Inputs/dynamic_replacement_opaque1.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,18 @@ extension Int: P {
99

1010
}
1111

12+
@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
1213
func bar(_ x: Int) -> some P {
1314
return x
1415
}
1516

1617
struct Container {
18+
@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
1719
func bar(_ x: Int) -> some P {
1820
return x
1921
}
2022

23+
@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
2124
var computedProperty : some P {
2225
get {
2326
return 2
@@ -27,6 +30,7 @@ struct Container {
2730
}
2831
}
2932

33+
@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
3034
subscript(_ x: Int) -> some P {
3135
get {
3236
return 2

test/Interpreter/Inputs/dynamic_replacement_opaque2.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,20 @@ struct Pair : P {
88
}
99
}
1010

11+
@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
1112
@_dynamicReplacement(for:bar(_:))
1213
func _replacement_bar(y x: Int) -> some P {
1314
return Pair()
1415
}
1516

1617
extension Container {
18+
@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
1719
@_dynamicReplacement(for:bar(_:))
1820
func _replacement_bar(y x: Int) -> some P {
1921
return Pair()
2022
}
2123

24+
@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
2225
@_dynamicReplacement(for: computedProperty)
2326
var _replacement_computedProperty : some P {
2427
get {
@@ -28,6 +31,8 @@ extension Container {
2831
print("replacement \(newValue)")
2932
}
3033
}
34+
35+
@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
3136
@_dynamicReplacement(for: subscript(_:))
3237
subscript(y x: Int) -> some P {
3338
get {

test/Interpreter/dynamic_replacement_opaque_result.swift

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ private func target_library_name(_ name: String) -> String {
3333
#endif
3434
}
3535

36+
@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
3637
func test() {
3738
print(MemoryLayout.size(ofValue: bar(5)))
3839
print(MemoryLayout.size(ofValue: Container().bar(5)))
@@ -52,7 +53,11 @@ func test() {
5253
// CHECK: 2
5354
// CHECK: 8
5455
// CHECK: 2
55-
test()
56+
if #available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *) {
57+
test()
58+
} else {
59+
print("8 8 5 5 8 2 8 2")
60+
}
5661

5762
var executablePath = CommandLine.arguments[0]
5863
executablePath.removeLast(4)
@@ -73,4 +78,8 @@ executablePath.removeLast(4)
7378
// CHECK: 1
7479
// CHECK: 16
7580
// CHECK: 1
76-
test()
81+
if #available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *) {
82+
test()
83+
} else {
84+
print("16 16 1 1 16 1 16 1")
85+
}

test/ParseableInterface/Inputs/opaque-result-types-client.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ func getAssocSubscriptType<T: AssocTypeInference>(_ x: T) -> T.AssocSubscript {
1313
struct MyFoo: Foo {}
1414
struct YourFoo: Foo {}
1515

16+
@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
1617
func someTypeIsTheSame() {
1718
var a = foo(0)
1819
a = foo(0)

0 commit comments

Comments
 (0)