parser: move mut in if/match to expr (#6973)

pull/6975/head
Daniel Däschle 2020-11-27 03:08:42 +01:00 committed by GitHub
parent 62ee436944
commit 966b95ca4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 45 additions and 79 deletions

View File

@ -106,6 +106,8 @@ pub:
pos token.Position pos token.Position
expr Expr // expr.field_name expr Expr // expr.field_name
field_name string field_name string
is_mut bool // is used for the case `if mut ident.selector is MyType {`, it indicates if the root ident is mutable
mut_pos token.Position
pub mut: pub mut:
expr_type table.Type // type of `Foo` in `Foo.bar` expr_type table.Type // type of `Foo` in `Foo.bar`
typ table.Type // type of the entire thing (`Foo.bar`) typ table.Type // type of the entire thing (`Foo.bar`)
@ -447,6 +449,7 @@ pub:
language table.Language language table.Language
tok_kind token.Kind tok_kind token.Kind
pos token.Position pos token.Position
mut_pos token.Position
pub mut: pub mut:
obj ScopeObject obj ScopeObject
mod string mod string
@ -529,14 +532,13 @@ pub mut:
pub struct IfBranch { pub struct IfBranch {
pub: pub:
cond Expr cond Expr
pos token.Position pos token.Position
body_pos token.Position body_pos token.Position
comments []Comment comments []Comment
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
} }
pub struct UnsafeExpr { pub struct UnsafeExpr {
@ -562,7 +564,6 @@ pub:
cond Expr cond Expr
branches []MatchBranch branches []MatchBranch
pos token.Position pos token.Position
is_mut bool // `match mut ast_node {`
pub mut: pub mut:
is_expr bool // returns a value is_expr bool // returns a value
return_type table.Type return_type table.Type

View File

@ -202,21 +202,3 @@ pub fn (sc &Scope) show(depth int, max_depth int) string {
pub fn (sc &Scope) str() string { pub fn (sc &Scope) str() string {
return sc.show(0, 0) return sc.show(0, 0)
} }
// is_selector_root_mutable checks if the root ident is mutable
// Example:
// ```
// mut x := MyStruct{}
// x.foo.bar.z
// ```
// Since x is mutable, it returns true.
pub fn (s &Scope) is_selector_root_mutable(t &table.Table, selector_expr SelectorExpr) bool {
if mut selector_expr.expr is SelectorExpr {
return s.is_selector_root_mutable(t, selector_expr.expr)
} else if mut selector_expr.expr is Ident {
if v := s.find_var(selector_expr.expr.name) {
return v.is_mut
}
}
return false
}

View File

@ -623,6 +623,16 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
c.warn('pointer arithmetic is only allowed in `unsafe` blocks', left_pos) c.warn('pointer arithmetic is only allowed in `unsafe` blocks', left_pos)
} }
mut return_type := left_type mut return_type := left_type
if infix_expr.op != .key_is {
match mut infix_expr.left {
ast.Ident, ast.SelectorExpr {
if infix_expr.left.is_mut {
c.error('remove unnecessary `mut`', infix_expr.left.mut_pos)
}
}
else {}
}
}
// Single side check // Single side check
// Place these branches according to ops' usage frequency to accelerate. // Place these branches according to ops' usage frequency to accelerate.
// TODO: First branch includes ops where single side check is not needed, or needed but hasn't been implemented. // TODO: First branch includes ops where single side check is not needed, or needed but hasn't been implemented.
@ -3451,11 +3461,6 @@ pub fn (mut c Checker) match_expr(mut node ast.MatchExpr) table.Type {
// node.expected_type = c.expected_type // node.expected_type = c.expected_type
// } // }
node.return_type = ret_type node.return_type = ret_type
if node.is_mut {
// Mark `x` in `match mut x {` as changed, and ensure it's mutable
// TODO2 enable when code is fixed
// c.fail_if_immutable(node.cond)
}
return ret_type return ret_type
} }
@ -3585,9 +3590,8 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, type_sym table.TypeSymbol
if field := scope.find_struct_field(node.cond.expr_type, node.cond.field_name) { if field := scope.find_struct_field(node.cond.expr_type, node.cond.field_name) {
sum_type_casts << field.sum_type_casts sum_type_casts << field.sum_type_casts
} }
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 // smartcast either if the value is immutable or if the mut argument is explicitly given
if (!is_root_mut && !is_mut) || node.is_mut { if !is_mut || node.cond.is_mut {
sum_type_casts << expr_type sum_type_casts << expr_type
scope.register_struct_field(ast.ScopeStructField{ scope.register_struct_field(ast.ScopeStructField{
struct_type: node.cond.expr_type struct_type: node.cond.expr_type
@ -3608,14 +3612,14 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, type_sym table.TypeSymbol
is_already_casted = v.pos.pos == node.cond.pos.pos is_already_casted = v.pos.pos == node.cond.pos.pos
} }
// smartcast either if the value is immutable or if the mut argument is explicitly given // smartcast either if the value is immutable or if the mut argument is explicitly given
if (!is_mut || node.is_mut) && !is_already_casted { if (!is_mut || node.cond.is_mut) && !is_already_casted {
sum_type_casts << expr_type sum_type_casts << expr_type
scope.register(node.cond.name, ast.Var{ scope.register(node.cond.name, ast.Var{
name: node.cond.name name: node.cond.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.cond.is_mut
sum_type_casts: sum_type_casts sum_type_casts: sum_type_casts
}) })
} }
@ -3846,7 +3850,7 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
} }
if left_sym.kind == .sum_type { if left_sym.kind == .sum_type {
// smartcast either if the value is immutable or if the mut argument is explicitly given // smartcast either if the value is immutable or if the mut argument is explicitly given
if !is_mut || branch.is_mut_name { if !is_mut || infix.left.is_mut {
sum_type_casts << right_expr.typ sum_type_casts << right_expr.typ
scope.register(infix.left.name, ast.Var{ scope.register(infix.left.name, ast.Var{
name: infix.left.name name: infix.left.name
@ -3879,12 +3883,8 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
infix.left.field_name) { infix.left.field_name) {
sum_type_casts << field.sum_type_casts sum_type_casts << field.sum_type_casts
} }
is_root_mut := scope.is_selector_root_mutable(c.table,
infix.left)
// smartcast either if the value is immutable or if the mut argument is explicitly given // smartcast either if the value is immutable or if the mut argument is explicitly given
if ((!is_root_mut && !is_mut) || if (!is_mut || infix.left.is_mut) && left_sym.kind == .sum_type {
branch.is_mut_name) &&
left_sym.kind == .sum_type {
sum_type_casts << right_expr.typ sum_type_casts << right_expr.typ
scope.register_struct_field(ast.ScopeStructField{ scope.register_struct_field(ast.ScopeStructField{
struct_type: infix.left.expr_type struct_type: infix.left.expr_type

View File

@ -251,9 +251,6 @@ pub fn (mut f Fmt) stmt(node ast.Stmt) {
for i, left in node.left { for i, left in node.left {
if left is ast.Ident { if left is ast.Ident {
var_info := left.var_info() var_info := left.var_info()
if var_info.is_mut {
f.write(var_info.share.str() + ' ')
}
if var_info.is_static { if var_info.is_static {
f.write('static ') f.write('static ')
} }
@ -835,10 +832,12 @@ pub fn (mut f Fmt) expr(node ast.Expr) {
f.if_expr(node) f.if_expr(node)
} }
ast.Ident { ast.Ident {
f.write_language_prefix(node.language) if mut node.info is ast.IdentVar {
if true { if node.info.is_mut {
} else { f.write(node.info.share.str() + ' ')
}
} }
f.write_language_prefix(node.language)
if node.name == 'it' && f.it_name != '' && !f.inside_lambda { // allow `it` in lambdas if node.name == 'it' && f.it_name != '' && !f.inside_lambda { // allow `it` in lambdas
f.write(f.it_name) f.write(f.it_name)
} else if node.kind == .blank_ident { } else if node.kind == .blank_ident {
@ -1411,9 +1410,6 @@ 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.is_mut_name {
f.write('mut ')
}
f.expr(branch.cond) f.expr(branch.cond)
f.write(' ') f.write(' ')
} }
@ -1532,9 +1528,6 @@ pub fn (mut f Fmt) call_expr(node ast.CallExpr) {
pub fn (mut f Fmt) match_expr(it ast.MatchExpr) { pub fn (mut f Fmt) match_expr(it ast.MatchExpr) {
f.write('match ') f.write('match ')
if it.is_mut {
f.write('mut ')
}
f.expr(it.cond) f.expr(it.cond)
if it.cond is ast.Ident { if it.cond is ast.Ident {
f.it_name = it.cond.name f.it_name = it.cond.name

View File

@ -84,15 +84,6 @@ fn (mut p Parser) if_expr(is_comptime bool) ast.IfExpr {
p.error('cannot use `match` with `if` statements') p.error('cannot use `match` with `if` statements')
} }
comments << p.eat_comments() comments << p.eat_comments()
// `if mut name is T`
mut is_mut_name := false
mut mut_pos := token.Position{}
if p.tok.kind == .key_mut {
is_mut_name = true
mut_pos = p.tok.position()
p.next()
comments << p.eat_comments()
}
mut cond := ast.Expr{} mut cond := ast.Expr{}
mut is_guard := false mut is_guard := false
// `if x := opt() {` // `if x := opt() {`
@ -120,15 +111,6 @@ fn (mut p Parser) if_expr(is_comptime bool) ast.IfExpr {
cond = p.expr(0) cond = p.expr(0)
} }
comments << p.eat_comments() comments << p.eat_comments()
if mut cond is ast.InfixExpr {
// if sum is T
is_is_cast := cond.op == .key_is
if !is_is_cast && is_mut_name {
p.error_with_pos('remove unnecessary `mut`', mut_pos)
}
} else if is_mut_name {
p.error_with_pos('remove unnecessary `mut`', mut_pos)
}
end_pos := p.prev_tok.position() end_pos := p.prev_tok.position()
body_pos := p.tok.position() body_pos := p.tok.position()
p.inside_if = false p.inside_if = false
@ -142,7 +124,6 @@ fn (mut p Parser) if_expr(is_comptime bool) ast.IfExpr {
pos: start_pos.extend(end_pos) pos: start_pos.extend(end_pos)
body_pos: body_pos.extend(p.prev_tok.position()) body_pos: body_pos.extend(p.prev_tok.position())
comments: comments comments: comments
is_mut_name: is_mut_name
} }
comments = p.eat_comments() comments = p.eat_comments()
if is_comptime { if is_comptime {
@ -170,11 +151,7 @@ fn (mut p Parser) match_expr() ast.MatchExpr {
match_first_pos := p.tok.position() match_first_pos := p.tok.position()
p.inside_match = true p.inside_match = true
p.check(.key_match) p.check(.key_match)
is_mut := p.tok.kind == .key_mut
mut is_sum_type := false mut is_sum_type := false
if is_mut {
p.next()
}
cond := p.expr(0) cond := p.expr(0)
p.inside_match = false p.inside_match = false
no_lcbr := p.tok.kind != .lcbr no_lcbr := p.tok.kind != .lcbr
@ -281,7 +258,6 @@ fn (mut p Parser) match_expr() ast.MatchExpr {
cond: cond cond: cond
is_sum_type: is_sum_type is_sum_type: is_sum_type
pos: pos pos: pos
is_mut: is_mut
} }
} }

View File

@ -914,6 +914,7 @@ pub fn (mut p Parser) parse_ident(language table.Language) ast.Ident {
// p.warn('name ') // p.warn('name ')
is_shared := p.tok.kind == .key_shared is_shared := p.tok.kind == .key_shared
is_atomic := p.tok.kind == .key_atomic is_atomic := p.tok.kind == .key_atomic
mut_pos := p.tok.position()
is_mut := p.tok.kind == .key_mut || is_shared || is_atomic is_mut := p.tok.kind == .key_mut || is_shared || is_atomic
if is_mut { if is_mut {
p.next() p.next()
@ -951,6 +952,7 @@ pub fn (mut p Parser) parse_ident(language table.Language) ast.Ident {
mod: p.mod mod: p.mod
pos: pos pos: pos
is_mut: is_mut is_mut: is_mut
mut_pos: mut_pos
info: ast.IdentVar{ info: ast.IdentVar{
is_mut: is_mut is_mut: is_mut
is_static: is_static is_static: is_static
@ -1349,10 +1351,22 @@ fn (mut p Parser) dot_expr(left ast.Expr) ast.Expr {
} }
return mcall_expr return mcall_expr
} }
mut is_mut := false
mut mut_pos := token.Position{}
if p.inside_match || p.inside_if_expr {
match left {
ast.Ident, ast.SelectorExpr {
is_mut = left.is_mut
mut_pos = left.mut_pos
}
else {}
}
}
sel_expr := ast.SelectorExpr{ sel_expr := ast.SelectorExpr{
expr: left expr: left
field_name: field_name field_name: field_name
pos: name_pos pos: name_pos
is_mut: is_mut
} }
mut node := ast.Expr{} mut node := ast.Expr{}
node = sel_expr node = sel_expr

View File

@ -1,6 +1,6 @@
vlib/v/parser/tests/unnecessary_mut_2.vv:2:5: error: remove unnecessary `mut` vlib/v/parser/tests/unnecessary_mut_2.vv:2:9: error: unexpected token `true`
1 | fn main() { 1 | fn main() {
2 | if mut true { 2 | if mut true {
| ~~~ | ~~~~
3 | println(true) 3 | println(true)
4 | } 4 | }