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 {
|
for i, field in node.fields {
|
||||||
c.const_decl = field.name
|
c.const_decl = field.name
|
||||||
c.const_deps << 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)
|
node.fields[i].typ = c.table.mktyp(typ)
|
||||||
for cd in c.const_deps {
|
for cd in c.const_deps {
|
||||||
for j, f in node.fields {
|
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
|
mut typ := obj.typ
|
||||||
if typ == 0 {
|
if typ == 0 {
|
||||||
typ = c.expr(obj.expr)
|
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.name = name
|
||||||
ident.kind = .constant
|
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.
|
// Unwrap the optional now that the testing code has been prepended.
|
||||||
// `pos := s.index(...
|
// `pos := s.index(...
|
||||||
// `int pos = *(int)_t10.data;`
|
// `int pos = *(int)_t10.data;`
|
||||||
g.write('*($styp*)')
|
|
||||||
if g.is_autofree {
|
if g.is_autofree {
|
||||||
|
g.write('*($styp*)')
|
||||||
g.write(tmp_opt + '.data/*FFz*/')
|
g.write(tmp_opt + '.data/*FFz*/')
|
||||||
g.right_is_opt = false
|
g.right_is_opt = false
|
||||||
g.is_assign_rhs = 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 {
|
if str_add || op_overloaded {
|
||||||
g.write(')')
|
g.write(')')
|
||||||
}
|
}
|
||||||
|
@ -4623,7 +4616,7 @@ fn (mut g Gen) const_decl(node ast.ConstDecl) {
|
||||||
g.definitions.writeln('$styp _const_$name; // fixed array const')
|
g.definitions.writeln('$styp _const_$name; // fixed array const')
|
||||||
}
|
}
|
||||||
} else {
|
} 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 {
|
ast.StringLiteral {
|
||||||
|
@ -4635,13 +4628,15 @@ fn (mut g Gen) const_decl(node ast.ConstDecl) {
|
||||||
ast.CallExpr {
|
ast.CallExpr {
|
||||||
if val.starts_with('Option_') {
|
if val.starts_with('Option_') {
|
||||||
g.inits[field.mod].writeln(val)
|
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 {
|
} 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 {
|
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)
|
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{}`
|
// Initialize more complex consts in `void _vinit/2{}`
|
||||||
// (C doesn't allow init expressions that can't be resolved at compile time).
|
// (C doesn't allow init expressions that can't be resolved at compile time).
|
||||||
styp := g.typ(typ)
|
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);')
|
g.inits[mod].writeln('\t_const_os__args = os__init_os_args(___argc, (byte**)___argv);')
|
||||||
}
|
}
|
||||||
} else {
|
} 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 g.is_autofree {
|
||||||
if styp.starts_with('array_') {
|
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
|
expr_stmt := stmt as ast.ExprStmt
|
||||||
g.stmt_path_pos << g.out.len
|
g.stmt_path_pos << g.out.len
|
||||||
g.write('*($mr_styp*) ${cvar_name}.data = ')
|
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))
|
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) {
|
if g.inside_ternary == 0 && !(expr_stmt.expr is ast.IfExpr) {
|
||||||
g.writeln(';')
|
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.
|
// the defered statements are generated.
|
||||||
g.write_defer_stmts()
|
g.write_defer_stmts()
|
||||||
// Now that option types are distinct we need a cast here
|
// Now that option types are distinct we need a cast here
|
||||||
styp := g.typ(g.fn_decl.return_type)
|
if g.fn_decl.return_type == table.void_type {
|
||||||
err_obj := g.new_tmp_var()
|
g.writeln('\treturn;')
|
||||||
g.writeln('\t$styp $err_obj;')
|
} else {
|
||||||
g.writeln('\tmemcpy(&$err_obj, &$cvar_name, sizeof(Option));')
|
styp := g.typ(g.fn_decl.return_type)
|
||||||
g.writeln('\treturn $err_obj;')
|
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('}')
|
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)
|
g.or_block(tmp_opt, node.or_block, node.return_type)
|
||||||
}
|
}
|
||||||
if is_gen_or_and_assign_rhs {
|
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.write('\n /*call_expr cur_line:*/ $cur_line /*C*/ $tmp_opt /*end*/')
|
||||||
// g.insert_before_stmt('\n /* VVV */ $tmp_opt')
|
// 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
|
elapsed_ms := f64(elapsed)/time.millisecond
|
||||||
println('elapsed: ${elapsed_ms:.1f}ms')
|
println('elapsed: ${elapsed_ms:.1f}ms')
|
||||||
assert elapsed_ms >= 195.0
|
assert elapsed_ms >= 190.0
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue