all: mutable smartcasts (#6878)

pull/6881/head
Daniel Däschle 2020-11-19 17:28:46 +01:00 committed by GitHub
parent 48b117618d
commit 9feb010355
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 93 additions and 22 deletions

View File

@ -533,7 +533,7 @@ pub:
body_pos token.Position body_pos token.Position
comments []Comment comments []Comment
left_as_name string // `name` in `if cond is SumType as name` left_as_name string // `name` in `if cond is SumType as name`
mut_name bool // `if mut name is` is_mut_name bool // `if mut name is`
pub mut: pub mut:
stmts []Stmt stmts []Stmt
smartcast bool // true when cond is `x is SumType`, set in checker.if_expr // no longer needed with union sum types TODO: remove smartcast bool // true when cond is `x is SumType`, set in checker.if_expr // no longer needed with union sum types TODO: remove

View File

@ -3516,21 +3516,41 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, type_sym table.TypeSymbol
} }
mut scope := c.file.scope.innermost(branch.pos.pos) mut scope := c.file.scope.innermost(branch.pos.pos)
match node.cond as node_cond { match node.cond as node_cond {
ast.SelectorExpr { scope.register_struct_field(ast.ScopeStructField{ ast.SelectorExpr {
expr_sym := c.table.get_type_symbol(node_cond.expr_type)
field := c.table.struct_find_field(expr_sym, node_cond.field_name) or {
table.Field{}
}
is_mut := field.is_mut
is_root_mut := scope.is_selector_root_mutable(c.table, node_cond)
// smartcast either if the value is immutable or if the mut argument is explicitly given
if (!is_root_mut && !is_mut) || node.is_mut {
scope.register_struct_field(ast.ScopeStructField{
struct_type: node_cond.expr_type struct_type: node_cond.expr_type
name: node_cond.field_name name: node_cond.field_name
typ: node.cond_type typ: node.cond_type
sum_type_cast: expr_type sum_type_cast: expr_type
pos: node_cond.pos pos: node_cond.pos
}) } })
ast.Ident { scope.register(node.var_name, ast.Var{ }
}
ast.Ident {
mut is_mut := false
if v := scope.find_var(node_cond.name) {
is_mut = v.is_mut
}
// smartcast either if the value is immutable or if the mut argument is explicitly given
if !is_mut || node.is_mut {
scope.register(node.var_name, ast.Var{
name: node.var_name name: node.var_name
typ: node.cond_type typ: node.cond_type
pos: node_cond.pos pos: node_cond.pos
is_used: true is_used: true
is_mut: node.is_mut is_mut: node.is_mut
sum_type_cast: expr_type sum_type_cast: expr_type
}) } })
}
}
else {} else {}
} }
} }
@ -3762,7 +3782,9 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
if v := scope.find_var(infix_left.name) { if v := scope.find_var(infix_left.name) {
is_mut = v.is_mut is_mut = v.is_mut
} }
if !is_mut && left_sym.kind == .union_sum_type { // smartcast either if the value is immutable or if the mut argument is explicitly given
if (!is_mut || branch.is_mut_name) &&
left_sym.kind == .union_sum_type {
scope.register(branch.left_as_name, ast.Var{ scope.register(branch.left_as_name, ast.Var{
name: branch.left_as_name name: branch.left_as_name
typ: infix.left_type typ: infix.left_type
@ -3780,7 +3802,10 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
is_mut = field.is_mut is_mut = field.is_mut
is_root_mut := scope.is_selector_root_mutable(c.table, is_root_mut := scope.is_selector_root_mutable(c.table,
selector) selector)
if !is_root_mut && !is_mut && left_sym.kind == .union_sum_type { // smartcast either if the value is immutable or if the mut argument is explicitly given
if ((!is_root_mut && !is_mut) ||
branch.is_mut_name) &&
left_sym.kind == .union_sum_type {
scope.register_struct_field(ast.ScopeStructField{ scope.register_struct_field(ast.ScopeStructField{
struct_type: selector.expr_type struct_type: selector.expr_type
name: selector.field_name name: selector.field_name

View File

@ -1423,7 +1423,7 @@ pub fn (mut f Fmt) if_expr(it ast.IfExpr) {
} }
if i < it.branches.len - 1 || !it.has_else { if i < it.branches.len - 1 || !it.has_else {
f.write('${dollar}if ') f.write('${dollar}if ')
if branch.mut_name { if branch.is_mut_name {
f.write('mut ') f.write('mut ')
} }
f.expr(branch.cond) f.expr(branch.cond)

View File

@ -86,9 +86,9 @@ fn (mut p Parser) if_expr(is_comptime bool) ast.IfExpr {
} }
comments << p.eat_comments() comments << p.eat_comments()
// `if mut name is T` // `if mut name is T`
mut mut_name := false mut is_mut_name := false
if p.tok.kind == .key_mut && p.peek_tok2.kind == .key_is { if p.tok.kind == .key_mut && p.peek_tok2.kind == .key_is {
mut_name = true is_mut_name = true
p.next() p.next()
comments << p.eat_comments() comments << p.eat_comments()
} }
@ -150,7 +150,7 @@ fn (mut p Parser) if_expr(is_comptime bool) ast.IfExpr {
body_pos: body_pos.extend(p.prev_tok.position()) body_pos: body_pos.extend(p.prev_tok.position())
comments: comments comments: comments
left_as_name: left_as_name left_as_name: left_as_name
mut_name: mut_name is_mut_name: is_mut_name
} }
comments = p.eat_comments() comments = p.eat_comments()
if is_comptime { if is_comptime {

View File

@ -346,10 +346,12 @@ fn test_zero_value_init() {
} }
struct Milk { struct Milk {
mut:
name string name string
} }
struct Eggs { struct Eggs {
mut:
name string name string
} }
@ -364,6 +366,50 @@ fn test_match_aggregate() {
} }
} }
fn test_match_mut() {
mut f := Food(Milk{'test'})
match union mut f {
Eggs {
f.name = 'eggs'
assert f.name == 'eggs'
}
Milk {
f.name = 'milk'
assert f.name == 'milk'
}
}
}
fn test_match_not_mut() {
mut f := Food(Milk{'test'})
match union f {
Eggs {
// only works without smartcast
assert f is Eggs
}
Milk {
// only works without smartcast
assert f is Milk
}
}
}
fn test_if_mut() {
mut f := Food(Milk{'test'})
if mut f is Milk {
f.name = 'milk'
assert f.name == 'milk'
}
}
fn test_if_not_mut() {
mut f := Food(Milk{'test'})
if f is Milk {
// only works without smartcast
assert f is Milk
}
}
fn test_sum_type_match() { fn test_sum_type_match() {
// TODO: Remove these casts // TODO: Remove these casts
assert is_gt_simple('3', int(2)) assert is_gt_simple('3', int(2))