Skip to content

Latest commit

 

History

History
557 lines (463 loc) · 15 KB

File metadata and controls

557 lines (463 loc) · 15 KB

TODO

Inlining

  • If the function is inlined, and the passed parameter is not used, then if a function with side effects is passed, after inlining the side effects will not be produced, since the entire function call will be deleted.
  • If the argument is passed by pointer and the passed value is not a pointer, then the case of accessing a structure field through this parameter after inline must be correctly handled.
  • Do not inline recursive functions
  • After inlining, automatic address take insertion takes the address from the field
    struct Foo {
        name string
    }
    
    fn (f &Foo) get_name() -> string {
        return f.name
    }
    
    fn main() {
        f := Foo{}
        println(f.get_name())
    }
    

Compile time

  • If a variable is defined in a block for windows and the block ends with an output and a variable with the same name is defined outside the block, then a C code compilation error occurs

Cgen

  • Sort type aliases as for structures
  • Determine when constants with Foo{} can be const initialized
  • If the C structure accepts a fixed array, then when initializing it you need to add a call to the data field

Parser

  • struct Capture { ch chan &net.TcpConn{} } parser error looks bad
  • name_or_type.ident() or { ast.new_identifier('_') }.val should it be parsed without parentheses?

Errors output

  • Not the best error highlighting when returning the wrong type from a function in the form of structure initialization.
  • Add nice errors if a++ is used as an expression
  • Think about how to show type errors when they are aliases. Now we show the internal type of the alias, but this is not always what is needed.
  • Give better error for fn split_address(addr string) -> string, i32 {
  • In errors, count the length for UTF-8
  • When offering to fix code, we need to check that the file is not in the standard library
  • When proposing to define a method for an operator, take into account that the structure can be generic

Smartcasts

  • Two !is casts in a row cause a C gen error, since after the first cast the type becomes a pointer to a specific structure
  • Support several smartcast on single variable

Stdlib

  • Some values in errno for Windows are defined under #ifndef, if they are defined, the generated code will give a compilation error.
  • Use strerror_r whenever possible.
  • Since slice does not return null-terminated strings, we need to consider all uses of C functions, as they may not work correctly.
  • For each string method, describe whether it works with ASCII or UTF-8
  • When compressing memory is allocated twice, consider specifying to use GC directly
  • Better support of i128/u128

Inspections

  • Add a check that each method of a generic structure defines generic parameters
  • Check for the presence of methods in constraints for primitives
  • No error/handling of assigning a void function to a variable
  • Check for mutating method calls on rvalue
  • E0150 suggests inserting a default value for the array in the form of initializing the array structure, rather than []i32{}
  • Clearer error when passing an immutable pointer to an unsafe mutable reference parameter
  • Checks that contains has the correct signature
  • Check shift count >= width of type
  • Prohibit __ in names
  • A check that will check a segment in a slice for a fixed array
  • Check for duplicate fields in the initializer
  • There is no check when a map with one value type is cast to an alias with another
  • Prohibit casting one reference to another outside of unsafe
  • Check the case when Union has one variant of an empty structure and we smartcast to it
  • Prohibit safe casting to the interface if a non-union is being cast
  • Better error message for mismatched function types via aliases
  • Check cast to function type with _ parameter in function with _ parameter
  • Forbid pointer arithmetic on references
  • Check passing immutable pointer to mutable one
  • Check for is when left side is Option

Linter inspections

Inspections that would be nice to have, but in a separate linter. They are not critical and can be implemented much later.

  • For expressions a !is Foo && a.age suggest a correction that will change to a is Foo && a.age
  • Add a check that string concatenation is performed in the loop, suggest using Builder
  • For _, _ := foo(), should we suggest replacing it with one _?
  • A check that will say that code like arr.filter(cond).len > 0 can be replaced with any(...).
  • ![Error] can be replaced with !, ![unit, MyError] with ![MyError], ![i32, Error] with !i32
  • If a function accepts a non-mutable pointer and the expression &mut a is passed, then give a warning that &a is sufficient

Implementation

  • Optimize automatically generated comparisons based on the complexity of the field comparison, making comparisons of primitive types first.
  • Revise precedence for as
  • If panic_strategy == abort generate defer not as a runtime function call, but as a copy of the code before each function exit point.
  • Handle \r\n in source code
  • Correctly parse arr[0](), now this is considered a generic function call
  • When casting a rvalue to an interface, a cgen error occurs since you cannot take the address from a rvalue
  • <-ch.unwrap() has not intuitive precedence
  • ast.PointerType.mutable( resolves although it should not, since mutable is a field
  • goto from a nested block at the end of a function does not work due to an error
  • p.data += size does not work if data is a pointer
  • Do not generate err variable inside or if it is not used
  • If we use a constant under the condition $if windows and the constant is defined in a file only for windows, then an error is thrown
  • When casting a pointer stored in a constant, do not send it to the hip
  • The following code panics fn canonical_addr(url &url.URL) -> string due to the fact that the url parameter overlaps the url module
  • When casting an array to a fixed array with a constant size, correctly infer the type
  • Check map traversal with pointers as values
  • Check the use of the + operator for arrays
  • Support .goo in if-else statements when the enum type can be inferred from other branches
  • If in a map literal you use a value with an alias type for a string, when the function accepts a map with strings, then there is no error and cgen crashes
  • Forbid array element pointer escaping (&mut arr[0])
  • Support if rec_stack.get(node as *mut Node as usize) or { false } { ... }
  • Can't return ![i32, SomeError] from function with !i32 return type
  • If some variable smartcasted to non-none give better error message when use it if-unwrapping

Investigations

  • Think about how to solve the problem of nested or blocks
  • Is it possible to assign an array of mutable pointers to an array of non-mutable pointers?
  • Check "" in [1, 2, 3]
  • Think about what to do in this case, the backtrace field obscures the module name
    struct Alloc {
        ptr   &mut void
        size  usize
        freed bool
    
        backtrace []backtrace.Frame
        alloc_backtrace []backtrace.Frame
    }
    
  • What position should we pass in a function call with #[track_caller] as the default field value?
  • Check deferring when a function in return calls another function
  • Generate only used enum values?
  • Inline Enum values?
  • Check or blocks inside nested calls and lambdas
  • Deal with more than two variables in for-in
  • For zero-sized types that implement an interface, you don’t have to generate separate fields in the structure that represents the interface in C code. Also, when converting a pointer to such a type into an interface, you can avoid allocating memory, since dereferencing such a pointer does not make sense. For methods of these types, it is possible not to generate an argument, since it is always empty one way or another.
  • Check the alias for the map in the third level module
  • What if the array is created in a generic function and that function is then called with an interface type. If the array is not zero lengths then it must have init in its initializer. Apparently, we need an analysis of monomorphic functions to find such cases.
  • What to do if the interface does not have any implementation? This is currently causing a cgen error.
  • mem.assume_safe() for C struct without typedef gives C error
  • Each test file should define a new scope and using names from other files is not allowed.
  • In case when we check if X is Y interface and return it from function with return type X, for now we generate the wrong C code.
  • Check defers in resolve_ip_address
  • Escape % in print functions
  • Check casting strings.Builder to []u8 when it escapes
  • Check BIN_PATH = './bin/v-analyzer' + $if windows { '.exe' } $else { '' }
  • Cannot use alias for integer as map key type
  • Check all_before_last.join(', ') + ' or ' + mapped[mapped.len - 1]

Result & Option types

  • Forbid Result in all places except return type
  • If the function returns Result[], then there is no clear error if the type does not implement this interface
  • If the value type in Result is less than eight bytes, then generate is_error next to the value field (when we will have a result via a union type)
  • What to do if one function returns ![(), Error] and another ![unit, Error]? This is currently causing a cgen error.
  • Invalid cgen when propagate ! from function with [i32, MyError]

Features

  • Support |x| { 10 }
  • Support {} as expressions, in case of type mismatch as with unsafe, point to the last expression
  • Support embedded at level greater than 1

Type inference

  • Support type inference for a lambda if context type with vararg
  • if start == -1 { 0 } else { start } if the type is int_literal try to infer a specific type from other branches
  • If a function returns an array, then infer types from it for literals inside the array?
  • Deal with type inference for if/match when the first branch uses a generic parameter defined as a constant
  • If in the one-line solution aoc 1 you remove the types from reduce, then there will be an endless loop of error output
  • Check that as? does not perform calculations two times
  • labels_per_line.get_or_insert(label_pos.line as i32, []) cannot infer array type
  • Add checks for castes to aliases
  • Array of strings passed to array of string alias gives cgen error
  • What to do if ?. is used with a method or field that itself returns/has an Option type?

Interpreter

  • During the initialization of a structure in the interpreter, if a function call initializes one of the fields, then the interpreter crashes.
  • Correctly insert field values by index if they are mixed during initialization in the interpreter

Generics

  • Add checks for generic constraints when using the operator

Tests

Formatter

  • Alignment of long function calls
  • Move long expressions to a new line

Don't move all match expressions to the same line, preserve any newlines

fn TyPrimitive.is_integer(name string) bool {
	return match name {
		'u8', 'u16', 'u32', 'u64', 'u128', 'usize',
		'i8', 'i16', 'i32', 'i64', 'i128', 'isize' -> true
		else -> false
	}
}

Not working code

Stack overflow

interface Namer {
    fn values(self) -> []string
}

struct Foo {
    values []string = ["foo", "bar"]
    inside Namer = Foo{
        values: ["foo", "bar"]
    }
}

fn (foo Foo) values() -> []string {
    return ["foo"]
}

fn main() {
    Foo{} as Namer
}

Cgen error:

pub struct Set[T: MapKey] {
    m &mut Map[T, unit] = new_map()
}

Support:

fn get_variadic_cb() -> fn (_ i32, _ ...i32) {
    return |a, b...| println(a, b.str())
}

fn main() {
    cb := get_variadic_cb()
    cb(1, 2, 3, 4)
}

Cgen error:

struct Foo {
    name     string
    children [8]?&Foo
}

fn main() {
    mut f := Foo{ name: "foo" }
    f.children[0] = &Foo{ name: "bar" }
    f.children[1] = &Foo{ name: "baz" }

    for i in 0 .. 8 {
        child := f.children[i] or { break }
        println(child.name)
    }

    first_child := f.children[0]?.children
    first_child_uwnrapped := first_child or { return }
    println(first_child_uwnrapped[0]?.name.str())
}

Support:

type Tuple[const Size as usize] = [Size]i32

fn Tuple.new[const Size as usize](vals ...i32) -> Tuple[Size] {
    mut arr := [Size]i32{}
    if vals.len != Size {
        panic("Tuple must have exactly Size elements")
    }
    for i in 0 .. Size {
        arr[i] = vals[i]
    }
    return arr as Tuple[Size]
}

fn main () {
    t1 := Tuple.new[3](1, 2, 3)
    t2 := Tuple.new[3](4, 5, 6)
    println(t1)
}
println({ (1, 2): 1 }.str())
module main

type Thing = i32

struct Things {
    items []&Thing
}

fn (t &mut Things) sort() {
    t.items.sort(fn (a &&Thing, b &&Thing) -> i32 {
        return 0
    })
}

fn main() {
    mut t := Things{}
    t.sort()
}
struct Foo {
	foo i32
}

fn main() {
	mut f := Foo{foo: 1}
	foo(&mut f)
}

fn foo(f &mut Foo) {
	f2 := &f
	f.foo = 100
	println(f.foo)
	println(f2.foo)
}
enum TestEnum {
    a
    b
}

const (
    x = {
        TestEnum.a: 'Alpha'
        .b: 'Beta'
    }
)

fn main() {
    println(x[.a])
    println(x[.b])
}
fn main() {
    a := [[1]]
    println([1] in a)
}
fn is_num(v Var) -> bool {
    match v {
        i32 -> {
            return true
        }
        else -> return false
    }
}
fn main() {
    mut indices := []i32{len: 3}

    for i, mut v in indices {
        *v = i
        a := v
        println('${i} ${v} ${a}')
    }
}
struct Dog {}

struct Cat {}

fn (d Dog) speak() {
    println('woof')
}

fn (c Cat) speak() {
    println('meow')
}

union Pet = Dog | Cat

fn (p &mut Pet) speak() {
    println('Speak')
    match p {
        Dog -> {
            p.speak()
        }
        Cat -> {
            p.speak()
        }
    }
}

fn main() {
    mut pet := Cat{} as Pet
    pet.speak()
}
module main

type Num = i32

union Var = Num | string

fn main() {
    five := 5
    println(is_num(five))
    hello := 'Hello'
    println(is_num(hello))
}

fn is_num(v Var) -> bool {
    match v {
        Num -> {
            return true
        }
        else -> {
            return false
        }
    }

    return false
}
fn get_color_mode_by_name(name string) -> ?ColorMode {
    return match name {
        'auto' -> .auto
        'always' -> .always
        'never' -> .never
        else -> none
    }
}
 cases := [
    ("abc", "abc", true, none as ?glob.BadPattern),
    ("*", "abc", true, none),
    ("*c", "abc", true, none),
    ("a*", "a", true, none),
    ("a*", "abc", true, none),
]

Features

  • err variable in else block of if unwrapping
  • Track stack overflow
  • #[pure] attribute
  • obj attribute for linking an object file
  • define attribute for C-interoperability
  • safe cast from int to enum
  • In the logging library, take into account that logs should be parsed without problems and add the ability in the library to load logs into memory
  • Support generic lambdas and function literals
  • Support ... in array and map literals?
  • init function for module