fmt: unwrap long infix exprs inside parenthesis if necessary (#8609)

pull/8631/head
Lukas Neubert 2021-02-07 23:10:39 +01:00 committed by GitHub
parent ff1aa06455
commit 7f4c582f1a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 93 additions and 52 deletions

View File

@ -1298,11 +1298,11 @@ fn (mut c Checker) check_map_and_filter(is_map bool, elem_typ table.Type, call_e
ast.AnonFn { ast.AnonFn {
if arg_expr.decl.params.len > 1 { if arg_expr.decl.params.len > 1 {
c.error('function needs exactly 1 argument', arg_expr.decl.pos) c.error('function needs exactly 1 argument', arg_expr.decl.pos)
} else if is_map } else if is_map && (arg_expr.decl.return_type == table.void_type
&& (arg_expr.decl.return_type == table.void_type || arg_expr.decl.params[0].typ != elem_typ) { || arg_expr.decl.params[0].typ != elem_typ) {
c.error('type mismatch, should use `fn(a $elem_sym.name) T {...}`', arg_expr.decl.pos) c.error('type mismatch, should use `fn(a $elem_sym.name) T {...}`', arg_expr.decl.pos)
} else if !is_map } else if !is_map && (arg_expr.decl.return_type != table.bool_type
&& (arg_expr.decl.return_type != table.bool_type || arg_expr.decl.params[0].typ != elem_typ) { || arg_expr.decl.params[0].typ != elem_typ) {
c.error('type mismatch, should use `fn(a $elem_sym.name) bool {...}`', c.error('type mismatch, should use `fn(a $elem_sym.name) bool {...}`',
arg_expr.decl.pos) arg_expr.decl.pos)
} }
@ -2389,8 +2389,8 @@ pub fn (mut c Checker) return_stmt(mut return_stmt ast.Return) {
} }
for i, exp_type in expected_types { for i, exp_type in expected_types {
got_typ := c.unwrap_generic(got_types[i]) got_typ := c.unwrap_generic(got_types[i])
if got_typ.has_flag(.optional) if got_typ.has_flag(.optional) && (!exp_type.has_flag(.optional)
&& (!exp_type.has_flag(.optional) || c.table.type_to_str(got_typ) != c.table.type_to_str(exp_type)) { || c.table.type_to_str(got_typ) != c.table.type_to_str(exp_type)) {
pos := return_stmt.exprs[i].position() pos := return_stmt.exprs[i].position()
c.error('cannot use `${c.table.type_to_str(got_typ)}` as type `${c.table.type_to_str(exp_type)}` in return argument', c.error('cannot use `${c.table.type_to_str(got_typ)}` as type `${c.table.type_to_str(exp_type)}` in return argument',
pos) pos)
@ -3765,7 +3765,8 @@ pub fn (mut c Checker) cast_expr(mut node ast.CastExpr) table.Type {
node.pos) node.pos)
} }
} else if node.typ == table.string_type } else if node.typ == table.string_type
&& (from_type_sym.kind in [.int_literal, .int, .byte, .byteptr, .bool] || (from_type_sym.kind == .array && from_type_sym.name == 'array_byte')) { && (from_type_sym.kind in [.int_literal, .int, .byte, .byteptr, .bool]
|| (from_type_sym.kind == .array && from_type_sym.name == 'array_byte')) {
type_name := c.table.type_to_str(node.expr_type) type_name := c.table.type_to_str(node.expr_type)
c.error('cannot cast type `$type_name` to string, use `x.str()` instead', node.pos) c.error('cannot cast type `$type_name` to string, use `x.str()` instead', node.pos)
} else if node.expr_type == table.string_type { } else if node.expr_type == table.string_type {
@ -5640,9 +5641,8 @@ fn (mut c Checker) sql_stmt(mut node ast.SqlStmt) table.Type {
} }
fn (mut c Checker) fetch_and_verify_orm_fields(info table.Struct, pos token.Position, table_name string) []table.Field { fn (mut c Checker) fetch_and_verify_orm_fields(info table.Struct, pos token.Position, table_name string) []table.Field {
fields := info.fields.filter( fields := info.fields.filter((it.typ in [table.string_type, table.int_type, table.bool_type]
(it.typ in [table.string_type, table.int_type, table.bool_type] || c.table.types[int(it.typ)].kind == .struct_) || c.table.types[int(it.typ)].kind == .struct_) && !it.attrs.contains('skip'))
&& !it.attrs.contains('skip'))
if fields.len == 0 { if fields.len == 0 {
c.error('V orm: select: empty fields in `$table_name`', pos) c.error('V orm: select: empty fields in `$table_name`', pos)
return []table.Field{} return []table.Field{}

View File

@ -1541,7 +1541,7 @@ pub fn (mut f Fmt) infix_expr(node ast.InfixExpr) {
if node.op == .left_shift { if node.op == .left_shift {
f.is_assign = true // To write ternary if on a single line f.is_assign = true // To write ternary if on a single line
} }
infix_start := f.out.len start_pos := f.out.len
start_len := f.line_len start_len := f.line_len
f.expr(node.left) f.expr(node.left)
is_one_val_array_init := node.op in [.key_in, .not_in] && node.right is ast.ArrayInit is_one_val_array_init := node.op in [.key_in, .not_in] && node.right is ast.ArrayInit
@ -1562,14 +1562,14 @@ pub fn (mut f Fmt) infix_expr(node ast.InfixExpr) {
if !buffering_save && f.buffering { if !buffering_save && f.buffering {
f.buffering = false f.buffering = false
if !f.single_line_if && f.line_len > fmt.max_len.last() { if !f.single_line_if && f.line_len > fmt.max_len.last() {
f.wrap_infix(infix_start, start_len) f.wrap_infix(start_pos, start_len, false)
} }
} }
f.is_assign = is_assign_save f.is_assign = is_assign_save
f.or_expr(node.or_block) f.or_expr(node.or_block)
} }
pub fn (mut f Fmt) wrap_infix(start_pos int, start_len int) { pub fn (mut f Fmt) wrap_infix(start_pos int, start_len int, ignore_paren bool) {
cut_span := f.out.len - start_pos cut_span := f.out.len - start_pos
condstr := f.out.cut_last(cut_span) condstr := f.out.cut_last(cut_span)
is_cond_infix := condstr.contains_any_substr(['&&', '||']) is_cond_infix := condstr.contains_any_substr(['&&', '||'])
@ -1604,6 +1604,9 @@ pub fn (mut f Fmt) wrap_infix(start_pos int, start_len int) {
index++ index++
} else { } else {
conditions[index] += '$cp ' conditions[index] += '$cp '
if ignore_paren {
continue
}
if cp.starts_with('(') { if cp.starts_with('(') {
grouped_cond = true grouped_cond = true
} else if cp.ends_with(')') { } else if cp.ends_with(')') {
@ -1614,15 +1617,21 @@ pub fn (mut f Fmt) wrap_infix(start_pos int, start_len int) {
for i, c in conditions { for i, c in conditions {
cnd := c.trim_space() cnd := c.trim_space()
if f.line_len + cnd.len < fmt.max_len[penalties[i]] { if f.line_len + cnd.len < fmt.max_len[penalties[i]] {
if i > 0 && (!is_cond_infix || i < conditions.len - 1) { if (i > 0 && i < conditions.len) || (ignore_paren && i == 0 && cnd[3] == `(`) {
f.write(' ') f.write(' ')
} }
f.write(cnd) f.write(cnd)
} else { } else {
prev_len := f.line_len
prev_pos := f.out.len
f.writeln('') f.writeln('')
f.indent++ f.indent++
f.write(cnd) f.write(cnd)
f.indent-- f.indent--
if f.line_len > fmt.max_len.last() && (cnd[0] == `(` || cnd[3] == `(`)
&& cnd.ends_with(')') {
f.wrap_infix(prev_pos, prev_len, true)
}
} }
} }
} }
@ -2129,8 +2138,9 @@ pub fn (mut f Fmt) struct_init(it ast.StructInit) {
f.writeln('') f.writeln('')
} }
f.comments(field.next_comments, inline: false, has_nl: true, level: .keep) f.comments(field.next_comments, inline: false, has_nl: true, level: .keep)
if single_line_fields if single_line_fields && (field.comments.len > 0
&& (field.comments.len > 0 || field.next_comments.len > 0 || !expr_is_single_line(field.expr) || field.next_comments.len > 0
|| !expr_is_single_line(field.expr)
|| f.line_len > fmt.max_len.last()) { || f.line_len > fmt.max_len.last()) {
single_line_fields = false single_line_fields = false
f.out.go_back_to(fields_start) f.out.go_back_to(fields_start)

View File

@ -0,0 +1,16 @@
fn grouped_cond_single_line() {
// fmt tries to keep grouped conditions together...
_ := one_condition_before && another_condition
&& (inside_paren || is_kept_together || if_possible) && end_cond
}
fn unwrap_grouped_conds() {
// ...but sometimes they have to be splitted
_ := one_condition && before_condition && (conds_inside_paren
|| are_kept_together || if_possible || but_this_is_really_too_much
|| for_one_line)
_ := (also_inside_parens || just_as_above || but_this_is_also_more
|| than_a_single_line_could_fit) && end_cond
fields = fields.filter((it.typ in [string_type, int_type, bool_type]
|| c.table.types[int(it.typ)].kind == .struct_) && !it.attrs.contains('skip'))
}

View File

@ -0,0 +1,11 @@
fn grouped_cond_single_line() {
// fmt tries to keep grouped conditions together...
_ := one_condition_before && another_condition && (inside_paren || is_kept_together || if_possible) && end_cond
}
fn unwrap_grouped_conds() {
// ...but sometimes they have to be splitted
_ := one_condition && before_condition && (conds_inside_paren || are_kept_together || if_possible || but_this_is_really_too_much || for_one_line)
_ := (also_inside_parens || just_as_above || but_this_is_also_more || than_a_single_line_could_fit) && end_cond
fields = fields.filter((it.typ in [string_type, int_type, bool_type] || c.table.types[int(it.typ)].kind == .struct_) && !it.attrs.contains('skip'))
}

View File

@ -2028,7 +2028,8 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
} else { } else {
g.out.go_back_to(pos) g.out.go_back_to(pos)
is_var_mut := !is_decl && left is ast.Ident is_var_mut := !is_decl && left is ast.Ident
&& (g.for_in_mut_val_name == (left as ast.Ident).name || (left as ast.Ident).name in g.fn_mut_arg_names) && (g.for_in_mut_val_name == (left as ast.Ident).name
|| (left as ast.Ident).name in g.fn_mut_arg_names)
addr := if is_var_mut { '' } else { '&' } addr := if is_var_mut { '' } else { '&' }
g.writeln('') g.writeln('')
g.write('memcpy($addr') g.write('memcpy($addr')
@ -2100,7 +2101,8 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
} }
if !is_fixed_array_copy || is_decl { if !is_fixed_array_copy || is_decl {
if !is_decl && var_type != table.string_type_idx && left is ast.Ident if !is_decl && var_type != table.string_type_idx && left is ast.Ident
&& (g.for_in_mut_val_name == (left as ast.Ident).name || (left as ast.Ident).name in g.fn_mut_arg_names) { && (g.for_in_mut_val_name == (left as ast.Ident).name
|| (left as ast.Ident).name in g.fn_mut_arg_names) {
g.write('*') g.write('*')
} }
g.expr(left) g.expr(left)
@ -4006,8 +4008,9 @@ fn (mut g Gen) if_expr(node ast.IfExpr) {
// (as it used to be done). // (as it used to be done).
// Always use this in -autofree, since ?: can have tmp expressions that have to be freed. // Always use this in -autofree, since ?: can have tmp expressions that have to be freed.
first_branch := node.branches[0] first_branch := node.branches[0]
needs_tmp_var := node.is_expr needs_tmp_var := node.is_expr && (g.is_autofree || (g.pref.experimental
&& (g.is_autofree || (g.pref.experimental && (first_branch.stmts.len > 1 || (first_branch.stmts[0] is ast.ExprStmt && (first_branch.stmts[0] as ast.ExprStmt).expr is ast.IfExpr)))) && (first_branch.stmts.len > 1 || (first_branch.stmts[0] is ast.ExprStmt
&& (first_branch.stmts[0] as ast.ExprStmt).expr is ast.IfExpr))))
/* /*
needs_tmp_var := node.is_expr && needs_tmp_var := node.is_expr &&
(g.autofree || g.pref.experimental) && (g.autofree || g.pref.experimental) &&

View File

@ -343,8 +343,8 @@ fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype table.Type) {
} else if sym_has_str_method } else if sym_has_str_method
|| sym.kind in [.array, .array_fixed, .map, .struct_, .multi_return, .sum_type, .interface_] { || sym.kind in [.array, .array_fixed, .map, .struct_, .multi_return, .sum_type, .interface_] {
is_ptr := typ.is_ptr() is_ptr := typ.is_ptr()
is_var_mut := expr is ast.Ident is_var_mut := expr is ast.Ident && ((expr as ast.Ident).name == g.for_in_mut_val_name
&& ((expr as ast.Ident).name == g.for_in_mut_val_name || (expr as ast.Ident).name in g.fn_mut_arg_names) || (expr as ast.Ident).name in g.fn_mut_arg_names)
str_fn_name := g.gen_str_for_type(typ) str_fn_name := g.gen_str_for_type(typ)
if is_ptr && !is_var_mut { if is_ptr && !is_var_mut {
g.write('_STR("&%.*s\\000", 2, ') g.write('_STR("&%.*s\\000", 2, ')

View File

@ -180,8 +180,8 @@ fn (mut p Parser) match_expr() ast.MatchExpr {
p.next() p.next()
} else if (p.tok.kind == .name && !(p.tok.lit == 'C' && p.peek_tok.kind == .dot) } else if (p.tok.kind == .name && !(p.tok.lit == 'C' && p.peek_tok.kind == .dot)
&& (p.tok.lit in table.builtin_type_names || p.tok.lit[0].is_capital() && (p.tok.lit in table.builtin_type_names || p.tok.lit[0].is_capital()
|| (p.peek_tok.kind == .dot && p.peek_tok2.lit.len > 0 && p.peek_tok2.lit[0].is_capital()))) || (p.peek_tok.kind == .dot && p.peek_tok2.lit.len > 0
|| p.tok.kind == .lsbr { && p.peek_tok2.lit[0].is_capital()))) || p.tok.kind == .lsbr {
mut types := []table.Type{} mut types := []table.Type{}
for { for {
// Sum type match // Sum type match

View File

@ -1091,8 +1091,9 @@ fn (mut s Scanner) ident_string() string {
s.error(r'`\x` used with no following hex digits') s.error(r'`\x` used with no following hex digits')
} }
// Escape `\u` // Escape `\u`
if c == `u` if c == `u` && (s.text[s.pos + 1] == s.quote
&& (s.text[s.pos + 1] == s.quote || s.text[s.pos + 2] == s.quote || s.text[s.pos + 3] == s.quote || s.text[s.pos + 4] == s.quote || !s.text[s.pos + 1].is_hex_digit() || s.text[s.pos + 2] == s.quote || s.text[s.pos + 3] == s.quote
|| s.text[s.pos + 4] == s.quote || !s.text[s.pos + 1].is_hex_digit()
|| !s.text[s.pos + 2].is_hex_digit() || !s.text[s.pos + 2].is_hex_digit()
|| !s.text[s.pos + 3].is_hex_digit() || !s.text[s.pos + 3].is_hex_digit()
|| !s.text[s.pos + 4].is_hex_digit()) { || !s.text[s.pos + 4].is_hex_digit()) {

View File

@ -534,8 +534,8 @@ fn handle_conn<T>(mut conn net.TcpConn, mut app T) {
if route_words.len == 1 && route_words[0] in vweb.methods_without_first { if route_words.len == 1 && route_words[0] in vweb.methods_without_first {
req_method << route_words[0] req_method << route_words[0]
} }
if url_words.len == route_words.len if url_words.len == route_words.len || (url_words.len >= route_words.len - 1
|| (url_words.len >= route_words.len - 1 && route_words.len > 0 && route_words.last().ends_with('...')) { && route_words.len > 0 && route_words.last().ends_with('...')) {
if req_method.len > 0 { if req_method.len > 0 {
if req_method_str.to_lower()[1..] !in req_method { if req_method_str.to_lower()[1..] !in req_method {
continue continue