perf: separate checker union-find links from node metadata
This commit is contained in:
@@ -69,6 +69,8 @@ name resolution (`@source/sema`) runs after parsing. it predeclares package name
|
|||||||
|
|
||||||
type checking (`@source/sema/check`) runs after name resolution. `check.check` borrows the AST and binding table and returns owned per-node types and interned array descriptors; query with `check.type_of` and `check.array_type`, and release with `check.deinit`. declarations infer their initializer types, including forward references and function aliases; function types identify the declaration supplying the callable signature. annotations support builtin types and fixed arrays; type names are not ordinary values. `void` is valid as a function result, not as a parameter or stored value.
|
type checking (`@source/sema/check`) runs after name resolution. `check.check` borrows the AST and binding table and returns owned per-node types and interned array descriptors; query with `check.type_of` and `check.array_type`, and release with `check.deinit`. declarations infer their initializer types, including forward references and function aliases; function types identify the declaration supplying the callable signature. annotations support builtin types and fixed arrays; type names are not ordinary values. `void` is valid as a function result, not as a parameter or stored value.
|
||||||
|
|
||||||
|
the checker keeps union-find parent links and group sizes in a compact array separate from per-node inference metadata. root walks and path compression access only that link storage; both temporary arrays are released before `check.check` returns.
|
||||||
|
|
||||||
numeric typing follows contextual rules within Honey's current `int` and `float` families. integer literals can adopt either family; float literals remain float. numeric demands propagate through arithmetic and inferred bindings before undemanded integers default to `int`. conflicting demands are errors; fixed `int` values do not implicitly convert to `float`. `+`, `-`, `*` and unary `-` require compatible numeric operands; `/` requires and supplies float context. `3 / 2`, `3.0 / 2`, and `ratio float :: 3 / 2` are valid; division involving fixed `int` values requires explicit conversion.
|
numeric typing follows contextual rules within Honey's current `int` and `float` families. integer literals can adopt either family; float literals remain float. numeric demands propagate through arithmetic and inferred bindings before undemanded integers default to `int`. conflicting demands are errors; fixed `int` values do not implicitly convert to `float`. `+`, `-`, `*` and unary `-` require compatible numeric operands; `/` requires and supplies float context. `3 / 2`, `3.0 / 2`, and `ratio float :: 3 / 2` are valid; division involving fixed `int` values requires explicit conversion.
|
||||||
|
|
||||||
type errors carry source spans and diagnostic identities; invalid operands propagate their existing identity without duplicate errors, while independent expressions, arguments and nested bodies are still checked. inference cycles without a type anchor are diagnosed. function signatures are checked independently of their bodies. bare `return` and same-line `return expression` are supported inside function bodies and must match the declared result type. nonvoid return-path checking is structural: every path must return or terminate in a diagnostic trap, and both conditional successors are considered without constant folding. a missing `else` or a loop permits fallthrough, even for a literal `true` condition; a later return can close that path. statements after a return and untaken branches or loops are still type-checked but are not executed.
|
type errors carry source spans and diagnostic identities; invalid operands propagate their existing identity without duplicate errors, while independent expressions, arguments and nested bodies are still checked. inference cycles without a type anchor are diagnosed. function signatures are checked independently of their bodies. bare `return` and same-line `return expression` are supported inside function bodies and must match the declared result type. nonvoid return-path checking is structural: every path must return or terminate in a diagnostic trap, and both conditional successors are considered without constant folding. a missing `else` or a loop permits fallthrough, even for a literal `true` condition; a later return can close that path. statements after a return and untaken branches or loops are still type-checked but are not executed.
|
||||||
|
|||||||
+19
-10
@@ -70,10 +70,14 @@ Role :: enum {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@hide:file
|
@hide:file
|
||||||
Cell :: struct {
|
GroupLink :: struct {
|
||||||
role Role = .none
|
|
||||||
parent usize = 0
|
parent usize = 0
|
||||||
size usize = 1
|
size usize = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
@hide:file
|
||||||
|
Cell :: struct {
|
||||||
|
role Role = .none
|
||||||
type Type = Type{}
|
type Type = Type{}
|
||||||
numeric bool = false
|
numeric bool = false
|
||||||
anchored bool = false
|
anchored bool = false
|
||||||
@@ -106,6 +110,7 @@ State :: struct {
|
|||||||
diagnostics @mut diagnostics.Store
|
diagnostics @mut diagnostics.Store
|
||||||
types []mut Type
|
types []mut Type
|
||||||
cells []mut Cell
|
cells []mut Cell
|
||||||
|
groups []mut GroupLink
|
||||||
edges arraylist.ArrayList(Edge)
|
edges arraylist.ArrayList(Edge)
|
||||||
arrays arraylist.ArrayList(ArrayType)
|
arrays arraylist.ArrayList(ArrayType)
|
||||||
collecting_assignment bool = false
|
collecting_assignment bool = false
|
||||||
@@ -127,7 +132,10 @@ check proc(
|
|||||||
cells :: try mem.alloc(Cell, allocator, count)
|
cells :: try mem.alloc(Cell, allocator, count)
|
||||||
defer mem.free(allocator, cells)
|
defer mem.free(allocator, cells)
|
||||||
mem.set(cells, Cell{})
|
mem.set(cells, Cell{})
|
||||||
for (0..count) |i| cells[i].parent = i
|
groups :: try mem.alloc(GroupLink, allocator, count)
|
||||||
|
defer mem.free(allocator, groups)
|
||||||
|
mem.set(groups, GroupLink{})
|
||||||
|
for (0..count) |i| groups[i].parent = i
|
||||||
queue :: try mem.alloc(ast.NodeId, allocator, count)
|
queue :: try mem.alloc(ast.NodeId, allocator, count)
|
||||||
defer mem.free(allocator, queue)
|
defer mem.free(allocator, queue)
|
||||||
state := State{
|
state := State{
|
||||||
@@ -136,6 +144,7 @@ check proc(
|
|||||||
diagnostics = diagnostic_store,
|
diagnostics = diagnostic_store,
|
||||||
types = types,
|
types = types,
|
||||||
cells = cells,
|
cells = cells,
|
||||||
|
groups = groups,
|
||||||
edges = arraylist.init(allocator),
|
edges = arraylist.init(allocator),
|
||||||
arrays = arraylist.init(allocator),
|
arrays = arraylist.init(allocator),
|
||||||
}
|
}
|
||||||
@@ -432,11 +441,11 @@ invalid_type proc(diagnostic diagnostics.DiagnosticId) Type {
|
|||||||
@hide:file
|
@hide:file
|
||||||
root proc(state @mut State, index usize) usize {
|
root proc(state @mut State, index usize) usize {
|
||||||
current := index
|
current := index
|
||||||
while (state.cells[current].parent != current) current = state.cells[current].parent
|
while (state.groups[current].parent != current) current = state.groups[current].parent
|
||||||
next := index
|
next := index
|
||||||
while (state.cells[next].parent != next) {
|
while (state.groups[next].parent != next) {
|
||||||
parent :: state.cells[next].parent
|
parent :: state.groups[next].parent
|
||||||
state.cells[next].parent = current
|
state.groups[next].parent = current
|
||||||
next = parent
|
next = parent
|
||||||
}
|
}
|
||||||
return current
|
return current
|
||||||
@@ -458,13 +467,13 @@ join proc(state @mut State, left, right ast.NodeId) void {
|
|||||||
a := root(state, usize(left))
|
a := root(state, usize(left))
|
||||||
b := root(state, usize(right))
|
b := root(state, usize(right))
|
||||||
if (a == b) return
|
if (a == b) return
|
||||||
if (state.cells[a].size < state.cells[b].size) {
|
if (state.groups[a].size < state.groups[b].size) {
|
||||||
saved :: a
|
saved :: a
|
||||||
a = b
|
a = b
|
||||||
b = saved
|
b = saved
|
||||||
}
|
}
|
||||||
state.cells[b].parent = a
|
state.groups[b].parent = a
|
||||||
state.cells[a].size += state.cells[b].size
|
state.groups[a].size += state.groups[b].size
|
||||||
if (state.cells[a].type.kind == .none or state.cells[b].type.kind == .invalid) {
|
if (state.cells[a].type.kind == .none or state.cells[b].type.kind == .invalid) {
|
||||||
state.cells[a].type = state.cells[b].type
|
state.cells[a].type = state.cells[b].type
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user