diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index d2c65f6a9b..45f1c1c967 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -388,9 +388,10 @@ pub: method_idx int rec_mut bool // is receiver mutable rec_share ShareType - language Language - no_body bool // just a definition `fn C.malloc()` - is_builtin bool // this function is defined in builtin/strconv + language Language // V, C, JS + file_mode Language // whether *the file*, where a function was a '.c.v', '.js.v' etc. + no_body bool // just a definition `fn C.malloc()` + is_builtin bool // this function is defined in builtin/strconv body_pos token.Position // function bodys position file string generic_names []string diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index cc8c8df274..b5bc605639 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -87,6 +87,7 @@ pub: is_keep_alive bool // passed memory must not be freed (by GC) before function returns no_body bool // a pure declaration like `fn abc(x int)`; used in .vh files, C./JS. fns. mod string + file_mode Language pos token.Position return_type_pos token.Position pub mut: diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 29700fec9c..e2eefa8478 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -364,6 +364,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { && (p.file_base.ends_with('_test.v') || p.file_base.all_before_last('.v').all_before_last('.').ends_with('_test')) + file_mode := p.file_backend_mode // Register if is_method { mut type_sym := p.table.get_type_symbol(rec.typ) @@ -386,6 +387,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { } type_sym_method_idx = type_sym.register_method(ast.Fn{ name: name + file_mode: file_mode params: params return_type: return_type is_variadic: is_variadic @@ -412,11 +414,21 @@ fn (mut p Parser) fn_decl() ast.FnDecl { } else { name = p.prepend_mod(name) } - if !p.pref.translated && language == .v && name in p.table.fns { - p.table.redefined_fns << name + if !p.pref.translated && language == .v { + if existing := p.table.fns[name] { + if existing.name != '' { + if file_mode == .v && existing.file_mode != .v { + // a definition made in a .c.v file, should have a priority over a .v file definition of the same function + name = p.prepend_mod('pure_v_but_overriden_by_${existing.file_mode}_$short_fn_name') + } else { + p.table.redefined_fns << name + } + } + } } p.table.register_fn(ast.Fn{ name: name + file_mode: file_mode params: params return_type: return_type is_variadic: is_variadic diff --git a/vlib/v/tests/project_with_c_code_3/.gitignore b/vlib/v/tests/project_with_c_code_3/.gitignore new file mode 100644 index 0000000000..4607858382 --- /dev/null +++ b/vlib/v/tests/project_with_c_code_3/.gitignore @@ -0,0 +1,3 @@ +main +mod1/c/implementation.o +main_test diff --git a/vlib/v/tests/project_with_c_code_3/.v.mod.stop b/vlib/v/tests/project_with_c_code_3/.v.mod.stop new file mode 100644 index 0000000000..abdf0f97cf --- /dev/null +++ b/vlib/v/tests/project_with_c_code_3/.v.mod.stop @@ -0,0 +1,4 @@ +Do not delete this file. +It is used by V to stop the lookup for v.mod, +so that the top level vlib/v.mod is not found, +if you delete mod1/v.mod . diff --git a/vlib/v/tests/project_with_c_code_3/main.v b/vlib/v/tests/project_with_c_code_3/main.v new file mode 100644 index 0000000000..0f6fe9b392 --- /dev/null +++ b/vlib/v/tests/project_with_c_code_3/main.v @@ -0,0 +1,15 @@ +module main + +import v.tests.project_with_c_code_3.mod1 + +fn main() { + res := mod1.vadd(1, 2) + println('mod1.vadd(1, 2): ' + res.str()) + $if js { + assert res == 2003 + } $else { + assert res == 1003 + } + println('mod1.a_common_pure_v_fn(): ' + mod1.a_common_pure_v_fn().str()) + assert mod1.a_common_pure_v_fn() == 987654 +} diff --git a/vlib/v/tests/project_with_c_code_3/main_test.v b/vlib/v/tests/project_with_c_code_3/main_test.v new file mode 100644 index 0000000000..179349de5f --- /dev/null +++ b/vlib/v/tests/project_with_c_code_3/main_test.v @@ -0,0 +1,13 @@ +import v.tests.project_with_c_code_3.mod1 + +fn test_using_c_code_in_the_same_module_works() { + $if js { + assert 2003 == mod1.vadd(1, 2) + } $else { + assert 1003 == mod1.vadd(1, 2) + } +} + +fn test_a_common_pure_v_fn_works() { + assert mod1.a_common_pure_v_fn() == 987654 +} diff --git a/vlib/v/tests/project_with_c_code_3/mod1/v.mod b/vlib/v/tests/project_with_c_code_3/mod1/v.mod new file mode 100644 index 0000000000..72ddcfdaf2 --- /dev/null +++ b/vlib/v/tests/project_with_c_code_3/mod1/v.mod @@ -0,0 +1,5 @@ +Module { + name: 'mod1', + description: 'A simple module, containing C code.', + dependencies: [] +} diff --git a/vlib/v/tests/project_with_c_code_3/mod1/wrapper.c.v b/vlib/v/tests/project_with_c_code_3/mod1/wrapper.c.v new file mode 100644 index 0000000000..ce2d1599e9 --- /dev/null +++ b/vlib/v/tests/project_with_c_code_3/mod1/wrapper.c.v @@ -0,0 +1,5 @@ +module mod1 + +pub fn vadd(a int, b int) int { + return 1003 +} diff --git a/vlib/v/tests/project_with_c_code_3/mod1/wrapper.js.v b/vlib/v/tests/project_with_c_code_3/mod1/wrapper.js.v new file mode 100644 index 0000000000..0670fc1925 --- /dev/null +++ b/vlib/v/tests/project_with_c_code_3/mod1/wrapper.js.v @@ -0,0 +1,6 @@ +module mod1 + +// NB: the function here, overrides the one from wrapper.v +pub fn vadd(a int, b int) int { + return 2003 +} diff --git a/vlib/v/tests/project_with_c_code_3/mod1/wrapper.v b/vlib/v/tests/project_with_c_code_3/mod1/wrapper.v new file mode 100644 index 0000000000..c161903c53 --- /dev/null +++ b/vlib/v/tests/project_with_c_code_3/mod1/wrapper.v @@ -0,0 +1,11 @@ +module mod1 + +// NB: the function here, should be overriden by the one in the wrapper.c.v file with the same name +pub fn vadd(a int, b int) int { + return 123456 +} + +// this should NOT be overriden by the different wrapper.X.v files: +pub fn a_common_pure_v_fn() int { + return 987654 +}