diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index c1ab6bfb06..35375eae08 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -1211,6 +1211,14 @@ pub fn (mut c Checker) call_expr(mut call_expr ast.CallExpr) table.Type { c.expected_or_type = call_expr.return_type.clear_flag(.optional) c.stmts(call_expr.or_block.stmts) c.expected_or_type = table.void_type + if call_expr.or_block.kind == .propagate && !c.cur_fn.return_type.has_flag(.optional) + && !c.inside_const { + cur_names := c.cur_fn.name.split('.') + if cur_names[cur_names.len - 1] != 'main' { + c.error('to propagate the optional call, `$c.cur_fn.name` must return an optional', + call_expr.or_block.pos) + } + } return typ } @@ -3707,7 +3715,7 @@ fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) table.Type { c.error('could not find method `$method_name`', node.method_pos) return table.void_type } - println(f.name + ' ' + c.table.type_to_str(f.return_type)) + // println(f.name + ' ' + c.table.type_to_str(f.return_type)) node.result_type = f.return_type return f.return_type } @@ -3877,7 +3885,9 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type { ast.ConstField { mut typ := obj.typ if typ == 0 { + c.inside_const = true typ = c.expr(obj.expr) + c.inside_const = false if obj.expr is ast.CallExpr { if obj.expr.or_block.kind != .absent { typ = typ.clear_flag(.optional) diff --git a/vlib/v/checker/tests/comptime_call_no_unused_var.out b/vlib/v/checker/tests/comptime_call_no_unused_var.out index c4726e12cb..072c308100 100644 --- a/vlib/v/checker/tests/comptime_call_no_unused_var.out +++ b/vlib/v/checker/tests/comptime_call_no_unused_var.out @@ -1,4 +1,3 @@ -print void vlib/v/checker/tests/comptime_call_no_unused_var.vv:11:8: error: unknown identifier `w` 9 | abc := 'print' 10 | test.$abc() // OK @@ -20,7 +19,7 @@ vlib/v/checker/tests/comptime_call_no_unused_var.vv:15:8: error: todo: not a str | ^ 16 | s2 := 'x' 17 | test.$s2() -details: v.ast.InfixExpr +Details: v.ast.InfixExpr vlib/v/checker/tests/comptime_call_no_unused_var.vv:17:8: error: could not find method `x` 15 | test.$s() 16 | s2 := 'x' diff --git a/vlib/v/checker/tests/optional_propagate_nested.out b/vlib/v/checker/tests/optional_propagate_nested.out new file mode 100644 index 0000000000..f113a890bd --- /dev/null +++ b/vlib/v/checker/tests/optional_propagate_nested.out @@ -0,0 +1,14 @@ +vlib/v/checker/tests/optional_propagate_nested.vv:10:19: error: to propagate the optional call, `xx_prop` must return an optional + 8 | + 9 | fn xx_prop() string { + 10 | s := ret(raise() ?) + | ^ + 11 | return s + 12 | } +vlib/v/checker/tests/optional_propagate_nested.vv:28:22: error: to propagate the optional call, `aa_propagate` must return an optional + 26 | + 27 | fn (mut s St) aa_propagate() { + 28 | f := retf(s.raise() ?) + | ^ + 29 | s.z = 7.5 + 30 | println(f) diff --git a/vlib/v/checker/tests/optional_propagate_nested.vv b/vlib/v/checker/tests/optional_propagate_nested.vv new file mode 100644 index 0000000000..d00ef5392c --- /dev/null +++ b/vlib/v/checker/tests/optional_propagate_nested.vv @@ -0,0 +1,31 @@ +fn ret(s string) string { + return s +} + +fn raise() ?string { + return none +} + +fn xx_prop() string { + s := ret(raise() ?) + return s +} + +struct St { +mut: + z f64 +} + +fn (mut s St) raise() ?f64 { + return error('some error') +} + +fn retf(f f64) f64 { + return f +} + +fn (mut s St) aa_propagate() { + f := retf(s.raise() ?) + s.z = 7.5 + println(f) +} diff --git a/vlib/v/tests/nested_option_call_test.v b/vlib/v/tests/nested_option_call_test.v index b70a496ad6..2f53e56aee 100644 --- a/vlib/v/tests/nested_option_call_test.v +++ b/vlib/v/tests/nested_option_call_test.v @@ -15,6 +15,16 @@ fn test_nested_or() { xx() } +fn xx_prop() ?string { + s := ret(raise() ?) + return s +} + +fn test_nested_propagation() { + a := xx_prop() or { 'propagated' } + assert a == 'propagated' +} + struct St { mut: z f64 @@ -41,3 +51,19 @@ fn test_nested_or_method_call() { x.aa() assert x.z == 2.25 } + +fn (mut s St) aa_propagate() ? { + f := retf(s.raise() ?) + s.z = 7.5 + println(f) +} + +fn test_nested_propagation_method() { + mut x := St{ + z: 2.25 + } + x.aa_propagate() or { + x.z = 13.0625 + } + assert x.z == 13.0625 +}