From c2e436518b5b2fe5ae05598bc946b7db66531d48 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Mon, 27 Jan 2025 06:42:27 -0300 Subject: [PATCH] checker: fix private symbol visibility checking (fix #23518) (#23543) --- vlib/builtin/cfns.c.v | 2 +- vlib/builtin/int.v | 2 +- vlib/builtin/js/int.js.v | 2 +- vlib/builtin/wasm/wasi/int.v | 2 +- vlib/compress/szip/szip.c.v | 2 +- vlib/encoding/csv/csv_reader_random_access.v | 2 +- vlib/v/ast/table.v | 1 + vlib/v/ast/types.v | 105 +++++++++++------- vlib/v/checker/checker.v | 25 ++++- .../checker/tests/modules/private_symbol.out | 23 ++++ .../tests/modules/private_symbol/main.v | 19 ++++ .../tests/modules/private_symbol/priv_sym.v | 12 ++ .../templating/dtm/dynamic_template_manager.v | 2 +- 13 files changed, 148 insertions(+), 51 deletions(-) create mode 100644 vlib/v/checker/tests/modules/private_symbol.out create mode 100644 vlib/v/checker/tests/modules/private_symbol/main.v create mode 100644 vlib/v/checker/tests/modules/private_symbol/priv_sym.v diff --git a/vlib/builtin/cfns.c.v b/vlib/builtin/cfns.c.v index b09ad1a1c4..bffec65d28 100644 --- a/vlib/builtin/cfns.c.v +++ b/vlib/builtin/cfns.c.v @@ -236,7 +236,7 @@ fn C.sysctl(name &int, namelen u32, oldp voidptr, oldlenp voidptr, newp voidptr, @[trusted] fn C._fileno(int) int -type C.intptr_t = voidptr +pub type C.intptr_t = voidptr fn C._get_osfhandle(fd int) C.intptr_t diff --git a/vlib/builtin/int.v b/vlib/builtin/int.v index 4c8e1b1d74..a085e965fa 100644 --- a/vlib/builtin/int.v +++ b/vlib/builtin/int.v @@ -7,7 +7,7 @@ pub struct VContext { allocator int } -type byte = u8 +pub type byte = u8 // ptr_str returns the address of `ptr` as a `string`. pub fn ptr_str(ptr voidptr) string { diff --git a/vlib/builtin/js/int.js.v b/vlib/builtin/js/int.js.v index fdce4078fd..41e53192bc 100644 --- a/vlib/builtin/js/int.js.v +++ b/vlib/builtin/js/int.js.v @@ -1,6 +1,6 @@ module builtin -type byte = u8 +pub type byte = u8 pub const min_i8 = i8(-128) pub const max_i8 = i8(127) diff --git a/vlib/builtin/wasm/wasi/int.v b/vlib/builtin/wasm/wasi/int.v index 289890d8cd..0c31ce96f4 100644 --- a/vlib/builtin/wasm/wasi/int.v +++ b/vlib/builtin/wasm/wasi/int.v @@ -1,6 +1,6 @@ module builtin -type byte = u8 +pub type byte = u8 // type i32 = int diff --git a/vlib/compress/szip/szip.c.v b/vlib/compress/szip/szip.c.v index 91a7ee64c7..44bba6bd57 100644 --- a/vlib/compress/szip/szip.c.v +++ b/vlib/compress/szip/szip.c.v @@ -14,7 +14,7 @@ pub: pub struct C.zip_t { } -type Zip = C.zip_t +pub type Zip = C.zip_t pub type Fn_on_extract_entry = fn (&&char, &&char) int diff --git a/vlib/encoding/csv/csv_reader_random_access.v b/vlib/encoding/csv/csv_reader_random_access.v index e26502ab96..97f953b961 100644 --- a/vlib/encoding/csv/csv_reader_random_access.v +++ b/vlib/encoding/csv/csv_reader_random_access.v @@ -421,7 +421,7 @@ pub fn (mut cr RandomAccessReader) get_cell(cfg GetCellConfig) !string { return cr.default_cell } -type CellValue = f32 | int | string +pub type CellValue = f32 | int | string // get_cellt read a single cell and return a sum type CellValue pub fn (mut cr RandomAccessReader) get_cellt(cfg GetCellConfig) !CellValue { diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index 3ff7417c51..2a62889d71 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -1337,6 +1337,7 @@ pub fn (mut t Table) add_placeholder_type(name string, language Language) int { cname: util.no_dots(name).replace_each(['&', '']) language: language mod: modname + is_pub: true is_builtin: name in builtins } return t.register_sym(ph_type) diff --git a/vlib/v/ast/types.v b/vlib/v/ast/types.v index d9df49b3ad..52afd493c7 100644 --- a/vlib/v/ast/types.v +++ b/vlib/v/ast/types.v @@ -1051,52 +1051,76 @@ pub fn (mut t Table) register_builtin_type_symbols() { // save index check, 0 will mean not found // THE ORDER MUST BE THE SAME AS xxx_type_idx CONSTS EARLIER IN THIS FILE t.register_sym(kind: .placeholder, name: 'reserved_0') - t.register_sym(kind: .void, name: 'void', cname: 'void', mod: 'builtin') // 1 - t.register_sym(kind: .voidptr, name: 'voidptr', cname: 'voidptr', mod: 'builtin') // 2 - t.register_sym(kind: .byteptr, name: 'byteptr', cname: 'byteptr', mod: 'builtin') // 3 - t.register_sym(kind: .charptr, name: 'charptr', cname: 'charptr', mod: 'builtin') // 4 - t.register_sym(kind: .i8, name: 'i8', cname: 'i8', mod: 'builtin') // 5 - t.register_sym(kind: .i16, name: 'i16', cname: 'i16', mod: 'builtin') // 6 - t.register_sym(kind: .i32, name: 'i32', cname: 'i32', mod: 'builtin') // 7 - t.register_sym(kind: .int, name: 'int', cname: int_type_name, mod: 'builtin') // 8 - t.register_sym(kind: .i64, name: 'i64', cname: 'i64', mod: 'builtin') // 9 - t.register_sym(kind: .isize, name: 'isize', cname: 'isize', mod: 'builtin') // 10 - t.register_sym(kind: .u8, name: 'u8', cname: 'u8', mod: 'builtin') // 11 - t.register_sym(kind: .u16, name: 'u16', cname: 'u16', mod: 'builtin') // 12 - t.register_sym(kind: .u32, name: 'u32', cname: 'u32', mod: 'builtin') // 13 - t.register_sym(kind: .u64, name: 'u64', cname: 'u64', mod: 'builtin') // 14 - t.register_sym(kind: .usize, name: 'usize', cname: 'usize', mod: 'builtin') // 15 - t.register_sym(kind: .f32, name: 'f32', cname: 'f32', mod: 'builtin') // 16 - t.register_sym(kind: .f64, name: 'f64', cname: 'f64', mod: 'builtin') // 17 - t.register_sym(kind: .char, name: 'char', cname: 'char', mod: 'builtin') // 18 - t.register_sym(kind: .bool, name: 'bool', cname: 'bool', mod: 'builtin') // 19 - t.register_sym(kind: .none, name: 'none', cname: 'none', mod: 'builtin') // 20 - t.register_sym(kind: .string, name: 'string', cname: 'string', mod: 'builtin', is_builtin: true) // 21 - t.register_sym(kind: .rune, name: 'rune', cname: 'rune', mod: 'builtin') // 22 - t.register_sym(kind: .array, name: 'array', cname: 'array', mod: 'builtin', is_builtin: true) // 23 - t.register_sym(kind: .map, name: 'map', cname: 'map', mod: 'builtin', is_builtin: true) // 24 - t.register_sym(kind: .chan, name: 'chan', cname: 'chan', mod: 'builtin') // 25 - t.register_sym(kind: .any, name: 'any', cname: 'any', mod: 'builtin') // 26 + t.register_sym(kind: .void, name: 'void', cname: 'void', mod: 'builtin', is_pub: true) // 1 + t.register_sym(kind: .voidptr, name: 'voidptr', cname: 'voidptr', mod: 'builtin', is_pub: true) // 2 + t.register_sym(kind: .byteptr, name: 'byteptr', cname: 'byteptr', mod: 'builtin', is_pub: true) // 3 + t.register_sym(kind: .charptr, name: 'charptr', cname: 'charptr', mod: 'builtin', is_pub: true) // 4 + t.register_sym(kind: .i8, name: 'i8', cname: 'i8', mod: 'builtin', is_pub: true) // 5 + t.register_sym(kind: .i16, name: 'i16', cname: 'i16', mod: 'builtin', is_pub: true) // 6 + t.register_sym(kind: .i32, name: 'i32', cname: 'i32', mod: 'builtin', is_pub: true) // 7 + t.register_sym(kind: .int, name: 'int', cname: int_type_name, mod: 'builtin', is_pub: true) // 8 + t.register_sym(kind: .i64, name: 'i64', cname: 'i64', mod: 'builtin', is_pub: true) // 9 + t.register_sym(kind: .isize, name: 'isize', cname: 'isize', mod: 'builtin', is_pub: true) // 10 + t.register_sym(kind: .u8, name: 'u8', cname: 'u8', mod: 'builtin', is_pub: true) // 11 + t.register_sym(kind: .u16, name: 'u16', cname: 'u16', mod: 'builtin', is_pub: true) // 12 + t.register_sym(kind: .u32, name: 'u32', cname: 'u32', mod: 'builtin', is_pub: true) // 13 + t.register_sym(kind: .u64, name: 'u64', cname: 'u64', mod: 'builtin', is_pub: true) // 14 + t.register_sym(kind: .usize, name: 'usize', cname: 'usize', mod: 'builtin', is_pub: true) // 15 + t.register_sym(kind: .f32, name: 'f32', cname: 'f32', mod: 'builtin', is_pub: true) // 16 + t.register_sym(kind: .f64, name: 'f64', cname: 'f64', mod: 'builtin', is_pub: true) // 17 + t.register_sym(kind: .char, name: 'char', cname: 'char', mod: 'builtin', is_pub: true) // 18 + t.register_sym(kind: .bool, name: 'bool', cname: 'bool', mod: 'builtin', is_pub: true) // 19 + t.register_sym(kind: .none, name: 'none', cname: 'none', mod: 'builtin', is_pub: true) // 20 t.register_sym( - kind: .float_literal - name: 'float literal' - cname: 'float_literal' - mod: 'builtin' + kind: .string + name: 'string' + cname: 'string' + mod: 'builtin' + is_builtin: true + is_pub: true + ) // 21 + t.register_sym(kind: .rune, name: 'rune', cname: 'rune', mod: 'builtin', is_pub: true) // 22 + t.register_sym( + kind: .array + name: 'array' + cname: 'array' + mod: 'builtin' + is_builtin: true + is_pub: true + ) // 23 + t.register_sym( + kind: .map + name: 'map' + cname: 'map' + mod: 'builtin' + is_builtin: true + is_pub: true + ) // 24 + t.register_sym(kind: .chan, name: 'chan', cname: 'chan', mod: 'builtin', is_pub: true) // 25 + t.register_sym(kind: .any, name: 'any', cname: 'any', mod: 'builtin', is_pub: true) // 26 + t.register_sym( + kind: .float_literal + name: 'float literal' + cname: 'float_literal' + mod: 'builtin' + is_pub: true ) // 27 t.register_sym( - kind: .int_literal - name: 'int literal' - cname: 'int_literal' - mod: 'builtin' + kind: .int_literal + name: 'int literal' + cname: 'int_literal' + mod: 'builtin' + is_pub: true ) // 28 t.register_sym( - kind: .thread - name: 'thread' - cname: '__v_thread' - mod: 'builtin' - info: Thread{ + kind: .thread + name: 'thread' + cname: '__v_thread' + mod: 'builtin' + info: Thread{ return_type: void_type } + is_pub: true ) // 29 t.register_sym( kind: .interface @@ -1104,8 +1128,9 @@ pub fn (mut t Table) register_builtin_type_symbols() { cname: 'IError' mod: 'builtin' is_builtin: true + is_pub: true ) // 30 - t.register_sym(kind: .voidptr, name: 'nil', cname: 'voidptr', mod: 'builtin') // 31 + t.register_sym(kind: .voidptr, name: 'nil', cname: 'voidptr', mod: 'builtin', is_pub: true) // 31 } @[inline] diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 532bede4f3..7bb67c003a 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -5293,10 +5293,27 @@ fn (mut c Checker) ensure_type_exists(typ ast.Type, pos token.Pos) bool { return false } sym := c.table.sym(typ) - if !c.is_builtin_mod && sym.kind == .struct && !sym.is_pub && sym.mod != c.mod { - c.error('struct `${sym.name}` was declared as private to module `${sym.mod}`, so it can not be used inside module `${c.mod}`', - pos) - return false + if !c.is_builtin_mod && !sym.is_pub && sym.mod != c.mod && sym.mod != 'main' { + if sym.kind == .function { + fn_info := sym.info as ast.FnType + // hack: recover fn mod from func name + mut fn_mod := sym.mod + if fn_mod == '' { + fn_mod = fn_info.func.name.all_before_last('.') + if fn_mod == fn_info.func.name { + fn_mod = 'builtin' + } + } + if fn_mod != '' && fn_mod != c.mod && fn_info.func.name != '' && !fn_info.is_anon { + c.error('function type `${fn_info.func.name}` was declared as private to module `${fn_mod}`, so it can not be used inside module `${c.mod}`', + pos) + return false + } + } else if sym.mod != '' { + c.error('${sym.kind} `${sym.name}` was declared as private to module `${sym.mod}`, so it can not be used inside module `${c.mod}`', + pos) + return false + } } match sym.kind { .placeholder { diff --git a/vlib/v/checker/tests/modules/private_symbol.out b/vlib/v/checker/tests/modules/private_symbol.out new file mode 100644 index 0000000000..9fa9da0221 --- /dev/null +++ b/vlib/v/checker/tests/modules/private_symbol.out @@ -0,0 +1,23 @@ +vlib/v/checker/tests/modules/private_symbol/main.v:10:11: error: function `priv_sym.priv` is private + 8 | + 9 | fn main() { + 10 | priv_sym.priv() + | ~~~~~~ + 11 | a := priv_sym.Foo(0) + 12 | dump(a) +vlib/v/checker/tests/modules/private_symbol/main.v:11:16: error: unknown type `priv_sym.Foo`. +Did you mean `priv_sym.PubFoo`? + 9 | fn main() { + 10 | priv_sym.priv() + 11 | a := priv_sym.Foo(0) + | ~~~~~~ + 12 | dump(a) + 13 | b := priv_sym.BarFn(t) +vlib/v/checker/tests/modules/private_symbol/main.v:13:16: error: unknown type `priv_sym.BarFn`. +Did you mean `priv_sym.PubFoo`? + 11 | a := priv_sym.Foo(0) + 12 | dump(a) + 13 | b := priv_sym.BarFn(t) + | ~~~~~~~~ + 14 | dump(b) + 15 | c := priv_sym.PubFoo(0) diff --git a/vlib/v/checker/tests/modules/private_symbol/main.v b/vlib/v/checker/tests/modules/private_symbol/main.v new file mode 100644 index 0000000000..f7084928bd --- /dev/null +++ b/vlib/v/checker/tests/modules/private_symbol/main.v @@ -0,0 +1,19 @@ +module main + +import priv_sym + +fn t() int { + return 0 +} + +fn main() { + priv_sym.priv() + a := priv_sym.Foo(0) + dump(a) + b := priv_sym.BarFn(t) + dump(b) + c := priv_sym.PubFoo(0) + dump(c) + d := priv_sym.PubBarFn(t) + dump(d) +} diff --git a/vlib/v/checker/tests/modules/private_symbol/priv_sym.v b/vlib/v/checker/tests/modules/private_symbol/priv_sym.v new file mode 100644 index 0000000000..718b89c41e --- /dev/null +++ b/vlib/v/checker/tests/modules/private_symbol/priv_sym.v @@ -0,0 +1,12 @@ +// sub module +module priv_sym + +type PrivFoo = int +pub type PubFoo = int + +type PrivBarFn = fn () int + +pub type PubBarFn = fn () int + +fn priv() { +} diff --git a/vlib/x/templating/dtm/dynamic_template_manager.v b/vlib/x/templating/dtm/dynamic_template_manager.v index 891e8f3371..01053bb7fe 100644 --- a/vlib/x/templating/dtm/dynamic_template_manager.v +++ b/vlib/x/templating/dtm/dynamic_template_manager.v @@ -7,7 +7,7 @@ import time import regex // These are all the types of dynamic values that the DTM allows to be returned in the context of a map -type DtmMultiTypeMap = f32 | f64 | i16 | i64 | i8 | int | string | u16 | u32 | u64 | u8 +pub type DtmMultiTypeMap = f32 | f64 | i16 | i64 | i8 | int | string | u16 | u32 | u64 | u8 // type MiddlewareFn = fn (mut Context, string) bool