Skip to content

Commit 8867b9d

Browse files
committed
[CSRanking] Favour members on concrete types over protocol members
This commit adds a new rule to `isDeclAsSpecializedAs` in order to favour a member on a concrete type over a protocol member. This rule is effectively an extension of the existing rule that prefers concrete type members over protocol extension members.
1 parent 15ada53 commit 8867b9d

File tree

3 files changed

+137
-11
lines changed

3 files changed

+137
-11
lines changed

lib/Sema/CSRanking.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,18 @@ static bool isDeclAsSpecializedAs(TypeChecker &tc, DeclContext *dc,
446446
return inProtocolExtension2;
447447
}
448448

449+
// A concrete type member is always more specialised than a protocol
450+
// member (bearing in mind that we have already handled the case where
451+
// exactly one member is in a protocol extension). Only apply this rule in
452+
// Swift 5 mode to better maintain source compatibility under Swift 4
453+
// mode.
454+
if (tc.Context.isSwiftVersionAtLeast(5)) {
455+
auto *proto1 = dyn_cast<ProtocolDecl>(outerDC1);
456+
auto *proto2 = dyn_cast<ProtocolDecl>(outerDC2);
457+
if (proto1 != proto2)
458+
return proto2;
459+
}
460+
449461
Type type1 = decl1->getInterfaceType();
450462
Type type2 = decl2->getInterfaceType();
451463

test/Constraints/ranking.swift

Lines changed: 114 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-emit-silgen %s -verify | %FileCheck %s
1+
// RUN: %target-swift-emit-silgen %s -verify -swift-version 5 | %FileCheck %s
22

