Skip to content

Commit b96aeda

Browse files
committed
[Sema] Match Swift 4.0/4.1 overloading behaviour for properties in extensions of generic types.
The patch that nailed down our semantics here missed an additional case that required a compatibility hack: a property on a generic type and a same-named one in an (unconstrained) extension: struct Foo<T> { var x: Int { return 0 } } extension Foo { var x: Bool { return false } } Fixes rdar://problem/40685642.
1 parent 8dcad45 commit b96aeda

File tree

5 files changed

+50
-5
lines changed

5 files changed

+50
-5
lines changed

lib/AST/Decl.cpp

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1747,7 +1747,30 @@ bool swift::conflicting(ASTContext &ctx,
17471747
}
17481748

17491749
// Otherwise, the declarations conflict if the overload types are the same.
1750-
return sig1Type == sig2Type;
1750+
if (sig1Type != sig2Type)
1751+
return false;
1752+
1753+
// The Swift 5 overload types are the same, but similar to the above, prior to
1754+
// Swift 5, a variable not in an extension of a generic type got a null
1755+
// overload type instead of a function type as it does now, so we really
1756+
// follow that behaviour and warn if there's going to be a conflict in future.
1757+
if (!ctx.isSwiftVersionAtLeast(5)) {
1758+
auto swift4Sig1Type = sig1.IsVariable && !sig1.InExtensionOfGenericType
1759+
? CanType()
1760+
: sig1Type;
1761+
auto swift4Sig2Type = sig1.IsVariable && !sig2.InExtensionOfGenericType
1762+
? CanType()
1763+
: sig1Type;
1764+
if (swift4Sig1Type != swift4Sig2Type) {
1765+
// Old was different to the new behaviour!
1766+
if (wouldConflictInSwift5)
1767+
*wouldConflictInSwift5 = true;
1768+
1769+
return false;
1770+
}
1771+
}
1772+
1773+
return true;
17511774
}
17521775

17531776
static Type mapSignatureFunctionType(ASTContext &ctx, Type type,

lib/Sema/TypeCheckDecl.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,6 +1049,17 @@ static void checkRedeclaration(TypeChecker &tc, ValueDecl *current) {
10491049
continue;
10501050
}
10511051

1052+
// If both are VarDecls, and both have exactly the same type, then
1053+
// matching the Swift 4 behaviour (i.e. just emitting the future-compat
1054+
// warning) will result in SILGen crashes due to both properties mangling
1055+
// the same, so it's better to just follow the Swift 5 behaviour and emit
1056+
// the actual error.
1057+
if (wouldBeSwift5Redeclaration && isa<VarDecl>(current) &&
1058+
isa<VarDecl>(other) &&
1059+
current->getInterfaceType()->isEqual(other->getInterfaceType())) {
1060+
wouldBeSwift5Redeclaration = false;
1061+
}
1062+
10521063
// If this isn't a redeclaration in the current version of Swift, but
10531064
// would be in Swift 5 mode, emit a warning instead of an error.
10541065
if (wouldBeSwift5Redeclaration) {

test/IDE/complete_value_expr.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1855,7 +1855,7 @@ func testDeDuped(_ x: dedupS) {
18551855
}
18561856
func testDeDuped2(_ x: dedupP) {
18571857
x#^PROTOCOL_EXT_DEDUP_2^#
1858-
// PROTOCOL_EXT_DEDUP_2: Begin completions, 4 items
1858+
// PROTOCOL_EXT_DEDUP_2: Begin completions, 5 items
18591859
// PROTOCOL_EXT_DEDUP_2: Decl[InstanceMethod]/CurrNominal: .foo()[#dedupP.T#]; name=foo()
18601860
// PROTOCOL_EXT_DEDUP_2: Decl[InstanceVar]/CurrNominal: .bar[#dedupP.T#]; name=bar
18611861
// PROTOCOL_EXT_DEDUP_2: Decl[Subscript]/CurrNominal: [{#Self.T#}][#Self.T#]; name=[Self.T]
@@ -1864,7 +1864,7 @@ func testDeDuped2(_ x: dedupP) {
18641864
}
18651865
func testDeDuped3<T : dedupP where T.T == Int>(_ x: T) {
18661866
x#^PROTOCOL_EXT_DEDUP_3^#
1867-
// PROTOCOL_EXT_DEDUP_3: Begin completions, 4 items
1867+
// PROTOCOL_EXT_DEDUP_3: Begin completions, 5 items
18681868
// PROTOCOL_EXT_DEDUP_3: Decl[InstanceMethod]/Super: .foo()[#Int#]; name=foo()
18691869
// PROTOCOL_EXT_DEDUP_3: Decl[InstanceVar]/Super: .bar[#Int#]; name=bar
18701870
// PROTOCOL_EXT_DEDUP_3: Decl[Subscript]/Super: [{#Self.T#}][#Self.T#]; name=[Self.T]

test/decl/overload.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -448,8 +448,8 @@ struct SR7249<T> {
448448
}
449449

450450
extension SR7249 {
451-
var x: Int { fatalError() } // expected-error{{invalid redeclaration of 'x'}}
452-
var y: T { fatalError() } // expected-error{{invalid redeclaration of 'y'}}
451+
var x: Int { fatalError() } // expected-warning{{redeclaration of 'x' is deprecated and will be an error in Swift 5}}
452+
var y: T { fatalError() } // expected-warning{{redeclaration of 'y' is deprecated and will be an error in Swift 5}}
453453
var z: Int { fatalError() } // expected-error{{invalid redeclaration of 'z'}}
454454
}
455455

test/decl/overload_swift5.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,14 @@ extension SR7251 {
1111
struct k {} // expected-error{{invalid redeclaration of 'k'}}
1212
}
1313

14+
struct SR7249<T> {
15+
var x: T { fatalError() } // expected-note {{previously declared}}
16+
var y: Int // expected-note {{previously declared}}
17+
var z: Int // expected-note {{previously declared}}
18+
}
19+
20+
extension SR7249 {
21+
var x: Int { fatalError() } // expected-error{{invalid redeclaration of 'x'}}
22+
var y: T { fatalError() } // expected-error{{invalid redeclaration of 'y'}}
23+
var z: Int { fatalError() } // expected-error{{invalid redeclaration of 'z'}}
24+
}

0 commit comments

Comments
 (0)