checker: check fn return type mismatch (#14081)

yuyi 2022-04-19 18:04:41 +08:00 committed by Jef Roosens
parent f291e5fdd8
commit 33005becf1
Signed by: Jef Roosens
GPG Key ID: B75D4F293C7052DB
3 changed files with 27 additions and 8 deletions

View File

@ -32,7 +32,8 @@ pub fn (mut c Checker) return_stmt(mut node ast.Return) {
}
}
mut got_types := []ast.Type{}
for expr in node.exprs {
mut expr_idxs := []int{}
for i, expr in node.exprs {
typ := c.expr(expr)
if typ == ast.void_type {
c.error('`$expr` used as value', node.pos)
@ -42,9 +43,11 @@ pub fn (mut c Checker) return_stmt(mut node ast.Return) {
if sym.kind == .multi_return {
for t in sym.mr_info().types {
got_types << t
expr_idxs << i
}
} else {
got_types << typ
expr_idxs << i
}
}
node.types = got_types
@ -82,7 +85,7 @@ pub fn (mut c Checker) return_stmt(mut node ast.Return) {
got_typ := c.unwrap_generic(got_types[i])
if got_typ.has_flag(.optional) && (!exp_type.has_flag(.optional)
|| c.table.type_to_str(got_typ) != c.table.type_to_str(exp_type)) {
pos := node.exprs[i].pos()
pos := node.exprs[expr_idxs[i]].pos()
c.error('cannot use `${c.table.type_to_str(got_typ)}` as type `${c.table.type_to_str(exp_type)}` in return argument',
pos)
}
@ -93,19 +96,19 @@ pub fn (mut c Checker) return_stmt(mut node ast.Return) {
if c.type_implements(got_typ, exp_type, node.pos) {
if !got_typ.is_ptr() && !got_typ.is_pointer() && got_typ_sym.kind != .interface_
&& !c.inside_unsafe {
c.mark_as_referenced(mut &node.exprs[i], true)
c.mark_as_referenced(mut &node.exprs[expr_idxs[i]], true)
}
}
continue
}
pos := node.exprs[i].pos()
pos := node.exprs[expr_idxs[i]].pos()
c.error('cannot use `$got_typ_sym.name` as type `${c.table.type_to_str(exp_type)}` in return argument',
pos)
}
if (got_typ.is_ptr() || got_typ.is_pointer())
&& (!exp_type.is_ptr() && !exp_type.is_pointer()) {
pos := node.exprs[i].pos()
if node.exprs[i].is_auto_deref_var() {
pos := node.exprs[expr_idxs[i]].pos()
if node.exprs[expr_idxs[i]].is_auto_deref_var() {
continue
}
c.error('fn `$c.table.cur_fn.name` expects you to return a non reference type `${c.table.type_to_str(exp_type)}`, but you are returning `${c.table.type_to_str(got_typ)}` instead',
@ -114,8 +117,8 @@ pub fn (mut c Checker) return_stmt(mut node ast.Return) {
if (exp_type.is_ptr() || exp_type.is_pointer())
&& (!got_typ.is_ptr() && !got_typ.is_pointer()) && got_typ != ast.int_literal_type
&& !c.pref.translated && !c.file.is_translated {
pos := node.exprs[i].pos()
if node.exprs[i].is_auto_deref_var() {
pos := node.exprs[expr_idxs[i]].pos()
if node.exprs[expr_idxs[i]].is_auto_deref_var() {
continue
}
c.error('fn `$c.table.cur_fn.name` expects you to return a reference type `${c.table.type_to_str(exp_type)}`, but you are returning `${c.table.type_to_str(got_typ)}` instead',

View File

@ -0,0 +1,7 @@
vlib/v/checker/tests/fn_return_type_mismatch.vv:6:9: error: cannot use `i64` as type `int` in return argument
4 |
5 | fn func2() (int, int) {
6 | return func1()
| ~~~~~~~
7 | }
8 |

View File

@ -0,0 +1,9 @@
fn func1() (i64, i64) {
return i64(1), i64(2)
}
fn func2() (int, int) {
return func1()
}
fn main() {}