DanielGavin / ols

Language server for Odin
MIT License
373 stars 55 forks source link

Unhandled specialization `&Pointer_Type` #402

Open DragosPopse opened 3 weeks ago

DragosPopse commented 3 weeks ago

The language server crashes on some generics it seems. Could a temporary fix be to make things that are not handled just ignored rather than a full panic crash?

Error message:

D:/a/ols/ols/src/server/generics.odin(287:3) panic: log.panicf
[Error - 1:04:40 PM] Unhandled specialization &Pointer_Type{node = Expr{expr_base = Node{pos = Pos{file = "C:\\dev\\cdc\\cdc\\mlw\\adt\\sparse_set\\sparse_set.odin", offset = 1017, line = 45, column = 21}, end = Pos{file = "C:\\dev\\cdc\\cdc\\mlw\\adt\\sparse_set\\sparse_set.odin", offset = 1036, line = 45, column = 40}, state_flags = Node_State_Flags{}, derived = 0x1F04609C970}, derived_expr = 0x1F04609C970}, tag = <nil>, pointer = Pos{file = "\a\xff\xb4H\xf0\x01\x00\x00\x17\x00\x00\x00\x00\x00\x00\x00h\u05b9H\xf0\x01\x00\x00\x10\xf4\xb9H\xf0\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10", offset = 1017, line = 45, column = 21}, elem = 0x1F04609CA20}

Code that produces this error (self contained, so it might just work to add it in a project for testing

package mlw_sparse_set

import "base:runtime"

Handle :: bit_field u64 {
    index     : int | 48,
    generation: int | 16,
}

Sparse_Set :: struct($I: typeid, $T: typeid) {
    sparse     : []int,
    dense      : []T,
    generations: []int,
    free_queue : []int,
    queue_top  : int,
    size       : int,
    count      : int,
    allocator  : runtime.Allocator,
}

init :: proc(set: $S/^Sparse_Set($I, $T), #any_int capacity: int, allocator := context.allocator) {
    context.allocator = allocator
    set.allocator = allocator
    cap := capacity + 1
    set.size = cap
    set.sparse = make([]int, cap)
    set.dense = make([]T, cap)
    set.generations = make([]int, cap)
    set.free_queue = make([]int, cap)

    for i := set.size - 1; i >= 1; i -= 1 {
        set.free_queue[set.queue_top] = i
        set.queue_top += 1
    }
}

destroy :: proc(set: $S/^Sparse_Set($I, $T)) {
    context.allocator = set.allocator
}

slice :: proc(set: $S/Sparse_Set($I, $T)) -> (values: []T) {
    return set.dense[:set.count]
}

add :: proc(set: $S/^Sparse_Set($I, $T), val: T) -> (handle: I) {
    assert(set != nil)
    assert(set.free_queue != nil)

    if set.queue_top > 0 {
        set.queue_top -= 1
        handle.index = set.free_queue[set.queue_top]
        handle.generation = set.generations[handle.index]
        val_pos := set.count
        set.dense[val_pos] = val
        set.sparse[handle.index] = val_pos

        set.count += 1
    }

    return handle
}

remove :: proc(set: $S/^Sparse_Set($I, $T), handle: I) {
    assert(set != nil)
    assert(set.free_queue != nil)
    assert(handle.index > 0 && handle.index < set.size)
    assert(handle.generation == set.generations[handle.index], "Generation mismatch")
    assert(set.queue_top < set.size, "No more items to remove")
    set.free_queue[set.queue_top] = handle.index
    set.generations[handle.index] += 1
    set.queue_top += 1
    last_packed := set.count - 1
    set.dense[set.sparse[handle.index]] = set.dense[last_packed]
    set.count -= 1
    assert(set.queue_top <= set.size - 1)
}

get :: proc(set: $S/^Sparse_Set($I, $T), handle: I) -> (ptr: ^T) {
    if handle.generation != set.generations[handle.index] {
        return nil
    }
    if handle.index <= 0 || handle.index >= set.size {
        return nil
    }
    return &set.dense[set.sparse[handle.index]]
}

// TESTING

import "core:testing"
import "core:fmt"

print_details :: proc(set: ^Sparse_Set($I, $T)) {
    fmt.printf("Sparse: %v\n", set.sparse)
    fmt.printf("Dense: %v\n", set.dense)
    fmt.printf("Queue: %v top: %v\n", set.free_queue, set.queue_top)
    fmt.printf("Values: %v\n", slice(set^))
}

add_print :: proc(set: ^Sparse_Set($I, $T), val: T) -> I {
    handle := add(set, val)
    fmt.printf("Add value %v at %v\n", val, handle)
    print_details(set)
    fmt.println()
    return handle
}

remove_print :: proc(set: ^Sparse_Set($I, $T), i: I) {
    fmt.printf("Removing %v with value %v\n", i, get(set, i)^)
    remove(set, i)
    print_details(set)
}

@test
sparse_set_test :: proc(T: ^testing.T) {
    set: Sparse_Set(Handle, int)
    init(&set, 6)
    val1 := add_print(&set, 1)
    val2 := add_print(&set, 2)
    val3 := add_print(&set, 3)
    remove_print(&set, val2)
    val4 := add_print(&set, 100)
}

Not having the file open will not trigger the crash.

DanielGavin commented 3 weeks ago

Currently working on the rename branch, so it has been fixed there. Closing issue when merged.