ast, checker, cgen: fix error for multi-return in or expr (fix #14167) (#14172)

yuyi 2022-04-26 17:17:05 +08:00 committed by Jef Roosens
parent 0302cd69bd
commit 2b0f0820e6
Signed by: Jef Roosens
GPG Key ID: B75D4F293C7052DB
5 changed files with 51 additions and 11 deletions

View File

@ -1156,7 +1156,7 @@ pub fn (mut t Table) find_or_register_multi_return(mr_typs []Type) int {
mut name := '('
mut cname := 'multi_return'
for i, mr_typ in mr_typs {
mr_type_sym := t.sym(mr_typ)
mr_type_sym := t.sym(mktyp(mr_typ))
ref, cref := if mr_typ.is_ptr() { '&', 'ref_' } else { '', '' }
name += '$ref$mr_type_sym.name'
cname += '_$cref$mr_type_sym.cname'

View File

@ -248,6 +248,20 @@ pub fn (mut c Checker) check_basic(got ast.Type, expected ast.Type) bool {
return true
}
got_sym, exp_sym := c.table.sym(got), c.table.sym(expected)
// multi return
if exp_sym.kind == .multi_return && got_sym.kind == .multi_return {
exp_types := exp_sym.mr_info().types
got_types := got_sym.mr_info().types.map(ast.mktyp(it))
if exp_types.len != got_types.len {
return false
}
for i in 0 .. exp_types.len {
if !c.check_types(got_types[i], exp_types[i]) {
return false
}
}
return true
}
// array/map as argument
if got_sym.kind in [.array, .map, .array_fixed] && exp_sym.kind == got_sym.kind {
if c.table.type_to_str(got) == c.table.type_to_str(expected).trim('&') {

View File

@ -217,16 +217,6 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
if is_noreturn_callexpr(last_expr.expr) {
continue
}
node_sym := c.table.sym(node.typ)
last_sym := c.table.sym(last_expr.typ)
if node_sym.kind == .multi_return && last_sym.kind == .multi_return {
node_types := node_sym.mr_info().types
last_types := last_sym.mr_info().types.map(ast.mktyp(it))
if node_types == last_types {
continue
}
}
c.error('mismatched types `${c.table.type_to_str(node.typ)}` and `${c.table.type_to_str(last_expr.typ)}`',
node.pos)
}

View File

@ -195,6 +195,7 @@ mut:
referenced_fns shared map[string]bool // functions that have been referenced
nr_closures int
expected_cast_type ast.Type // for match expr of sumtypes
or_expr_return_type ast.Type // or { 0, 1 } return type
anon_fn bool
tests_inited bool
has_main bool
@ -3864,6 +3865,8 @@ fn (mut g Gen) concat_expr(node ast.ConcatExpr) {
mut styp := g.typ(node.return_type)
if g.inside_return {
styp = g.typ(g.fn_decl.return_type)
} else if g.inside_or_block {
styp = g.typ(g.or_expr_return_type)
}
sym := g.table.sym(node.return_type)
is_multi := sym.kind == .multi_return
@ -4933,6 +4936,7 @@ fn (mut g Gen) or_block(var_name string, or_block ast.OrExpr, return_type ast.Ty
g.writeln('if (${cvar_name}.state != 0) { /*or block*/ ')
}
if or_block.kind == .block {
g.or_expr_return_type = return_type.clear_flag(.optional)
if g.inside_or_block {
g.writeln('\terr = ${cvar_name}.err;')
} else {
@ -4970,6 +4974,7 @@ fn (mut g Gen) or_block(var_name string, or_block ast.OrExpr, return_type ast.Ty
g.writeln(';')
}
}
g.or_expr_return_type = ast.void_type
} else if or_block.kind == .propagate {
if g.file.mod.name == 'main' && (isnil(g.fn_decl) || g.fn_decl.is_main) {
// In main(), an `opt()?` call is sugar for `opt() or { panic(err) }`

View File

@ -0,0 +1,31 @@
fn multi_return1() ?(int, int) {
return 1, 2
}
fn multi_return2() ?(i64, i64) {
return 11, 22
}
fn multi_return3() ?(int, i64) {
return 11, 22
}
fn test_multi_return_in_or_expr() {
a1, b1 := multi_return1() or { 0, -1 }
println('$a1, $b1')
assert a1 == 1
assert b1 == 2
a2, b2 := multi_return2() or { 0, -1 }
println('$a2, $b2')
assert a2 == 11
assert b2 == 22
a3, b3 := multi_return3() or { 0, -1 }
println('$a3, $b3')
assert a3 == 11
assert b3 == 22
}