diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 18ea54901d..d87beb4beb 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -567,8 +567,10 @@ pub: // `if [x := opt()] {` pub struct IfGuardExpr { pub: - var_name string - expr Expr + var_name string + expr Expr +mut: + expr_type table.Type } // `or { ... }` diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 183ce50652..561cb798ed 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -631,6 +631,7 @@ pub fn (c mut Checker) expr(node ast.Expr) table.Type { return c.if_expr(mut it) } ast.IfGuardExpr { + it.expr_type = c.expr(it.expr) return table.bool_type } ast.IndexExpr { diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 3747ed4e8b..665c1522d1 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -350,7 +350,7 @@ fn (g mut Gen) expr_with_cast(got_type table.Type, exp_type table.Type, expr ast got_styp := g.typ(got_type) exp_styp := g.typ(exp_type) got_idx := table.type_idx(got_type) - g.write('/* SUM TYPE CAST */ ($exp_styp) {.obj = memdup(&(${got_styp}[]) {') + g.write('/* sum type cast */ ($exp_styp) {.obj = memdup(&(${got_styp}[]) {') g.expr(expr) g.writeln('}, sizeof($got_styp)), .typ = $got_idx};') } @@ -683,51 +683,7 @@ fn (g mut Gen) expr(node ast.Expr) { g.ident(it) } ast.IfExpr { - // If expression? Assign the value to a temp var. - // Previously ?: was used, but it's too unreliable. - type_sym := g.table.get_type_symbol(it.typ) - mut tmp := '' - if type_sym.kind != .void { - tmp = g.new_tmp_var() - // g.writeln('$ti.name $tmp;') - } - // one line ?: - // TODO clean this up once `is` is supported - if it.stmts.len == 1 && it.else_stmts.len == 1 && type_sym.kind != .void { - cond := it.cond - stmt1 := it.stmts[0] - else_stmt1 := it.else_stmts[0] - match stmt1 { - ast.ExprStmt { - g.expr(cond) - g.write(' ? ') - expr_stmt := stmt1 as ast.ExprStmt - g.expr(expr_stmt.expr) - g.write(' : ') - g.stmt(else_stmt1) - } - else {} - } - } - else { - g.write('if (') - g.expr(it.cond) - g.writeln(') {') - for i, stmt in it.stmts { - // Assign ret value - if i == it.stmts.len - 1 && type_sym.kind != .void {} - // g.writeln('$tmp =') - g.stmt(stmt) - } - g.writeln('}') - if it.else_stmts.len > 0 { - g.writeln('else { ') - for stmt in it.else_stmts { - g.stmt(stmt) - } - g.writeln('}') - } - } + g.if_expr(it) } ast.IfGuardExpr { g.write('/* guard */') @@ -1098,6 +1054,69 @@ fn (g mut Gen) ident(node ast.Ident) { } } +fn (g mut Gen) if_expr(node ast.IfExpr) { + // If expression? Assign the value to a temp var. + // Previously ?: was used, but it's too unreliable. + type_sym := g.table.get_type_symbol(node.typ) + mut tmp := '' + if type_sym.kind != .void { + tmp = g.new_tmp_var() + // g.writeln('$ti.name $tmp;') + } + // one line ?: + // TODO clean this up once `is` is supported + if node.stmts.len == 1 && node.else_stmts.len == 1 && type_sym.kind != .void { + cond := node.cond + stmt1 := node.stmts[0] + else_stmt1 := node.else_stmts[0] + match stmt1 { + ast.ExprStmt { + g.expr(cond) + g.write(' ? ') + expr_stmt := stmt1 as ast.ExprStmt + g.expr(expr_stmt.expr) + g.write(' : ') + g.stmt(else_stmt1) + } + else {} + } + } + else { + mut is_guard := false + match node.cond { + ast.IfGuardExpr { + is_guard = true + g.write('/* if guard */{${g.typ(it.expr_type)} $it.var_name = ') + g.expr(it.expr) + g.writeln(';') + g.writeln('if (${it.var_name}.ok) {') + } + else { + g.write('if (') + g.expr(node.cond) + g.writeln(') {') + } + } + for i, stmt in node.stmts { + // Assign ret value + if i == node.stmts.len - 1 && type_sym.kind != .void {} + // g.writeln('$tmp =') + g.stmt(stmt) + } + if is_guard { + g.write('}') + } + g.writeln('}') + if node.else_stmts.len > 0 { + g.writeln('else { ') + for stmt in node.else_stmts { + g.stmt(stmt) + } + g.writeln('}') + } + } +} + fn (g mut Gen) index_expr(node ast.IndexExpr) { // TODO else doesn't work with sum types mut is_range := false