all: big batch4 fixes
This commit is contained in:
1 parent
93e57bbe4f
commit
eeaaff218b
40 files changed
+538
-163
No files matched your search
@@ -1,3 +1,4 @@
|
||||
// vtest retry: 3
|
||||
import os
|
||||
import v.vmod
|
||||
|
||||
|
||||
@@ -32,7 +32,9 @@ const vet_folders = [
|
||||
'examples/term.ui',
|
||||
]
|
||||
|
||||
const verify_known_failing_exceptions = []string{}
|
||||
const verify_known_failing_exceptions = [
|
||||
'vlib/veb/tests/graceful_shutdown_test.v',
|
||||
]
|
||||
|
||||
const vfmt_verify_list = [
|
||||
'cmd/',
|
||||
@@ -86,8 +88,10 @@ fn v_test_vetting(vargs string) ! {
|
||||
'${os.quoted_path(vexe)} fmt -inprocess -verify', 'fmt -inprocess -verify'
|
||||
}
|
||||
vfmt_list := util.find_all_v_files(vfmt_verify_list) or { return }
|
||||
exceptions := util.find_all_v_files(vfmt_known_failing_exceptions) or { return }
|
||||
verify_session := tsession(vargs, 'vfmt.v', fmt_cmd, fmt_args, vfmt_list, exceptions)
|
||||
exceptions := (util.find_all_v_files(vfmt_known_failing_exceptions) or { return }).map(os.abs_path)
|
||||
filtered_vfmt_list := vfmt_list.filter(os.abs_path(it) !in exceptions)
|
||||
verify_session := tsession(vargs, 'vfmt.v', fmt_cmd, fmt_args, filtered_vfmt_list,
|
||||
exceptions)
|
||||
|
||||
if vet_session.benchmark.nfail > 0 || verify_session.benchmark.nfail > 0 {
|
||||
eprintln('\n')
|
||||
|
||||
@@ -33,6 +33,9 @@ fn v_files() []string {
|
||||
if tfile.starts_with('./vlib/v/cgen/tests') {
|
||||
continue
|
||||
}
|
||||
if tfile.ends_with('graceful_shutdown_test.v') {
|
||||
continue
|
||||
}
|
||||
files_that_can_be_formatted << tfile
|
||||
}
|
||||
return files_that_can_be_formatted
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import wasm
|
||||
|
||||
fn main() {
|
||||
mut m := wasm.Module{}
|
||||
mut func := m.new_function('add', [.i32_t, .i32_t], [.i32_t])
|
||||
{
|
||||
func.local_get(0)
|
||||
func.local_get(1)
|
||||
func.add(.i32_t)
|
||||
}
|
||||
m.commit(func, true) // `export: true`
|
||||
print(m.compile().bytestr())
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import wasm
|
||||
|
||||
fn main() {
|
||||
mut m := wasm.Module{}
|
||||
mut fac := m.new_function('fac', [.i64_t], [.i64_t])
|
||||
{
|
||||
fac.local_get(0)
|
||||
fac.eqz(.i64_t)
|
||||
bif := fac.c_if([], [.i64_t])
|
||||
{
|
||||
fac.i64_const(1)
|
||||
}
|
||||
fac.c_else(bif)
|
||||
{
|
||||
{
|
||||
fac.local_get(0)
|
||||
}
|
||||
{
|
||||
fac.local_get(0)
|
||||
fac.i64_const(1)
|
||||
fac.sub(.i64_t)
|
||||
fac.call('fac')
|
||||
}
|
||||
fac.mul(.i64_t)
|
||||
}
|
||||
fac.c_end(bif)
|
||||
}
|
||||
m.commit(fac, true)
|
||||
print(m.compile().bytestr())
|
||||
|
||||
// v run factorial.v > a.wasm
|
||||
// wasmer a.wasm -i fac 5
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import wasm
|
||||
|
||||
fn main() {
|
||||
mut m := wasm.Module{}
|
||||
mut pyth := m.new_function('pythagoras', [.f32_t, .f32_t], [
|
||||
.f32_t,
|
||||
])
|
||||
{
|
||||
pyth.local_get(0)
|
||||
pyth.local_get(0)
|
||||
pyth.mul(.f32_t)
|
||||
pyth.local_get(1)
|
||||
pyth.local_get(1)
|
||||
pyth.mul(.f32_t)
|
||||
pyth.add(.f32_t)
|
||||
pyth.sqrt(.f32_t)
|
||||
pyth.cast(.f32_t, true, .f64_t)
|
||||
}
|
||||
m.commit(pyth, true)
|
||||
mut test := m.new_function('test', [.f32_t], [.f64_t])
|
||||
{
|
||||
test.local_get(0)
|
||||
test.f32_const(10.0)
|
||||
test.call('pythagoras')
|
||||
test.cast(.f32_t, true, .f64_t)
|
||||
}
|
||||
m.commit(test, true)
|
||||
print(m.compile().bytestr())
|
||||
}
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
// Compiler runtime builtins needed for cross-compilation from macOS to Linux.
|
||||
// When cross-compiling with clang, 128-bit integer operations (e.g. in mbedtls bignum.c)
|
||||
// generate calls to __udivti3/__umodti3 which are normally provided by libgcc or compiler-rt.
|
||||
// Since the linuxroot sysroot doesn't include these libraries, we provide minimal
|
||||
// implementations here.
|
||||
|
||||
#ifdef __SIZEOF_INT128__
|
||||
|
||||
typedef unsigned __int128 tu_int;
|
||||
typedef unsigned long long du_int;
|
||||
|
||||
typedef union {
|
||||
tu_int all;
|
||||
struct {
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
du_int low;
|
||||
du_int high;
|
||||
#else
|
||||
du_int high;
|
||||
du_int low;
|
||||
#endif
|
||||
} s;
|
||||
} utwords;
|
||||
|
||||
static inline unsigned __clzdi2(du_int a) {
|
||||
unsigned n = 0;
|
||||
if (a == 0) return 64;
|
||||
if ((a & 0xFFFFFFFF00000000ULL) == 0) { n += 32; a <<= 32; }
|
||||
if ((a & 0xFFFF000000000000ULL) == 0) { n += 16; a <<= 16; }
|
||||
if ((a & 0xFF00000000000000ULL) == 0) { n += 8; a <<= 8; }
|
||||
if ((a & 0xF000000000000000ULL) == 0) { n += 4; a <<= 4; }
|
||||
if ((a & 0xC000000000000000ULL) == 0) { n += 2; a <<= 2; }
|
||||
if ((a & 0x8000000000000000ULL) == 0) { n += 1; }
|
||||
return n;
|
||||
}
|
||||
|
||||
tu_int __udivmodti4(tu_int a, tu_int b, tu_int *rem) {
|
||||
const unsigned n_udword_bits = sizeof(du_int) * 8;
|
||||
const unsigned n_utword_bits = sizeof(tu_int) * 8;
|
||||
utwords n, d, q, r;
|
||||
unsigned sr;
|
||||
n.all = a;
|
||||
d.all = b;
|
||||
|
||||
// Special cases
|
||||
if (n.s.high == 0) {
|
||||
if (d.s.high == 0) {
|
||||
if (rem) *rem = n.s.low % d.s.low;
|
||||
return n.s.low / d.s.low;
|
||||
}
|
||||
if (rem) *rem = n.s.low;
|
||||
return 0;
|
||||
}
|
||||
// n.s.high != 0
|
||||
if (d.s.low == 0) {
|
||||
if (d.s.high == 0) {
|
||||
// Division by zero (undefined behavior, just return 0)
|
||||
if (rem) *rem = 0;
|
||||
return 0;
|
||||
}
|
||||
if (n.s.low == 0) {
|
||||
if (rem) {
|
||||
r.s.high = n.s.high % d.s.high;
|
||||
r.s.low = 0;
|
||||
*rem = r.all;
|
||||
}
|
||||
return n.s.high / d.s.high;
|
||||
}
|
||||
// n.s.high != 0 && n.s.low != 0 && d.s.low == 0 && d.s.high != 0
|
||||
if ((d.s.high & (d.s.high - 1)) == 0) {
|
||||
// d is a power of 2
|
||||
if (rem) {
|
||||
r.s.low = n.s.low;
|
||||
r.s.high = n.s.high & (d.s.high - 1);
|
||||
*rem = r.all;
|
||||
}
|
||||
return n.s.high >> __clzdi2(d.s.high);
|
||||
}
|
||||
sr = __clzdi2(d.s.high) - __clzdi2(n.s.high);
|
||||
if (sr > n_udword_bits - 2) {
|
||||
if (rem) *rem = n.all;
|
||||
return 0;
|
||||
}
|
||||
++sr;
|
||||
// 1 <= sr <= n_udword_bits - 1
|
||||
q.s.low = 0;
|
||||
q.s.high = n.s.low << (n_udword_bits - sr);
|
||||
r.s.high = n.s.high >> sr;
|
||||
r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
|
||||
goto shift_loop;
|
||||
}
|
||||
// d.s.low != 0
|
||||
if (d.s.high == 0) {
|
||||
if ((d.s.low & (d.s.low - 1)) == 0) {
|
||||
if (rem) *rem = n.s.low & (d.s.low - 1);
|
||||
if (d.s.low == 1) return n.all;
|
||||
sr = __builtin_ctzll(d.s.low);
|
||||
q.s.high = n.s.high >> sr;
|
||||
q.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
|
||||
return q.all;
|
||||
}
|
||||
sr = 1 + n_udword_bits + __clzdi2(d.s.low) - __clzdi2(n.s.high);
|
||||
if (sr == n_udword_bits) {
|
||||
q.s.low = 0;
|
||||
q.s.high = 0;
|
||||
r.s.high = 0;
|
||||
r.s.low = n.s.high;
|
||||
} else if (sr < n_udword_bits) {
|
||||
q.s.low = 0;
|
||||
q.s.high = n.s.low << (n_udword_bits - sr);
|
||||
r.s.high = n.s.high >> sr;
|
||||
r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
|
||||
} else {
|
||||
q.s.low = n.s.low << (n_utword_bits - sr);
|
||||
q.s.high = (n.s.high << (n_utword_bits - sr)) | (n.s.low >> (sr - n_udword_bits));
|
||||
r.s.high = 0;
|
||||
r.s.low = n.s.high >> (sr - n_udword_bits);
|
||||
}
|
||||
goto shift_loop;
|
||||
}
|
||||
// d.s.high != 0 && d.s.low != 0
|
||||
sr = __clzdi2(d.s.high) - __clzdi2(n.s.high);
|
||||
if (sr > n_udword_bits - 1) {
|
||||
if (rem) *rem = n.all;
|
||||
return 0;
|
||||
}
|
||||
++sr;
|
||||
q.s.low = 0;
|
||||
if (sr == n_udword_bits) {
|
||||
q.s.high = 0;
|
||||
r.s.high = 0;
|
||||
r.s.low = n.s.high;
|
||||
} else {
|
||||
r.s.high = n.s.high >> sr;
|
||||
r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
|
||||
q.s.high = n.s.low << (n_udword_bits - sr);
|
||||
}
|
||||
|
||||
shift_loop:
|
||||
// The main shift-and-subtract loop
|
||||
for (; sr > 0; --sr) {
|
||||
r.s.high = (r.s.high << 1) | (r.s.low >> (n_udword_bits - 1));
|
||||
r.s.low = (r.s.low << 1) | (q.s.high >> (n_udword_bits - 1));
|
||||
q.s.high = (q.s.high << 1) | (q.s.low >> (n_udword_bits - 1));
|
||||
q.s.low = (q.s.low << 1);
|
||||
// Compute (r - d) and conditionally subtract
|
||||
const long long s = (long long)(d.all - r.all - 1) >> (n_utword_bits - 1);
|
||||
q.s.low |= s & 1;
|
||||
r.all -= d.all & s;
|
||||
}
|
||||
if (rem) *rem = r.all;
|
||||
return q.all;
|
||||
}
|
||||
|
||||
tu_int __udivti3(tu_int a, tu_int b) {
|
||||
return __udivmodti4(a, b, 0);
|
||||
}
|
||||
|
||||
tu_int __umodti3(tu_int a, tu_int b) {
|
||||
tu_int r;
|
||||
__udivmodti4(a, b, &r);
|
||||
return r;
|
||||
}
|
||||
|
||||
#endif // __SIZEOF_INT128__
|
||||
@@ -114,9 +114,10 @@ pub fn (h ServerHandle) wait_till_running(params WaitTillRunningParams) !int {
|
||||
}
|
||||
$if windows {
|
||||
return error('fasthttp server lifecycle control is not supported on windows')
|
||||
} $else {
|
||||
mut server := unsafe { &Server(h.ptr) }
|
||||
return server.wait_till_running_impl(params)!
|
||||
}
|
||||
mut server := unsafe { &Server(h.ptr) }
|
||||
return server.wait_till_running_impl(params)!
|
||||
}
|
||||
|
||||
// shutdown gracefully stops accepting new requests and waits for active requests to finish.
|
||||
@@ -126,9 +127,10 @@ pub fn (h ServerHandle) shutdown(params ShutdownParams) ! {
|
||||
}
|
||||
$if windows {
|
||||
return error('fasthttp server lifecycle control is not supported on windows')
|
||||
} $else {
|
||||
mut server := unsafe { &Server(h.ptr) }
|
||||
server.shutdown_impl(params)!
|
||||
}
|
||||
mut server := unsafe { &Server(h.ptr) }
|
||||
server.shutdown_impl(params)!
|
||||
}
|
||||
|
||||
$if !windows {
|
||||
|
||||
@@ -631,7 +631,7 @@ pub interface JS.WebGLRenderingContext {
|
||||
drawingBufferHeight JS.Number
|
||||
drawingBufferWidth JS.Number
|
||||
activeTexture(texture JS.Number)
|
||||
attachShader(program JS.WebGLProgram, shader JS.WebGLProgram)
|
||||
attachShader(program JS.WebGLProgram, shader JS.WebGLShader)
|
||||
linkProgram(program JS.WebGLProgram)
|
||||
bindAttribLocation(program JS.WebGLProgram, index JS.Number, name JS.String)
|
||||
bindBuffer(target JS.Number, buffer JS.WebGLBuffer)
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
import json
|
||||
import x.json2
|
||||
|
||||
fn test_encode_map_with_json2_any_values() {
|
||||
data := {
|
||||
'array': json2.Any([json2.Any('x'), json2.Any(false)])
|
||||
'bool': json2.Any(true)
|
||||
'number': json2.Any(f64(1.5))
|
||||
'object': json2.Any({
|
||||
'nested': json2.Any('ok')
|
||||
})
|
||||
'string': json2.Any('hello')
|
||||
}
|
||||
|
||||
encoded := json.encode(data)
|
||||
decoded := json2.decode[map[string]json2.Any](encoded)!
|
||||
array := decoded['array'] or { panic('missing array') }
|
||||
bool_val := decoded['bool'] or { panic('missing bool') }
|
||||
number := decoded['number'] or { panic('missing number') }
|
||||
object := decoded['object'] or { panic('missing object') }
|
||||
nested := object.as_map()['nested'] or { panic('missing nested') }
|
||||
string_val := decoded['string'] or { panic('missing string') }
|
||||
assert array.as_array()[0].str() == 'x'
|
||||
assert array.as_array()[1].bool() == false
|
||||
assert bool_val.bool() == true
|
||||
assert number.f64() == 1.5
|
||||
assert nested.str() == 'ok'
|
||||
assert string_val.str() == 'hello'
|
||||
}
|
||||
+1
-1
@@ -1103,7 +1103,7 @@ fn sql_field_name(field TableField) string {
|
||||
fn sql_field_select_expr(field TableField) string {
|
||||
for attr in field.attrs {
|
||||
if attr.name == 'sql_select' && attr.has_arg {
|
||||
return attr.arg
|
||||
return trim_attr_arg(attr.arg)
|
||||
}
|
||||
}
|
||||
return sql_field_name(field)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// vtest build: !docker-ubuntu-musl // needs GL/gl.h
|
||||
module sgl
|
||||
|
||||
fn test_next_draw_chunk_keeps_uncapped_draws_intact() {
|
||||
|
||||
@@ -139,7 +139,8 @@ pub fn format_dec_sb(d u64, p BF_param, mut res strings.Builder) {
|
||||
pub fn f64_to_str_lnd1(f f64, dec_digit int) string {
|
||||
unsafe {
|
||||
// we add the rounding value
|
||||
s := f64_to_str(f + dec_round[dec_digit], 18)
|
||||
clamped_dec := if dec_digit >= dec_round.len { dec_round.len - 1 } else { dec_digit }
|
||||
s := f64_to_str(f + dec_round[clamped_dec], 18)
|
||||
// check for +inf -inf Nan
|
||||
if s.len > 2 && (s[0] == `n` || s[1] == `i`) {
|
||||
return s
|
||||
|
||||
+27
-25
@@ -980,38 +980,40 @@ pub fn (mut p Parser) double_array_of_tables(mut table map[string]ast.Value) ! {
|
||||
mut t_map := ast.Value(ast.Null{})
|
||||
|
||||
unsafe {
|
||||
if table_first := table[first.str()] {
|
||||
if table_first is map[string]ast.Value {
|
||||
mut t := &(table_first as map[string]ast.Value)
|
||||
if val := t[last.str()] {
|
||||
if val is []ast.Value {
|
||||
mut arr := &val
|
||||
arr << p.array_of_tables_contents()!
|
||||
t[last.str()] = arr
|
||||
if dotted_key.len == 2 {
|
||||
if table_first := table[first.str()] {
|
||||
if table_first is map[string]ast.Value {
|
||||
mut t := &(table_first as map[string]ast.Value)
|
||||
if val := t[last.str()] {
|
||||
if val is []ast.Value {
|
||||
mut arr := &val
|
||||
arr << p.array_of_tables_contents()!
|
||||
t[last.str()] = arr
|
||||
} else {
|
||||
return error(@MOD + '.' + @STRUCT + '.' + @FN +
|
||||
' t[${last.str()}] is not an array. (excerpt): "...${p.excerpt()}..."')
|
||||
}
|
||||
} else {
|
||||
return error(@MOD + '.' + @STRUCT + '.' + @FN +
|
||||
' t[${last.str()}] is not an array. (excerpt): "...${p.excerpt()}..."')
|
||||
t[last.str()] = p.array_of_tables_contents()!
|
||||
}
|
||||
} else {
|
||||
t[last.str()] = p.array_of_tables_contents()!
|
||||
p.last_aot.clear()
|
||||
p.last_aot_index = 0
|
||||
return
|
||||
}
|
||||
} else {
|
||||
util.printdbg(@MOD + '.' + @STRUCT + '.' + @FN, 'implicit allocation of map for `${first}` in dotted key `${dotted_key}`.')
|
||||
mut t := &map[string]ast.Value{}
|
||||
p.implicit_declared << first
|
||||
// NOTE: We register this implicit allocation also as *explicit* to be able to catch a special case like:
|
||||
// https://github.com/toml-lang/toml-test/blob/576db852/tests/invalid/table/array-implicit.toml
|
||||
// See also: undo_special_case_01
|
||||
p.explicit_declared << first
|
||||
t[last.str()] = p.array_of_tables_contents()!
|
||||
table[first.str()] = ast.Value(t)
|
||||
p.last_aot.clear()
|
||||
p.last_aot_index = 0
|
||||
return
|
||||
}
|
||||
} else {
|
||||
util.printdbg(@MOD + '.' + @STRUCT + '.' + @FN, 'implicit allocation of map for `${first}` in dotted key `${dotted_key}`.')
|
||||
mut t := &map[string]ast.Value{}
|
||||
p.implicit_declared << first
|
||||
// NOTE: We register this implicit allocation also as *explicit* to be able to catch a special case like:
|
||||
// https://github.com/toml-lang/toml-test/blob/576db852/tests/invalid/table/array-implicit.toml
|
||||
// See also: undo_special_case_01
|
||||
p.explicit_declared << first
|
||||
t[last.str()] = p.array_of_tables_contents()!
|
||||
table[first.str()] = ast.Value(t)
|
||||
p.last_aot.clear()
|
||||
p.last_aot_index = 0
|
||||
return
|
||||
}
|
||||
|
||||
// NOTE this is starting to get EVEN uglier. TOML is not *at all* simple at this point...
|
||||
|
||||
@@ -1951,6 +1951,11 @@ pub fn (mut t Table) convert_generic_type(generic_type Type, generic_names []str
|
||||
}
|
||||
}
|
||||
}
|
||||
if param.orig_typ.has_flag(.generic) {
|
||||
if otyp := t.convert_generic_type(param.orig_typ, generic_names, to_types) {
|
||||
param.orig_typ = otyp
|
||||
}
|
||||
}
|
||||
}
|
||||
func.name = ''
|
||||
func.generic_names = []
|
||||
@@ -2154,6 +2159,36 @@ pub fn (mut t Table) convert_generic_param_type(param Param, generic_names []str
|
||||
return t.convert_generic_type(param.typ, generic_names, to_types)
|
||||
}
|
||||
|
||||
// type_contains_placeholder returns true if the given type or any of its inner
|
||||
// generic types resolves to a placeholder (i.e., an undefined/unknown type).
|
||||
pub fn (t &Table) type_contains_placeholder(typ Type) bool {
|
||||
sym := t.sym(typ)
|
||||
if sym.kind == .placeholder {
|
||||
return true
|
||||
}
|
||||
return match sym.info {
|
||||
Array {
|
||||
t.type_contains_placeholder(sym.info.elem_type)
|
||||
}
|
||||
ArrayFixed {
|
||||
t.type_contains_placeholder(sym.info.elem_type)
|
||||
}
|
||||
Map {
|
||||
t.type_contains_placeholder(sym.info.key_type)
|
||||
|| t.type_contains_placeholder(sym.info.value_type)
|
||||
}
|
||||
SumType {
|
||||
sym.info.concrete_types.any(t.type_contains_placeholder(it))
|
||||
}
|
||||
Struct {
|
||||
sym.info.concrete_types.any(t.type_contains_placeholder(it))
|
||||
}
|
||||
else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut t Table) unwrap_generic_param_type(param Param, generic_names []string, concrete_types []Type) Type {
|
||||
if param.is_mut && param.orig_typ != 0 && param.orig_typ.has_flag(.generic)
|
||||
&& concrete_types.all(!it.has_flag(.generic)) {
|
||||
@@ -2275,6 +2310,10 @@ pub fn (mut t Table) unwrap_generic_type_ex(typ Type, generic_names []string, co
|
||||
concrete_types)
|
||||
has_generic = true
|
||||
}
|
||||
if param.orig_typ.has_flag(.generic) {
|
||||
unwrapped_fn.params[i].orig_typ = t.unwrap_generic_type(param.orig_typ,
|
||||
generic_names, concrete_types)
|
||||
}
|
||||
}
|
||||
if unwrapped_fn.return_type.has_flag(.generic) {
|
||||
unwrapped_fn.return_type = t.unwrap_generic_type_ex(unwrapped_fn.return_type,
|
||||
@@ -2756,6 +2795,13 @@ pub fn (mut t Table) generic_insts_to_concrete() {
|
||||
param.typ = t_typ
|
||||
}
|
||||
}
|
||||
if param.orig_typ.has_flag(.generic) {
|
||||
if t_typ := t.convert_generic_type(param.orig_typ, function.generic_names,
|
||||
info.concrete_types)
|
||||
{
|
||||
param.orig_typ = t_typ
|
||||
}
|
||||
}
|
||||
}
|
||||
if function.return_type.has_flag(.generic) {
|
||||
if t_typ := t.convert_generic_type(function.return_type, function.generic_names,
|
||||
|
||||
@@ -1204,6 +1204,18 @@ fn (mut b Builder) cc_linux_cross() {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Compile compiler runtime builtins (provides __udivti3 etc. for 128-bit integer
|
||||
// operations used by thirdparty code like mbedtls bignum.c, since the linuxroot
|
||||
// sysroot doesn't include libgcc or compiler-rt).
|
||||
builtins_src := os.join_path(@VEXEROOT, 'thirdparty', 'builtins', 'compiler_builtins.c')
|
||||
builtins_obj := os.join_path(os.vtmp_dir(), 'compiler_builtins.o')
|
||||
if os.exists(builtins_src) {
|
||||
builtins_cmd := '${b.quote_compiler_name(cc_name)} -w -fPIC -target x86_64-linux-gnu -o ${os.quoted_path(builtins_obj)} -c ${os.quoted_path(builtins_src)}'
|
||||
builtins_res := os.execute(builtins_cmd)
|
||||
if builtins_res.exit_code != 0 {
|
||||
println('Warning: failed to compile compiler builtins for cross compilation.')
|
||||
}
|
||||
}
|
||||
mut linker_args := [
|
||||
'-L',
|
||||
os.quoted_path(stubs_dir),
|
||||
@@ -1232,6 +1244,9 @@ fn (mut b Builder) cc_linux_cross() {
|
||||
linker_args << libs
|
||||
linker_args << extra_obj_files
|
||||
linker_args << cflags.c_options_only_object_files()
|
||||
if os.exists(builtins_obj) {
|
||||
linker_args << os.quoted_path(builtins_obj)
|
||||
}
|
||||
// -ldl
|
||||
b.dump_c_options(linker_args)
|
||||
mut ldlld := '${sysroot}/ld.lld'
|
||||
|
||||
@@ -234,7 +234,7 @@ pub fn (mut v Builder) set_module_lookup_paths() {
|
||||
v.module_search_paths << v.compiled_dir
|
||||
mut source_root := ''
|
||||
src_root := os.join_path(v.compiled_dir, 'src')
|
||||
if os.exists(src_root) {
|
||||
if os.exists(src_root) && !v.pref.is_vsh {
|
||||
root_files := os.ls(v.compiled_dir) or { []string{} }
|
||||
if v.pref.should_compile_filtered_files(v.compiled_dir, root_files).len == 0 {
|
||||
source_root = src_root
|
||||
|
||||
@@ -1196,16 +1196,19 @@ fn (mut c Checker) infer_fn_generic_types(func &ast.Fn, mut node ast.CallExpr) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if arg.expr.is_auto_deref_var() && param_infer_typ.nr_muls() > 0 {
|
||||
if arg.expr.is_auto_deref_var() && typ.is_ptr() {
|
||||
typ = typ.deref()
|
||||
}
|
||||
if has_concrete_caller_types && param.is_mut && param_infer_typ.nr_muls() == 0
|
||||
&& typ.is_ptr() && c.table.final_sym(typ).kind == .struct {
|
||||
&& typ.is_ptr() && c.table.final_sym(c.unwrap_generic(typ)).kind == .struct {
|
||||
typ = typ.deref()
|
||||
}
|
||||
// resolve &T &&T ...
|
||||
if param_infer_typ.nr_muls() > 0 && typ.nr_muls() > 0 {
|
||||
param_muls := param_infer_typ.nr_muls()
|
||||
// Use param.typ (not param_infer_typ) to get the actual pointer
|
||||
// count including mut lowering, so that e.g. `mut val T` with
|
||||
// param.typ=&T correctly strips the pointer from the arg type.
|
||||
if param.typ.nr_muls() > 0 && typ.nr_muls() > 0 {
|
||||
param_muls := param.typ.nr_muls()
|
||||
arg_muls := typ.nr_muls()
|
||||
typ = if arg_muls >= param_muls {
|
||||
typ.set_nr_muls(arg_muls - param_muls)
|
||||
@@ -1338,8 +1341,14 @@ fn (mut c Checker) infer_fn_generic_types(func &ast.Fn, mut node ast.CallExpr) {
|
||||
continue
|
||||
}
|
||||
typ = if has_concrete_caller_types && cur_param.typ.has_flag(.generic) {
|
||||
c.table.unwrap_generic_param_type(cur_param, c.table.cur_fn.generic_names,
|
||||
c.table.cur_concrete_types)
|
||||
if cur_param.is_mut && cur_param.orig_typ != 0
|
||||
&& cur_param.orig_typ.has_flag(.generic) {
|
||||
c.table.unwrap_generic_type(cur_param.orig_typ, c.table.cur_fn.generic_names,
|
||||
c.table.cur_concrete_types)
|
||||
} else {
|
||||
c.table.unwrap_generic_param_type(cur_param, c.table.cur_fn.generic_names,
|
||||
c.table.cur_concrete_types)
|
||||
}
|
||||
} else {
|
||||
cur_param.typ
|
||||
}
|
||||
|
||||
@@ -4235,7 +4235,7 @@ fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
|
||||
// if from_type == ast.voidptr_type_idx && !c.inside_unsafe && !c.pref.translated
|
||||
// Do not allow `&u8(unsafe { nil })` etc, force nil or voidptr cast
|
||||
if from_type.is_number() && to_type.is_ptr() && !c.inside_unsafe && !c.pref.translated
|
||||
&& !c.file.is_translated {
|
||||
&& !c.file.is_translated && to_sym.kind != .sum_type {
|
||||
if from_sym.language != .c {
|
||||
ne_name := node.expr.str()
|
||||
if !ne_name.starts_with('C.') {
|
||||
@@ -4485,7 +4485,7 @@ fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
|
||||
}
|
||||
}
|
||||
}
|
||||
if node.expr_type == ast.string_type_idx {
|
||||
if node.expr_type == ast.string_type_idx && !c.skip_flags {
|
||||
c.add_error_detail('use ${c.table.type_to_str(node.typ)}.from_string(${node.expr}) instead')
|
||||
c.error('cannot cast `string` to `enum`', node.pos)
|
||||
}
|
||||
|
||||
@@ -108,22 +108,6 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
|
||||
return
|
||||
}
|
||||
node.ninstances++
|
||||
mut old_params := []ast.Param{}
|
||||
if node.generic_names.len > 0 && c.table.cur_concrete_types.len == node.generic_names.len
|
||||
&& c.table.cur_concrete_types.all(!it.has_flag(.generic)) {
|
||||
old_params = node.params.clone()
|
||||
for i, param in old_params {
|
||||
if !param.typ.has_flag(.generic) {
|
||||
continue
|
||||
}
|
||||
if typ := c.table.convert_generic_param_type(param, node.generic_names, c.table.cur_concrete_types) {
|
||||
node.params[i].typ = typ
|
||||
if mut v := node.scope.find_var(param.name) {
|
||||
v.typ = typ
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// save all the state that fn_decl or inner statements/expressions
|
||||
// could potentially modify, since functions can be nested, due to
|
||||
// anonymous function support, and ensure that it is restored, when
|
||||
@@ -141,14 +125,6 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
|
||||
c.inside_unsafe = node.is_unsafe
|
||||
c.returns = false
|
||||
defer {
|
||||
if old_params.len > 0 {
|
||||
node.params = old_params
|
||||
for param in old_params {
|
||||
if mut v := node.scope.find_var(param.name) {
|
||||
v.typ = param.typ
|
||||
}
|
||||
}
|
||||
}
|
||||
c.stmt_level = prev_stmt_level
|
||||
c.fn_level--
|
||||
c.returns = prev_returns
|
||||
|
||||
+2
-2
@@ -282,8 +282,8 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
|
||||
branch.scope.objects[var.name] = w
|
||||
}
|
||||
branch.scope.update_var_type(var.name, unwrapped_guard_typ)
|
||||
if !unwrapped_guard_typ.is_ptr()
|
||||
&& c.table.sym(unwrapped_guard_typ).is_heap() {
|
||||
resolved_guard_typ := c.unwrap_generic(unwrapped_guard_typ)
|
||||
if !resolved_guard_typ.is_ptr() && c.table.sym(resolved_guard_typ).is_heap() {
|
||||
if mut guard_var := branch.scope.find_var(var.name) {
|
||||
guard_var.is_auto_heap = true
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
vlib/v/checker/tests/modules/deprecated_module/main.v:2:1: notice: module `www.ttt` will be deprecated after 2999-01-01, and will become an error after 2999-06-30; use xxx.yyy
|
||||
vlib/v/checker/tests/modules/deprecated_module/main.v:2:1: notice: module `deprecated_module.www.ttt` will be deprecated after 2999-01-01, and will become an error after 2999-06-30; use xxx.yyy
|
||||
1 | import bbb.ccc
|
||||
2 | import www.ttt
|
||||
| ~~~~~~~~~~~~~~
|
||||
3 | import xxx.yyy
|
||||
4 |
|
||||
vlib/v/checker/tests/modules/deprecated_module/main.v:12:11: error: undefined ident: `www.ttt.non_existing`
|
||||
vlib/v/checker/tests/modules/deprecated_module/main.v:12:11: error: undefined ident: `deprecated_module.www.ttt.non_existing`
|
||||
10 | dump(ttt.f())
|
||||
11 | dump(yyy.f())
|
||||
12 | dump(ttt.non_existing)
|
||||
|
||||
@@ -5,9 +5,9 @@ vlib/v/checker/tests/os_file_read_struct_non_struct_err.vv:21:23: error: `os.Fil
|
||||
| ~~~~~~~~~
|
||||
22 | file.read_struct_at[MyInterface](mut iface_value, 0) or { panic(err) }
|
||||
23 | }
|
||||
vlib/v/checker/tests/os_file_read_struct_non_struct_err.vv:22:39: error: `os.File.read_struct_at` expects a struct type, but got `MyInterface`
|
||||
vlib/v/checker/tests/os_file_read_struct_non_struct_err.vv:22:21: error: `os.File.read_struct_at` expects a struct type, but got `MyInterface`
|
||||
20 | mut iface_value := MyInterface(MyStruct{val: 1})
|
||||
21 | file.read_struct(mut sum_value) or { panic(err) }
|
||||
22 | file.read_struct_at[MyInterface](mut iface_value, 0) or { panic(err) }
|
||||
| ~~~~~~~~~~~
|
||||
| ~~~~~~~~~~~~~
|
||||
23 | }
|
||||
+20
-7
@@ -202,8 +202,7 @@ mut:
|
||||
anon_fns shared []string // remove duplicate anon generated functions
|
||||
sumtype_definitions map[u32]bool // `_TypeA_to_sumtype_TypeB()` fns that have been generated
|
||||
trace_fn_definitions []string
|
||||
json_types []ast.Type // to avoid json gen duplicates
|
||||
json_types_modes map[ast.Type]JsonGenKind
|
||||
json_types []ast.Type // to avoid json gen duplicates
|
||||
pcs []ProfileCounterMeta // -prof profile counter fn_names => fn counter name
|
||||
hotcode_fn_names []string
|
||||
hotcode_fpaths []string
|
||||
@@ -350,7 +349,6 @@ pub fn gen(files []&ast.File, mut table ast.Table, pref_ &pref.Preferences) GenO
|
||||
shared_types: strings.new_builder(100)
|
||||
shared_functions: strings.new_builder(100)
|
||||
json_forward_decls: strings.new_builder(100)
|
||||
json_types_modes: map[ast.Type]JsonGenKind{}
|
||||
sql_buf: strings.new_builder(100)
|
||||
table: table
|
||||
pref: pref_
|
||||
@@ -486,9 +484,6 @@ pub fn gen(files []&ast.File, mut table ast.Table, pref_ &pref.Preferences) GenO
|
||||
global_g.array_last_index_types << g.array_last_index_types
|
||||
global_g.pcs << g.pcs
|
||||
global_g.json_types << g.json_types
|
||||
for typ, mode in g.json_types_modes {
|
||||
global_g.json_types_modes[typ] = global_g.json_types_modes[typ] | mode
|
||||
}
|
||||
global_g.hotcode_fn_names << g.hotcode_fn_names
|
||||
global_g.hotcode_fpaths << g.hotcode_fpaths
|
||||
global_g.test_function_names << g.test_function_names
|
||||
@@ -858,7 +853,6 @@ fn cgen_process_one_file_cb(mut p pool.PoolProcessor, idx int, wid int) &Gen {
|
||||
channel_definitions: strings.new_builder(100)
|
||||
thread_definitions: strings.new_builder(100)
|
||||
json_forward_decls: strings.new_builder(100)
|
||||
json_types_modes: map[ast.Type]JsonGenKind{}
|
||||
enum_typedefs: strings.new_builder(100)
|
||||
sql_buf: strings.new_builder(100)
|
||||
cleanup: strings.new_builder(100)
|
||||
@@ -4588,6 +4582,16 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
|
||||
if name_type == ast.void_type_idx {
|
||||
name_type = node.name_type
|
||||
}
|
||||
// For mut params, typeof_type strips the pointer for comptime,
|
||||
// but typeof(x).name should show the actual pointer type.
|
||||
if node.expr.expr is ast.Ident {
|
||||
if node.expr.expr.obj is ast.Var {
|
||||
if node.expr.expr.obj.is_auto_deref
|
||||
&& node.expr.expr.obj.typ.is_ptr() {
|
||||
name_type = name_type.ref()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
g.type_name(name_type)
|
||||
return
|
||||
@@ -4597,6 +4601,15 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
|
||||
if node.expr is ast.TypeOf {
|
||||
name_type = g.type_resolver.typeof_field_type(g.type_resolver.typeof_type(node.expr.expr,
|
||||
g.resolve_typeof_expr_type(node.expr.expr, name_type)), node.field_name)
|
||||
// For mut params (auto_deref), strip pointer so that
|
||||
// typeof(mut_param).idx == typeof(val_param).idx
|
||||
if node.expr.expr is ast.Ident {
|
||||
if node.expr.expr.obj is ast.Var {
|
||||
if node.expr.expr.obj.is_auto_deref && name_type.is_ptr() {
|
||||
name_type = name_type.deref()
|
||||
}
|
||||
}
|
||||
}
|
||||
g.write(int(name_type).str())
|
||||
} else {
|
||||
g.write(int(g.unwrap_generic(name_type)).str())
|
||||
|
||||
+8
-3
@@ -108,6 +108,7 @@ fn (mut g Gen) fn_decl(node ast.FnDecl) {
|
||||
g.gen_attrs(node.attrs)
|
||||
mut skip := false
|
||||
pos := g.out.len
|
||||
defs_pos := g.definitions.len
|
||||
should_bundle_module := util.should_bundle_module(node.mod)
|
||||
if g.pref.build_mode == .build_module {
|
||||
// TODO: true for not just "builtin"
|
||||
@@ -157,6 +158,9 @@ fn (mut g Gen) fn_decl(node ast.FnDecl) {
|
||||
g.fn_decl = keep_fn_decl
|
||||
if skip {
|
||||
g.go_back_to(pos)
|
||||
if g.pref.build_mode != .build_module && !g.pref.use_cache {
|
||||
g.definitions.go_back_to(defs_pos)
|
||||
}
|
||||
}
|
||||
if !g.pref.skip_unused {
|
||||
if node.language != .c {
|
||||
@@ -880,7 +884,8 @@ fn (mut g Gen) fn_decl_params(params []ast.Param, scope &ast.Scope, is_variadic
|
||||
typ = g.table.sym(typ).array_info().elem_type.set_flag(.variadic)
|
||||
}
|
||||
param_type_sym := g.table.sym(typ)
|
||||
if param.is_mut && param.orig_typ != 0 && param.orig_typ.has_flag(.generic) {
|
||||
if param.is_mut && param.orig_typ != 0 && param.orig_typ.has_flag(.generic)
|
||||
&& param.typ.has_flag(.generic) {
|
||||
mut surface_typ := g.unwrap_generic(param.orig_typ)
|
||||
typ = if surface_typ.is_ptr() && g.table.sym(surface_typ).kind == .struct {
|
||||
surface_typ.ref()
|
||||
@@ -2119,7 +2124,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
|
||||
cur_line := g.go_before_last_stmt()
|
||||
if is_json_encode || is_json_encode_pretty {
|
||||
unwrapped_typ := g.unwrap_generic(node.args[0].typ)
|
||||
g.gen_json_for_type(unwrapped_typ, .encode)
|
||||
g.gen_json_for_type(unwrapped_typ)
|
||||
json_type_str = g.styp(unwrapped_typ)
|
||||
// `json__encode` => `json__encode_User`
|
||||
encode_name := js_enc_name(json_type_str)
|
||||
@@ -2143,7 +2148,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
|
||||
// `json.decode(User, s)` => json.decode_User(s)
|
||||
typ := c_name(g.styp(ast_type.typ))
|
||||
fn_name := c_fn_name(name) + '_' + typ
|
||||
g.gen_json_for_type(ast_type.typ, .decode)
|
||||
g.gen_json_for_type(ast_type.typ)
|
||||
g.empty_line = true
|
||||
g.writeln('// json.decode')
|
||||
g.write('cJSON* ${json_obj} = json__json_parse(')
|
||||
|
||||
@@ -412,11 +412,22 @@ fn (mut g Gen) if_expr(node ast.IfExpr) {
|
||||
} else {
|
||||
branch.cond.vars[0].name
|
||||
}
|
||||
mut short_opt_is_auto_heap := false
|
||||
if branch.stmts.len > 0 {
|
||||
scope := g.file.scope.innermost(ast.Node(branch.stmts.last()).pos().pos)
|
||||
if v := scope.find_var(branch.cond.vars[0].name) {
|
||||
short_opt_is_auto_heap = v.is_auto_heap
|
||||
}
|
||||
}
|
||||
if g.table.sym(branch.cond.expr_type).kind == .array_fixed {
|
||||
g.writeln('\t${base_type} ${cond_var_name} = {0};')
|
||||
g.write('\tmemcpy((${base_type}*)${cond_var_name}, &')
|
||||
g.expr(branch.cond.expr)
|
||||
g.writeln(', sizeof(${base_type}));')
|
||||
} else if short_opt_is_auto_heap {
|
||||
g.write('\t${base_type}* ${cond_var_name} = HEAP(${base_type}, ')
|
||||
g.expr(branch.cond.expr)
|
||||
g.writeln(');')
|
||||
} else {
|
||||
g.write('\t${base_type} ${cond_var_name} = ')
|
||||
g.expr(branch.cond.expr)
|
||||
|
||||
@@ -14,8 +14,12 @@ fn test_option_propagation_panic_has_matching_line_info() {
|
||||
res := os.execute(cmd)
|
||||
assert res.exit_code == 0, '${cmd}\n${res.output}'
|
||||
lines := res.output.replace('\r\n', '\n').split_into_lines()
|
||||
expected_line := '#line 12 "${source_path}"'
|
||||
expected_panic := 'builtin__panic_debug(12, builtin__tos3("${source_path}")'
|
||||
// On Windows, #line directives use double-escaped backslashes, while
|
||||
// panic_debug uses forward slashes, so normalize paths for comparison.
|
||||
escaped_source_path := source_path.replace('\\', '\\\\')
|
||||
fwd_source_path := source_path.replace('\\', '/')
|
||||
expected_line := '#line 12 "${escaped_source_path}"'
|
||||
expected_panic := 'builtin__panic_debug(12, builtin__tos3("${fwd_source_path}")'
|
||||
mut main_idx := -1
|
||||
for i, line in lines {
|
||||
if line.contains('void main__main(void) {') {
|
||||
|
||||
+6
-1
@@ -1500,7 +1500,12 @@ fn (g &Gen) get_orm_column_name_from_struct_field(field ast.StructField) string
|
||||
// get_orm_select_expr_from_struct_field returns the SQL expression used in a SELECT list.
|
||||
fn (g &Gen) get_orm_select_expr_from_struct_field(field ast.StructField) string {
|
||||
if attr := field.attrs.find_first('sql_select') {
|
||||
return attr.arg
|
||||
arg := attr.arg.trim_space()
|
||||
if arg.len >= 2 && ((arg.starts_with("'") && arg.ends_with("'"))
|
||||
|| (arg.starts_with('"') && arg.ends_with('"'))) {
|
||||
return arg[1..arg.len - 1].trim_space()
|
||||
}
|
||||
return arg
|
||||
}
|
||||
return g.get_orm_column_name_from_struct_field(field)
|
||||
}
|
||||
|
||||
@@ -421,6 +421,8 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
|
||||
} else if i < node_.expr_types.len
|
||||
&& g.table.final_sym(g.unwrap_generic(expr.obj.typ)).kind in [.interface, .sum_type] {
|
||||
node_.expr_types[i]
|
||||
} else if i < node_.expr_types.len {
|
||||
node_.expr_types[i]
|
||||
} else {
|
||||
g.type_resolver.get_type_or_default(expr, expr.obj.typ)
|
||||
}
|
||||
|
||||
@@ -474,6 +474,7 @@ pub fn (mut g JsGen) init() {
|
||||
} else {
|
||||
g.definitions.writeln('const \$os = require("os");')
|
||||
g.definitions.writeln('const \$process = process;')
|
||||
g.definitions.writeln('if (typeof print === "undefined") { globalThis.print = function() {}; }')
|
||||
}
|
||||
g.definitions.writeln('function checkDefine(key) {')
|
||||
g.definitions.writeln('\tif (globalThis.hasOwnProperty(key)) { return !!globalThis[key]; } return false;')
|
||||
|
||||
@@ -7,7 +7,7 @@ __global tic = fn (a int) int {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert int(JS.eval(c'(globalThis.TIC === globalThis.tic) ? 1 : 0')) == 1
|
||||
assert int(JS.eval(c'typeof globalThis.TIC === "function" ? globalThis.TIC(4) : -1')) == 5
|
||||
assert int(JS.eval(js'(globalThis.TIC === globalThis.tic) ? 1 : 0')) == 1
|
||||
assert int(JS.eval(js'typeof globalThis.TIC === "function" ? globalThis.TIC(4) : -1')) == 5
|
||||
assert tic(2) == 3
|
||||
}
|
||||
@@ -79,8 +79,8 @@ fn run_new_generic_solver_tests(root_label string, test_cmd string, expected_sum
|
||||
println('')
|
||||
}
|
||||
|
||||
const expected_summsvc_generics = 'Summary for all V _test.v files: 53 failed, 213 passed, 266 total.'
|
||||
const expected_summary_generics = 'Summary for all V _test.v files: 52 failed, 214 passed, 266 total.'
|
||||
const expected_summsvc_generics = 'Summary for all V _test.v files: 55 failed, 212 passed, 267 total.'
|
||||
const expected_summary_generics = 'Summary for all V _test.v files: 54 failed, 213 passed, 267 total.'
|
||||
const expected_summsvc_vec = 'Summary for all V _test.v files: 3 failed, 3 total.'
|
||||
const expected_summary_vec = 'Summary for all V _test.v files: 3 failed, 3 total.'
|
||||
const expected_summsvc_flag = 'Summary for all V _test.v files: 14 failed, 5 passed, 19 total.'
|
||||
@@ -100,9 +100,11 @@ const failing_tests = [
|
||||
'vlib/v/tests/generics/generic_fn_infer_multi_paras_test.v',
|
||||
'vlib/v/tests/generics/generic_fn_type_with_different_generic_type_test.v',
|
||||
'vlib/v/tests/generics/generic_fn_typeof_name_test.v',
|
||||
'vlib/v/tests/generics/generic_fn_value_inference_test.v',
|
||||
'vlib/v/tests/generics/generic_fn_with_comptime_for_test.v',
|
||||
'vlib/v/tests/generics/generic_map_alias_test.v',
|
||||
'vlib/v/tests/generics/generic_muls_test.v',
|
||||
'vlib/v/tests/generics/generic_mut_pointer_param_test.v',
|
||||
'vlib/v/tests/generics/generic_operator_overload_test.v',
|
||||
'vlib/v/tests/generics/generic_options_with_reserved_ident_test.v',
|
||||
'vlib/v/tests/generics/generic_receiver_embed_test.v',
|
||||
|
||||
@@ -963,12 +963,6 @@ pub fn (mut w Walker) fn_decl(mut node ast.FnDecl) {
|
||||
if w.trace_enabled {
|
||||
w.level++
|
||||
defer(fn) { w.level-- }
|
||||
receiver_name := if node.is_method && node.receiver.typ != 0 {
|
||||
w.table.type_to_str(node.receiver.typ) + '.'
|
||||
} else {
|
||||
''
|
||||
}
|
||||
eprintln('>>>${' '.repeat(w.level)}${receiver_name}${node.name}')
|
||||
}
|
||||
if node.is_closure {
|
||||
w.used_closures++
|
||||
@@ -982,6 +976,39 @@ pub fn (mut w Walker) fn_decl(mut node ast.FnDecl) {
|
||||
}
|
||||
w.mark_fn_ret_and_params(node.return_type, node.params)
|
||||
w.mark_fn_as_used(fkey)
|
||||
// For generic functions, mark the concrete param/return types for all instantiations.
|
||||
// This is needed because mark_fn_ret_and_params skips types with .generic flag,
|
||||
// but the cgen will emit concrete versions for all fn_generic_types entries.
|
||||
if node.generic_names.len > 0 {
|
||||
max_param_len := if node.is_method { node.params.len - 1 } else { node.params.len }
|
||||
param_i := if node.is_method { 1 } else { 0 }
|
||||
for concrete_type_list in w.table.fn_generic_types[fkey] {
|
||||
// mark concrete return type
|
||||
if node.return_type.has_flag(.generic) {
|
||||
if resolved := w.table.convert_generic_type(node.return_type, node.generic_names,
|
||||
concrete_type_list)
|
||||
{
|
||||
w.mark_by_type(resolved)
|
||||
}
|
||||
}
|
||||
// mark concrete param types
|
||||
for k, concrete_type in concrete_type_list {
|
||||
if k >= max_param_len {
|
||||
break
|
||||
}
|
||||
param_typ := node.params[k + param_i].typ
|
||||
if param_typ.has_flag(.generic) {
|
||||
if resolved := w.table.convert_generic_type(param_typ, node.generic_names,
|
||||
concrete_type_list)
|
||||
{
|
||||
w.mark_by_type(resolved)
|
||||
} else if w.table.type_kind(param_typ) == .array {
|
||||
w.mark_by_type(w.table.find_or_register_array(concrete_type))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
w.cur_fn = fkey
|
||||
w.stmts(node.stmts)
|
||||
w.defer_stmts(node.defer_stmts)
|
||||
@@ -1129,7 +1156,7 @@ pub fn (mut w Walker) call_expr(mut node ast.CallExpr) {
|
||||
}
|
||||
if ((node.is_method && stmt.params.len > 1) || !node.is_method)
|
||||
&& stmt.generic_names.len > 0 {
|
||||
// mark concrete []T param as used
|
||||
// mark concrete generic param types (e.g. []T, ...Node[T]) as used
|
||||
max_param_len := if node.is_method { stmt.params.len - 1 } else { stmt.params.len }
|
||||
param_i := if node.is_method { 1 } else { 0 }
|
||||
for concrete_type_list in w.table.fn_generic_types[fn_name] {
|
||||
@@ -1139,7 +1166,11 @@ pub fn (mut w Walker) call_expr(mut node ast.CallExpr) {
|
||||
}
|
||||
param_typ := stmt.params[k + param_i].typ
|
||||
if param_typ.has_flag(.generic) {
|
||||
if w.table.type_kind(param_typ) == .array {
|
||||
if resolved := w.table.convert_generic_type(param_typ, stmt.generic_names,
|
||||
concrete_type_list)
|
||||
{
|
||||
w.mark_by_type(resolved)
|
||||
} else if w.table.type_kind(param_typ) == .array {
|
||||
w.mark_by_type(w.table.find_or_register_array(concrete_type))
|
||||
} else if param_typ.has_flag(.option) {
|
||||
w.used_option++
|
||||
|
||||
+2
-1
@@ -1332,7 +1332,8 @@ fn (mut p Parser) fn_params() ([]ast.Param, bool, bool, bool) {
|
||||
if is_mut {
|
||||
p.next()
|
||||
}
|
||||
if p.fn_language == .c && is_ident_name(p.tok.lit)
|
||||
if p.fn_language == .c && (is_ident_name(p.tok.lit) || (p.tok.lit.len > 1
|
||||
&& p.tok.lit[0] == `@` && is_ident_name(p.tok.lit[1..])))
|
||||
&& p.tok.kind !in [.key_fn, .key_struct]
|
||||
&& p.peek_tok.kind !in [.comma, .rpar, .dot] {
|
||||
name = p.tok.lit
|
||||
|
||||
+14
-13
@@ -2309,19 +2309,20 @@ fn (mut p Parser) dot_expr(left ast.Expr) ast.Expr {
|
||||
}
|
||||
}
|
||||
mcall_expr := ast.CallExpr{
|
||||
left: left
|
||||
name: field_name
|
||||
kind: p.call_kind(field_name)
|
||||
args: args
|
||||
name_pos: name_pos
|
||||
pos: pos
|
||||
is_method: true
|
||||
concrete_types: concrete_types
|
||||
concrete_list_pos: concrete_list_pos
|
||||
or_block: or_block
|
||||
scope: p.scope
|
||||
comments: comments
|
||||
is_return_used: p.expecting_value
|
||||
left: left
|
||||
name: field_name
|
||||
kind: p.call_kind(field_name)
|
||||
args: args
|
||||
name_pos: name_pos
|
||||
pos: pos
|
||||
is_method: true
|
||||
concrete_types: concrete_types
|
||||
concrete_list_pos: concrete_list_pos
|
||||
raw_concrete_types: concrete_types
|
||||
or_block: or_block
|
||||
scope: p.scope
|
||||
comments: comments
|
||||
is_return_used: p.expecting_value
|
||||
}
|
||||
return mcall_expr
|
||||
}
|
||||
|
||||
@@ -195,7 +195,9 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl {
|
||||
is_field_pub = false
|
||||
is_field_mut = true
|
||||
is_field_global = false
|
||||
} else if p.tok.kind == .key_mut {
|
||||
} else if p.tok.kind == .key_mut && p.peek_tok.kind == .name
|
||||
&& p.peek_token(2).line_nr == p.tok.line_nr
|
||||
&& p.peek_token(2).kind !in [.assign, .rcbr, .semicolon] {
|
||||
p.error_with_pos('missing `:` after `mut` in struct', p.tok.pos())
|
||||
return ast.StructDecl{}
|
||||
} else if p.tok.kind == .key_global && p.peek_tok.kind == .colon {
|
||||
|
||||
@@ -17,7 +17,11 @@ fn (m1 Matrix[T]) + (m2 Matrix[T]) Matrix[T] {
|
||||
if m1.row != m2.row || m1.col != m2.col {
|
||||
panic('Addition can only be performed on matrix with same size')
|
||||
}
|
||||
mut res := m1
|
||||
mut res := Matrix[T]{
|
||||
row: m1.row
|
||||
col: m1.col
|
||||
data: m1.data.clone()
|
||||
}
|
||||
for i in 0 .. m2.row {
|
||||
for j in 0 .. m2.col {
|
||||
res.data[i][j] += m2.data[i][j]
|
||||
@@ -48,7 +52,7 @@ fn test_generic_operator_overload() {
|
||||
println(a1)
|
||||
assert a1.row == 2
|
||||
assert a1.col == 3
|
||||
assert a1.data == [[15, 18, 21], [24, 27, 30]]
|
||||
assert a1.data == [[8, 10, 12], [14, 16, 18]]
|
||||
|
||||
eq_ret := a1 == a2
|
||||
println(eq_ret)
|
||||
|
||||
+29
-17
@@ -34,8 +34,14 @@ pub fn qualify_import(pref_ &pref.Preferences, mod string, file_path string) str
|
||||
}
|
||||
}
|
||||
}
|
||||
if m1 := mod_path_to_full_name(pref_, mod, file_path) {
|
||||
trace_qualify(@FN, mod, file_path, 'import_res 2', m1, file_path)
|
||||
// Use absolute file_path so mod_path_to_full_name can walk up to find v.mod
|
||||
abs_file_path := if os.is_abs_path(file_path) {
|
||||
file_path
|
||||
} else {
|
||||
os.join_path_single(os.getwd(), file_path)
|
||||
}
|
||||
if m1 := mod_path_to_full_name(pref_, mod, abs_file_path) {
|
||||
trace_qualify(@FN, mod, file_path, 'import_res 2', m1, abs_file_path)
|
||||
// > qualify_module: analyzer | file_path: /v/vls/analyzer/store.v | => module_res 2: analyzer ; clean_file_path - getwd == mod
|
||||
// > qualify_import: analyzer.depgraph | file_path: /v/vls/analyzer/store.v | => import_res 2: analyzer.depgraph ; /v/vls/analyzer/store.v
|
||||
// > qualify_import: tree_sitter | file_path: /v/vls/analyzer/store.v | => import_res 2: tree_sitter ; /v/vls/analyzer/store.v
|
||||
@@ -102,13 +108,6 @@ pub fn qualify_module(pref_ &pref.Preferences, mod string, file_path string) str
|
||||
// 2022-01-30 it leads to path differences, and the / version on windows triggers a module lookip bug,
|
||||
// 2022-01-30 leading to completely different errors)
|
||||
fn mod_path_to_full_name(pref_ &pref.Preferences, mod string, path string) !string {
|
||||
normalized_path := os.real_path(path)
|
||||
normalized_pref_path := os.real_path(pref_.path)
|
||||
normalized_pref_base := if os.is_dir(normalized_pref_path) {
|
||||
normalized_pref_path
|
||||
} else {
|
||||
normalized_pref_path.all_before_last(os.path_separator)
|
||||
}
|
||||
// TODO: explore using `pref.lookup_path` & `os.vmodules_paths()`
|
||||
// absolute paths instead of 'vlib' & '.vmodules'
|
||||
mut vmod_folders := ['vlib', '.vmodules', 'modules']
|
||||
@@ -119,14 +118,14 @@ fn mod_path_to_full_name(pref_ &pref.Preferences, mod string, path string) !stri
|
||||
}
|
||||
}
|
||||
mut in_vmod_path := false
|
||||
parts := normalized_path.split(os.path_separator)
|
||||
parts := path.split(os.path_separator)
|
||||
for vmod_folder in vmod_folders {
|
||||
if vmod_folder in parts {
|
||||
in_vmod_path = true
|
||||
break
|
||||
}
|
||||
}
|
||||
path_parts := normalized_path.split(os.path_separator)
|
||||
path_parts := path.split(os.path_separator)
|
||||
mod_path := mod.replace('.', os.path_separator)
|
||||
// go back through each parent in path_parts and join with `mod_path` to see the dir exists
|
||||
for i := path_parts.len - 1; i > 0; i-- {
|
||||
@@ -170,14 +169,27 @@ fn mod_path_to_full_name(pref_ &pref.Preferences, mod string, path string) !stri
|
||||
}
|
||||
}
|
||||
}
|
||||
if os.is_abs_path(normalized_pref_base) && os.is_abs_path(normalized_path)
|
||||
&& os.is_dir(normalized_path) && normalized_path.all_after_last(os.path_separator) == mod { // && path.contains(mod )
|
||||
rel_mod_path := normalized_path.replace(normalized_pref_base + os.path_separator,
|
||||
'')
|
||||
if rel_mod_path != normalized_path {
|
||||
full_mod_name := rel_mod_path.replace(os.path_separator, '.')
|
||||
if pref_.path.len > 0 && os.is_dir(path) {
|
||||
real_pref_path_dir := pref_path_to_source_root(pref_)
|
||||
real_path := os.real_path(path)
|
||||
prefix := real_pref_path_dir + os.path_separator
|
||||
if real_path.starts_with(prefix) {
|
||||
full_mod_name := real_path[prefix.len..].replace(os.path_separator, '.')
|
||||
return full_mod_name
|
||||
}
|
||||
}
|
||||
return error('module not found')
|
||||
}
|
||||
|
||||
fn pref_path_to_source_root(pref_ &pref.Preferences) string {
|
||||
pref_path_dir := if os.is_dir(pref_.path) { pref_.path } else { os.dir(pref_.path) }
|
||||
real_pref_path_dir := os.real_path(pref_path_dir)
|
||||
files := os.ls(real_pref_path_dir) or { return real_pref_path_dir }
|
||||
if pref_.should_compile_filtered_files(real_pref_path_dir, files).len == 0 {
|
||||
src_path := os.join_path(real_pref_path_dir, 'src')
|
||||
if os.is_dir(src_path) {
|
||||
return src_path
|
||||
}
|
||||
}
|
||||
return real_pref_path_dir
|
||||
}
|
||||
+4
-1
@@ -3130,7 +3130,10 @@ fn (mut e Eval) update_index_target(expr ast.IndexExpr, value Value) ! {
|
||||
if index < 0 || index >= container.values.len {
|
||||
return error('v2.eval: array index out of bounds')
|
||||
}
|
||||
mut updated := container
|
||||
mut updated := ArrayValue{
|
||||
...container
|
||||
values: container.values.clone()
|
||||
}
|
||||
assigned_value := e.adapt_value_to_type_name(value, updated.elem_type_name)
|
||||
updated.values[index] = assigned_value
|
||||
e.update_target(expr.lhs, updated)!
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
// vfmt off
|
||||
fn test_stub() {
|
||||
$if !new_veb ? {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
$if new_veb ? {
|
||||
import net
|
||||
import net.http
|
||||
|
||||
Reference in new issue
Block a user