vlang / v

Simple, fast, safe, compiled language for developing maintainable software. Compiles itself in <1s with zero library dependencies. Supports automatic C => V translation. https://vlang.io
MIT License
35.75k stars 2.16k forks source link

got unexpected value #15826

Closed ken0x0a closed 2 years ago

ken0x0a commented 2 years ago

V version: V 0.3.1 d7758b2.69c9d47 OS: macos, macOS, 12.6, 21G115

What did you do?


pub struct Vec<T> {
mut:
    data &T
    cap  usize
    len  usize
}

pub struct Iter<T> {
mut:
    v   &Vec<T>
    pos usize
}

pub fn with_cap<T>(cap usize) Vec<T> {
    new_data := unsafe { C.malloc(cap * usize(sizeof(T))) }

    return Vec<T>{
        data: new_data
        cap: cap
        len: 0
    }
}

pub fn (ar &Vec<T>) iter() Iter<T> {
    return Iter<T>{
        v: unsafe { ar }
    }
}

pub fn (mut iter Iter<T>) next() ?&T {
    if iter.pos >= iter.v.len {
        return none
    }
    defer {
        iter.pos++
    }
    return unsafe { &iter.v.data[iter.pos] }
}

pub fn (mut ar Vec<T>) push(elm T) {
    ar.len += 1
    unsafe {
        ar.data[ar.len - 1] = elm
    }
}

fn test_vec_iter() ? {
    mut arr := with_cap<int>(5)
    for i in 0..5 {
        arr.push(i)
    }
    for g in arr.iter() {
        dump(*g)
    }

    mut iter := arr.iter()
    assert *(iter.next()?) == 0
    assert *(iter.next()?) == 1 // iter.next()? => `&3` ... (why not `&1`?)
    assert *(iter.next()?) == 2
    assert *(iter.next()?) == 3
    assert *(iter.next()?) == 4
    if _ := iter.next() {
        assert false
    }
}

What did you expect to see? pass test

What did you see instead?

---- Testing... ---------------------------------
 FAIL   824.189 ms unexpected_value_vec_test.v
[unexpected_value_vec_test.v:54] *g: 0
[unexpected_value_vec_test.v:54] *g: 1
[unexpected_value_vec_test.v:54] *g: 2
[unexpected_value_vec_test.v:54] *g: 3
[unexpected_value_vec_test.v:54] *g: 4
unexpected_value_vec_test.v:83: ✗ fn test_vec_iter
   > assert iter.next()? == 1
     Left value: &3
    Right value: 1
ken0x0a commented 2 years ago

The whole test & original code is here https://github.com/vpkgs/std/blob/main/vec/vec_test.v https://github.com/vpkgs/std/blob/main/vec/vec.v

I was trying to implement an array, that I can inspect value in lldb easily (without casting type).

yuyi98 commented 2 years ago

This is an error due to the assert mechanism, assert calls the left and right expression repeatedly. The following is ok:

fn main() {
    mut arr := with_cap<int>(5)
    for i in 0 .. 5 {
        arr.push(i)
    }
    for g in arr.iter() {
        dump(*g)
    }

    mut iter := arr.iter()
    r1 := *(iter.next()?)
    assert r1 == 0
    r2 := *(iter.next()?)
    assert r2 == 1
    r3 := *(iter.next()?)
    assert r3 == 2
    r4 := *(iter.next()?)
    assert r4 == 3
    r5 := *(iter.next()?)
    assert r5 == 4
    if _ := iter.next() {
        assert false
    }
}
ken0x0a commented 2 years ago

I understand that the generated C code has multiple next call for *(...).

for *(iter.next()?)

    _option_int_ptr _t3 = main__Iter_T_int_next_T_int(&iter);
    if (_t3.state != 0) {
        main__TestRunner_name_table[test_runner._typ]._method_fn_error(test_runner._object, 58, tos3("unexpected_value_vec_test.v"), tos3("main"), tos3("test_vec_iter"), IError_name_table[_t3.err._typ]._method_msg(_t3.err._object) );
        longjmp(g_jump_buffer, 1);
    }
    _option_int_ptr _t5 = main__Iter_T_int_next_T_int(&iter);
    if (_t5.state != 0) {
        main__TestRunner_name_table[test_runner._typ]._method_fn_error(test_runner._object, 58, tos3("unexpected_value_vec_test.v"), tos3("main"), tos3("test_vec_iter"), IError_name_table[_t5.err._typ]._method_msg(_t5.err._object) );
        longjmp(g_jump_buffer, 1);
    }
    _option_int_ptr _t7 = main__Iter_T_int_next_T_int(&iter);
    if (_t7.state != 0) {
        main__TestRunner_name_table[test_runner._typ]._method_fn_error(test_runner._object, 58, tos3("unexpected_value_vec_test.v"), tos3("main"), tos3("test_vec_iter"), IError_name_table[_t7.err._typ]._method_msg(_t7.err._object) );
        longjmp(g_jump_buffer, 1);
    }

for iter.next()?

    _option_int_ptr _t9 = main__Iter_T_int_next_T_int(&iter);
    if (_t9.state != 0) {
        main__TestRunner_name_table[test_runner._typ]._method_fn_error(test_runner._object, 59, tos3("unexpected_value_vec_test.v"), tos3("main"), tos3("test_vec_iter"), IError_name_table[_t9.err._typ]._method_msg(_t9.err._object) );
        longjmp(g_jump_buffer, 1);
    }

But I don't know why assert act like this.

I'm closing this, as this behavior is intentional(?).

Please reopen, if it's not intentional.