From a9ab79d301b2cc3971f6d1b9308dae9158e7d59f Mon Sep 17 00:00:00 2001 From: Swastik Baranwal Date: Thu, 31 Dec 2020 17:11:30 +0530 Subject: [PATCH] checker: ban any_int/any_float outside buitlin (#7675) --- vlib/v/ast/ast.v | 8 ++-- vlib/v/checker/checker.v | 28 ++++++++++--- .../v/checker/tests/any_int_float_ban_err.out | 41 +++++++++++++++++++ vlib/v/checker/tests/any_int_float_ban_err.vv | 15 +++++++ vlib/v/checker/tests/sum_type_exists.out | 6 +-- vlib/v/table/table.v | 3 +- vlib/x/json2/decoder.v | 2 +- vlib/x/json2/encoder.v | 6 --- 8 files changed, 88 insertions(+), 21 deletions(-) create mode 100644 vlib/v/checker/tests/any_int_float_ban_err.out create mode 100644 vlib/v/checker/tests/any_int_float_ban_err.vv diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index ff47894dad..b4c9061542 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -292,17 +292,17 @@ pub: is_variadic bool is_anon bool receiver Field - receiver_pos token.Position + receiver_pos token.Position // `(u User)` in `fn (u User) name()` position is_method bool - method_type_pos token.Position + method_type_pos token.Position // `User` in ` fn (u User)` position method_idx int rec_mut bool // is receiver mutable rec_share table.ShareType language table.Language no_body bool // just a definition `fn C.malloc()` is_builtin bool // this function is defined in builtin/strconv - pos token.Position - body_pos token.Position + pos token.Position // function declaration position + body_pos token.Position // function bodys position file string is_generic bool is_direct_arr bool // direct array access diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 1cf529c539..8b05c2f973 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -316,7 +316,7 @@ pub fn (mut c Checker) type_decl(node ast.TypeDecl) { c.check_valid_pascal_case(node.name, 'type alias', node.pos) } typ_sym := c.table.get_type_symbol(node.parent_type) - if typ_sym.kind == .placeholder { + if typ_sym.kind in [.placeholder, .any_int, .any_float] { c.error("type `$typ_sym.name` doesn't exist", node.pos) } else if typ_sym.kind == .alias { orig_sym := c.table.get_type_symbol((typ_sym.info as table.Alias).parent_type) @@ -353,10 +353,10 @@ pub fn (mut c Checker) type_decl(node ast.TypeDecl) { if sym.name in names_used { c.error('sum type $node.name cannot hold the type `$sym.name` more than once', variant.pos) - } else if sym.kind == .placeholder { - c.error("type `$sym.name` doesn't exist", node.pos) + } else if sym.kind in [.placeholder, .any_int, .any_float] { + c.error("type `$sym.name` doesn't exist", variant.pos) } else if sym.kind == .interface_ { - c.error('sum type cannot hold an interface', node.pos) + c.error('sum type cannot hold an interface', variant.pos) } names_used << sym.name } @@ -397,6 +397,16 @@ pub fn (mut c Checker) struct_decl(decl ast.StructDecl) { c.error(util.new_suggestion(sym.name, c.table.known_type_names()).say('unknown type `$sym.name`'), field.type_pos) } + // Separate error condition for `any_int` and `any_float` because `util.suggestion` may give different + // suggestions due to f32 comparision issue. + if sym.kind in [.any_int, .any_float] { + msg := if sym.kind == .any_int { + 'unknown type `$sym.name`.\nDid you mean `int`?' + } else { + 'unknown type `$sym.name`.\nDid you mean `f64`?' + } + c.error(msg, field.type_pos) + } if sym.kind == .array { array_info := sym.array_info() elem_sym := c.table.get_type_symbol(array_info.elem_type) @@ -4861,11 +4871,17 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) { // Make sure all types are valid for arg in node.params { sym := c.table.get_type_symbol(arg.typ) - if sym.kind == .placeholder { - c.error('unknown type `$sym.name`', node.method_type_pos) + if sym.kind == .placeholder || + (sym.kind in [table.Kind.any_int, .any_float] && !c.is_builtin_mod) { + c.error('unknown type `$sym.name`', node.pos) } } } + return_sym := c.table.get_type_symbol(node.return_type) + if node.language == .v && + return_sym.kind in [.placeholder, .any_int, .any_float] && return_sym.language == .v { + c.error('unknown type `$return_sym.name`', node.pos) + } 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) diff --git a/vlib/v/checker/tests/any_int_float_ban_err.out b/vlib/v/checker/tests/any_int_float_ban_err.out new file mode 100644 index 0000000000..8225def4cd --- /dev/null +++ b/vlib/v/checker/tests/any_int_float_ban_err.out @@ -0,0 +1,41 @@ +vlib/v/checker/tests/any_int_float_ban_err.vv:1:12: error: type `any_int` doesn't exist + 1 | type Foo = any_int | any_float + | ~~~~~~~ + 2 | type Fo2 = any_int + 3 | +vlib/v/checker/tests/any_int_float_ban_err.vv:2:1: error: type `any_int` doesn't exist + 1 | type Foo = any_int | any_float + 2 | type Fo2 = any_int + | ~~~~~~~~ + 3 | + 4 | struct Int { +vlib/v/checker/tests/any_int_float_ban_err.vv:5:7: error: unknown type `any_int`. +Did you mean `int`? + 3 | + 4 | struct Int { + 5 | i any_int + | ~~~~~~~ + 6 | f any_float + 7 | } +vlib/v/checker/tests/any_int_float_ban_err.vv:6:7: error: unknown type `any_float`. +Did you mean `f64`? + 4 | struct Int { + 5 | i any_int + 6 | f any_float + | ~~~~~~~~~ + 7 | } + 8 | +vlib/v/checker/tests/any_int_float_ban_err.vv:9:1: error: unknown type `any_int` + 7 | } + 8 | + 9 | fn foo(i any_int) any_int { + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + 10 | return i + 11 | } +vlib/v/checker/tests/any_int_float_ban_err.vv:13:1: error: unknown type `any_int` + 11 | } + 12 | + 13 | fn foo2() any_int { + | ~~~~~~~~~~~~~~~~~ + 14 | return 1 + 15 | } diff --git a/vlib/v/checker/tests/any_int_float_ban_err.vv b/vlib/v/checker/tests/any_int_float_ban_err.vv new file mode 100644 index 0000000000..b6706f2e13 --- /dev/null +++ b/vlib/v/checker/tests/any_int_float_ban_err.vv @@ -0,0 +1,15 @@ +type Foo = any_int | any_float +type Fo2 = any_int + +struct Int { + i any_int + f any_float +} + +fn foo(i any_int) any_int { + return i +} + +fn foo2() any_int { + return 1 +} diff --git a/vlib/v/checker/tests/sum_type_exists.out b/vlib/v/checker/tests/sum_type_exists.out index 112bff190f..55849aba91 100644 --- a/vlib/v/checker/tests/sum_type_exists.out +++ b/vlib/v/checker/tests/sum_type_exists.out @@ -1,5 +1,5 @@ -vlib/v/checker/tests/sum_type_exists.vv:1:1: error: type `Nope` doesn't exist +vlib/v/checker/tests/sum_type_exists.vv:1:22: error: type `Nope` doesn't exist 1 | type Miscellaneous = Nope | Inexistant | int - | ~~~~~~~~~~~~~~~~~~ - 2 | + | ~~~~ + 2 | 3 | fn main() { diff --git a/vlib/v/table/table.v b/vlib/v/table/table.v index ebb06c5bf6..10164861fc 100644 --- a/vlib/v/table/table.v +++ b/vlib/v/table/table.v @@ -732,7 +732,8 @@ pub fn (table &Table) sumtype_has_variant(parent Type, variant Type) bool { pub fn (table &Table) known_type_names() []string { mut res := []string{} for _, idx in table.type_idxs { - if idx == 0 { + // Skip `any_int_type_idx` and `any_flt_type_idx` because they shouldn't be visible to the User. + if idx in [0, any_int_type_idx, any_flt_type_idx] { continue } res << table.type_to_str(idx) diff --git a/vlib/x/json2/decoder.v b/vlib/x/json2/decoder.v index bce944e792..d47d584570 100644 --- a/vlib/x/json2/decoder.v +++ b/vlib/x/json2/decoder.v @@ -11,7 +11,7 @@ import v.util import v.pref // `Any` is a sum type that lists the possible types to be decoded and used. -pub type Any = string | int | i64 | f32 | f64 | any_int | any_float | bool | Null | []Any | map[string]Any +pub type Any = string | int | i64 | f32 | f64 | bool | Null | []Any | map[string]Any // `Null` struct is a simple representation of the `null` value in JSON. pub struct Null { diff --git a/vlib/x/json2/encoder.v b/vlib/x/json2/encoder.v index 8ffc047c49..087f5f504a 100644 --- a/vlib/x/json2/encoder.v +++ b/vlib/x/json2/encoder.v @@ -79,12 +79,6 @@ pub fn (f Any) str() string { str_f64 } } - any_int { - return f.str() - } - any_float { - return f.str() - } bool { return f.str() }