checker: support nested propagation cases `f(g() ?)` (#8447)

pull/8449/head
Uwe Krüger 2021-01-30 16:53:31 +01:00 committed by GitHub
parent 19784ab89b
commit 9c82eec529
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 83 additions and 3 deletions

View File

@ -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)

View File

@ -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'

View File

@ -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)

View File

@ -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)
}

View File

@ -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
}