mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
checker: fix and improve return stmt error messages (#17477)
This commit is contained in:
parent
c5832379e7
commit
72cbca9653
|
@ -5,6 +5,21 @@ module checker
|
||||||
import v.ast
|
import v.ast
|
||||||
import v.pref
|
import v.pref
|
||||||
|
|
||||||
|
// error_type_name returns a proper type name reference for error messages
|
||||||
|
// ? => Option type
|
||||||
|
// ! => Result type
|
||||||
|
// others => type `name`
|
||||||
|
[inline]
|
||||||
|
fn (mut c Checker) error_type_name(exp_type ast.Type) string {
|
||||||
|
return if exp_type == ast.void_type.set_flag(.result) {
|
||||||
|
'Result type'
|
||||||
|
} else if exp_type == ast.void_type.set_flag(.option) {
|
||||||
|
'Option type'
|
||||||
|
} else {
|
||||||
|
'type `${c.table.type_to_str(exp_type)}`'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: non deferred
|
// TODO: non deferred
|
||||||
fn (mut c Checker) return_stmt(mut node ast.Return) {
|
fn (mut c Checker) return_stmt(mut node ast.Return) {
|
||||||
if c.table.cur_fn == unsafe { nil } {
|
if c.table.cur_fn == unsafe { nil } {
|
||||||
|
@ -22,6 +37,12 @@ fn (mut c Checker) return_stmt(mut node ast.Return) {
|
||||||
if node.exprs.len > 0 && c.table.cur_fn.return_type == ast.void_type {
|
if node.exprs.len > 0 && c.table.cur_fn.return_type == ast.void_type {
|
||||||
c.error('unexpected argument, current function does not return anything', node.exprs[0].pos())
|
c.error('unexpected argument, current function does not return anything', node.exprs[0].pos())
|
||||||
return
|
return
|
||||||
|
} else if node.exprs.len > 1 && c.table.cur_fn.return_type == ast.void_type.set_flag(.option) {
|
||||||
|
c.error('can only return `none` from an Option-only return function', node.exprs[0].pos())
|
||||||
|
return
|
||||||
|
} else if node.exprs.len > 1 && c.table.cur_fn.return_type == ast.void_type.set_flag(.result) {
|
||||||
|
c.error('functions with Result-only return types can only return an error', node.exprs[0].pos())
|
||||||
|
return
|
||||||
} else if node.exprs.len == 0 && !(c.expected_type == ast.void_type
|
} else if node.exprs.len == 0 && !(c.expected_type == ast.void_type
|
||||||
|| expected_type_sym.kind == .void) {
|
|| expected_type_sym.kind == .void) {
|
||||||
stype := c.table.type_to_str(expected_type)
|
stype := c.table.type_to_str(expected_type)
|
||||||
|
@ -100,7 +121,7 @@ fn (mut c Checker) return_stmt(mut node ast.Return) {
|
||||||
c.warn('Option and Result types have been split, use `!Foo` to return errors',
|
c.warn('Option and Result types have been split, use `!Foo` to return errors',
|
||||||
node.pos)
|
node.pos)
|
||||||
} else if exp_is_result && got_types_0_idx == ast.none_type_idx {
|
} else if exp_is_result && got_types_0_idx == ast.none_type_idx {
|
||||||
c.warn('Option and Result types have been split, use `?Foo` to return none', node.pos)
|
c.warn('Option and Result types have been split, use `?` to return none', node.pos)
|
||||||
}
|
}
|
||||||
if (exp_is_option
|
if (exp_is_option
|
||||||
&& got_types_0_idx in [ast.none_type_idx, ast.error_type_idx, option_type_idx])
|
&& got_types_0_idx in [ast.none_type_idx, ast.error_type_idx, option_type_idx])
|
||||||
|
@ -143,13 +164,13 @@ 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(.option) && got_typ.clear_flag(.option) != exp_type.clear_flag(.option) {
|
if got_typ.has_flag(.option) && got_typ.clear_flag(.option) != exp_type.clear_flag(.option) {
|
||||||
pos := node.exprs[expr_idxs[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 ${c.error_type_name(exp_type)} in return argument',
|
||||||
pos)
|
pos)
|
||||||
}
|
}
|
||||||
if got_typ.has_flag(.result) && (!exp_type.has_flag(.result)
|
if got_typ.has_flag(.result) && (!exp_type.has_flag(.result)
|
||||||
|| 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[expr_idxs[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 ${c.error_type_name(exp_type)} in return argument',
|
||||||
pos)
|
pos)
|
||||||
}
|
}
|
||||||
if node.exprs[expr_idxs[i]] !is ast.ComptimeCall {
|
if node.exprs[expr_idxs[i]] !is ast.ComptimeCall {
|
||||||
|
@ -161,7 +182,7 @@ fn (mut c Checker) return_stmt(mut node ast.Return) {
|
||||||
if node.exprs[expr_idxs[i]] is ast.IntegerLiteral {
|
if node.exprs[expr_idxs[i]] is ast.IntegerLiteral {
|
||||||
var := (node.exprs[expr_idxs[i]] as ast.IntegerLiteral).val
|
var := (node.exprs[expr_idxs[i]] as ast.IntegerLiteral).val
|
||||||
if var[0] == `-` {
|
if var[0] == `-` {
|
||||||
c.note('cannot use a negative value as value of type `${c.table.type_to_str(exp_type)}` in return argument',
|
c.note('cannot use a negative value as value of ${c.error_type_name(exp_type)} in return argument',
|
||||||
pos)
|
pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -194,7 +215,7 @@ fn (mut c Checker) return_stmt(mut node ast.Return) {
|
||||||
} else {
|
} else {
|
||||||
got_typ_sym.name
|
got_typ_sym.name
|
||||||
}
|
}
|
||||||
c.error('cannot use `${got_typ_name}` as type `${c.table.type_to_str(exp_type)}` in return argument',
|
c.error('cannot use `${got_typ_name}` as ${c.error_type_name(exp_type)} in return argument',
|
||||||
pos)
|
pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
47
vlib/v/checker/tests/void_fn_multiple_ret_err.out
Normal file
47
vlib/v/checker/tests/void_fn_multiple_ret_err.out
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
vlib/v/checker/tests/void_fn_multiple_ret_err.vv:6:2: warning: Option and Result types have been split, use `?` to return none
|
||||||
|
4 |
|
||||||
|
5 | fn foo_result_2() ! {
|
||||||
|
6 | return none
|
||||||
|
| ~~~~~~~~~~~
|
||||||
|
7 | }
|
||||||
|
8 |
|
||||||
|
vlib/v/checker/tests/void_fn_multiple_ret_err.vv:2:9: error: functions with Result-only return types can only return an error
|
||||||
|
1 | fn foo_result_1() ! {
|
||||||
|
2 | return none, 100
|
||||||
|
| ~~~~
|
||||||
|
3 | }
|
||||||
|
4 |
|
||||||
|
vlib/v/checker/tests/void_fn_multiple_ret_err.vv:6:9: error: cannot use `none` as Result type in return argument
|
||||||
|
4 |
|
||||||
|
5 | fn foo_result_2() ! {
|
||||||
|
6 | return none
|
||||||
|
| ~~~~
|
||||||
|
7 | }
|
||||||
|
8 |
|
||||||
|
vlib/v/checker/tests/void_fn_multiple_ret_err.vv:14:9: error: cannot use `int literal` as Result type in return argument
|
||||||
|
12 |
|
||||||
|
13 | fn foo_result_4() ! {
|
||||||
|
14 | return 1
|
||||||
|
| ^
|
||||||
|
15 | }
|
||||||
|
16 |
|
||||||
|
vlib/v/checker/tests/void_fn_multiple_ret_err.vv:21:9: error: cannot use `string` as type `!int` in return argument
|
||||||
|
19 |
|
||||||
|
20 | fn foo_result_6() !int {
|
||||||
|
21 | return ''
|
||||||
|
| ~~
|
||||||
|
22 | }
|
||||||
|
23 |
|
||||||
|
vlib/v/checker/tests/void_fn_multiple_ret_err.vv:25:9: error: can only return `none` from an Option-only return function
|
||||||
|
23 |
|
||||||
|
24 | fn foo_option_1() ? {
|
||||||
|
25 | return none, 100
|
||||||
|
| ~~~~
|
||||||
|
26 | }
|
||||||
|
27 |
|
||||||
|
vlib/v/checker/tests/void_fn_multiple_ret_err.vv:36:9: error: cannot use `int literal` as Option type in return argument
|
||||||
|
34 |
|
||||||
|
35 | fn foo_option_3() ? {
|
||||||
|
36 | return 1
|
||||||
|
| ^
|
||||||
|
37 | }
|
37
vlib/v/checker/tests/void_fn_multiple_ret_err.vv
Normal file
37
vlib/v/checker/tests/void_fn_multiple_ret_err.vv
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
fn foo_result_1() ! {
|
||||||
|
return none, 100
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo_result_2() ! {
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo_result_3() ! {
|
||||||
|
return error('')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo_result_4() ! {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo_result_5() ! {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo_result_6() !int {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo_option_1() ? {
|
||||||
|
return none, 100
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo_option_2() ? {
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo_option_3() ? {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo_option_3() ? {
|
||||||
|
return 1
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user