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.77k stars 2.16k forks source link

Using a sum type or interface for `os.File.write_struct` or `os.File.read_struct` (and the `*_at` variants) caues a builder error or a (silent) error. #19117

Open MinekPo1 opened 1 year ago

MinekPo1 commented 1 year ago

Describe the bug

While the documentation (and name) of these methods clearly state that a struct should be used, no error will be reported if a interface or sum type are used. This is likely to cause either builder errors or silent errors.

Expected Behavior

An error, maybe some sort of handling sum types (see the possible solution part), but there should definitely be an error for interfaces.

Current Behavior

/tmp/v_1000/struct_read_write.10311223961213307523.tmp.c:17996: error: cannot convert 'struct main__MySumType' to 'struct main__MySumType *'
builder error: 
==================
C error. This should never happen.

This is a compiler bug, please report it using `v bug file.v`.

https://github.com/vlang/v/issues/new/choose

You can also use #help on Discord: https://discord.gg/vlang

A similar error is reported, if that line is commented out, for the interface.

If the first section is commented out, the code compiles and no error is reported (!) until we try to print out the interface:

MyStruct{
    val:     i32(0)
}
unknown sum type value
/tmp/v_1000/struct_read_write.7769821454601624171.tmp.c:3076: at indent_main__MyInterface_str: RUNTIME ERROR: invalid memory access
/tmp/v_1000/struct_read_write.7769821454601624171.tmp.c:3027: by main__MyInterface_str
/tmp/v_1000/struct_read_write.7769821454601624171.tmp.c:17974: by main__main
/tmp/v_1000/struct_read_write.7769821454601624171.tmp.c:18039: by main

Reproduction Steps

module main

import os

struct MyStruct {
    val   i32
}

struct SomeOtherStruct {
    val   i32
}

type MySumType = MyStruct | SomeOtherStruct

interface MyInterface {
    val   i32
}

fn main() {
    mut file1 := os.open_file("test.bin", "w") !

    // /*
    p1 := MyStruct{12}
    s1 := MySumType(p1)
    i1 := MyInterface(p1)

    file1.write_struct(p1) !
    file1.write_struct(s1) !
    file1.write_struct(i1) !
    file1.close()

    // */
    //prepare file
    //so we dont have an eof panic

    for _ in 0 .. 64 {
        file1.write([ u8(0) ]) !
    }

    file1.close()

    mut file2 := os.open_file("test.bin", "r") !
    defer { file2.close() }
    mut p2 := MyStruct{}
    mut s2 := MySumType(p2)
    mut i2 := MyInterface(p2)

    file2.read_struct[MyStruct   ](mut p2) !
    file2.read_struct[MySumType  ](mut s2) !
    file2.read_struct[MyInterface](mut i2) !
    println(p2)
    println(s2)
    println(i2)

}

You may comment out line 29 or remove the line comment on line 23 to see further errors.

Possible Solution

As mentioned previously, I believe an error should be raised, at compile time, if a non pure struct type is used. However with type sums, using some sort of magic number matching (like in ImHex's pattern language), but I do not believe changes needed to support this are needed nor outweigh the effort needed to implement them.

I think this should be handled with a bit of syntax, perhaps like such:

fn example[T struct]() {
    // ...
}

This could be also migrated into the type system, to allow binding a generic type parameters to a type/interface.

Additional Information/Context

No response

V version

V 0.4.0 3211a65.5a0d9e7

Environment details (OS name and version, etc.)

OS: linux, Ubuntu 23.04
Processor: 8 cpus, 64bit, little endian, AMD Ryzen 5 3500U with Radeon Vega Mobile Gfx

getwd: /home/lily/Documents/vtest
vexe: /home/lily/Documents/builds/v/v
vexe mtime: 2023-08-11 16:55:59

vroot: OK, value: /home/lily/Documents/builds/v
VMODULES: OK, value: /home/lily/.vmodules
VTMP: OK, value: /tmp/v_1000

Git version: git version 2.39.2
Git vroot status: weekly.2023.32-24-g5a0d9e7d-dirty (2 commit(s) behind V master)
.git/config present: true

CC version: cc (Ubuntu 12.3.0-1ubuntu1~23.04) 12.3.0
thirdparty/tcc status: thirdparty-linux-amd64 12f392c3
MinekPo1 commented 1 year ago

I think the builder error is caused by casting a type sum/interface to a voidptr. I will investigate this and treat it as what it is: a separate issue.

Doesn't seem like it is the case.