all: `if` guard optional: define `err` in `else` branch (#5853)
parent
ea322bdd97
commit
39f90e25f3
|
@ -433,7 +433,7 @@ pub:
|
||||||
left Expr // `a` in `a := if ...`
|
left Expr // `a` in `a := if ...`
|
||||||
pos token.Position
|
pos token.Position
|
||||||
pub mut:
|
pub mut:
|
||||||
branches []IfBranch
|
branches []IfBranch // includes all `else if` branches
|
||||||
is_expr bool
|
is_expr bool
|
||||||
typ table.Type
|
typ table.Type
|
||||||
has_else bool
|
has_else bool
|
||||||
|
|
|
@ -2368,12 +2368,15 @@ fn (mut g Gen) if_expr(node ast.IfExpr) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
mut is_guard := false
|
mut is_guard := false
|
||||||
mut guard_vars := []string{len: node.branches.len}
|
mut guard_idx := 0
|
||||||
|
mut guard_vars := []string{}
|
||||||
for i, branch in node.branches {
|
for i, branch in node.branches {
|
||||||
cond := branch.cond
|
cond := branch.cond
|
||||||
if cond is ast.IfGuardExpr {
|
if cond is ast.IfGuardExpr {
|
||||||
if !is_guard {
|
if !is_guard {
|
||||||
is_guard = true
|
is_guard = true
|
||||||
|
guard_idx = i
|
||||||
|
guard_vars = []string{ len: node.branches.len }
|
||||||
g.writeln('{ /* if guard */ ')
|
g.writeln('{ /* if guard */ ')
|
||||||
}
|
}
|
||||||
var_name := g.new_tmp_var()
|
var_name := g.new_tmp_var()
|
||||||
|
@ -2385,8 +2388,15 @@ fn (mut g Gen) if_expr(node ast.IfExpr) {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
g.write('} else ')
|
g.write('} else ')
|
||||||
}
|
}
|
||||||
|
// if last branch is `else {`
|
||||||
if i == node.branches.len - 1 && node.has_else {
|
if i == node.branches.len - 1 && node.has_else {
|
||||||
g.writeln('{')
|
g.writeln('{')
|
||||||
|
// define `err` only for simple `if val := opt {...} else {`
|
||||||
|
if is_guard && guard_idx == i - 1 {
|
||||||
|
cvar_name := guard_vars[guard_idx]
|
||||||
|
g.writeln('\tstring err = ${cvar_name}.v_error;')
|
||||||
|
g.writeln('\tint errcode = ${cvar_name}.ecode;')
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
match branch.cond as cond {
|
match branch.cond as cond {
|
||||||
ast.IfGuardExpr {
|
ast.IfGuardExpr {
|
||||||
|
|
|
@ -17,6 +17,7 @@ fn (mut p Parser) if_expr() ast.IfExpr {
|
||||||
mut branches := []ast.IfBranch{}
|
mut branches := []ast.IfBranch{}
|
||||||
mut has_else := false
|
mut has_else := false
|
||||||
mut comments := []ast.Comment{}
|
mut comments := []ast.Comment{}
|
||||||
|
mut prev_guard := false
|
||||||
for p.tok.kind in [.key_if, .key_else] {
|
for p.tok.kind in [.key_if, .key_else] {
|
||||||
p.inside_if = true
|
p.inside_if = true
|
||||||
start_pos := p.tok.position()
|
start_pos := p.tok.position()
|
||||||
|
@ -28,26 +29,46 @@ fn (mut p Parser) if_expr() ast.IfExpr {
|
||||||
if p.tok.kind == .key_if {
|
if p.tok.kind == .key_if {
|
||||||
p.next()
|
p.next()
|
||||||
} else {
|
} else {
|
||||||
|
// else {
|
||||||
has_else = true
|
has_else = true
|
||||||
p.inside_if = false
|
p.inside_if = false
|
||||||
end_pos := p.prev_tok.position()
|
end_pos := p.prev_tok.position()
|
||||||
body_pos := p.tok.position()
|
body_pos := p.tok.position()
|
||||||
|
// only declare `err` if previous branch was an `if` guard
|
||||||
|
if prev_guard {
|
||||||
|
p.open_scope()
|
||||||
|
p.scope.register('errcode', ast.Var{
|
||||||
|
name: 'errcode'
|
||||||
|
typ: table.int_type
|
||||||
|
pos: body_pos
|
||||||
|
is_used: true
|
||||||
|
})
|
||||||
|
p.scope.register('err', ast.Var{
|
||||||
|
name: 'err'
|
||||||
|
typ: table.string_type
|
||||||
|
pos: body_pos
|
||||||
|
is_used: true
|
||||||
|
})
|
||||||
|
}
|
||||||
branches << ast.IfBranch{
|
branches << ast.IfBranch{
|
||||||
stmts: p.parse_block()
|
stmts: p.parse_block()
|
||||||
pos: start_pos.extend(end_pos)
|
pos: start_pos.extend(end_pos)
|
||||||
body_pos: body_pos.extend(p.tok.position())
|
body_pos: body_pos.extend(p.tok.position())
|
||||||
comments: comments
|
comments: comments
|
||||||
}
|
}
|
||||||
|
if prev_guard {
|
||||||
|
p.close_scope()
|
||||||
|
}
|
||||||
comments = []
|
comments = []
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mut cond := ast.Expr{}
|
mut cond := ast.Expr{}
|
||||||
mut is_or := false
|
mut is_guard := false
|
||||||
// `if x := opt() {`
|
// `if x := opt() {`
|
||||||
if p.peek_tok.kind == .decl_assign {
|
if p.peek_tok.kind == .decl_assign {
|
||||||
is_or = true
|
|
||||||
p.open_scope()
|
p.open_scope()
|
||||||
|
is_guard = true
|
||||||
var_pos := p.tok.position()
|
var_pos := p.tok.position()
|
||||||
var_name := p.check_name()
|
var_name := p.check_name()
|
||||||
p.check(.decl_assign)
|
p.check(.decl_assign)
|
||||||
|
@ -61,13 +82,14 @@ fn (mut p Parser) if_expr() ast.IfExpr {
|
||||||
var_name: var_name
|
var_name: var_name
|
||||||
expr: expr
|
expr: expr
|
||||||
}
|
}
|
||||||
|
prev_guard = true
|
||||||
} else {
|
} else {
|
||||||
|
prev_guard = false
|
||||||
cond = p.expr(0)
|
cond = p.expr(0)
|
||||||
}
|
}
|
||||||
mut left_as_name := ''
|
mut left_as_name := ''
|
||||||
is_infix := cond is ast.InfixExpr
|
if cond is ast.InfixExpr as infix {
|
||||||
if is_infix {
|
// if sum is T
|
||||||
infix := cond as ast.InfixExpr
|
|
||||||
is_is_cast := infix.op == .key_is
|
is_is_cast := infix.op == .key_is
|
||||||
is_ident := infix.left is ast.Ident
|
is_ident := infix.left is ast.Ident
|
||||||
left_as_name = if is_is_cast && p.tok.kind == .key_as {
|
left_as_name = if is_is_cast && p.tok.kind == .key_as {
|
||||||
|
@ -84,7 +106,7 @@ fn (mut p Parser) if_expr() ast.IfExpr {
|
||||||
body_pos := p.tok.position()
|
body_pos := p.tok.position()
|
||||||
p.inside_if = false
|
p.inside_if = false
|
||||||
stmts := p.parse_block()
|
stmts := p.parse_block()
|
||||||
if is_or {
|
if is_guard {
|
||||||
p.close_scope()
|
p.close_scope()
|
||||||
}
|
}
|
||||||
branches << ast.IfBranch{
|
branches << ast.IfBranch{
|
||||||
|
|
|
@ -3,13 +3,20 @@ fn opt_err_with_code() ?string {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_err_with_code() {
|
fn test_err_with_code() {
|
||||||
|
if w := opt_err_with_code() {
|
||||||
|
assert false
|
||||||
|
_ := w
|
||||||
|
} else {
|
||||||
|
assert err == 'hi'
|
||||||
|
assert errcode == 137
|
||||||
|
}
|
||||||
v := opt_err_with_code() or {
|
v := opt_err_with_code() or {
|
||||||
assert err == 'hi'
|
assert err == 'hi'
|
||||||
assert errcode == 137
|
assert errcode == 137
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
assert false
|
assert false
|
||||||
println(v) // suppress not used error
|
_ := v
|
||||||
}
|
}
|
||||||
|
|
||||||
fn opt_err() ?string {
|
fn opt_err() ?string {
|
||||||
|
@ -69,7 +76,7 @@ fn test_if_else_opt() {
|
||||||
if _ := err_call(false) {
|
if _ := err_call(false) {
|
||||||
assert false
|
assert false
|
||||||
} else {
|
} else {
|
||||||
assert true
|
assert err.len != 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,12 +157,12 @@ fn test_or_return() {
|
||||||
if _ := or_return_error() {
|
if _ := or_return_error() {
|
||||||
assert false
|
assert false
|
||||||
} else {
|
} else {
|
||||||
assert true
|
assert err.len != 0
|
||||||
}
|
}
|
||||||
if _ := or_return_none() {
|
if _ := or_return_none() {
|
||||||
assert false
|
assert false
|
||||||
} else {
|
} else {
|
||||||
assert true
|
assert err.len == 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue