checker: add check for strict .str() method signature
parent
4403c76406
commit
35431d457b
|
@ -24,7 +24,7 @@ pub fn (node &FnDecl) modname() string {
|
|||
|
||||
// These methods are used only by vfmt, vdoc, and for debugging.
|
||||
|
||||
pub fn (node &FnDecl) str(t &table.Table) string {
|
||||
pub fn (node &FnDecl) stringify(t &table.Table) string {
|
||||
mut f := strings.new_builder(30)
|
||||
if node.is_pub {
|
||||
f.write('pub ')
|
||||
|
|
|
@ -2950,6 +2950,16 @@ fn (mut c Checker) fn_decl(node ast.FnDecl) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if node.language == .v && node.is_method && node.name == 'str' {
|
||||
if node.return_type != table.string_type {
|
||||
c.error('.str() methods should return `string`', node.pos)
|
||||
}
|
||||
if node.args.len != 1 {
|
||||
c.error('.str() methods should have 0 arguments', node.pos)
|
||||
}
|
||||
}
|
||||
|
||||
c.expected_type = table.void_type
|
||||
c.cur_fn = &node
|
||||
c.stmts(node.stmts)
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
vlib/v/checker/tests/str_method_0_arguments.v:5:1: error: .str() methods should have 0 arguments
|
||||
3 | }
|
||||
4 |
|
||||
5 | fn (z Zzz) str(x int) string {
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
6 | return 'z: $z.x'
|
||||
7 | }
|
|
@ -0,0 +1,11 @@
|
|||
struct Zzz {
|
||||
x int
|
||||
}
|
||||
|
||||
fn (z Zzz) str(x int) string {
|
||||
return 'z: $z.x'
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println(Zzz{123})
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
vlib/v/checker/tests/str_method_return_string.v:5:1: error: .str() methods should return `string`
|
||||
3 | }
|
||||
4 |
|
||||
5 | fn (z Zzz) str(x int) int {
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
6 | return z.x
|
||||
7 | }
|
|
@ -0,0 +1,11 @@
|
|||
struct Zzz {
|
||||
x int
|
||||
}
|
||||
|
||||
fn (z Zzz) str(x int) int {
|
||||
return z.x
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println(Zzz{123})
|
||||
}
|
|
@ -119,7 +119,7 @@ pub fn (mut d Doc) get_signature(stmt ast.Stmt, file &ast.File) string {
|
|||
return 'module $stmt.name'
|
||||
}
|
||||
ast.FnDecl {
|
||||
return stmt.str(d.table).replace(d.fmt.cur_mod + '.', '')
|
||||
return stmt.stringify(d.table).replace(d.fmt.cur_mod + '.', '')
|
||||
}
|
||||
else {
|
||||
d.fmt.out = strings.new_builder(1000)
|
||||
|
|
|
@ -421,7 +421,7 @@ pub fn (mut f Fmt) stmt(node ast.Stmt) {
|
|||
f.writeln('interface $it.name {')
|
||||
for method in it.methods {
|
||||
f.write('\t')
|
||||
f.writeln(method.str(f.table).after('fn '))
|
||||
f.writeln(method.stringify(f.table).after('fn '))
|
||||
}
|
||||
f.writeln('}\n')
|
||||
}
|
||||
|
@ -1134,7 +1134,7 @@ pub fn (mut f Fmt) comments(some_comments []ast.Comment, remove_last_new_line bo
|
|||
pub fn (mut f Fmt) fn_decl(node ast.FnDecl) {
|
||||
// println('$it.name find_comment($it.pos.line_nr)')
|
||||
// f.find_comment(it.pos.line_nr)
|
||||
s := node.str(f.table)
|
||||
s := node.stringify(f.table)
|
||||
f.write(s.replace(f.cur_mod + '.', '')) // `Expr` instead of `ast.Expr` in mod ast
|
||||
if node.language == .v {
|
||||
f.writeln(' {')
|
||||
|
|
|
@ -3232,9 +3232,9 @@ fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype table.Type) ?bool {
|
|||
g.expr(expr)
|
||||
if sym.kind == .struct_ && !sym_has_str_method {
|
||||
if is_p {
|
||||
g.write('),0))')
|
||||
g.write(')))')
|
||||
} else {
|
||||
g.write(',0)')
|
||||
g.write(')')
|
||||
}
|
||||
} else {
|
||||
if is_p {
|
||||
|
@ -4062,8 +4062,12 @@ fn (mut g Gen) gen_str_for_struct(info table.Struct, styp, str_fn_name string) {
|
|||
fnames2strfunc[field_styp] = field_fn_name
|
||||
}
|
||||
}
|
||||
g.type_definitions.writeln('string ${str_fn_name}($styp x, int indent_count); // auto')
|
||||
g.auto_str_funcs.writeln('string ${str_fn_name}($styp x, int indent_count) {')
|
||||
// _str() functions should have a single argument, the indenting ones take 2:
|
||||
g.type_definitions.writeln('string ${str_fn_name}($styp x); // auto')
|
||||
g.auto_str_funcs.writeln('string ${str_fn_name}($styp x) { return indent_${str_fn_name}(x,0);}')
|
||||
//
|
||||
g.type_definitions.writeln('string indent_${str_fn_name}($styp x, int indent_count); // auto')
|
||||
g.auto_str_funcs.writeln('string indent_${str_fn_name}($styp x, int indent_count) {')
|
||||
mut clean_struct_v_type_name := styp.replace('__', '.')
|
||||
if styp.ends_with('*') {
|
||||
deref_typ := styp.replace('*', '')
|
||||
|
@ -4090,7 +4094,6 @@ fn (mut g Gen) gen_str_for_struct(info table.Struct, styp, str_fn_name string) {
|
|||
for i, field in info.fields {
|
||||
sym := g.table.get_type_symbol(field.typ)
|
||||
has_custom_str := sym.has_method('str')
|
||||
second_str_param := if has_custom_str { '' } else { ', indent_count + 1' }
|
||||
mut field_styp := g.typ(field.typ)
|
||||
if field_styp.ends_with('*') {
|
||||
field_styp = field_styp.replace('*', '')
|
||||
|
@ -4101,7 +4104,11 @@ fn (mut g Gen) gen_str_for_struct(info table.Struct, styp, str_fn_name string) {
|
|||
g.auto_str_funcs.write('${field_styp_fn_name}( it->${c_name(field.name)} ) ')
|
||||
} else if sym.kind == .struct_ {
|
||||
g.auto_str_funcs.write('indents, ')
|
||||
g.auto_str_funcs.write('${field_styp_fn_name}( it->${c_name(field.name)}$second_str_param ) ')
|
||||
if has_custom_str {
|
||||
g.auto_str_funcs.write('${field_styp_fn_name}( it->${c_name(field.name)} ) ')
|
||||
}else{
|
||||
g.auto_str_funcs.write('indent_${field_styp_fn_name}( it->${c_name(field.name)}, indent_count + 1 ) ')
|
||||
}
|
||||
} else if sym.kind in [.array, .array_fixed, .map] {
|
||||
g.auto_str_funcs.write('indents, ')
|
||||
g.auto_str_funcs.write('${field_styp_fn_name}( it->${c_name(field.name)}) ')
|
||||
|
@ -4145,9 +4152,9 @@ fn (mut g Gen) gen_str_for_array(info table.Array, styp, str_fn_name string) {
|
|||
g.auto_str_funcs.writeln('\t\t$field_styp it = (*($field_styp*)array_get(a, i));')
|
||||
if sym.kind == .struct_ && !sym_has_str_method {
|
||||
if is_elem_ptr {
|
||||
g.auto_str_funcs.writeln('\t\tstring x = ${elem_str_fn_name}(*it,0);')
|
||||
g.auto_str_funcs.writeln('\t\tstring x = ${elem_str_fn_name}(*it);')
|
||||
} else {
|
||||
g.auto_str_funcs.writeln('\t\tstring x = ${elem_str_fn_name}(it,0);')
|
||||
g.auto_str_funcs.writeln('\t\tstring x = ${elem_str_fn_name}(it);')
|
||||
}
|
||||
} else if sym.kind in [.f32, .f64] {
|
||||
g.auto_str_funcs.writeln('\t\tstring x = _STR("%g", 1, it);')
|
||||
|
@ -4201,7 +4208,7 @@ fn (mut g Gen) gen_str_for_array_fixed(info table.ArrayFixed, styp, str_fn_name
|
|||
g.auto_str_funcs.writeln('\tstrings__Builder_write(&sb, tos_lit("["));')
|
||||
g.auto_str_funcs.writeln('\tfor (int i = 0; i < $info.size; ++i) {')
|
||||
if sym.kind == .struct_ && !sym_has_str_method {
|
||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${elem_str_fn_name}(a[i],0));')
|
||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${elem_str_fn_name}(a[i]));')
|
||||
} else if sym.kind in [.f32, .f64] {
|
||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, _STR("%g", 1, a[i]));')
|
||||
} else if sym.kind == .string {
|
||||
|
@ -4252,7 +4259,7 @@ fn (mut g Gen) gen_str_for_map(info table.Map, styp, str_fn_name string) {
|
|||
if val_sym.kind == .string {
|
||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, _STR("\'%.*s\\000\'", 2, it));')
|
||||
} else if val_sym.kind == .struct_ && !val_sym.has_method('str') {
|
||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${elem_str_fn_name}(it,0));')
|
||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${elem_str_fn_name}(it));')
|
||||
} else if val_sym.kind in [.f32, .f64] {
|
||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, _STR("%g", 1, it));')
|
||||
} else {
|
||||
|
@ -4273,12 +4280,7 @@ fn (mut g Gen) gen_str_for_varg(styp, str_fn_name string, has_str_method bool) {
|
|||
g.auto_str_funcs.writeln('\tstrings__Builder sb = strings__new_builder(it.len);')
|
||||
g.auto_str_funcs.writeln('\tstrings__Builder_write(&sb, tos_lit("["));')
|
||||
g.auto_str_funcs.writeln('\tfor(int i=0; i<it.len; ++i) {')
|
||||
if has_str_method {
|
||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${str_fn_name}(it.args[i]));')
|
||||
} else {
|
||||
// autogenerated str methods take the indent level as a second argument:
|
||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${str_fn_name}(it.args[i], 0));')
|
||||
}
|
||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${str_fn_name}(it.args[i]));')
|
||||
g.auto_str_funcs.writeln('\t\tif (i < it.len-1) {')
|
||||
g.auto_str_funcs.writeln('\t\t\tstrings__Builder_write(&sb, tos_lit(", "));')
|
||||
g.auto_str_funcs.writeln('\t\t}')
|
||||
|
@ -4313,7 +4315,7 @@ fn (mut g Gen) gen_str_for_multi_return(info table.MultiReturn, styp, str_fn_nam
|
|||
arg_str_fn_name = styp_to_str_fn_name(field_styp)
|
||||
}
|
||||
if sym.kind == .struct_ && !sym_has_str_method {
|
||||
g.auto_str_funcs.writeln('\tstrings__Builder_write(&sb, ${str_fn_name}(a.arg$i,0));')
|
||||
g.auto_str_funcs.writeln('\tstrings__Builder_write(&sb, ${str_fn_name}(a.arg$i));')
|
||||
} else if sym.kind in [.f32, .f64] {
|
||||
g.auto_str_funcs.writeln('\tstrings__Builder_write(&sb, _STR("%g", 1, a.arg$i));')
|
||||
} else if sym.kind == .string {
|
||||
|
|
|
@ -515,10 +515,6 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
|
|||
g.write('*')
|
||||
}
|
||||
g.expr(expr)
|
||||
if !typ.has_flag(.variadic) && sym.kind == .struct_ &&
|
||||
styp != 'ptr' && !sym.has_method('str') {
|
||||
g.write(', 0') // trailing 0 is initial struct indent count
|
||||
}
|
||||
}
|
||||
g.write('))')
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue