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 | ||||||
|  | @ -533,7 +536,6 @@ pub: | ||||||
| 	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
 | ||||||
|  | @ -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