From 9ed18efa53c8242f47cb4ff103cf7177015d3691 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Thu, 10 Feb 2022 12:26:30 +0200 Subject: [PATCH] checker: error on redefining any of the public builtin functions, not just ['print', 'println', 'eprint', 'eprintln', 'isnil', 'panic', 'exit'] (#13419) --- vlib/v/ast/ast.v | 5 +++-- vlib/v/ast/table.v | 4 ++++ vlib/v/checker/fn.v | 3 +++ .../tests/redefining_builtin_pub_functions.out | 12 ++++++++++++ .../tests/redefining_builtin_pub_functions.vv | 11 +++++++++++ vlib/v/gen/js/fn.v | 9 +++++---- vlib/v/parser/fn.v | 10 +++------- vlib/v/parser/parser.v | 3 +-- vlib/v/parser/struct.v | 1 + vlib/v/parser/tests/fn_use_builtin_err.out | 4 ++-- 10 files changed, 45 insertions(+), 17 deletions(-) create mode 100644 vlib/v/checker/tests/redefining_builtin_pub_functions.out create mode 100644 vlib/v/checker/tests/redefining_builtin_pub_functions.vv diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 0b0dafc78a..95245f5cab 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -449,8 +449,9 @@ pub mut: // function or method declaration pub struct FnDecl { pub: - name string - mod string + name string // 'math.bits.normalize' + short_name string // 'normalize' + mod string // 'math.bits' is_deprecated bool is_pub bool is_variadic bool diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index a449979c70..71ff4d5029 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -41,6 +41,7 @@ pub mut: enum_decls map[string]EnumDecl mdeprecated_msg map[string]string // module deprecation message mdeprecated_after map[string]time.Time // module deprecation date + builtin_pub_fns map[string]bool } // used by vls to avoid leaks @@ -315,6 +316,9 @@ pub fn (mut t Table) mark_module_as_deprecated_after(mname string, after_date st pub fn (mut t Table) register_fn(new_fn Fn) { t.fns[new_fn.name] = new_fn + if new_fn.is_pub && new_fn.mod == 'builtin' { + t.builtin_pub_fns[new_fn.name] = true + } } pub fn (mut t Table) register_interface(idecl InterfaceDecl) { diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index 0c72fc8d4b..d882830fe1 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -70,6 +70,9 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) { } if node.language == .v && !c.is_builtin_mod && !node.is_anon { c.check_valid_snake_case(node.name, 'function name', node.pos) + if !node.is_method && node.mod == 'main' && node.short_name in c.table.builtin_pub_fns { + c.error('cannot redefine builtin public function `$node.short_name`', node.pos) + } } if node.name == 'main.main' { c.main_fn_decl_node = *node diff --git a/vlib/v/checker/tests/redefining_builtin_pub_functions.out b/vlib/v/checker/tests/redefining_builtin_pub_functions.out new file mode 100644 index 0000000000..e51d52ea15 --- /dev/null +++ b/vlib/v/checker/tests/redefining_builtin_pub_functions.out @@ -0,0 +1,12 @@ +vlib/v/checker/tests/redefining_builtin_pub_functions.vv:1:1: error: cannot redefine builtin public function `exit` + 1 | fn exit(x string) { + | ~~~~~~~~~~~~~~~~~ + 2 | println('my exit: $x') + 3 | } +vlib/v/checker/tests/redefining_builtin_pub_functions.vv:5:1: error: cannot redefine builtin public function `print_backtrace` + 3 | } + 4 | + 5 | fn print_backtrace() { + | ~~~~~~~~~~~~~~~~~~~~ + 6 | println('hello') + 7 | } diff --git a/vlib/v/checker/tests/redefining_builtin_pub_functions.vv b/vlib/v/checker/tests/redefining_builtin_pub_functions.vv new file mode 100644 index 0000000000..40a76f0c26 --- /dev/null +++ b/vlib/v/checker/tests/redefining_builtin_pub_functions.vv @@ -0,0 +1,11 @@ +fn exit(x string) { + println('my exit: $x') +} + +fn print_backtrace() { + println('hello') +} + +fn main() { + print_backtrace() +} diff --git a/vlib/v/gen/js/fn.v b/vlib/v/gen/js/fn.v index 0cb6748691..d583111314 100644 --- a/vlib/v/gen/js/fn.v +++ b/vlib/v/gen/js/fn.v @@ -2,9 +2,10 @@ module js import v.ast import v.util -import v.parser import strings +pub const builtin_functions = ['print', 'println', 'eprint', 'eprintln', 'isnil', 'panic', 'exit'] + fn (mut g JsGen) js_mname(name_ string) string { mut is_js := false is_overload := ['+', '-', '*', '/', '==', '<', '>'] @@ -406,7 +407,7 @@ fn (mut g JsGen) gen_call_expr(it ast.CallExpr) { mut name := g.js_name(it.name) is_print := name in ['print', 'println', 'eprint', 'eprintln', 'panic'] - if name in parser.builtin_functions { + if name in js.builtin_functions { name = 'builtin__$name' } print_method := name @@ -623,7 +624,7 @@ fn (mut g JsGen) gen_method_decl(it ast.FnDecl, typ FnGenType) { name = g.js_name(name) name = g.generic_fn_name(g.cur_concrete_types, name, true) - if name in parser.builtin_functions { + if name in js.builtin_functions { name = 'builtin__$name' } if it.is_pub && !it.is_method { @@ -797,7 +798,7 @@ fn (mut g JsGen) gen_anon_fn(mut fun ast.AnonFn) { name = g.js_name(name) name = g.generic_fn_name(g.table.cur_concrete_types, name, true) - if name in parser.builtin_functions { + if name in js.builtin_functions { name = 'builtin__$name' } if it.is_pub && !it.is_method { diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index ba1d8f6cf1..c4b8140de8 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -281,12 +281,6 @@ fn (mut p Parser) fn_decl() ast.FnDecl { } } if !p.pref.is_fmt { - if !is_method && !p.builtin_mod && name in builtin_functions { - p.error_with_pos('cannot redefine builtin function `$name`', name_pos) - return ast.FnDecl{ - scope: 0 - } - } if name in p.imported_symbols { p.error_with_pos('cannot redefine imported function `$name`', name_pos) return ast.FnDecl{ @@ -493,6 +487,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { // } fn_decl := ast.FnDecl{ name: name + short_name: short_fn_name mod: p.mod stmts: stmts return_type: return_type @@ -704,6 +699,7 @@ fn (mut p Parser) anon_fn() ast.AnonFn { return ast.AnonFn{ decl: ast.FnDecl{ name: name + short_name: '' mod: p.mod stmts: stmts return_type: return_type @@ -1011,7 +1007,7 @@ fn (mut p Parser) check_fn_atomic_arguments(typ ast.Type, pos token.Pos) { fn have_fn_main(stmts []ast.Stmt) bool { for stmt in stmts { if stmt is ast.FnDecl { - if stmt.name == 'main.main' && stmt.mod == 'main' { + if stmt.name == 'main.main' { return true } } diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index f5b0167242..8fc35758a2 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -14,8 +14,6 @@ import v.errors import os import hash.fnv1a -pub const builtin_functions = ['print', 'println', 'eprint', 'eprintln', 'isnil', 'panic', 'exit'] - pub struct Parser { pref &pref.Preferences mut: @@ -654,6 +652,7 @@ pub fn (mut p Parser) top_stmt() ast.Stmt { p.close_scope() return ast.FnDecl{ name: 'main.main' + short_name: 'main' mod: 'main' is_main: true stmts: stmts diff --git a/vlib/v/parser/struct.v b/vlib/v/parser/struct.v index c9e2a1d90a..92ff8f6966 100644 --- a/vlib/v/parser/struct.v +++ b/vlib/v/parser/struct.v @@ -584,6 +584,7 @@ fn (mut p Parser) interface_decl() ast.InterfaceDecl { args << args2 mut method := ast.FnDecl{ name: name + short_name: name mod: p.mod params: args file: p.file_name diff --git a/vlib/v/parser/tests/fn_use_builtin_err.out b/vlib/v/parser/tests/fn_use_builtin_err.out index 5e57fe2ff1..3340a4af96 100644 --- a/vlib/v/parser/tests/fn_use_builtin_err.out +++ b/vlib/v/parser/tests/fn_use_builtin_err.out @@ -1,5 +1,5 @@ -vlib/v/parser/tests/fn_use_builtin_err.vv:1:4: error: cannot redefine builtin function `print` +vlib/v/parser/tests/fn_use_builtin_err.vv:1:1: error: cannot redefine builtin public function `print` 1 | fn print(strings ...string) { - | ~~~~~ + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2 | for s in strings { 3 | println(s)