Skip to content

Commit ce1ba2a

Browse files
authored
checker: check fn returning fn type mismatch (fix #15988) (#15997)
1 parent 49aac93 commit ce1ba2a

File tree

4 files changed

+59
-9
lines changed

4 files changed

+59
-9
lines changed

vlib/v/checker/check_types.v

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -384,8 +384,10 @@ pub fn (mut c Checker) check_matching_function_symbols(got_type_sym &ast.TypeSym
384384
}
385385
for i, got_arg in got_fn.params {
386386
exp_arg := exp_fn.params[i]
387-
exp_arg_is_ptr := exp_arg.typ.is_ptr() || exp_arg.typ.is_pointer()
388-
got_arg_is_ptr := got_arg.typ.is_ptr() || got_arg.typ.is_pointer()
387+
exp_arg_typ := c.unwrap_generic(exp_arg.typ)
388+
got_arg_typ := c.unwrap_generic(got_arg.typ)
389+
exp_arg_is_ptr := exp_arg_typ.is_ptr() || exp_arg_typ.is_pointer()
390+
got_arg_is_ptr := got_arg_typ.is_ptr() || got_arg_typ.is_pointer()
389391
if exp_arg_is_ptr != got_arg_is_ptr {
390392
exp_arg_pointedness := if exp_arg_is_ptr { 'a pointer' } else { 'NOT a pointer' }
391393
got_arg_pointedness := if got_arg_is_ptr { 'a pointer' } else { 'NOT a pointer' }
@@ -397,9 +399,11 @@ pub fn (mut c Checker) check_matching_function_symbols(got_type_sym &ast.TypeSym
397399
}
398400
return false
399401
} else if exp_arg_is_ptr && got_arg_is_ptr {
400-
continue
402+
if exp_arg_typ.is_pointer() || got_arg_typ.is_pointer() {
403+
continue
404+
}
401405
}
402-
if got_arg.typ != exp_arg.typ {
406+
if c.table.unaliased_type(got_arg_typ).idx() != c.table.unaliased_type(exp_arg_typ).idx() {
403407
return false
404408
}
405409
}

vlib/v/checker/return.v

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -134,12 +134,12 @@ pub fn (mut c Checker) return_stmt(mut node ast.Return) {
134134
}
135135
continue
136136
}
137-
if got_typ_sym.kind == .function && exp_typ_sym.kind == .function {
138-
if (got_typ_sym.info as ast.FnType).is_anon {
139-
continue
140-
}
137+
got_typ_name := if got_typ_sym.kind == .function {
138+
'${c.table.type_to_str(got_typ)}'
139+
} else {
140+
got_typ_sym.name
141141
}
142-
c.error('cannot use `$got_typ_sym.name` as type `${c.table.type_to_str(exp_type)}` in return argument',
142+
c.error('cannot use `$got_typ_name` as type `${c.table.type_to_str(exp_type)}` in return argument',
143143
pos)
144144
}
145145
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
vlib/v/checker/tests/fn_return_fn_type_mismatch_err.vv:22:9: error: cannot use `fn (&WrongType, i64, u64) int` as type `fn (&ExpectedType, i64, u64) int` in return argument
2+
20 | pub fn bad_signature() Fn {
3+
21 | // create closure that has nonmatching signature due to first arg. Compiler should reject it
4+
22 | return fn (n &WrongType, a i64, b u64) int {
5+
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
6+
23 | println('bad signature param0=$n')
7+
24 | return 0
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
pub struct ExpectedType {
2+
a u32
3+
b u32
4+
}
5+
6+
struct WrongType {
7+
c string
8+
d int
9+
}
10+
11+
pub type Fn = fn (&ExpectedType, i64, u64) int
12+
13+
pub fn good_signature() Fn {
14+
return fn (n &ExpectedType, a i64, b u64) int {
15+
println('good signature param0=$n')
16+
return 0
17+
}
18+
}
19+
20+
pub fn bad_signature() Fn {
21+
// create closure that has nonmatching signature due to first arg. Compiler should reject it
22+
return fn (n &WrongType, a i64, b u64) int {
23+
println('bad signature param0=$n')
24+
return 0
25+
}
26+
}
27+
28+
fn main() {
29+
arg := &ExpectedType{
30+
a: 3
31+
b: 7
32+
}
33+
34+
mut cb := good_signature()
35+
cb(arg, 1, 1)
36+
37+
cb = bad_signature()
38+
cb(arg, 1, 1)
39+
}

0 commit comments

Comments
 (0)