mirror of
https://github.com/vlang/v.git
synced 2025-08-04 10:17:22 -04:00
checker,cgen: fix missing validation for selector unwrapping + fix default return none
for unwrapping (#23183)
This commit is contained in:
parent
75ff2e0c86
commit
a200c4540a
@ -1412,7 +1412,7 @@ fn (mut c Checker) check_or_expr(node ast.OrExpr, ret_type ast.Type, expr_return
|
|||||||
node.pos)
|
node.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if expr !is ast.Ident && !expr_return_type.has_flag(.option) {
|
if expr !in [ast.Ident, ast.SelectorExpr] && !expr_return_type.has_flag(.option) {
|
||||||
if expr_return_type.has_flag(.result) {
|
if expr_return_type.has_flag(.result) {
|
||||||
c.error('propagating a Result like an Option is deprecated, use `foo()!` instead of `foo()?`',
|
c.error('propagating a Result like an Option is deprecated, use `foo()!` instead of `foo()?`',
|
||||||
node.pos)
|
node.pos)
|
||||||
@ -1791,7 +1791,7 @@ fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
node.typ = field.typ
|
node.typ = field.typ
|
||||||
if node.or_block.kind == .block {
|
if node.or_block.kind != .absent {
|
||||||
unwrapped_typ := c.unwrap_generic(node.typ)
|
unwrapped_typ := c.unwrap_generic(node.typ)
|
||||||
c.expected_or_type = unwrapped_typ.clear_option_and_result()
|
c.expected_or_type = unwrapped_typ.clear_option_and_result()
|
||||||
c.stmts_ending_with_expression(mut node.or_block.stmts, c.expected_or_type)
|
c.stmts_ending_with_expression(mut node.or_block.stmts, c.expected_or_type)
|
||||||
|
@ -10,7 +10,7 @@ pub fn (mut m Message) update_text(new_text string) {
|
|||||||
m.text = new_text
|
m.text = new_text
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut m Message) update_ext_text(new_text string) {
|
pub fn (mut m Message) update_ext_text(new_text string) ? {
|
||||||
m.m2?.text = new_text
|
m.m2?.text = new_text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
14
vlib/v/checker/tests/option_selector_fn_unwrap_err.out
Normal file
14
vlib/v/checker/tests/option_selector_fn_unwrap_err.out
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
vlib/v/checker/tests/option_selector_fn_unwrap_err.vv:7:17: error: to propagate the call, `callback` must return an Option type
|
||||||
|
5 |
|
||||||
|
6 | fn callback(foo &Foo) bool {
|
||||||
|
7 | return foo.func? == callback
|
||||||
|
| ^
|
||||||
|
8 | }
|
||||||
|
9 |
|
||||||
|
Details: vlib/v/checker/tests/option_selector_fn_unwrap_err.vv:6:23: details: prepend ? before the declaration of the return type of `callback`
|
||||||
|
4 | }
|
||||||
|
5 |
|
||||||
|
6 | fn callback(foo &Foo) bool {
|
||||||
|
| ~~~~
|
||||||
|
7 | return foo.func? == callback
|
||||||
|
8 | }
|
13
vlib/v/checker/tests/option_selector_fn_unwrap_err.vv
Normal file
13
vlib/v/checker/tests/option_selector_fn_unwrap_err.vv
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
struct Foo {
|
||||||
|
mut:
|
||||||
|
func ?fn (voidptr) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
fn callback(foo &Foo) bool {
|
||||||
|
return foo.func? == callback
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
t := Foo{}
|
||||||
|
assert callback(&t)
|
||||||
|
}
|
@ -7041,11 +7041,15 @@ fn (mut g Gen) or_block(var_name string, or_block ast.OrExpr, return_type ast.Ty
|
|||||||
// Now that option types are distinct we need a cast here
|
// Now that option types are distinct we need a cast here
|
||||||
if g.fn_decl == unsafe { nil } || g.fn_decl.return_type == ast.void_type {
|
if g.fn_decl == unsafe { nil } || g.fn_decl.return_type == ast.void_type {
|
||||||
g.writeln('\treturn;')
|
g.writeln('\treturn;')
|
||||||
} else {
|
} else if g.fn_decl.return_type.clear_option_and_result() == return_type.clear_option_and_result() {
|
||||||
styp := g.styp(g.fn_decl.return_type).replace('*', '_ptr')
|
styp := g.styp(g.fn_decl.return_type).replace('*', '_ptr')
|
||||||
err_obj := g.new_tmp_var()
|
err_obj := g.new_tmp_var()
|
||||||
g.writeln2('\t${styp} ${err_obj};', '\tmemcpy(&${err_obj}, &${cvar_name}, sizeof(_option));')
|
g.writeln2('\t${styp} ${err_obj};', '\tmemcpy(&${err_obj}, &${cvar_name}, sizeof(_option));')
|
||||||
g.writeln('\treturn ${err_obj};')
|
g.writeln('\treturn ${err_obj};')
|
||||||
|
} else {
|
||||||
|
g.write('\treturn ')
|
||||||
|
g.gen_option_error(g.fn_decl.return_type, ast.None{})
|
||||||
|
g.writeln(';')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ fn new_linked_list[T]() &LinkedList[T] {
|
|||||||
return &LinkedList[T]{}
|
return &LinkedList[T]{}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut li LinkedList[T]) add[T](data T) {
|
fn (mut li LinkedList[T]) add[T](data T) ? {
|
||||||
mut node := &Node[T]{data, none, none}
|
mut node := &Node[T]{data, none, none}
|
||||||
|
|
||||||
if li.head == none {
|
if li.head == none {
|
||||||
|
13
vlib/v/tests/options/option_selector_fn_none_test.v
Normal file
13
vlib/v/tests/options/option_selector_fn_none_test.v
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
struct Foo {
|
||||||
|
mut:
|
||||||
|
func ?fn (voidptr) ?bool
|
||||||
|
}
|
||||||
|
|
||||||
|
fn callback(foo &Foo) ?bool {
|
||||||
|
return foo.func? == callback
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_main() {
|
||||||
|
t := Foo{}
|
||||||
|
assert callback(&t) == none
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user