checker: check fn return type mismatch (#14081)
parent
4400efeb9f
commit
6164654d11
|
@ -32,7 +32,8 @@ pub fn (mut c Checker) return_stmt(mut node ast.Return) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mut got_types := []ast.Type{}
|
mut got_types := []ast.Type{}
|
||||||
for expr in node.exprs {
|
mut expr_idxs := []int{}
|
||||||
|
for i, expr in node.exprs {
|
||||||
typ := c.expr(expr)
|
typ := c.expr(expr)
|
||||||
if typ == ast.void_type {
|
if typ == ast.void_type {
|
||||||
c.error('`$expr` used as value', node.pos)
|
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 {
|
if sym.kind == .multi_return {
|
||||||
for t in sym.mr_info().types {
|
for t in sym.mr_info().types {
|
||||||
got_types << t
|
got_types << t
|
||||||
|
expr_idxs << i
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
got_types << typ
|
got_types << typ
|
||||||
|
expr_idxs << i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
node.types = got_types
|
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])
|
got_typ := c.unwrap_generic(got_types[i])
|
||||||
if got_typ.has_flag(.optional) && (!exp_type.has_flag(.optional)
|
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)) {
|
|| 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',
|
c.error('cannot use `${c.table.type_to_str(got_typ)}` as type `${c.table.type_to_str(exp_type)}` in return argument',
|
||||||
pos)
|
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 c.type_implements(got_typ, exp_type, node.pos) {
|
||||||
if !got_typ.is_ptr() && !got_typ.is_pointer() && got_typ_sym.kind != .interface_
|
if !got_typ.is_ptr() && !got_typ.is_pointer() && got_typ_sym.kind != .interface_
|
||||||
&& !c.inside_unsafe {
|
&& !c.inside_unsafe {
|
||||||
c.mark_as_referenced(mut &node.exprs[i], true)
|
c.mark_as_referenced(mut &node.exprs[expr_idxs[i]], true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue
|
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',
|
c.error('cannot use `$got_typ_sym.name` as type `${c.table.type_to_str(exp_type)}` in return argument',
|
||||||
pos)
|
pos)
|
||||||
}
|
}
|
||||||
if (got_typ.is_ptr() || got_typ.is_pointer())
|
if (got_typ.is_ptr() || got_typ.is_pointer())
|
||||||
&& (!exp_type.is_ptr() && !exp_type.is_pointer()) {
|
&& (!exp_type.is_ptr() && !exp_type.is_pointer()) {
|
||||||
pos := node.exprs[i].pos()
|
pos := node.exprs[expr_idxs[i]].pos()
|
||||||
if node.exprs[i].is_auto_deref_var() {
|
if node.exprs[expr_idxs[i]].is_auto_deref_var() {
|
||||||
continue
|
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',
|
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())
|
if (exp_type.is_ptr() || exp_type.is_pointer())
|
||||||
&& (!got_typ.is_ptr() && !got_typ.is_pointer()) && got_typ != ast.int_literal_type
|
&& (!got_typ.is_ptr() && !got_typ.is_pointer()) && got_typ != ast.int_literal_type
|
||||||
&& !c.pref.translated && !c.file.is_translated {
|
&& !c.pref.translated && !c.file.is_translated {
|
||||||
pos := node.exprs[i].pos()
|
pos := node.exprs[expr_idxs[i]].pos()
|
||||||
if node.exprs[i].is_auto_deref_var() {
|
if node.exprs[expr_idxs[i]].is_auto_deref_var() {
|
||||||
continue
|
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',
|
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',
|
||||||
|
|
|
@ -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 |
|
|
@ -0,0 +1,9 @@
|
||||||
|
fn func1() (i64, i64) {
|
||||||
|
return i64(1), i64(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn func2() (int, int) {
|
||||||
|
return func1()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
Loading…
Reference in New Issue