checker: disallow `opt_returning_string() or { ... 123 }` (closes #6711)
parent
d040af4939
commit
4e760c703e
|
@ -1609,7 +1609,7 @@ pub fn (mut c Checker) check_expr_opt_call(expr ast.Expr, ret_type table.Type) t
|
||||||
expr.pos)
|
expr.pos)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
c.check_or_expr(expr.or_block, ret_type)
|
c.check_or_expr(expr.or_block, ret_type, expr.return_type.clear_flag(.optional))
|
||||||
}
|
}
|
||||||
// remove optional flag
|
// remove optional flag
|
||||||
// return ret_type.clear_flag(.optional)
|
// return ret_type.clear_flag(.optional)
|
||||||
|
@ -1626,7 +1626,7 @@ pub fn (mut c Checker) check_expr_opt_call(expr ast.Expr, ret_type table.Type) t
|
||||||
return ret_type
|
return ret_type
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c Checker) check_or_expr(or_expr ast.OrExpr, ret_type table.Type) {
|
pub fn (mut c Checker) check_or_expr(or_expr ast.OrExpr, ret_type table.Type, expr_return_type table.Type) {
|
||||||
if or_expr.kind == .propagate {
|
if or_expr.kind == .propagate {
|
||||||
if !c.cur_fn.return_type.has_flag(.optional) && c.cur_fn.name != 'main.main' {
|
if !c.cur_fn.return_type.has_flag(.optional) && c.cur_fn.name != 'main.main' {
|
||||||
c.error('to propagate the optional call, `$c.cur_fn.name` must itself return an optional',
|
c.error('to propagate the optional call, `$c.cur_fn.name` must itself return an optional',
|
||||||
|
@ -1646,10 +1646,10 @@ pub fn (mut c Checker) check_or_expr(or_expr ast.OrExpr, ret_type table.Type) {
|
||||||
}
|
}
|
||||||
last_stmt := or_expr.stmts[stmts_len - 1]
|
last_stmt := or_expr.stmts[stmts_len - 1]
|
||||||
if ret_type != table.void_type {
|
if ret_type != table.void_type {
|
||||||
match mut last_stmt {
|
match last_stmt {
|
||||||
ast.ExprStmt {
|
ast.ExprStmt {
|
||||||
last_stmt.typ = c.expr(last_stmt.expr)
|
last_stmt_typ := c.expr(last_stmt.expr)
|
||||||
type_fits := c.check_types(last_stmt.typ, ret_type)
|
type_fits := c.check_types(last_stmt_typ, ret_type)
|
||||||
is_panic_or_exit := is_expr_panic_or_exit(last_stmt.expr)
|
is_panic_or_exit := is_expr_panic_or_exit(last_stmt.expr)
|
||||||
if type_fits || is_panic_or_exit {
|
if type_fits || is_panic_or_exit {
|
||||||
return
|
return
|
||||||
|
@ -1659,7 +1659,7 @@ pub fn (mut c Checker) check_or_expr(or_expr ast.OrExpr, ret_type table.Type) {
|
||||||
c.error('`or` block must provide a default value of type `$expected_type_name`, or return/exit/continue/break/panic',
|
c.error('`or` block must provide a default value of type `$expected_type_name`, or return/exit/continue/break/panic',
|
||||||
last_stmt.pos)
|
last_stmt.pos)
|
||||||
} else {
|
} else {
|
||||||
type_name := c.table.type_to_str(last_stmt.typ)
|
type_name := c.table.type_to_str(last_stmt_typ)
|
||||||
c.error('wrong return type `$type_name` in the `or {}` block, expected `$expected_type_name`',
|
c.error('wrong return type `$type_name` in the `or {}` block, expected `$expected_type_name`',
|
||||||
last_stmt.pos)
|
last_stmt.pos)
|
||||||
}
|
}
|
||||||
|
@ -1680,6 +1680,26 @@ pub fn (mut c Checker) check_or_expr(or_expr ast.OrExpr, ret_type table.Type) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
match last_stmt {
|
||||||
|
ast.ExprStmt {
|
||||||
|
if last_stmt.typ == table.void_type {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if is_expr_panic_or_exit(last_stmt.expr) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if c.check_types(last_stmt.typ, expr_return_type) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// opt_returning_string() or { ... 123 }
|
||||||
|
type_name := c.table.type_to_str(last_stmt.typ)
|
||||||
|
expr_return_type_name := c.table.type_to_str(expr_return_type)
|
||||||
|
c.error('the default expression type in the `or` block should be `$expr_return_type_name`, instead you gave a value of type `$type_name`',
|
||||||
|
last_stmt.expr.position())
|
||||||
|
}
|
||||||
|
else {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
vlib/v/checker/tests/optional_or_block_returns_value_of_incompatible_type.vv:13:3: error: the default expression type in the `or` block should be `string`, instead you gave a value of type `any_int`
|
||||||
|
11 | // must be of the same type of the return
|
||||||
|
12 | // type of the `test_optional` function
|
||||||
|
13 | 123
|
||||||
|
| ~~~
|
||||||
|
14 | // 'I break things'
|
||||||
|
15 | }
|
|
@ -0,0 +1,16 @@
|
||||||
|
fn test_optional(fail bool) ?string {
|
||||||
|
if fail {
|
||||||
|
return error('false')
|
||||||
|
}
|
||||||
|
return 'fff'
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// a := test_optional(false) or { println(err) }
|
||||||
|
test_optional(true) or {
|
||||||
|
// must be of the same type of the return
|
||||||
|
// type of the `test_optional` function
|
||||||
|
123
|
||||||
|
// 'I break things'
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue