all: if-is smartcast part 1 (#5730)
parent
3b0dfd9ae1
commit
b62bf59c21
|
@ -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 {
|
||||||
|
|
|
@ -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 += ','
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 = []
|
||||||
|
|
Loading…
Reference in New Issue