33
protocol P {
44
var p: P { get set }
@@ -155,3 +155,116 @@ func testDerived(b: B) {
155155
f0(f1(b))
156156
// CHECK: end sil function '$S7ranking11testDerived1byAA1BC_tF'
157157
}
158+
159+
protocol X {
160+
var foo: Int { get }
161+
var bar: Int { get }
162+
func baz() -> Int
163+
subscript(foo: String) -> Int { get }
164+
}
165+
166+
class Y {
167+
var foo: Int = 0
168+
func baz() -> Int { return foo }
169+
subscript(foo: String) -> Int { return 0 }
170+
}
171+
extension Y {
172+
var bar: Int { return foo }
173+
}
174+
175+
protocol Z : Y {
176+
var foo: Int { get }
177+
var bar: Int { get }
178+
func baz() -> Int
179+
subscript(foo: String) -> Int { get }
180+
}
181+
182+
class GenericClass<T> {
183+
var foo: T
184+
init(_ foo: T) { self.foo = foo }
185+
func baz() -> T { return foo }
186+
}
187+
extension GenericClass {
188+
var bar: T { return foo }
189+
subscript(foo: String) -> Int { return 0 }
190+
}
191+
192+
// Make sure we favour the class implementation over the protocol requirement.
193+
194+
// CHECK-LABEL: sil hidden @$S7ranking32testGenericPropertyProtocolClassyyxAA1YCRbzAA1XRzlF
195+
func testGenericPropertyProtocolClass<T : X & Y>(_ t: T) {
196+
_ = t.foo // CHECK: class_method {{%.*}} : $Y, #Y.foo!getter.1
197+
_ = t.bar // CHECK: function_ref @$S7ranking1YC3barSivg
198+
_ = t.baz() // CHECK: class_method {{%.*}} : $Y, #Y.baz
199+
_ = t[""] // CHECK: class_method {{%.*}} : $Y, #Y.subscript!getter.1
200+
}
201+
202+
// CHECK-LABEL: sil hidden @$S7ranking36testExistentialPropertyProtocolClassyyAA1X_AA1YCXcF
203+
func testExistentialPropertyProtocolClass(_ t: X & Y) {
204+
_ = t.foo // CHECK: class_method {{%.*}} : $Y, #Y.foo!getter.1
205+
_ = t.bar // CHECK: function_ref @$S7ranking1YC3barSivg
206+
_ = t.baz() // CHECK: class_method {{%.*}} : $Y, #Y.baz
207+
_ = t[""] // CHECK: class_method {{%.*}} : $Y, #Y.subscript!getter.1
208+
}
209+
210+
// CHECK-LABEL: sil hidden @$S7ranking46testGenericPropertySubclassConstrainedProtocolyyxAA1ZRzlF
211+
func testGenericPropertySubclassConstrainedProtocol<T : Z>(_ t: T) {
212+
_ = t.foo // CHECK: class_method {{%.*}} : $Y, #Y.foo!getter.1
213+
_ = t.bar // CHECK: function_ref @$S7ranking1YC3barSivg
214+
_ = t.baz() // CHECK: class_method {{%.*}} : $Y, #Y.baz
215+
_ = t[""] // CHECK: class_method {{%.*}} : $Y, #Y.subscript!getter.1
216+
}
217+
218+
// CHECK-LABEL: sil hidden @$S7ranking50testExistentialPropertySubclassConstrainedProtocolyyAA1Z_pF
219+
func testExistentialPropertySubclassConstrainedProtocol(_ t: Z) {
220+
_ = t.foo // CHECK: class_method {{%.*}} : $Y, #Y.foo!getter.1
221+
_ = t.bar // CHECK: function_ref @$S7ranking1YC3barSivg
222+
_ = t.baz() // CHECK: class_method {{%.*}} : $Y, #Y.baz
223+
_ = t[""] // CHECK: class_method {{%.*}} : $Y, #Y.subscript!getter.1
224+
}
225+
226+
// CHECK-LABEL: sil hidden @$S7ranking43testExistentialPropertyProtocolGenericClassyyAA1X_AA0fG0CySiGXcF
227+
func testExistentialPropertyProtocolGenericClass(_ t: GenericClass<Int> & X) {
228+
_ = t.foo // CHECK: class_method {{%.*}} : $GenericClass<Int>, #GenericClass.foo!getter.1
229+
_ = t.bar // CHECK: function_ref @$S7ranking12GenericClassC3barxvg
230+
_ = t.baz() // CHECK: class_method {{%.*}} : $GenericClass<Int>, #GenericClass.baz
231+
_ = t[""] // CHECK: function_ref @$S7ranking12GenericClassCySiSScig
232+
}
233+
234+
// CHECK-LABEL: sil hidden @$S7ranking43testExistentialPropertyProtocolGenericClassyyAA1X_AA0fG0CySSGXcF
235+
func testExistentialPropertyProtocolGenericClass(_ t: GenericClass<String> & X) {
236+
_ = t.foo // CHECK: class_method {{%.*}} : $GenericClass<String>, #GenericClass.foo!getter.1
237+
_ = t.bar // CHECK: function_ref @$S7ranking12GenericClassC3barxvg
238+
_ = t.baz() // CHECK: class_method {{%.*}} : $GenericClass<String>, #GenericClass.baz
239+
_ = t[""] // CHECK: function_ref @$S7ranking12GenericClassCySiSScig
240+
}
241+
242+
extension X where Self : Y {
243+
// CHECK-LABEL: sil hidden @$S7ranking1XPA2A1YCRbzrlE32testGenericPropertyProtocolClassyyxF
244+
func testGenericPropertyProtocolClass(_ x: Self) {
245+
_ = self.foo // CHECK: class_method {{%.*}} : $Y, #Y.foo!getter.1
246+
_ = self.bar // CHECK: function_ref @$S7ranking1YC3barSivg
247+
_ = self.baz() // CHECK: class_method {{%.*}} : $Y, #Y.baz
248+
_ = self[""] // CHECK: class_method {{%.*}} : $Y, #Y.subscript!getter.1
249+
}
250+
}
251+
252+
extension X where Self : GenericClass<Int> {
253+
// CHECK-LABEL: sil hidden @$S7ranking1XPA2A12GenericClassCySiGRbzrlE04testb16PropertyProtocolbC0yyxF
254+
func testGenericPropertyProtocolGenericClass(_ x: Self) {
255+
_ = self.foo // CHECK: class_method {{%.*}} : $GenericClass<Int>, #GenericClass.foo!getter.1
256+
_ = self.bar // CHECK: function_ref @$S7ranking12GenericClassC3barxvg
257+
_ = self.baz() // CHECK: class_method {{%.*}} : $GenericClass<Int>, #GenericClass.baz
258+
_ = self[""] // CHECK: function_ref @$S7ranking12GenericClassCySiSScig
259+
}
260+
}
261+
262+
extension X where Self : GenericClass<String> {
263+
// CHECK-LABEL: sil hidden @$S7ranking1XPA2A12GenericClassCySSGRbzrlE04testb16PropertyProtocolbC0yyxF
264+
func testGenericPropertyProtocolGenericClass(_ x: Self) {
265+
_ = self.foo // CHECK: class_method {{%.*}} : $GenericClass<String>, #GenericClass.foo!getter.1
266+
_ = self.bar // CHECK: function_ref @$S7ranking12GenericClassC3barxvg
267+
_ = self.baz() // CHECK: class_method {{%.*}} : $GenericClass<String>, #GenericClass.baz
268+
_ = self[""] // CHECK: function_ref @$S7ranking12GenericClassCySiSScig
269+
}
270+
}

test/Constraints/rdar39401774.swift

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
// RUN: %target-typecheck-verify-swift
1+
// RUN: %target-typecheck-verify-swift -swift-version 5
22

33
class A<T> {
4-
var foo: Int? { return 42 } // expected-note {{found this candidate}}
5-
func baz() -> T { fatalError() } // expected-note {{found this candidate}}
6-
func fiz() -> Int { return 42 } // expected-note {{found this candidate}}
4+
var foo: Int? { return 42 }
5+
func baz() -> T { fatalError() }
6+
func fiz() -> Int { return 42 }
77
}
88

99
protocol P1 {
1010
associatedtype T
11-
var foo: Int? { get } // expected-note {{found this candidate}}
12-
func baz() -> T // expected-note {{found this candidate}}
13-
func fiz() -> Int // expected-note {{found this candidate}}
11+
var foo: Int? { get }
12+
func baz() -> T
13+
func fiz() -> Int
1414
}
1515

1616
protocol P2 : P1 {
@@ -19,8 +19,9 @@ protocol P2 : P1 {
1919

2020
extension P2 where Self: A<Int> {
2121
var bar: Int? {
22-
guard let foo = foo else { return 0 } // expected-error {{ambiguous use of 'foo'}}
23-
let _ = baz() // expected-error {{ambiguous use of 'baz()'}}
24-
return fiz() // expected-error {{ambiguous use of 'fiz()'}}
22+
guard let foo = foo else { return 0 }
23+
_ = foo
24+
let _ = baz()
25+
return fiz()
2526
}
2627
}

0 commit comments

Comments
 (0)