checker: add more `string(x)` checks, with more detailed replacement suggestions
parent
79cb303a6c
commit
f5d283721e
|
@ -5690,25 +5690,6 @@ pub fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
|
||||||
c.error('expression does not return a value so it cannot be cast', node.expr.position())
|
c.error('expression does not return a value so it cannot be cast', node.expr.position())
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
if to_type == ast.string_type {
|
|
||||||
if from_type in [ast.byte_type, ast.bool_type] {
|
|
||||||
c.error('cannot cast type `$from_type_sym.name` to string, use `${node.expr.str()}.str()` instead.',
|
|
||||||
node.pos)
|
|
||||||
}
|
|
||||||
if from_type.is_real_pointer() {
|
|
||||||
c.error('cannot cast pointer type `$from_type_sym.name` to string, use `&byte($node.expr.str()).vstring()` instead.',
|
|
||||||
node.pos)
|
|
||||||
}
|
|
||||||
if from_type.is_number() {
|
|
||||||
c.error('cannot cast number to string, use `${node.expr.str()}.str()` instead.',
|
|
||||||
node.pos)
|
|
||||||
}
|
|
||||||
if from_type_sym.kind == .alias && from_type_sym_final.name != 'string' {
|
|
||||||
c.error('cannot cast type `$from_type_sym.name` to string, use `x.str()` instead',
|
|
||||||
node.pos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//
|
|
||||||
if to_type_sym.kind == .sum_type {
|
if to_type_sym.kind == .sum_type {
|
||||||
if from_type in [ast.int_literal_type, ast.float_literal_type] {
|
if from_type in [ast.int_literal_type, ast.float_literal_type] {
|
||||||
xx := if from_type == ast.int_literal_type { ast.int_type } else { ast.f64_type }
|
xx := if from_type == ast.int_literal_type { ast.int_type } else { ast.f64_type }
|
||||||
|
@ -5723,15 +5704,6 @@ pub fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
|
||||||
c.error('cannot convert type `$from_type_sym.name` to `$to_type_sym.name` (alias to `$to_type_sym_final.name`)',
|
c.error('cannot convert type `$from_type_sym.name` to `$to_type_sym.name` (alias to `$to_type_sym_final.name`)',
|
||||||
node.pos)
|
node.pos)
|
||||||
}
|
}
|
||||||
} else if to_type != ast.string_type && from_type == ast.string_type
|
|
||||||
&& (!(to_type_sym.kind == .alias && to_type_sym_final.name == 'string')) {
|
|
||||||
mut error_msg := 'cannot cast a string to a type `$to_type_sym_final.name`, that is not an alias of string'
|
|
||||||
if mut node.expr is ast.StringLiteral {
|
|
||||||
if node.expr.val.len == 1 {
|
|
||||||
error_msg += ", for denoting characters use `$node.expr.val` instead of '$node.expr.val'"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c.error(error_msg, node.pos)
|
|
||||||
} else if to_type_sym.kind == .byte && from_type != ast.voidptr_type
|
} else if to_type_sym.kind == .byte && from_type != ast.voidptr_type
|
||||||
&& from_type_sym.kind != .enum_ && !from_type.is_int() && !from_type.is_float()
|
&& from_type_sym.kind != .enum_ && !from_type.is_int() && !from_type.is_float()
|
||||||
&& from_type != ast.bool_type && !from_type.is_ptr() && from_type_sym.kind == .alias
|
&& from_type != ast.bool_type && !from_type.is_ptr() && from_type_sym.kind == .alias
|
||||||
|
@ -5770,7 +5742,9 @@ pub fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
|
||||||
if (to_type.is_ptr() || to_type_sym.kind !in [.sum_type, .interface_]) && !c.is_builtin_mod {
|
if (to_type.is_ptr() || to_type_sym.kind !in [.sum_type, .interface_]) && !c.is_builtin_mod {
|
||||||
from_type_name := c.table.type_to_str(from_type)
|
from_type_name := c.table.type_to_str(from_type)
|
||||||
type_name := c.table.type_to_str(to_type)
|
type_name := c.table.type_to_str(to_type)
|
||||||
c.error('cannot cast struct `$from_type_name` to `$type_name`', node.pos)
|
snexpr := node.expr.str()
|
||||||
|
c.error('cannot cast struct `$from_type_name` to `$type_name`, use `${snexpr}.str()` instead.',
|
||||||
|
node.pos)
|
||||||
}
|
}
|
||||||
} else if from_type.has_flag(.optional) || from_type.has_flag(.variadic) {
|
} else if from_type.has_flag(.optional) || from_type.has_flag(.variadic) {
|
||||||
// variadic case can happen when arrays are converted into variadic
|
// variadic case can happen when arrays are converted into variadic
|
||||||
|
@ -5784,6 +5758,53 @@ pub fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
|
||||||
} else if from_type_sym.kind == .array_fixed && !from_type.is_ptr() {
|
} else if from_type_sym.kind == .array_fixed && !from_type.is_ptr() {
|
||||||
c.warn('cannot cast a fixed array (use e.g. `&arr[0]` instead)', node.pos)
|
c.warn('cannot cast a fixed array (use e.g. `&arr[0]` instead)', node.pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if to_type == ast.string_type {
|
||||||
|
if from_type in [ast.byte_type, ast.bool_type] {
|
||||||
|
snexpr := node.expr.str()
|
||||||
|
c.error('cannot cast type `$from_type_sym.name` to string, use `${snexpr}.str()` instead.',
|
||||||
|
node.pos)
|
||||||
|
} else if from_type.is_real_pointer() {
|
||||||
|
snexpr := node.expr.str()
|
||||||
|
c.error('cannot cast pointer type `$from_type_sym.name` to string, use `&byte($snexpr).vstring()` or `cstring_to_vstring($snexpr)` instead.',
|
||||||
|
node.pos)
|
||||||
|
} else if from_type.is_number() {
|
||||||
|
snexpr := node.expr.str()
|
||||||
|
c.error('cannot cast number to string, use `${snexpr}.str()` instead.', node.pos)
|
||||||
|
} else if from_type_sym.kind == .alias && from_type_sym_final.name != 'string' {
|
||||||
|
c.error('cannot cast type `$from_type_sym.name` to string, use `x.str()` instead.',
|
||||||
|
node.pos)
|
||||||
|
} else if from_type_sym_final.kind == .array {
|
||||||
|
snexpr := node.expr.str()
|
||||||
|
if from_type_sym_final.name == '[]byte' {
|
||||||
|
c.error('cannot cast []byte to string, use `${snexpr}.bytestr()` or `${snexpr}.str()` instead.',
|
||||||
|
node.pos)
|
||||||
|
} else {
|
||||||
|
first_elem_idx := '[0]'
|
||||||
|
c.error('cannot cast array to string, use `$snexpr${first_elem_idx}.str()` instead.',
|
||||||
|
node.pos)
|
||||||
|
}
|
||||||
|
} else if from_type_sym_final.kind == .enum_ {
|
||||||
|
snexpr := node.expr.str()
|
||||||
|
c.error('cannot cast enum to string, use ${snexpr}.str() instead.', node.pos)
|
||||||
|
} else if from_type_sym_final.kind == .map {
|
||||||
|
c.error('cannot cast map to string.', node.pos)
|
||||||
|
} else if from_type_sym_final.kind == .sum_type {
|
||||||
|
snexpr := node.expr.str()
|
||||||
|
c.error('cannot cast sumtype `$from_type_sym.name` to string, use `${snexpr}.str()` instead.',
|
||||||
|
node.pos)
|
||||||
|
} else if to_type != ast.string_type && from_type == ast.string_type
|
||||||
|
&& (!(to_type_sym.kind == .alias && to_type_sym_final.name == 'string')) {
|
||||||
|
mut error_msg := 'cannot cast a string to a type `$to_type_sym_final.name`, that is not an alias of string'
|
||||||
|
if mut node.expr is ast.StringLiteral {
|
||||||
|
if node.expr.val.len == 1 {
|
||||||
|
error_msg += ", for denoting characters use `$node.expr.val` instead of '$node.expr.val'"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.error(error_msg, node.pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if node.has_arg {
|
if node.has_arg {
|
||||||
c.expr(node.arg)
|
c.expr(node.arg)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,42 @@
|
||||||
vlib/v/checker/tests/cast_string_err.vv:2:7: error: cannot cast number to string, use `1.str()` instead.
|
vlib/v/checker/tests/cast_string_err.vv:14:9: error: cannot cast enum to string, use ev.str() instead.
|
||||||
1 | fn main() {
|
12 | fn main() {
|
||||||
2 | a := string(1)
|
13 | ev := MyEnum.val1
|
||||||
| ~~~~~~~~~
|
14 | sev := string(ev)
|
||||||
3 | println(a)
|
| ~~~~~~~~~~
|
||||||
4 | }
|
15 | println(sev)
|
||||||
|
16 | //
|
||||||
|
vlib/v/checker/tests/cast_string_err.vv:18:9: error: cannot cast sumtype `Sumtype` to string, use `st.str()` instead.
|
||||||
|
16 | //
|
||||||
|
17 | st := Sumtype(int(456))
|
||||||
|
18 | sst := string(st)
|
||||||
|
| ~~~~~~~~~~
|
||||||
|
19 | println(sst)
|
||||||
|
20 | //
|
||||||
|
vlib/v/checker/tests/cast_string_err.vv:22:10: error: cannot cast struct `Abc` to `string`, use `abc.str()` instead.
|
||||||
|
20 | //
|
||||||
|
21 | abc := Abc{}
|
||||||
|
22 | sabc := string(abc)
|
||||||
|
| ~~~~~~~~~~~
|
||||||
|
23 | println(sabc)
|
||||||
|
24 | //
|
||||||
|
vlib/v/checker/tests/cast_string_err.vv:26:8: error: cannot cast map to string.
|
||||||
|
24 | //
|
||||||
|
25 | mm := map[string]int{}
|
||||||
|
26 | sm := string(mm)
|
||||||
|
| ~~~~~~~~~~
|
||||||
|
27 | println(sm)
|
||||||
|
28 | //
|
||||||
|
vlib/v/checker/tests/cast_string_err.vv:30:8: error: cannot cast []byte to string, use `arr.bytestr()` or `arr.str()` instead.
|
||||||
|
28 | //
|
||||||
|
29 | arr := []byte{}
|
||||||
|
30 | sa := string(arr)
|
||||||
|
| ~~~~~~~~~~~
|
||||||
|
31 | println(sa)
|
||||||
|
32 | //
|
||||||
|
vlib/v/checker/tests/cast_string_err.vv:34:8: error: cannot cast number to string, use `ii.str()` instead.
|
||||||
|
32 | //
|
||||||
|
33 | ii := 1
|
||||||
|
34 | si := string(ii)
|
||||||
|
| ~~~~~~~~~~
|
||||||
|
35 | println(si)
|
||||||
|
36 | }
|
||||||
|
|
|
@ -1,4 +1,36 @@
|
||||||
fn main() {
|
struct Abc {
|
||||||
a := string(1)
|
x int
|
||||||
println(a)
|
}
|
||||||
|
|
||||||
|
type Sumtype = int | u64
|
||||||
|
|
||||||
|
enum MyEnum {
|
||||||
|
val1
|
||||||
|
val2
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
ev := MyEnum.val1
|
||||||
|
sev := string(ev)
|
||||||
|
println(sev)
|
||||||
|
//
|
||||||
|
st := Sumtype(int(456))
|
||||||
|
sst := string(st)
|
||||||
|
println(sst)
|
||||||
|
//
|
||||||
|
abc := Abc{}
|
||||||
|
sabc := string(abc)
|
||||||
|
println(sabc)
|
||||||
|
//
|
||||||
|
mm := map[string]int{}
|
||||||
|
sm := string(mm)
|
||||||
|
println(sm)
|
||||||
|
//
|
||||||
|
arr := []byte{}
|
||||||
|
sa := string(arr)
|
||||||
|
println(sa)
|
||||||
|
//
|
||||||
|
ii := 1
|
||||||
|
si := string(ii)
|
||||||
|
println(si)
|
||||||
}
|
}
|
|
@ -1,60 +1,60 @@
|
||||||
vlib/v/checker/tests/struct_type_cast_err.vv:5:10: error: cannot cast struct `Foo` to `string`
|
vlib/v/checker/tests/struct_type_cast_err.vv:5:10: error: cannot cast struct `Foo` to `string`, use `foo.str()` instead.
|
||||||
3 | fn main() {
|
3 | fn main() {
|
||||||
4 | foo := Foo{}
|
4 | foo := Foo{}
|
||||||
5 | _ := string(foo)
|
5 | _ := string(foo)
|
||||||
| ~~~~~~~~~~~
|
| ~~~~~~~~~~~
|
||||||
6 | _ := int(foo)
|
6 | _ := int(foo)
|
||||||
7 | _ := u64(foo)
|
7 | _ := u64(foo)
|
||||||
vlib/v/checker/tests/struct_type_cast_err.vv:6:10: error: cannot cast struct `Foo` to `int`
|
vlib/v/checker/tests/struct_type_cast_err.vv:6:10: error: cannot cast struct `Foo` to `int`, use `foo.str()` instead.
|
||||||
4 | foo := Foo{}
|
4 | foo := Foo{}
|
||||||
5 | _ := string(foo)
|
5 | _ := string(foo)
|
||||||
6 | _ := int(foo)
|
6 | _ := int(foo)
|
||||||
| ~~~~~~~~
|
| ~~~~~~~~
|
||||||
7 | _ := u64(foo)
|
7 | _ := u64(foo)
|
||||||
8 | _ := u32(foo)
|
8 | _ := u32(foo)
|
||||||
vlib/v/checker/tests/struct_type_cast_err.vv:7:10: error: cannot cast struct `Foo` to `u64`
|
vlib/v/checker/tests/struct_type_cast_err.vv:7:10: error: cannot cast struct `Foo` to `u64`, use `foo.str()` instead.
|
||||||
5 | _ := string(foo)
|
5 | _ := string(foo)
|
||||||
6 | _ := int(foo)
|
6 | _ := int(foo)
|
||||||
7 | _ := u64(foo)
|
7 | _ := u64(foo)
|
||||||
| ~~~~~~~~
|
| ~~~~~~~~
|
||||||
8 | _ := u32(foo)
|
8 | _ := u32(foo)
|
||||||
9 | _ := rune(foo)
|
9 | _ := rune(foo)
|
||||||
vlib/v/checker/tests/struct_type_cast_err.vv:8:10: error: cannot cast struct `Foo` to `u32`
|
vlib/v/checker/tests/struct_type_cast_err.vv:8:10: error: cannot cast struct `Foo` to `u32`, use `foo.str()` instead.
|
||||||
6 | _ := int(foo)
|
6 | _ := int(foo)
|
||||||
7 | _ := u64(foo)
|
7 | _ := u64(foo)
|
||||||
8 | _ := u32(foo)
|
8 | _ := u32(foo)
|
||||||
| ~~~~~~~~
|
| ~~~~~~~~
|
||||||
9 | _ := rune(foo)
|
9 | _ := rune(foo)
|
||||||
10 | _ := byte(foo)
|
10 | _ := byte(foo)
|
||||||
vlib/v/checker/tests/struct_type_cast_err.vv:9:10: error: cannot cast struct `Foo` to `rune`
|
vlib/v/checker/tests/struct_type_cast_err.vv:9:10: error: cannot cast struct `Foo` to `rune`, use `foo.str()` instead.
|
||||||
7 | _ := u64(foo)
|
7 | _ := u64(foo)
|
||||||
8 | _ := u32(foo)
|
8 | _ := u32(foo)
|
||||||
9 | _ := rune(foo)
|
9 | _ := rune(foo)
|
||||||
| ~~~~~~~~~
|
| ~~~~~~~~~
|
||||||
10 | _ := byte(foo)
|
10 | _ := byte(foo)
|
||||||
11 | _ := i8(foo)
|
11 | _ := i8(foo)
|
||||||
vlib/v/checker/tests/struct_type_cast_err.vv:10:10: error: cannot cast struct `Foo` to `byte`
|
vlib/v/checker/tests/struct_type_cast_err.vv:10:10: error: cannot cast struct `Foo` to `byte`, use `foo.str()` instead.
|
||||||
8 | _ := u32(foo)
|
8 | _ := u32(foo)
|
||||||
9 | _ := rune(foo)
|
9 | _ := rune(foo)
|
||||||
10 | _ := byte(foo)
|
10 | _ := byte(foo)
|
||||||
| ~~~~~~~~~
|
| ~~~~~~~~~
|
||||||
11 | _ := i8(foo)
|
11 | _ := i8(foo)
|
||||||
12 | _ := i64(foo)
|
12 | _ := i64(foo)
|
||||||
vlib/v/checker/tests/struct_type_cast_err.vv:11:10: error: cannot cast struct `Foo` to `i8`
|
vlib/v/checker/tests/struct_type_cast_err.vv:11:10: error: cannot cast struct `Foo` to `i8`, use `foo.str()` instead.
|
||||||
9 | _ := rune(foo)
|
9 | _ := rune(foo)
|
||||||
10 | _ := byte(foo)
|
10 | _ := byte(foo)
|
||||||
11 | _ := i8(foo)
|
11 | _ := i8(foo)
|
||||||
| ~~~~~~~
|
| ~~~~~~~
|
||||||
12 | _ := i64(foo)
|
12 | _ := i64(foo)
|
||||||
13 | _ := int(foo)
|
13 | _ := int(foo)
|
||||||
vlib/v/checker/tests/struct_type_cast_err.vv:12:10: error: cannot cast struct `Foo` to `i64`
|
vlib/v/checker/tests/struct_type_cast_err.vv:12:10: error: cannot cast struct `Foo` to `i64`, use `foo.str()` instead.
|
||||||
10 | _ := byte(foo)
|
10 | _ := byte(foo)
|
||||||
11 | _ := i8(foo)
|
11 | _ := i8(foo)
|
||||||
12 | _ := i64(foo)
|
12 | _ := i64(foo)
|
||||||
| ~~~~~~~~
|
| ~~~~~~~~
|
||||||
13 | _ := int(foo)
|
13 | _ := int(foo)
|
||||||
14 | _ = &I1(foo)
|
14 | _ = &I1(foo)
|
||||||
vlib/v/checker/tests/struct_type_cast_err.vv:13:10: error: cannot cast struct `Foo` to `int`
|
vlib/v/checker/tests/struct_type_cast_err.vv:13:10: error: cannot cast struct `Foo` to `int`, use `foo.str()` instead.
|
||||||
11 | _ := i8(foo)
|
11 | _ := i8(foo)
|
||||||
12 | _ := i64(foo)
|
12 | _ := i64(foo)
|
||||||
13 | _ := int(foo)
|
13 | _ := int(foo)
|
||||||
|
|
Loading…
Reference in New Issue