Skip to content

Commit 4741777

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 be4c33d commit 4741777

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
@@ -1768,7 +1768,30 @@ bool swift::conflicting(ASTContext &ctx,
17681768
}
17691769

17701770
// Otherwise, the declarations conflict if the overload types are the same.
1771-
return sig1Type == sig2Type;
1771+
if (sig1Type != sig2Type)
1772+
return false;
1773+
1774+
// The Swift 5 overload types are the same, but similar to the above, prior to
1775+
// Swift 5, a variable not in an extension of a generic type got a null
1776+
// overload type instead of a function type as it does now, so we really
1777+
// follow that behaviour and warn if there's going to be a conflict in future.
1778+
if (!ctx.isSwiftVersionAtLeast(5)) {
1779+
auto swift4Sig1Type = sig1.IsVariable && !sig1.InExtensionOfGenericType
1780+
? CanType()
1781+
: sig1Type;
1782+
auto swift4Sig2Type = sig1.IsVariable && !sig2.InExtensionOfGenericType
1783+
? CanType()
1784+
: sig1Type;
1785+
if (swift4Sig1Type != swift4Sig2Type) {
1786+
// Old was different to the new behaviour!
1787+
if (wouldConflictInSwift5)
1788+
*wouldConflictInSwift5 = true;
1789+
1790+
return false;
1791+
}
1792+
}
1793+
1794+
return true;
17721795
}
17731796

17741797
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
@@ -1063,6 +1063,17 @@ static void checkRedeclaration(TypeChecker &tc, ValueDecl *current) {
10631063
continue;
10641064
}
10651065

1066+
// If both are VarDecls, and both have exactly the same type, then
1067+
// matching the Swift 4 behaviour (i.e. just emitting the future-compat
1068+
// warning) will result in SILGen crashes due to both properties mangling
1069+
// the same, so it's better to just follow the Swift 5 behaviour and emit
1070+
// the actual error.
1071+
if (wouldBeSwift5Redeclaration && isa<VarDecl>(current) &&
1072+
isa<VarDecl>(other) &&
1073+
current->getInterfaceType()->isEqual(other->getInterfaceType())) {
1074+
wouldBeSwift5Redeclaration = false;
1075+
}
1076+
10661077
// If this isn't a redeclaration in the current version of Swift, but
10671078
// would be in Swift 5 mode, emit a warning instead of an error.
10681079
if (wouldBeSwift5Redeclaration) {

test/IDE/complete_value_expr.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1656,15 +1656,15 @@ func testDeDuped(_ x: dedupS) {
16561656
}
16571657
func testDeDuped2(_ x: dedupP) {
16581658
x#^PROTOCOL_EXT_DEDUP_2^#
1659-
// PROTOCOL_EXT_DEDUP_2: Begin completions, 3 items
1659+
// PROTOCOL_EXT_DEDUP_2: Begin completions, 4 items
16601660
// PROTOCOL_EXT_DEDUP_2: Decl[InstanceMethod]/CurrNominal: .foo()[#dedupP.T#]; name=foo()
16611661
// PROTOCOL_EXT_DEDUP_2: Decl[InstanceVar]/CurrNominal: .bar[#dedupP.T#]; name=bar
16621662
// PROTOCOL_EXT_DEDUP_2: Decl[Subscript]/CurrNominal: [{#Self.T#}][#Self.T#]; name=[Self.T]
16631663
// PROTOCOL_EXT_DEDUP_2: End completions
16641664
}
16651665
func testDeDuped3<T : dedupP where T.T == Int>(_ x: T) {
16661666
x#^PROTOCOL_EXT_DEDUP_3^#
1667-
// PROTOCOL_EXT_DEDUP_3: Begin completions, 3 items
1667+
// PROTOCOL_EXT_DEDUP_3: Begin completions, 4 items
16681668
// PROTOCOL_EXT_DEDUP_3: Decl[InstanceMethod]/Super: .foo()[#Int#]; name=foo()
16691669
// PROTOCOL_EXT_DEDUP_3: Decl[InstanceVar]/Super: .bar[#Int#]; name=bar
16701670
// 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)