From 7681a0b46db9835513a149167ff89517647af71d Mon Sep 17 00:00:00 2001 From: yuyi Date: Sun, 29 Oct 2023 20:20:16 +0800 Subject: [PATCH] checker: check error of implementing other module private interface (fix #19620) (#19688) --- vlib/crypto/cipher/cipher.v | 6 +++--- vlib/net/http/server.v | 2 +- vlib/v/checker/checker.v | 7 ++++++- .../tests/modules/implement_private_interface.out | 7 +++++++ .../tests/modules/implement_private_interface/baz.v | 10 ++++++++++ .../tests/modules/implement_private_interface/main.v | 12 ++++++++++++ vlib/v/embed_file/decoder.v | 2 +- 7 files changed, 40 insertions(+), 6 deletions(-) create mode 100644 vlib/v/checker/tests/modules/implement_private_interface.out create mode 100644 vlib/v/checker/tests/modules/implement_private_interface/baz.v create mode 100644 vlib/v/checker/tests/modules/implement_private_interface/main.v diff --git a/vlib/crypto/cipher/cipher.v b/vlib/crypto/cipher/cipher.v index 78290aabda8508..a364b565e07a7f 100644 --- a/vlib/crypto/cipher/cipher.v +++ b/vlib/crypto/cipher/cipher.v @@ -6,7 +6,7 @@ module cipher // using a given key. It provides the capability to encrypt // or decrypt individual blocks. The mode implementations // extend that capability to streams of blocks. -interface Block { +pub interface Block { block_size int // block_size returns the cipher's block size. encrypt(mut dst []u8, src []u8) // Encrypt encrypts the first block in src into dst. // Dst and src must overlap entirely or not at all. @@ -15,7 +15,7 @@ interface Block { } // A Stream represents a stream cipher. -interface Stream { +pub interface Stream { // xor_key_stream XORs each byte in the given slice with a byte from the // cipher's key stream. Dst and src must overlap entirely or not at all. // @@ -31,7 +31,7 @@ interface Stream { // A BlockMode represents a block cipher running in a block-based mode (CBC, // ECB etc). -interface BlockMode { +pub interface BlockMode { block_size int // block_size returns the mode's block size. crypt_blocks(mut dst []u8, src []u8) // crypt_blocks encrypts or decrypts a number of blocks. The length of // src must be a multiple of the block size. Dst and src must overlap diff --git a/vlib/net/http/server.v b/vlib/net/http/server.v index ed5aefd1bc5f2b..6e4538adc18179 100644 --- a/vlib/net/http/server.v +++ b/vlib/net/http/server.v @@ -18,7 +18,7 @@ pub enum ServerStatus { stopped } -interface Handler { +pub interface Handler { mut: handle(Request) Response } diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 9ef231970bcf00..86e70ce75a2a19 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -958,8 +958,14 @@ fn (mut c Checker) type_implements(typ ast.Type, interface_type ast.Type, pos to eprintln('> type_implements typ: ${typ.debug()} (`${c.table.type_to_str(typ)}`) | inter_typ: ${interface_type.debug()} (`${c.table.type_to_str(interface_type)}`)') } utyp := c.unwrap_generic(typ) + styp := c.table.type_to_str(utyp) typ_sym := c.table.sym(utyp) mut inter_sym := c.table.sym(interface_type) + if inter_sym.mod !in [typ_sym.mod, c.mod] && !inter_sym.is_pub && typ_sym.mod != 'builtin' { + c.error('`${styp}` cannot implement private interface `${inter_sym.name}` of other module', + pos) + return false + } // small hack for JS.Any type. Since `any` in regular V is getting deprecated we have our own JS.Any type for JS backend. if typ_sym.name == 'JS.Any' { @@ -1006,7 +1012,6 @@ fn (mut c Checker) type_implements(typ ast.Type, interface_type ast.Type, pos to // `none` "implements" the Error interface return true } - styp := c.table.type_to_str(utyp) if typ_sym.kind == .interface_ && inter_sym.kind == .interface_ && !styp.starts_with('JS.') && !inter_sym.name.starts_with('JS.') { c.error('cannot implement interface `${inter_sym.name}` with a different interface `${styp}`', diff --git a/vlib/v/checker/tests/modules/implement_private_interface.out b/vlib/v/checker/tests/modules/implement_private_interface.out new file mode 100644 index 00000000000000..f05842ac052175 --- /dev/null +++ b/vlib/v/checker/tests/modules/implement_private_interface.out @@ -0,0 +1,7 @@ +vlib/v/checker/tests/modules/implement_private_interface/main.v:7:16: error: `Bar` cannot implement private interface `baz.Foo` of other module + 5 | fn main() { + 6 | b := Bar{10} + 7 | baz.print_foo(b) // prints 10 + | ^ + 8 | } + 9 | diff --git a/vlib/v/checker/tests/modules/implement_private_interface/baz.v b/vlib/v/checker/tests/modules/implement_private_interface/baz.v new file mode 100644 index 00000000000000..cf03ee43a926b4 --- /dev/null +++ b/vlib/v/checker/tests/modules/implement_private_interface/baz.v @@ -0,0 +1,10 @@ +// sub module +module baz + +interface Foo { + a int +} + +pub fn print_foo(f Foo) { + println(f.a) +} diff --git a/vlib/v/checker/tests/modules/implement_private_interface/main.v b/vlib/v/checker/tests/modules/implement_private_interface/main.v new file mode 100644 index 00000000000000..2be3dec35aa88a --- /dev/null +++ b/vlib/v/checker/tests/modules/implement_private_interface/main.v @@ -0,0 +1,12 @@ +module main + +import baz + +fn main() { + b := Bar{10} + baz.print_foo(b) // prints 10 +} + +struct Bar { + a int +} diff --git a/vlib/v/embed_file/decoder.v b/vlib/v/embed_file/decoder.v index 238766658d8516..960df3236da08b 100644 --- a/vlib/v/embed_file/decoder.v +++ b/vlib/v/embed_file/decoder.v @@ -1,7 +1,7 @@ [has_globals] module embed_file -interface Decoder { +pub interface Decoder { decompress([]u8) ![]u8 }