Source: src/typechecker/expr.lx
Typechecking of Luma expressions.
Dispatches every expression node form to a per-kind typechecker, resolving each to a Luma type, and drives the static memory analyzer (use-after-free and leak tracking) for pointer-producing expressions.
pub #returns_ownership
typecheck_expression -> fn(
expr: *AST::AstNode,
scope: *CORE::Scope,
expected: *AST::AstNode
) *AST::AstNode
#returns_ownership
typecheck_expression_inner -> fn(
expr: *AST::AstNode,
scope: *CORE::Scope,
expected: *AST::AstNode
) *AST::AstNode
#returns_ownership
tc_literal -> fn(
expr: *AST::AstNode,
scope: *CORE::Scope
) *AST::AstNode
#returns_ownership
tc_identifier -> fn(
expr: *AST::AstNode,
scope: *CORE::Scope
) *AST::AstNode
#returns_ownership
tc_binary -> fn(
expr: *AST::AstNode,
scope: *CORE::Scope
) *AST::AstNode
#returns_ownership
tc_unary -> fn(
expr: *AST::AstNode,
scope: *CORE::Scope
) *AST::AstNode
#returns_ownership
tc_call -> fn(
expr: *AST::AstNode,
scope: *CORE::Scope
) *AST::AstNode
#returns_ownership
tc_assign -> fn(
expr: *AST::AstNode,
scope: *CORE::Scope
) *AST::AstNode
#returns_ownership
tc_ternary -> fn(
expr: *AST::AstNode,
scope: *CORE::Scope
) *AST::AstNode
#returns_ownership
tc_member -> fn(
expr: *AST::AstNode,
scope: *CORE::Scope
) *AST::AstNode
#returns_ownership
tc_index -> fn(
expr: *AST::AstNode,
scope: *CORE::Scope
) *AST::AstNode
#returns_ownership
tc_array -> fn(
expr: *AST::AstNode,
scope: *CORE::Scope,
expected: *AST::AstNode
) *AST::AstNode
#returns_ownership
tc_cast -> fn(
expr: *AST::AstNode,
scope: *CORE::Scope
) *AST::AstNode
#returns_ownership
tc_deref -> fn(
expr: *AST::AstNode,
scope: *CORE::Scope
) *AST::AstNode
#returns_ownership
tc_addr -> fn(
expr: *AST::AstNode,
scope: *CORE::Scope
) *AST::AstNode
#returns_ownership
tc_struct_expr -> fn(
expr: *AST::AstNode,
scope: *CORE::Scope,
expected: *AST::AstNode
) *AST::AstNode
check_uaf -> fn(
node: *AST::AstNode,
scope: *CORE::Scope
) void
track_free -> fn(
ptr_expr: *AST::AstNode,
scope: *CORE::Scope
) void
call_is_returns_ownership -> fn(
call_expr: *AST::AstNode,
scope: *CORE::Scope
) bool
pub track_pointer_source -> fn(
name: *byte,
value_expr: *AST::AstNode,
scope: *CORE::Scope
) void
Returns a heap-allocated a.b string splicing two identifiers.
pub #returns_ownership
qualify -> fn(
a: *byte,
b: *byte
) *byte
Returns a heap-allocated NUL-terminated copy of s.
#returns_ownership
dup_str -> fn(
s: *byte
) *byte
Unwraps a pointer type to its pointee type; non-pointers pass through.
strip_pointer -> fn(
t: *AST::AstNode
) *AST::AstNode
Reports a use-after-free error if node is an identifier freed earlier
in the enclosing function.
check_uaf -> fn(
node: *AST::AstNode,
scope: *CORE::Scope
) void
Records an explicit free of an identifier on the enclosing function's static memory analyzer (deferred to the function's deferred-frees list while tracking is skipped).
track_free -> fn(
ptr_expr: *AST::AstNode,
scope: *CORE::Scope
) void
Returns whether the callee symbol of a call is marked #returns_ownership.
call_is_returns_ownership -> fn(
call_expr: *AST::AstNode,
scope: *CORE::Scope
) bool
Returns whether a callee (identifier or module-qualified member) names a
symbol marked #takes_ownership.
call_is_takes_ownership -> fn(
callee: *AST::AstNode,
scope: *CORE::Scope
) bool
Tracks where a pointer binding gets its value — an alloc, a
#returns_ownership call, or an alias of another tracked variable — so
the leak checker can account for it.
pub track_pointer_source -> fn(
name: *byte,
value_expr: *AST::AstNode,
scope: *CORE::Scope
) void
Public entry point: typechecks an expression and stashes the resolved
type on the node (AstNode.resolved_type) so codegen can read a static
type straight off the AST without re-running inference.
pub #returns_ownership
typecheck_expression -> fn(
expr: *AST::AstNode,
scope: *CORE::Scope,
expected: *AST::AstNode
) *AST::AstNode
Dispatches an expression to its per-kind typechecker; grouping, system, alloc/free, sizeof, input, syscall, and memcpy forms are handled here.
#returns_ownership
typecheck_expression_inner -> fn(
expr: *AST::AstNode,
scope: *CORE::Scope,
expected: *AST::AstNode
) *AST::AstNode
Typechecks a literal, mapping its literal kind to the corresponding type.
#returns_ownership
tc_literal -> fn(
expr: *AST::AstNode,
scope: *CORE::Scope
) *AST::AstNode
Looks up an identifier in scope, reports undeclared identifiers, runs the use-after-free check, and returns the symbol's type.
#returns_ownership
tc_identifier -> fn(
expr: *AST::AstNode,
scope: *CORE::Scope
) *AST::AstNode
Typechecks a binary or range expression: comparisons and logic yield bool, bitwise yields i64, arithmetic follows numeric rank, and pointer arithmetic returns the pointer type.
#returns_ownership
tc_binary -> fn(
expr: *AST::AstNode,
scope: *CORE::Scope
) *AST::AstNode
Typechecks a unary expression: logical ! yields bool, otherwise the
operand's type.
#returns_ownership
tc_unary -> fn(
expr: *AST::AstNode,
scope: *CORE::Scope
) *AST::AstNode
Typechecks *ptr, returning the pointee type (error on non-pointers and
use-after-free).
#returns_ownership
tc_deref -> fn(
expr: *AST::AstNode,
scope: *CORE::Scope
) *AST::AstNode
Typechecks &x, returning a pointer to the operand's type and marking
the identifier's address taken for the analyzer.
#returns_ownership
tc_addr -> fn(
expr: *AST::AstNode,
scope: *CORE::Scope
) *AST::AstNode
Typechecks a[i]: the index must be an integer, and the result is the
array's element type or the pointer's pointee type.
#returns_ownership
tc_index -> fn(
expr: *AST::AstNode,
scope: *CORE::Scope
) *AST::AstNode
Typechecks member access: compiletime Enum::Member / Alias::symbol
(including module-alias and generic enum members) and runtime obj.field
access on nominal types.
#returns_ownership
tc_member -> fn(
expr: *AST::AstNode,
scope: *CORE::Scope
) *AST::AstNode
Resolves a callee to its function type; the output()/outputln()
builtins (variadic) are exempt and yield NULL.
#returns_ownership
resolve_callee_type -> fn(
callee: *AST::AstNode,
scope: *CORE::Scope
) *AST::AstNode
Typechecks a call: builtin output, explicit generic instantiations,
argument count/types, #takes_ownership tracking, and error reporting for
non-callable or undeclared callees.
#returns_ownership
tc_call -> fn(
expr: *AST::AstNode,
scope: *CORE::Scope
) *AST::AstNode
Typechecks an assignment: mutability, type match, pointer-source tracking, and escape handling for member targets.
#returns_ownership
tc_assign -> fn(
expr: *AST::AstNode,
scope: *CORE::Scope
) *AST::AstNode
Typechecks c ? a : b, returning the then-branch type (or the else-branch
type if the then-branch didn't resolve).
#returns_ownership
tc_ternary -> fn(
expr: *AST::AstNode,
scope: *CORE::Scope
) *AST::AstNode
Typechecks a cast by resolving the target type and rejecting casts between incompatible types.
#returns_ownership
tc_cast -> fn(
expr: *AST::AstNode,
scope: *CORE::Scope
) *AST::AstNode
Typechecks an array literal: the element type comes from the first element (or the expected type), the rest must match, and empty literals defer to the expected type.
#returns_ownership
tc_array -> fn(
expr: *AST::AstNode,
scope: *CORE::Scope,
expected: *AST::AstNode
) *AST::AstNode
Returns whether a struct (directly or via ...Embedded promotion) accepts
field in a literal; unknown decls stay permissive.
struct_decl_has_field -> fn(
scope: *CORE::Scope,
sname: *byte,
field: *byte
) bool
Reports a Type Error for the first unknown field name in a struct literal.
validate_struct_literal_fields -> fn(
expr: *AST::AstNode,
scope: *CORE::Scope,
sname: *byte
) void
Typechecks a struct literal: validates field names, instantiates generic
structs (Box<i64> { ... }, including through a module alias), resolves
bare vs. aliased names, and returns the struct's type.
#returns_ownership
tc_struct_expr -> fn(
expr: *AST::AstNode,
scope: *CORE::Scope,
expected: *AST::AstNode
) *AST::AstNode