checker: error on redefining any of the public builtin functions, not just ['print', 'println', 'eprint', 'eprintln', 'isnil', 'panic', 'exit'] (#13419)

pull/13428/head
Delyan Angelov 2022-02-10 12:26:30 +02:00 committed by GitHub
parent 43d6b97c21
commit 9ed18efa53
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 45 additions and 17 deletions

View File

@ -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

View File

@ -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) {

View File

@ -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

View File

@ -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 | }

View File

@ -0,0 +1,11 @@
fn exit(x string) {
println('my exit: $x')
}
fn print_backtrace() {
println('hello')
}
fn main() {
print_backtrace()
}

View File

@ -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 {

View File

@ -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
}
}

View File

@ -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

View File

@ -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

View File

@ -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)