From f995aa35ea168df3edf67bd1787791219b8b2519 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Sun, 15 Nov 2020 11:13:35 +0200 Subject: [PATCH] checker: add a check for `x := math.sin(0)` --- vlib/v/ast/ast.v | 1 + vlib/v/checker/checker.v | 3 +++ ...nerics_non_generic_fn_called_like_a_generic_one.out | 7 +++++++ ...enerics_non_generic_fn_called_like_a_generic_one.vv | 6 ++++++ vlib/v/parser/fn.v | 3 +++ vlib/v/table/atypes.v | 10 ++++++++++ 6 files changed, 30 insertions(+) create mode 100644 vlib/v/checker/tests/generics_non_generic_fn_called_like_a_generic_one.out create mode 100644 vlib/v/checker/tests/generics_non_generic_fn_called_like_a_generic_one.vv diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 05619e4be0..987f7e88cf 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -306,6 +306,7 @@ pub mut: return_type table.Type should_be_skipped bool generic_type table.Type // TODO array, to support multiple types + generic_list_pos token.Position free_receiver bool // true if the receiver expression needs to be freed // autofree_pregen string // autofree_vars []AutofreeArgVar diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 9347a56c2d..12e0e91159 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -1595,6 +1595,9 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type { } } } + if call_expr.generic_type.is_full() && !f.is_generic { + c.error('a non generic function called like a generic one', call_expr.generic_list_pos) + } if f.is_generic { return call_expr.return_type } diff --git a/vlib/v/checker/tests/generics_non_generic_fn_called_like_a_generic_one.out b/vlib/v/checker/tests/generics_non_generic_fn_called_like_a_generic_one.out new file mode 100644 index 0000000000..0c2c68e5eb --- /dev/null +++ b/vlib/v/checker/tests/generics_non_generic_fn_called_like_a_generic_one.out @@ -0,0 +1,7 @@ +vlib/v/checker/tests/generics_non_generic_fn_called_like_a_generic_one.vv:4:15: error: a non generic function called like a generic one + 2 | + 3 | fn main() { + 4 | x := math.sin(1.0) + | ~~~~~ + 5 | println(x) + 6 | } diff --git a/vlib/v/checker/tests/generics_non_generic_fn_called_like_a_generic_one.vv b/vlib/v/checker/tests/generics_non_generic_fn_called_like_a_generic_one.vv new file mode 100644 index 0000000000..d25ddd1bc6 --- /dev/null +++ b/vlib/v/checker/tests/generics_non_generic_fn_called_like_a_generic_one.vv @@ -0,0 +1,6 @@ +import math + +fn main() { + x := math.sin(1.0) + println(x) +} diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index b66729be87..dd8a34b7c5 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -27,12 +27,14 @@ pub fn (mut p Parser) call_expr(language table.Language, mod string) ast.CallExp or_kind = .block } mut generic_type := table.void_type + mut generic_list_pos := p.tok.position() if p.tok.kind == .lt { // `foo(10)` p.next() // `<` p.expr_mod = '' generic_type = p.parse_type() p.check(.gt) // `>` + generic_list_pos = generic_list_pos.extend(p.prev_tok.position()) // In case of `foo()` // T is unwrapped and registered in the checker. if !generic_type.has_flag(.generic) { @@ -98,6 +100,7 @@ pub fn (mut p Parser) call_expr(language table.Language, mod string) ast.CallExp pos: pos language: language generic_type: generic_type + generic_list_pos: generic_list_pos or_block: ast.OrExpr{ stmts: or_stmts kind: or_kind diff --git a/vlib/v/table/atypes.v b/vlib/v/table/atypes.v index 433a61f0dd..3879a8a91c 100644 --- a/vlib/v/table/atypes.v +++ b/vlib/v/table/atypes.v @@ -106,6 +106,16 @@ pub fn (t Type) idx() int { return u16(t) & 0xffff } +[inline] +pub fn (t Type) is_void() bool { + return t == void_type +} + +[inline] +pub fn (t Type) is_full() bool { + return t != 0 && t != void_type +} + // return nr_muls for `t` [inline] pub fn (t Type) nr_muls() int {