Skip to content

Commit 6e7d83c

Browse files
authored
Merge pull request #24821 from jckarter/opaque-type-check-availability-5.1
[5.1] Opaque types require a newer Swift runtime.
2 parents e996d5e + 5610b5d commit 6e7d83c

26 files changed

+153
-31
lines changed

include/swift/AST/DiagnosticsSema.def

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

4055+
ERROR(availability_opaque_types_only_version_newer, none,
4056+
"'some' return types are only available in %0 %1 or newer",
4057+
(StringRef, llvm::VersionTuple))
4058+
40554059
NOTE(availability_guard_with_version_check, none,
40564060
"add 'if #available' version check", ())
40574061

include/swift/Basic/LangOptions.h

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

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

lib/Sema/TypeCheckAvailability.cpp

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

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

lib/Sema/TypeCheckGeneric.cpp

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

170-
///
171-
/// Generic functions
172-
///
170+
//
171+
// Generic functions
172+
//
173+
174+
static AvailabilityContext getOpaqueTypeAvailability(ASTContext &Context) {
175+
if (Context.LangOpts.DisableAvailabilityChecking)
176+
return AvailabilityContext::alwaysAvailable();
177+
178+
auto target = Context.LangOpts.Target;
179+
180+
if (target.isMacOSX()
181+
|| target.isiOS()
182+
|| target.isWatchOS())
183+
// TODO: Update with OS versions that ship with runtime support
184+
return AvailabilityContext(
185+
VersionRange::allGTE(llvm::VersionTuple(9999,0,0)));
186+
187+
188+
return AvailabilityContext::alwaysAvailable();
189+
}
173190

174191
/// Get the opaque type representing the return type of a declaration, or
175192
/// create it if it does not yet exist.
@@ -181,6 +198,16 @@ Type TypeChecker::getOrCreateOpaqueResultType(TypeResolution resolution,
181198
return existingDecl->getDeclaredInterfaceType();
182199
}
183200

201+
// Check the availability of the opaque type runtime support.
202+
auto runningOS = overApproximateAvailabilityAtLocation(repr->getLoc(),
203+
originatingDecl->getInnermostDeclContext());
204+
auto availability = getOpaqueTypeAvailability(Context);
205+
if (!runningOS.isContainedIn(availability)) {
206+
diagnosePotentialOpaqueTypeUnavailability(repr->getSourceRange(),
207+
originatingDecl->getInnermostDeclContext(),
208+
UnavailabilityReason::requiresVersionRange(availability.getOSVersion()));
209+
}
210+
184211
// Try to resolve the constraint repr. It should be some kind of existential
185212
// type.
186213
TypeResolutionOptions options(TypeResolverContext::GenericRequirement);

lib/Sema/TypeChecker.h

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

2011+
void diagnosePotentialOpaqueTypeUnavailability(SourceRange ReferenceRange,
2012+
const DeclContext *ReferenceDC,
2013+
const UnavailabilityReason &Reason);
2014+
20112015
/// Emits a diagnostic for a reference to a storage accessor that is
20122016
/// potentially unavailable.
20132017
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
@@ -32,6 +32,7 @@ private func target_library_name(_ name: String) -> String {
3232
#endif
3333
}
3434

35+
@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
3536
func test() {
3637
print(MemoryLayout.size(ofValue: bar(5)))
3738
print(MemoryLayout.size(ofValue: Container().bar(5)))
@@ -51,7 +52,11 @@ func test() {
5152
// CHECK: 2
5253
// CHECK: 8
5354
// CHECK: 2
54-
test()
55+
if #available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *) {
56+
test()
57+
} else {
58+
print("8 8 5 5 8 2 8 2")
59+
}
5560

5661
var executablePath = CommandLine.arguments[0]
5762
executablePath.removeLast(4)
@@ -72,4 +77,8 @@ executablePath.removeLast(4)
7277
// CHECK: 1
7378
// CHECK: 16
7479
// CHECK: 1
75-
test()
80+
if #available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *) {
81+
test()
82+
} else {
83+
print("16 16 1 1 16 1 16 1")
84+
}

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)