parser: move mut in if/match to expr (#6973)
parent
62ee436944
commit
966b95ca4e
|
@ -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
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 | }
|
Loading…
Reference in New Issue