Skip to content

Commit 56ad8bd

Browse files
authored
Merge pull request #8386 from slavapestov/non-overlapping-availability-for-properties
Allow overloading properties with non-overlapping availability
2 parents 67e3d27 + 4da2611 commit 56ad8bd

File tree

4 files changed

+124
-6
lines changed

4 files changed

+124
-6
lines changed

lib/Sema/TypeCheckDecl.cpp

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -953,10 +953,10 @@ static void checkRedeclaration(TypeChecker &tc, ValueDecl *current) {
953953
continue;
954954
}
955955

956-
// If the conflicting declarations have non-overlapping availability and
957-
// - one throws and the other does not,
958-
// - or they are initializers with different failability
959-
// let them go.
956+
// If the conflicting declarations have non-overlapping availability and,
957+
// we allow the redeclaration to proceed if...
958+
//
959+
// - they are initializers with different failability,
960960
bool isAcceptableVersionBasedChange = false;
961961
{
962962
const auto *currentInit = dyn_cast<ConstructorDecl>(current);
@@ -967,6 +967,7 @@ static void checkRedeclaration(TypeChecker &tc, ValueDecl *current) {
967967
isAcceptableVersionBasedChange = true;
968968
}
969969
}
970+
// - one throws and the other does not,
970971
{
971972
const auto *currentAFD = dyn_cast<AbstractFunctionDecl>(current);
972973
const auto *otherAFD = dyn_cast<AbstractFunctionDecl>(other);
@@ -975,6 +976,19 @@ static void checkRedeclaration(TypeChecker &tc, ValueDecl *current) {
975976
isAcceptableVersionBasedChange = true;
976977
}
977978
}
979+
// - or they are computed properties of different types,
980+
{
981+
const auto *currentVD = dyn_cast<VarDecl>(current);
982+
const auto *otherVD = dyn_cast<VarDecl>(other);
983+
if (currentVD && otherVD &&
984+
!currentVD->hasStorage() &&
985+
!otherVD->hasStorage() &&
986+
!currentVD->getInterfaceType()->isEqual(
987+
otherVD->getInterfaceType())) {
988+
isAcceptableVersionBasedChange = true;
989+
}
990+
}
991+
978992
if (isAcceptableVersionBasedChange) {
979993
class AvailabilityRange {
980994
Optional<clang::VersionTuple> introduced;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
public class BeforeAndAfterOther {
2+
@available(swift, obsoleted: 4.0)
3+
public init(foo: ()) {}
4+
5+
@available(swift 4.0)
6+
public init?(foo: ()) {}
7+
8+
@available(swift, obsoleted: 4.0)
9+
public init() {}
10+
11+
@available(swift 4.0)
12+
public init() throws {}
13+
14+
@available(swift, obsoleted: 4.0)
15+
public static func foo() {}
16+
17+
@available(swift 4.0)
18+
public static func foo() throws {}
19+
20+
@available(swift 4.0)
21+
public var computed: Int16 { get { return 0 } set { } }
22+
23+
@available(swift, obsoleted: 4.0)
24+
public var computed: Int8 { get { return 0 } set { } }
25+
26+
@available(swift 4.0)
27+
public static var computed: Int16 { get { return 0 } set { } }
28+
29+
@available(swift, obsoleted: 4.0)
30+
public static var computed: Int8 { get { return 0 } set { } }
31+
}

test/SILGen/availability_overloads.swift

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,25 @@
1-
// RUN: %target-swift-frontend -emit-silgen %s
1+
// RUN: rm -rf %t
2+
// RUN: mkdir -p %t
3+
// RUN: %target-swift-frontend -emit-module-path %t/availability_overloads_other.swiftmodule -emit-module -primary-file %S/Inputs/availability_overloads_other.swift
4+
5+
// RUN: %target-swift-frontend -swift-version 3 -I %t -emit-silgen -primary-file %s
6+
// RUN: %target-swift-frontend -swift-version 3 -I %t -emit-silgen -emit-ir %s
7+
8+
// RUN: %target-swift-frontend -swift-version 4 -I %t -emit-silgen -primary-file %s
9+
// RUN: %target-swift-frontend -swift-version 4 -I %t -emit-silgen -emit-ir %s
10+
11+
// RUN: %target-swift-frontend -swift-version 3 -I %t -emit-module -emit-module-path /dev/null -primary-file %s
12+
// RUN: %target-swift-frontend -swift-version 4 -I %t -emit-module -emit-module-path /dev/null -primary-file %s
213

314
// This is a "don't crash with duplicate definition errors" test.
415
// We care about being able to express each of these "redeclarations" when the
516
// availability doesn't overlap.
617

7-
class BeforeAndAfter {
18+
import availability_overloads_other
19+
20+
// FIXME: What about method overrides and protocol witnesses?
21+
22+
public class BeforeAndAfter {
823
@available(swift, obsoleted: 4.0)
924
public init(foo: ()) {}
1025

@@ -22,4 +37,35 @@ class BeforeAndAfter {
2237

2338
@available(swift 4.0)
2439
public static func foo() throws {}
40+
41+
@available(swift 4.0)
42+
public var computed: Int16 { get { return 0 } set { } }
43+
44+
@available(swift, obsoleted: 4.0)
45+
public var computed: Int8 { get { return 0 } set { } }
46+
47+
@available(swift 4.0)
48+
public static var computed: Int16 { get { return 0 } set { } }
49+
50+
@available(swift, obsoleted: 4.0)
51+
public static var computed: Int8 { get { return 0 } set { } }
2552
}
53+
54+
55+
// Make sure we can generate calls to these overloads, too
56+
_ = BeforeAndAfter(foo: ())
57+
_ = try BeforeAndAfter()
58+
_ = try BeforeAndAfter.foo()
59+
_ = BeforeAndAfter.computed
60+
BeforeAndAfter.computed = 10
61+
_ = try BeforeAndAfter().computed
62+
try BeforeAndAfter().computed = 10
63+
64+
// Same thing but in a different module
65+
_ = BeforeAndAfterOther(foo: ())
66+
_ = try BeforeAndAfterOther()
67+
_ = try BeforeAndAfterOther.foo()
68+
_ = BeforeAndAfterOther.computed
69+
BeforeAndAfterOther.computed = 10
70+
_ = try BeforeAndAfterOther().computed
71+
try BeforeAndAfterOther().computed = 10

test/decl/init/swift-version-overload.swift renamed to test/Sema/availability_nonoverlapping.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,3 +335,30 @@ _ = ThrowingToNonThrowingReversed()
335335
_ = ThrowingToNonThrowingReversed.foo()
336336
// CHECK-3: :[[@LINE-1]]:{{.+}} not 4.0
337337
// CHECK-4: :[[@LINE-2]]:{{.+}} yes 4.0
338+
339+
class ChangePropertyType {
340+
341+
// We don't allow this for stored properties.
342+
343+
@available(swift 4.0)
344+
@available(*, deprecated, message: "yes 4.0")
345+
public var stored: Int16 = 0
346+
347+
@available(swift, obsoleted: 4.0)
348+
@available(*, deprecated, message: "not 4.0")
349+
public var stored: Int8 = 0 // CHECK: :[[@LINE]]:{{.+}} error: invalid redeclaration of 'stored'
350+
351+
// OK for computed properties.
352+
353+
@available(swift 4.0)
354+
@available(*, deprecated, message: "yes 4.0")
355+
public var computed: Int16 { get { } set { } }
356+
357+
@available(swift, obsoleted: 4.0)
358+
@available(*, deprecated, message: "not 4.0")
359+
public var computed: Int8 { get { } set { } } // NEGATIVE-NOT: :[[@LINE]]:{{.+}}error
360+
}
361+
362+
_ = ChangePropertyType().computed
363+
// CHECK-3: :[[@LINE-1]]:{{.+}} not 4.0
364+
// CHECK-4: :[[@LINE-2]]:{{.+}} yes 4.0

0 commit comments

Comments
 (0)