checker/cgen: support `return` from nested `or` (#8430)
parent
5af16f38fc
commit
5e9b528a9d
|
@ -2299,7 +2299,12 @@ pub fn (mut c Checker) const_decl(mut node ast.ConstDecl) {
|
|||
for i, field in node.fields {
|
||||
c.const_decl = field.name
|
||||
c.const_deps << field.name
|
||||
typ := c.expr(field.expr)
|
||||
mut typ := c.expr(field.expr)
|
||||
if field.expr is ast.CallExpr {
|
||||
if field.expr.or_block.kind != .absent {
|
||||
typ = typ.clear_flag(.optional)
|
||||
}
|
||||
}
|
||||
node.fields[i].typ = c.table.mktyp(typ)
|
||||
for cd in c.const_deps {
|
||||
for j, f in node.fields {
|
||||
|
@ -3840,6 +3845,11 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type {
|
|||
mut typ := obj.typ
|
||||
if typ == 0 {
|
||||
typ = c.expr(obj.expr)
|
||||
if obj.expr is ast.CallExpr {
|
||||
if obj.expr.or_block.kind != .absent {
|
||||
typ = typ.clear_flag(.optional)
|
||||
}
|
||||
}
|
||||
}
|
||||
ident.name = name
|
||||
ident.kind = .constant
|
||||
|
|
|
@ -2099,8 +2099,8 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
// Unwrap the optional now that the testing code has been prepended.
|
||||
// `pos := s.index(...
|
||||
// `int pos = *(int)_t10.data;`
|
||||
g.write('*($styp*)')
|
||||
if g.is_autofree {
|
||||
g.write('*($styp*)')
|
||||
g.write(tmp_opt + '.data/*FFz*/')
|
||||
g.right_is_opt = false
|
||||
g.is_assign_rhs = false
|
||||
|
@ -2156,13 +2156,6 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
}
|
||||
}
|
||||
}
|
||||
if unwrap_optional {
|
||||
if g.is_autofree {
|
||||
// g.write(tmp_opt + '/*FF*/')
|
||||
} else {
|
||||
g.write('.data')
|
||||
}
|
||||
}
|
||||
if str_add || op_overloaded {
|
||||
g.write(')')
|
||||
}
|
||||
|
@ -4623,7 +4616,7 @@ fn (mut g Gen) const_decl(node ast.ConstDecl) {
|
|||
g.definitions.writeln('$styp _const_$name; // fixed array const')
|
||||
}
|
||||
} else {
|
||||
g.const_decl_init_later(field.mod, name, val, field.typ)
|
||||
g.const_decl_init_later(field.mod, name, val, field.typ, false)
|
||||
}
|
||||
}
|
||||
ast.StringLiteral {
|
||||
|
@ -4635,13 +4628,15 @@ fn (mut g Gen) const_decl(node ast.ConstDecl) {
|
|||
ast.CallExpr {
|
||||
if val.starts_with('Option_') {
|
||||
g.inits[field.mod].writeln(val)
|
||||
g.const_decl_init_later(field.mod, name, g.current_tmp_var(), field.typ)
|
||||
unwrap_option := field.expr.or_block.kind != .absent
|
||||
g.const_decl_init_later(field.mod, name, g.current_tmp_var(), field.typ,
|
||||
unwrap_option)
|
||||
} else {
|
||||
g.const_decl_init_later(field.mod, name, val, field.typ)
|
||||
g.const_decl_init_later(field.mod, name, val, field.typ, false)
|
||||
}
|
||||
}
|
||||
else {
|
||||
g.const_decl_init_later(field.mod, name, val, field.typ)
|
||||
g.const_decl_init_later(field.mod, name, val, field.typ, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4656,7 +4651,7 @@ fn (mut g Gen) const_decl_simple_define(name string, val string) {
|
|||
g.definitions.writeln(val)
|
||||
}
|
||||
|
||||
fn (mut g Gen) const_decl_init_later(mod string, name string, val string, typ table.Type) {
|
||||
fn (mut g Gen) const_decl_init_later(mod string, name string, val string, typ table.Type, unwrap_option bool) {
|
||||
// Initialize more complex consts in `void _vinit/2{}`
|
||||
// (C doesn't allow init expressions that can't be resolved at compile time).
|
||||
styp := g.typ(typ)
|
||||
|
@ -4669,7 +4664,11 @@ fn (mut g Gen) const_decl_init_later(mod string, name string, val string, typ ta
|
|||
g.inits[mod].writeln('\t_const_os__args = os__init_os_args(___argc, (byte**)___argv);')
|
||||
}
|
||||
} else {
|
||||
g.inits[mod].writeln('\t$cname = $val;')
|
||||
if unwrap_option {
|
||||
g.inits[mod].writeln('\t$cname = *($styp*)${val}.data;')
|
||||
} else {
|
||||
g.inits[mod].writeln('\t$cname = $val;')
|
||||
}
|
||||
}
|
||||
if g.is_autofree {
|
||||
if styp.starts_with('array_') {
|
||||
|
@ -5305,15 +5304,7 @@ fn (mut g Gen) or_block(var_name string, or_block ast.OrExpr, return_type table.
|
|||
expr_stmt := stmt as ast.ExprStmt
|
||||
g.stmt_path_pos << g.out.len
|
||||
g.write('*($mr_styp*) ${cvar_name}.data = ')
|
||||
is_opt_call := expr_stmt.expr is ast.CallExpr
|
||||
&& expr_stmt.typ.has_flag(.optional)
|
||||
if is_opt_call {
|
||||
g.write('*($mr_styp*) ')
|
||||
}
|
||||
g.expr_with_cast(expr_stmt.expr, expr_stmt.typ, return_type.clear_flag(.optional))
|
||||
if is_opt_call {
|
||||
g.write('.data')
|
||||
}
|
||||
if g.inside_ternary == 0 && !(expr_stmt.expr is ast.IfExpr) {
|
||||
g.writeln(';')
|
||||
}
|
||||
|
@ -5342,11 +5333,15 @@ fn (mut g Gen) or_block(var_name string, or_block ast.OrExpr, return_type table.
|
|||
// the defered statements are generated.
|
||||
g.write_defer_stmts()
|
||||
// Now that option types are distinct we need a cast here
|
||||
styp := g.typ(g.fn_decl.return_type)
|
||||
err_obj := g.new_tmp_var()
|
||||
g.writeln('\t$styp $err_obj;')
|
||||
g.writeln('\tmemcpy(&$err_obj, &$cvar_name, sizeof(Option));')
|
||||
g.writeln('\treturn $err_obj;')
|
||||
if g.fn_decl.return_type == table.void_type {
|
||||
g.writeln('\treturn;')
|
||||
} else {
|
||||
styp := g.typ(g.fn_decl.return_type)
|
||||
err_obj := g.new_tmp_var()
|
||||
g.writeln('\t$styp $err_obj;')
|
||||
g.writeln('\tmemcpy(&$err_obj, &$cvar_name, sizeof(Option));')
|
||||
g.writeln('\treturn $err_obj;')
|
||||
}
|
||||
}
|
||||
}
|
||||
g.write('}')
|
||||
|
|
|
@ -315,7 +315,15 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
|
|||
g.or_block(tmp_opt, node.or_block, node.return_type)
|
||||
}
|
||||
if is_gen_or_and_assign_rhs {
|
||||
g.write('\n $cur_line $tmp_opt')
|
||||
unwrapped_typ := node.return_type.clear_flag(.optional)
|
||||
unwrapped_styp := g.typ(unwrapped_typ)
|
||||
if unwrapped_typ == table.void_type {
|
||||
g.write('\n $cur_line')
|
||||
} else if g.table.get_type_symbol(node.return_type).kind == .multi_return {
|
||||
g.write('\n $cur_line $tmp_opt')
|
||||
} else {
|
||||
g.write('\n $cur_line *($unwrapped_styp*)${tmp_opt}.data')
|
||||
}
|
||||
// g.write('\n /*call_expr cur_line:*/ $cur_line /*C*/ $tmp_opt /*end*/')
|
||||
// g.insert_before_stmt('\n /* VVV */ $tmp_opt')
|
||||
}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
fn ret(s string) string {
|
||||
return s
|
||||
}
|
||||
|
||||
fn raise() ?string {
|
||||
return none
|
||||
}
|
||||
|
||||
fn xx() {
|
||||
s := ret(raise() or { return })
|
||||
println(s)
|
||||
}
|
||||
|
||||
fn test_nested_or() {
|
||||
xx()
|
||||
}
|
||||
|
||||
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() {
|
||||
f := retf(s.raise() or { return })
|
||||
s.z = 7.5
|
||||
println(f)
|
||||
}
|
||||
|
||||
fn test_nested_or_method_call() {
|
||||
mut x := St{
|
||||
z: 2.25
|
||||
}
|
||||
x.aa()
|
||||
assert x.z == 2.25
|
||||
}
|
|
@ -24,5 +24,5 @@ fn test_semaphore() {
|
|||
}
|
||||
elapsed_ms := f64(elapsed)/time.millisecond
|
||||
println('elapsed: ${elapsed_ms:.1f}ms')
|
||||
assert elapsed_ms >= 195.0
|
||||
assert elapsed_ms >= 190.0
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue