all: if-is smartcast part 1 (#5730)

pull/5756/head
Daniel Däschle 2020-07-08 15:17:28 +02:00 committed by GitHub
parent 3b0dfd9ae1
commit b62bf59c21
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 58 additions and 14 deletions

View File

@ -425,10 +425,10 @@ pub mut:
pub struct IfExpr { pub struct IfExpr {
pub: pub:
tok_kind token.Kind tok_kind token.Kind
branches []IfBranch
left Expr // `a` in `a := if ...` left Expr // `a` in `a := if ...`
pos token.Position pos token.Position
pub mut: pub mut:
branches []IfBranch
is_expr bool is_expr bool
typ table.Type typ table.Type
has_else bool has_else bool
@ -439,7 +439,10 @@ pub:
cond Expr cond Expr
stmts []Stmt stmts []Stmt
pos token.Position pos token.Position
body_pos token.Position
comments []Comment comments []Comment
pub mut:
smartcast bool // should only be true if cond is `x is sumtype`, it will be set in checker - if_expr
} }
pub struct LockExpr { pub struct LockExpr {

View File

@ -286,7 +286,7 @@ pub fn (node Stmt) str() string {
} }
} }
out += left.str() out += left.str()
if i < it.left.len - 1 { if i < node.left.len - 1 {
out += ',' out += ','
} }
} }

View File

@ -2623,6 +2623,29 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
c.error('non-bool type `$typ_sym.name` used as if condition', branch.pos) c.error('non-bool type `$typ_sym.name` used as if condition', branch.pos)
} }
} }
// smartcast sumtypes when using `is`
if branch.cond is ast.InfixExpr {
infix := branch.cond as ast.InfixExpr
if infix.op == .key_is && infix.left is ast.Ident && infix.right is ast.Type {
left_expr := infix.left as ast.Ident
right_expr := infix.right as ast.Type
if left_expr.kind == .variable {
// Register shadow variable or `as` variable with actual type
left_sym := c.table.get_type_symbol(infix.left_type)
if left_sym.kind == .sum_type {
mut scope := c.file.scope.innermost(branch.body_pos.pos)
scope.register('it', ast.Var{
name: 'it'
typ: right_expr.typ.to_ptr()
pos: left_expr.pos
is_used: true
is_mut: left_expr.is_mut
})
node.branches[i].smartcast = true
}
}
}
}
c.stmts(branch.stmts) c.stmts(branch.stmts)
if expr_required { if expr_required {
if branch.stmts.len > 0 && branch.stmts[branch.stmts.len - 1] is ast.ExprStmt { if branch.stmts.len > 0 && branch.stmts[branch.stmts.len - 1] is ast.ExprStmt {

View File

@ -2311,6 +2311,20 @@ fn (mut g Gen) if_expr(node ast.IfExpr) {
} else if i == node.branches.len - 1 && node.has_else { } else if i == node.branches.len - 1 && node.has_else {
g.writeln('} else {') g.writeln('} else {')
} }
if branch.smartcast && branch.stmts.len > 0 {
infix := branch.cond as ast.InfixExpr
right_type := infix.right as ast.Type
left_type := infix.left_type
it_type := g.typ(right_type.typ)
g.write('\t$it_type* it = ($it_type*)')
g.expr(infix.left)
if left_type.is_ptr() {
g.write('->')
} else {
g.write('.')
}
g.writeln('obj;')
}
g.stmts(branch.stmts) g.stmts(branch.stmts)
} }
if is_guard { if is_guard {

View File

@ -663,27 +663,27 @@ fn (mut g JsGen) gen_assert_stmt(a ast.AssertStmt) {
g.writeln('}') g.writeln('}')
} }
fn (mut g JsGen) gen_assign_stmt(it ast.AssignStmt) { fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt) {
if it.left.len > it.right.len { if stmt.left.len > stmt.right.len {
// multi return // multi return
g.write('const [') g.write('const [')
for i, left in it.left { for i, left in stmt.left {
if !left.is_blank_ident() { if !left.is_blank_ident() {
g.expr(left) g.expr(left)
} }
if i < it.left.len - 1 { if i < stmt.left.len - 1 {
g.write(', ') g.write(', ')
} }
} }
g.write('] = ') g.write('] = ')
g.expr(it.right[0]) g.expr(stmt.right[0])
g.writeln(';') g.writeln(';')
} else { } else {
// `a := 1` | `a,b := 1,2` // `a := 1` | `a,b := 1,2`
for i, left in it.left { for i, left in stmt.left {
mut op := it.op mut op := stmt.op
if it.op == .decl_assign { op = .assign } if stmt.op == .decl_assign { op = .assign }
val := it.right[i] val := stmt.right[i]
mut is_mut := false mut is_mut := false
if left is ast.Ident { if left is ast.Ident {
ident := left as ast.Ident ident := left as ast.Ident
@ -698,13 +698,13 @@ fn (mut g JsGen) gen_assign_stmt(it ast.AssignStmt) {
} }
} }
mut styp := g.typ(it.left_types[i]) mut styp := g.typ(stmt.left_types[i])
if !g.inside_loop && styp.len > 0 { if !g.inside_loop && styp.len > 0 {
g.doc.gen_typ(styp) g.doc.gen_typ(styp)
} }
if it.op == .decl_assign { if stmt.op == .decl_assign {
if g.inside_loop || is_mut { if g.inside_loop || is_mut {
g.write('let ') g.write('let ')
} else { } else {

View File

@ -31,9 +31,11 @@ fn (mut p Parser) if_expr() ast.IfExpr {
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()
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())
comments: comments comments: comments
} }
comments = [] comments = []
@ -63,6 +65,7 @@ fn (mut p Parser) if_expr() ast.IfExpr {
cond = p.expr(0) cond = p.expr(0)
} }
end_pos := p.prev_tok.position() end_pos := p.prev_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_or {
@ -72,6 +75,7 @@ fn (mut p Parser) if_expr() ast.IfExpr {
cond: cond cond: cond
stmts: stmts stmts: stmts
pos: start_pos.extend(end_pos) pos: start_pos.extend(end_pos)
body_pos: body_pos.extend(p.tok.position())
comments: comments comments: comments
} }
comments = [] comments = []