Skip to content

Commit 2d90972

Browse files
committed
fix: preserve exact alias receiver methods in cgen
1 parent 6d601c8 commit 2d90972

2 files changed

Lines changed: 106 additions & 15 deletions

File tree

vlib/v/gen/c/fn.v

Lines changed: 72 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,28 @@ fn (g &Gen) method_decl_fkey(method ast.Fn) string {
121121
return method.fkey()
122122
}
123123

124+
fn (g &Gen) receiver_exact_method_for_type(typ ast.Type, method_name string) ?ast.Fn {
125+
if typ == 0 {
126+
return none
127+
}
128+
sym := g.table.sym(typ)
129+
for method in sym.methods {
130+
if method.name == method_name && method.receiver_type == typ {
131+
return method
132+
}
133+
}
134+
if sym.info is ast.Alias {
135+
parent_type := sym.info.parent_type.derive(typ)
136+
parent_sym := g.table.sym(parent_type)
137+
for method in parent_sym.methods {
138+
if method.name == method_name && method.receiver_type == parent_type {
139+
return method
140+
}
141+
}
142+
}
143+
return none
144+
}
145+
124146
fn (g &Gen) generic_parent_method_fkey(sym ast.TypeSymbol, method_name string) string {
125147
match sym.info {
126148
ast.Struct, ast.Interface, ast.SumType {
@@ -242,6 +264,22 @@ fn (g &Gen) prefers_msvc_compatible_code() bool {
242264

243265
fn (mut g Gen) node_decl_fkey(node ast.FnDecl) string {
244266
if node.is_method && !node.name.contains('_T_') {
267+
if !node.receiver.typ.has_flag(.generic)
268+
&& !g.type_has_unresolved_generic_parts(node.receiver.typ) {
269+
if structured_method := g.table.find_structured_receiver_method_with_types(node.receiver.typ,
270+
node.name)
271+
{
272+
if structured_method.method.receiver_type != node.receiver.typ {
273+
if exact_method := g.receiver_exact_method_for_type(node.receiver.typ,
274+
node.name)
275+
{
276+
if g.method_decl_fkey(exact_method) == node.fkey() {
277+
return node.fkey()
278+
}
279+
}
280+
}
281+
}
282+
}
245283
receiver_sym := g.table.sym(node.receiver.typ)
246284
receiver_has_concrete_generics := match receiver_sym.info {
247285
ast.Struct, ast.Interface, ast.SumType {
@@ -755,6 +793,20 @@ fn (mut g Gen) is_used_by_main(node ast.FnDecl) bool {
755793
}
756794
fkey := g.node_decl_fkey(node)
757795
is_used_by_main = g.table.used_features.used_fns[fkey]
796+
if !is_used_by_main && node.is_method && !node.receiver.typ.has_flag(.generic)
797+
&& !g.type_has_unresolved_generic_parts(node.receiver.typ) {
798+
if structured_method := g.table.find_structured_receiver_method_with_types(node.receiver.typ,
799+
node.name)
800+
{
801+
if structured_method.method.receiver_type != node.receiver.typ {
802+
if exact_method := g.receiver_exact_method_for_type(node.receiver.typ,
803+
node.name)
804+
{
805+
is_used_by_main = g.method_decl_fkey(exact_method) == node.fkey()
806+
}
807+
}
808+
}
809+
}
758810
if !is_used_by_main && g.effective_fn_generic_names(node).len > 0
759811
&& g.table.fn_generic_types[fkey].len > 0 {
760812
is_used_by_main = true
@@ -3411,21 +3463,19 @@ fn (mut g Gen) resolve_receiver_name(node ast.CallExpr, unwrapped_rec_type ast.T
34113463
}
34123464

34133465
fn (mut g Gen) receiver_generic_call_context(left_type ast.Type, method_name string) ([]ast.Type, ast.Fn) {
3466+
mut exact_method := ast.Fn{}
34143467
mut exact_method_exists := false
34153468
if left_type != 0 {
3416-
if exact_method := g.table.sym(left_type).find_method(method_name) {
3417-
exact_method_exists = exact_method.name == method_name
3418-
} else if exact_method := g.table.find_alias_parent_exact_method(left_type, method_name) {
3419-
exact_method_exists = exact_method.name == method_name
3469+
if method := g.receiver_exact_method_for_type(left_type, method_name) {
3470+
exact_method = method
3471+
exact_method_exists = true
34203472
}
34213473
}
3422-
mut structured_method_for_exact := ast.Fn{}
34233474
mut has_structured_method_for_exact := false
34243475
if structured_method := g.table.find_structured_receiver_method_with_types(left_type,
34253476
method_name)
34263477
{
34273478
if exact_method_exists {
3428-
structured_method_for_exact = structured_method.method
34293479
has_structured_method_for_exact = true
34303480
} else {
34313481
return structured_method.concrete_types.map(g.unwrap_generic(it)), structured_method.method
@@ -3434,6 +3484,9 @@ fn (mut g Gen) receiver_generic_call_context(left_type ast.Type, method_name str
34343484
rec_sym := g.table.final_sym(left_type)
34353485
mut receiver_concrete_types := []ast.Type{}
34363486
mut parent_method := ast.Fn{}
3487+
if has_structured_method_for_exact {
3488+
parent_method = exact_method
3489+
}
34373490
match rec_sym.info {
34383491
ast.Struct, ast.Interface, ast.SumType {
34393492
if rec_sym.info.concrete_types.len > 0 {
@@ -3445,8 +3498,7 @@ fn (mut g Gen) receiver_generic_call_context(left_type ast.Type, method_name str
34453498
if rec_sym.info.parent_type.has_flag(.generic) {
34463499
parent_sym := g.table.sym(rec_sym.info.parent_type)
34473500
if m := parent_sym.find_method(method_name) {
3448-
if !has_structured_method_for_exact
3449-
|| m.fkey() != structured_method_for_exact.fkey() {
3501+
if !has_structured_method_for_exact {
34503502
parent_method = m
34513503
}
34523504
}
@@ -3457,8 +3509,7 @@ fn (mut g Gen) receiver_generic_call_context(left_type ast.Type, method_name str
34573509
if rec_sym.info.parent_idx > 0 {
34583510
parent_sym := g.table.sym(ast.idx_to_type(rec_sym.info.parent_idx))
34593511
if m := parent_sym.find_method(method_name) {
3460-
if !has_structured_method_for_exact
3461-
|| m.fkey() != structured_method_for_exact.fkey() {
3512+
if !has_structured_method_for_exact {
34623513
parent_method = m
34633514
}
34643515
}
@@ -3477,8 +3528,7 @@ fn (mut g Gen) receiver_generic_call_context(left_type ast.Type, method_name str
34773528
if non_final_sym.info.parent_idx > 0 {
34783529
parent_sym := g.table.sym(ast.idx_to_type(non_final_sym.info.parent_idx))
34793530
if m := parent_sym.find_method(method_name) {
3480-
if !has_structured_method_for_exact
3481-
|| m.fkey() != structured_method_for_exact.fkey() {
3531+
if !has_structured_method_for_exact {
34823532
parent_method = m
34833533
}
34843534
}
@@ -3490,8 +3540,7 @@ fn (mut g Gen) receiver_generic_call_context(left_type ast.Type, method_name str
34903540
receiver_concrete_types = non_final_sym.generic_types.map(g.unwrap_generic(it))
34913541
parent_sym := g.table.sym(ast.idx_to_type(non_final_sym.parent_idx))
34923542
if m := parent_sym.find_method(method_name) {
3493-
if !has_structured_method_for_exact
3494-
|| m.fkey() != structured_method_for_exact.fkey() {
3543+
if !has_structured_method_for_exact {
34953544
parent_method = m
34963545
}
34973546
}
@@ -5210,7 +5259,15 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
52105259
}
52115260
}
52125261
concrete_types = concrete_types.filter(it != ast.void_type)
5213-
mut name_fkey := g.resolve_method_decl_fkey_for_type(left_type, method_name)
5262+
mut name_fkey := ''
5263+
if _ := g.table.find_structured_receiver_method_with_types(left_type, method_name) {
5264+
if exact_method := g.receiver_exact_method_for_type(left_type, method_name) {
5265+
name_fkey = g.method_decl_fkey(exact_method)
5266+
}
5267+
}
5268+
if name_fkey == '' {
5269+
name_fkey = g.resolve_method_decl_fkey_for_type(left_type, method_name)
5270+
}
52145271
if name_fkey == '' {
52155272
name_fkey = g.method_decl_fkey(full_method)
52165273
}

vlib/v/tests/generics/structured_generic_receiver_declaration_test.v

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,24 @@ fn (e ReceiverPatternExpect[map[K]V]) map_receiver_pattern_pairs_with_method_gen
6666
return value, extra
6767
}
6868

69+
fn (e ReceiverPatternExpect[map[K]V]) same_name_map_exact_prefers_concrete[U](extra U) string {
70+
_ = extra
71+
return 'pattern'
72+
}
73+
74+
fn (e ReceiverPatternExpect[map[string]int]) same_name_map_exact_prefers_concrete[U](extra U) string {
75+
_ = extra
76+
return 'concrete'
77+
}
78+
79+
fn (e ReceiverPatternExpect[map[K]V]) same_name_map_method() string {
80+
return 'pattern'
81+
}
82+
83+
fn (e ReceiverPatternExpect[map[string]int]) same_name_map_method() string {
84+
return 'concrete'
85+
}
86+
6987
fn (b MixedReceiverPatternBox[T, []U]) mixed_receiver_pattern_values_with_method_generic[V](fallback U,
7088
marker V) (T, U, V) {
7189
if b.items.len == 0 {
@@ -207,6 +225,22 @@ fn test_alias_to_map_receiver_pattern_binds_key_and_value_types() {
207225
assert extra
208226
}
209227

228+
fn test_alias_to_map_exact_generic_method_takes_precedence_over_structured_pattern() {
229+
assert StringIntMapExpect{
230+
value: {
231+
'one': 1
232+
}
233+
}.same_name_map_exact_prefers_concrete('alias') == 'concrete'
234+
}
235+
236+
fn test_alias_to_map_exact_method_takes_precedence_over_structured_pattern() {
237+
assert StringIntMapExpect{
238+
value: {
239+
'one': 1
240+
}
241+
}.same_name_map_method() == 'concrete'
242+
}
243+
210244
fn test_alias_receiver_exact_method_takes_precedence_over_structured_pattern() {
211245
assert IntListExpect{
212246
value: [1, 2, 3]

0 commit comments

Comments
 (0)