Merge remote-tracking branch 'remote/main' into implement-box

This commit is contained in:
Luke Boswell 2025-12-15 20:01:23 +11:00
commit 79c0cbb04b
No known key found for this signature in database
GPG key ID: 54A7324B1B975757
23 changed files with 675 additions and 63 deletions

View file

@ -996,6 +996,8 @@ fn createTestPlatformHostLib(
target: ResolvedTarget,
optimize: OptimizeMode,
roc_modules: modules.RocModules,
strip: bool,
omit_frame_pointer: ?bool,
) *Step.Compile {
const lib = b.addLibrary(.{
.name = name,
@ -1004,7 +1006,8 @@ fn createTestPlatformHostLib(
.root_source_file = b.path(host_path),
.target = target,
.optimize = optimize,
.strip = optimize != .Debug,
.strip = strip,
.omit_frame_pointer = omit_frame_pointer,
.pic = true, // Enable Position Independent Code for PIE compatibility
}),
});
@ -1026,6 +1029,8 @@ fn buildAndCopyTestPlatformHostLib(
target_name: []const u8,
optimize: OptimizeMode,
roc_modules: modules.RocModules,
strip: bool,
omit_frame_pointer: ?bool,
) *Step.UpdateSourceFiles {
const lib = createTestPlatformHostLib(
b,
@ -1034,6 +1039,8 @@ fn buildAndCopyTestPlatformHostLib(
target,
optimize,
roc_modules,
strip,
omit_frame_pointer,
);
// Use correct filename for target platform
@ -1162,6 +1169,8 @@ fn setupTestPlatforms(
optimize: OptimizeMode,
roc_modules: modules.RocModules,
test_platforms_step: *Step,
strip: bool,
omit_frame_pointer: ?bool,
) void {
// Clear the Roc cache when test platforms are rebuilt to ensure stale cached hosts aren't used
const clear_cache_step = createClearCacheStep(b);
@ -1176,6 +1185,8 @@ fn setupTestPlatforms(
native_target_name,
optimize,
roc_modules,
strip,
omit_frame_pointer,
);
clear_cache_step.dependOn(&copy_step.step);
}
@ -1192,6 +1203,8 @@ fn setupTestPlatforms(
cross_target.name,
optimize,
roc_modules,
strip,
omit_frame_pointer,
);
clear_cache_step.dependOn(&copy_step.step);
}
@ -1207,6 +1220,8 @@ fn setupTestPlatforms(
"wasm32",
optimize,
roc_modules,
strip,
omit_frame_pointer,
);
clear_cache_step.dependOn(&copy_step.step);
}
@ -1247,7 +1262,7 @@ pub fn build(b: *std.Build) void {
break :blk b.standardTargetOptions(.{ .default_target = default_target_query });
};
const optimize = b.standardOptimizeOption(.{});
const strip = b.option(bool, "strip", "Omit debug information");
const strip_flag = b.option(bool, "strip", "Omit debug information");
const no_bin = b.option(bool, "no-bin", "Skip emitting binaries (important for fast incremental compilation)") orelse false;
const trace_eval = b.option(bool, "trace-eval", "Enable detailed evaluation tracing for debugging") orelse (optimize == .Debug);
const trace_refcount = b.option(bool, "trace-refcount", "Enable detailed refcount tracing for debugging memory issues") orelse false;
@ -1284,15 +1299,36 @@ pub fn build(b: *std.Build) void {
build_options.addOption(bool, "trace_eval", trace_eval);
build_options.addOption(bool, "trace_refcount", trace_refcount);
build_options.addOption([]const u8, "compiler_version", getCompilerVersion(b, optimize));
if (target.result.os.tag == .macos and flag_tracy_callstack) {
std.log.warn("Tracy callstack does not work on MacOS, disabling.", .{});
build_options.addOption(bool, "enable_tracy_callstack", false);
} else {
build_options.addOption(bool, "enable_tracy_callstack", flag_tracy_callstack);
}
build_options.addOption(bool, "enable_tracy_callstack", flag_tracy_callstack);
build_options.addOption(bool, "enable_tracy_allocation", flag_tracy_allocation);
build_options.addOption(u32, "tracy_callstack_depth", flag_tracy_callstack_depth);
// Calculate effective strip value
// - If strip is explicitly set by user, use that (warn if tracy_callstack is also set)
// - Otherwise, default to stripping if not debug, unless tracy_callstack is enabled
const strip: bool = blk: {
if (strip_flag) |strip_bool| {
// User explicitly set strip
if (strip_bool and flag_tracy_callstack) {
std.log.warn("Both -Dstrip and -Dtracy-callstack are enabled. " ++
"Stripping will remove callstack information needed by Tracy.", .{});
}
break :blk strip_bool;
} else {
// User did not set strip - use defaults
if (flag_tracy_callstack) {
// Don't strip when tracy callstack is enabled (preserves debug info)
break :blk false;
} else {
// Default: strip in release modes
break :blk optimize != .Debug;
}
}
};
// Don't omit frame pointer when tracy callstack is enabled (needed for callstack capture)
const omit_frame_pointer: ?bool = if (flag_tracy_callstack) false else null;
const target_is_native =
// `query.isNative()` becomes false as soon as users override CPU features (e.g. -Dcpu=x86_64_v3),
// but we still want to treat those builds as native so macOS can link against real FSEvents.
@ -1386,9 +1422,9 @@ pub fn build(b: *std.Build) void {
roc_modules.eval.addImport("compiled_builtins", compiled_builtins_module);
// Setup test platform host libraries
setupTestPlatforms(b, target, optimize, roc_modules, test_platforms_step);
setupTestPlatforms(b, target, optimize, roc_modules, test_platforms_step, strip, omit_frame_pointer);
const roc_exe = addMainExe(b, roc_modules, target, optimize, strip, enable_llvm, use_system_llvm, user_llvm_path, flag_enable_tracy, zstd, compiled_builtins_module, write_compiled_builtins) orelse return;
const roc_exe = addMainExe(b, roc_modules, target, optimize, strip, omit_frame_pointer, enable_llvm, use_system_llvm, user_llvm_path, flag_enable_tracy, zstd, compiled_builtins_module, write_compiled_builtins, flag_enable_tracy) orelse return;
roc_modules.addAll(roc_exe);
install_and_run(b, no_bin, roc_exe, roc_step, run_step, run_args);
@ -1797,6 +1833,8 @@ pub fn build(b: *std.Build) void {
fx_host_target,
optimize,
roc_modules,
strip,
omit_frame_pointer,
);
// Copy the fx test platform host library to the source directory
@ -1992,7 +2030,8 @@ fn addMainExe(
roc_modules: modules.RocModules,
target: ResolvedTarget,
optimize: OptimizeMode,
strip: ?bool,
strip: bool,
omit_frame_pointer: ?bool,
enable_llvm: bool,
use_system_llvm: bool,
user_llvm_path: ?[]const u8,
@ -2000,6 +2039,7 @@ fn addMainExe(
zstd: *Dependency,
compiled_builtins_module: *std.Build.Module,
write_compiled_builtins: *Step.WriteFile,
flag_enable_tracy: ?[]const u8,
) ?*Step.Compile {
const exe = b.addExecutable(.{
.name = "roc",
@ -2008,6 +2048,7 @@ fn addMainExe(
.target = target,
.optimize = optimize,
.strip = strip,
.omit_frame_pointer = omit_frame_pointer,
.link_libc = true,
}),
});
@ -2026,6 +2067,8 @@ fn addMainExe(
native_target_name,
optimize,
roc_modules,
strip,
omit_frame_pointer,
);
b.getInstallStep().dependOn(&copy_step.step);
}
@ -2042,6 +2085,8 @@ fn addMainExe(
cross_target.name,
optimize,
roc_modules,
strip,
omit_frame_pointer,
);
b.getInstallStep().dependOn(&copy_step.step);
}
@ -2063,6 +2108,7 @@ fn addMainExe(
.target = target,
.optimize = optimize,
.strip = strip,
.omit_frame_pointer = omit_frame_pointer,
.pic = true, // Enable Position Independent Code for PIE compatibility
}),
});
@ -2077,7 +2123,8 @@ fn addMainExe(
.root_source_file = b.path("src/interpreter_shim/main.zig"),
.target = target,
.optimize = optimize,
.strip = optimize != .Debug,
.strip = strip,
.omit_frame_pointer = omit_frame_pointer,
.pic = true, // Enable Position Independent Code for PIE compatibility
}),
.linkage = .static,
@ -2103,6 +2150,9 @@ fn addMainExe(
copy_shim.addCopyFileToSource(shim_lib.getEmittedBin(), b.pathJoin(&.{ "src/cli", interpreter_shim_filename }));
exe.step.dependOn(&copy_shim.step);
// Add tracy support (required by parse/can/check modules)
add_tracy(b, roc_modules.build_options, shim_lib, b.graph.host, false, flag_enable_tracy);
// Cross-compile interpreter shim for all supported targets
// This allows `roc build --target=X` to work for cross-compilation
const cross_compile_shim_targets = [_]struct { name: []const u8, query: std.Target.Query }{
@ -2123,7 +2173,8 @@ fn addMainExe(
.root_source_file = b.path("src/builtins/static_lib.zig"),
.target = cross_resolved_target,
.optimize = optimize,
.strip = optimize != .Debug,
.strip = strip,
.omit_frame_pointer = omit_frame_pointer,
.pic = true,
}),
});
@ -2136,7 +2187,8 @@ fn addMainExe(
.root_source_file = b.path("src/interpreter_shim/main.zig"),
.target = cross_resolved_target,
.optimize = optimize,
.strip = optimize != .Debug,
.strip = strip,
.omit_frame_pointer = omit_frame_pointer,
.pic = true,
}),
.linkage = .static,

View file

@ -39,6 +39,13 @@ pub fn generateComprehensiveStub(
"munmap",
"mremap",
"msync",
// Used by Zig's CAllocator
"malloc",
"calloc",
"realloc",
"free",
"posix_memalign",
"malloc_usable_size",
// File I/O
"close",
"read",

View file

@ -303,19 +303,19 @@ pub const ModuleType = enum {
pub fn getDependencies(self: ModuleType) []const ModuleType {
return switch (self) {
.build_options => &.{},
.builtins => &.{},
.builtins => &.{.tracy},
.fs => &.{},
.tracy => &.{ .build_options, .builtins },
.tracy => &.{.build_options},
.collections => &.{},
.base => &.{ .collections, .builtins },
.roc_src => &.{},
.types => &.{ .base, .collections },
.types => &.{ .tracy, .base, .collections },
.reporting => &.{ .collections, .base },
.parse => &.{ .tracy, .collections, .base, .reporting },
.can => &.{ .tracy, .builtins, .collections, .types, .base, .parse, .reporting },
.check => &.{ .tracy, .builtins, .collections, .base, .parse, .types, .can, .reporting },
.layout => &.{ .collections, .base, .types, .builtins, .can },
.eval => &.{ .collections, .base, .types, .builtins, .parse, .can, .check, .layout, .build_options, .reporting },
.layout => &.{ .tracy, .collections, .base, .types, .builtins, .can },
.eval => &.{ .tracy, .collections, .base, .types, .builtins, .parse, .can, .check, .layout, .build_options, .reporting },
.compile => &.{ .tracy, .build_options, .fs, .builtins, .collections, .base, .types, .parse, .can, .check, .reporting, .layout, .eval, .unbundle },
.ipc => &.{},
.repl => &.{ .base, .collections, .compile, .parse, .types, .can, .check, .builtins, .layout, .eval },

View file

@ -133,6 +133,9 @@ pub fn TracyAllocator(comptime name: ?[:0]const u8) type {
}
fn allocFn(ptr: *anyopaque, len: usize, ptr_align: std.mem.Alignment, ret_addr: usize) ?[*]u8 {
const zone = traceNamed(@src(), "alloc");
defer zone.end();
const self: *Self = @ptrCast(@alignCast(ptr));
const result = self.parent_allocator.rawAlloc(len, ptr_align, ret_addr);
if (result) |data| {
@ -150,6 +153,9 @@ pub fn TracyAllocator(comptime name: ?[:0]const u8) type {
}
fn resizeFn(ptr: *anyopaque, buf: []u8, buf_align: std.mem.Alignment, new_len: usize, ret_addr: usize) bool {
const zone = traceNamed(@src(), "resize");
defer zone.end();
const self: *Self = @ptrCast(@alignCast(ptr));
if (self.parent_allocator.rawResize(buf, buf_align, new_len, ret_addr)) {
if (name) |n| {
@ -169,6 +175,9 @@ pub fn TracyAllocator(comptime name: ?[:0]const u8) type {
}
fn remapFn(ptr: *anyopaque, buf: []u8, buf_align: std.mem.Alignment, new_len: usize, ret_addr: usize) ?[*]u8 {
const zone = traceNamed(@src(), "remap");
defer zone.end();
const self: *Self = @ptrCast(@alignCast(ptr));
if (self.parent_allocator.rawRemap(buf, buf_align, new_len, ret_addr)) |remapped| {
if (name) |n| {
@ -188,6 +197,9 @@ pub fn TracyAllocator(comptime name: ?[:0]const u8) type {
}
fn freeFn(ptr: *anyopaque, buf: []u8, buf_align: std.mem.Alignment, ret_addr: usize) void {
const zone = traceNamed(@src(), "free");
defer zone.end();
const self: *Self = @ptrCast(@alignCast(ptr));
self.parent_allocator.rawFree(buf, buf_align, ret_addr);
// this condition is to handle free being called on an empty slice that was never even allocated
@ -270,7 +282,9 @@ inline fn frameMarkEnd(comptime name: [:0]const u8) void {
extern fn ___tracy_emit_frame_mark_start(name: [*:0]const u8) void;
extern fn ___tracy_emit_frame_mark_end(name: [*:0]const u8) void;
inline fn alloc(ptr: [*]u8, len: usize) void {
/// Records a memory allocation with Tracy's memory profiler.
/// Call this after allocating memory to track it in Tracy's memory view.
pub inline fn alloc(ptr: [*]u8, len: usize) void {
if (!enable) return;
if (enable_callstack) {
@ -290,7 +304,9 @@ inline fn allocNamed(ptr: [*]u8, len: usize, comptime name: [:0]const u8) void {
}
}
inline fn free(ptr: [*]u8) void {
/// Records a memory deallocation with Tracy's memory profiler.
/// Call this before freeing memory to track it in Tracy's memory view.
pub inline fn free(ptr: [*]u8) void {
if (!enable) return;
if (enable_callstack) {

View file

@ -9,6 +9,8 @@
//! This design makes Roc's ABI very simple; the calling convention is just "Ops pointer,
//! return pointer, args pointers".
const tracy = @import("tracy");
/// todo: describe RocCall
pub const RocCall = fn (
/// Function pointers that the Roc program uses, e.g. alloc, dealloc, etc.
@ -70,6 +72,9 @@ pub const RocOps = extern struct {
/// Helper function to crash the Roc program, returns control to the host.
pub fn crash(self: *RocOps, msg: []const u8) void {
const trace = tracy.trace(@src());
defer trace.end();
const roc_crashed_args = RocCrashed{
.utf8_bytes = @constCast(msg.ptr),
.len = msg.len,
@ -79,6 +84,9 @@ pub const RocOps = extern struct {
/// Helper function to send debug output to the host.
pub fn dbg(self: *RocOps, msg: []const u8) void {
const trace = tracy.trace(@src());
defer trace.end();
const roc_dbg_args = RocDbg{
.utf8_bytes = @constCast(msg.ptr),
.len = msg.len,
@ -87,16 +95,31 @@ pub const RocOps = extern struct {
}
pub fn alloc(self: *RocOps, alignment: usize, length: usize) *anyopaque {
const trace = tracy.trace(@src());
defer trace.end();
var roc_alloc_args = RocAlloc{
.alignment = alignment,
.length = length,
.answer = self.env,
};
self.roc_alloc(&roc_alloc_args, self.env);
if (tracy.enable_allocation) {
tracy.alloc(@ptrCast(roc_alloc_args.answer), length);
}
return roc_alloc_args.answer;
}
pub fn dealloc(self: *RocOps, ptr: *anyopaque, alignment: usize) void {
const trace = tracy.trace(@src());
defer trace.end();
if (tracy.enable_allocation) {
tracy.free(@ptrCast(ptr));
}
var roc_dealloc_args = RocDealloc{
.alignment = alignment,
.ptr = ptr,

View file

@ -1134,7 +1134,18 @@ pub fn diagnosticToReport(self: *Self, diagnostic: CIR.Diagnostic, allocator: st
try report.document.addAnnotatedText(owned_feature, .emphasized);
try report.document.addLineBreak();
try report.document.addLineBreak();
const owned_filename = try report.addOwnedString(filename);
const region_info = self.calcRegionInfo(data.region);
try report.document.addSourceRegion(
region_info,
.error_highlight,
owned_filename,
self.getSourceAll(),
self.getLineStartsAll(),
);
try report.document.addLineBreak();
try report.document.addReflowingText("This error doesn't have a proper diagnostic report yet. Let us know if you want to help improve Roc's error messages!");
try report.document.addLineBreak();
break :blk report;
},
.malformed_type_annotation => |data| blk: {

View file

@ -4,6 +4,7 @@
const std = @import("std");
const builtin = @import("builtin");
const build_options = @import("build_options");
const Allocator = std.mem.Allocator;
const base = @import("base");
const Allocators = base.Allocators;
@ -164,6 +165,11 @@ fn buildLinkArgs(allocs: *Allocators, config: LinkConfig) LinkError!std.array_li
// Link against system libraries on macOS
try args.append("-lSystem");
// Link C++ standard library if Tracy is enabled
if (build_options.enable_tracy) {
try args.append("-lc++");
}
},
.linux => {
// Add linker name for Linux
@ -218,6 +224,11 @@ fn buildLinkArgs(allocs: *Allocators, config: LinkConfig) LinkError!std.array_li
// Otherwise, dynamic linker is set via extra_args from caller
},
}
// Link C++ standard library if Tracy is enabled
if (build_options.enable_tracy) {
try args.append("-lstdc++");
}
},
.windows => {
// Add linker name for Windows COFF
@ -275,6 +286,11 @@ fn buildLinkArgs(allocs: *Allocators, config: LinkConfig) LinkError!std.array_li
// Suppress warnings using Windows style
try args.append("/ignore:4217"); // Ignore locally defined symbol imported warnings
try args.append("/ignore:4049"); // Ignore locally defined symbol imported warnings
// Link C++ standard library if Tracy is enabled
if (build_options.enable_tracy) {
try args.append("/defaultlib:msvcprt");
}
},
.freestanding => {
// WebAssembly linker (wasm-ld) for freestanding wasm32 target

View file

@ -3,6 +3,7 @@
const std = @import("std");
const builtin = @import("builtin");
const build_options = @import("build_options");
const tracy = @import("tracy");
/// Stack size for the interpreter. WASM targets use a smaller stack to avoid
/// memory pressure from repeated allocations that can't be efficiently coalesced.
@ -664,6 +665,9 @@ pub const Interpreter = struct {
/// Evaluates a Roc expression and returns the result.
pub fn eval(self: *Interpreter, expr_idx: can.CIR.Expr.Idx, roc_ops: *RocOps) Error!StackValue {
const trace = tracy.trace(@src());
defer trace.end();
// Clear flex_type_context at the start of each top-level evaluation.
// This prevents stale type mappings from previous evaluations from
// interfering with polymorphic function instantiation.
@ -692,6 +696,9 @@ pub const Interpreter = struct {
roc_ops: *RocOps,
arg_ptr: ?*anyopaque,
) Error!void {
const trace = tracy.trace(@src());
defer trace.end();
if (arg_ptr) |args_ptr| {
const func_val = try self.eval(expr_idx, roc_ops);
defer func_val.decref(&self.runtime_layout_store, roc_ops);
@ -1005,6 +1012,9 @@ pub const Interpreter = struct {
roc_ops: *RocOps,
work_stack: *WorkStack,
) !SortWithResult {
const trace = tracy.trace(@src());
defer trace.end();
var saved_rigid_subst = saved_rigid_subst_in;
std.debug.assert(list_arg.layout.tag == .list or list_arg.layout.tag == .list_of_zst);
@ -1152,6 +1162,9 @@ pub const Interpreter = struct {
roc_ops: *RocOps,
return_rt_var: types.Var,
) !StackValue {
const trace = tracy.trace(@src());
defer trace.end();
// Validate index is within bounds
if (hosted_fn_index >= roc_ops.hosted_fns.count) {
self.triggerCrash("Hosted function index out of bounds", false, roc_ops);
@ -1216,6 +1229,9 @@ pub const Interpreter = struct {
/// Version of callLowLevelBuiltin that also accepts a target type for operations like num_from_numeral
pub fn callLowLevelBuiltinWithTargetType(self: *Interpreter, op: can.CIR.Expr.LowLevel, args: []StackValue, roc_ops: *RocOps, return_rt_var: ?types.Var, target_type_var: ?types.Var) !StackValue {
const trace = tracy.trace(@src());
defer trace.end();
// For num_from_numeral, we need to pass the target type through a different mechanism
// since the standard handler extracts it from the return type which has a generic parameter.
// Store the target type temporarily so the handler can use it.
@ -1226,6 +1242,9 @@ pub const Interpreter = struct {
}
pub fn callLowLevelBuiltin(self: *Interpreter, op: can.CIR.Expr.LowLevel, args: []StackValue, roc_ops: *RocOps, return_rt_var: ?types.Var) !StackValue {
const trace = tracy.trace(@src());
defer trace.end();
switch (op) {
.str_is_empty => {
// Str.is_empty : Str -> Bool
@ -6325,6 +6344,9 @@ pub const Interpreter = struct {
_: types.Var, // rhs_var unused
roc_ops: *RocOps,
) StructuralEqError!bool {
const trace = tracy.trace(@src());
defer trace.end();
// Handle scalar comparisons (numbers, strings) directly.
if (lhs.layout.tag == .scalar and rhs.layout.tag == .scalar) {
const lhs_scalar = lhs.layout.data.scalar;
@ -7485,6 +7507,8 @@ pub const Interpreter = struct {
out_binds: *std.array_list.AlignedManaged(Binding, null),
expr_idx: ?can.CIR.Expr.Idx,
) !bool {
const trace = tracy.trace(@src());
defer trace.end();
const pat = self.env.store.getPattern(pattern_idx);
switch (pat) {
.assign => |_| {
@ -7971,6 +7995,9 @@ pub const Interpreter = struct {
roc_ops: *RocOps,
receiver_rt_var: ?types.Var,
) Error!StackValue {
const trace = tracy.trace(@src());
defer trace.end();
// Check method resolution cache first
const cache_key = MethodResolutionKey{
.origin_module = origin_module,
@ -8393,6 +8420,9 @@ pub const Interpreter = struct {
/// Get the layout for a runtime type var using the O(1) biased slot array.
pub fn getRuntimeLayout(self: *Interpreter, type_var: types.Var) !layout.Layout {
const trace = tracy.trace(@src());
defer trace.end();
var resolved = self.runtime_types.resolveVar(type_var);
// Apply rigid variable substitution if this is a rigid variable
@ -8800,6 +8830,9 @@ pub const Interpreter = struct {
/// Handles most structural types: tag unions, tuples, records, functions, and nominal types.
/// Uses caching to handle recursive types and avoid duplicate work.
pub fn translateTypeVar(self: *Interpreter, module: *can.ModuleEnv, compile_var: types.Var) Error!types.Var {
const trace = tracy.trace(@src());
defer trace.end();
const resolved = module.types.resolveVar(compile_var);
const key = ModuleVarKey{ .module = module, .var_ = resolved.var_ };
@ -8850,6 +8883,9 @@ pub const Interpreter = struct {
.structure => |flat| {
switch (flat) {
.tag_union => |tu| {
const tu_trace = tracy.traceNamed(@src(), "translateTypeVar.tag_union");
defer tu_trace.end();
var rt_tag_args = try std.ArrayList(types.Var).initCapacity(self.allocator, 8);
defer rt_tag_args.deinit(self.allocator);
@ -8905,6 +8941,9 @@ pub const Interpreter = struct {
break :blk try self.runtime_types.freshFromContent(.{ .structure = .empty_tag_union });
},
.tuple => |t| {
const tup_trace = tracy.traceNamed(@src(), "translateTypeVar.tuple");
defer tup_trace.end();
const ct_elems = module.types.sliceVars(t.elems);
var buf = try self.allocator.alloc(types.Var, ct_elems.len);
defer self.allocator.free(buf);
@ -8915,6 +8954,9 @@ pub const Interpreter = struct {
break :blk try self.runtime_types.freshFromContent(.{ .structure = .{ .tuple = .{ .elems = range } } });
},
.record => |rec| {
const rec_trace = tracy.traceNamed(@src(), "translateTypeVar.record");
defer rec_trace.end();
var acc = try FieldAccumulator.init(self.allocator);
defer acc.deinit();
var visited = std.AutoHashMap(types.Var, void).init(self.allocator);
@ -8947,6 +8989,9 @@ pub const Interpreter = struct {
break :blk try self.runtime_types.freshFromContent(.{ .structure = .{ .record = .{ .fields = rt_fields, .ext = rt_ext } } });
},
.record_unbound => |fields_range| {
const rub_trace = tracy.traceNamed(@src(), "translateTypeVar.record_unbound");
defer rub_trace.end();
// record_unbound has no extension - it's a complete set of fields
const ct_fields = module.types.getRecordFieldsSlice(fields_range);
var runtime_fields = try self.allocator.alloc(types.RecordField, ct_fields.len);
@ -8970,6 +9015,9 @@ pub const Interpreter = struct {
break :blk try self.runtime_types.freshFromContent(.{ .structure = .empty_record });
},
.fn_pure => |f| {
const fnp_trace = tracy.traceNamed(@src(), "translateTypeVar.fn_pure");
defer fnp_trace.end();
const ct_args = module.types.sliceVars(f.args);
var buf = try self.allocator.alloc(types.Var, ct_args.len);
defer self.allocator.free(buf);
@ -8981,6 +9029,9 @@ pub const Interpreter = struct {
break :blk try self.runtime_types.register(.{ .content = content, .rank = types.Rank.top_level, .mark = types.Mark.none });
},
.fn_effectful => |f| {
const fne_trace = tracy.traceNamed(@src(), "translateTypeVar.fn_effectful");
defer fne_trace.end();
const ct_args = module.types.sliceVars(f.args);
var buf = try self.allocator.alloc(types.Var, ct_args.len);
defer self.allocator.free(buf);
@ -8992,6 +9043,9 @@ pub const Interpreter = struct {
break :blk try self.runtime_types.register(.{ .content = content, .rank = types.Rank.top_level, .mark = types.Mark.none });
},
.fn_unbound => |f| {
const fnu_trace = tracy.traceNamed(@src(), "translateTypeVar.fn_unbound");
defer fnu_trace.end();
const ct_args = module.types.sliceVars(f.args);
var buf = try self.allocator.alloc(types.Var, ct_args.len);
defer self.allocator.free(buf);
@ -9003,6 +9057,9 @@ pub const Interpreter = struct {
break :blk try self.runtime_types.register(.{ .content = content, .rank = types.Rank.top_level, .mark = types.Mark.none });
},
.nominal_type => |nom| {
const nom_trace = tracy.traceNamed(@src(), "translateTypeVar.nominal_type");
defer nom_trace.end();
const ct_backing = module.types.getNominalBackingVar(nom);
const ct_args = module.types.sliceNominalArgs(nom);
@ -9266,6 +9323,9 @@ pub const Interpreter = struct {
/// Uses the standard Instantiator, filtering its output to only rigid->flex mappings
/// (the Instantiator maps all types, but layout computation only needs rigids).
fn instantiateType(self: *Interpreter, type_var: types.Var, subst_map: *std.AutoHashMap(types.Var, types.Var)) Error!types.Var {
const trace = tracy.trace(@src());
defer trace.end();
self.instantiate_scratch.clearRetainingCapacity();
// IMPORTANT: Use runtime_layout_store.env's ident store, NOT self.env.
@ -9303,6 +9363,9 @@ pub const Interpreter = struct {
module: *can.ModuleEnv,
tag_union: types.TagUnion,
) std.mem.Allocator.Error!std.ArrayList(types.Tag) {
const gt_trace = tracy.traceNamed(@src(), "gatherTags");
defer gt_trace.end();
var scratch_tags = try std.ArrayList(types.Tag).initCapacity(ctx.allocator, 8);
const tag_slice = module.types.getTagsSlice(tag_union.tags);
@ -9438,6 +9501,9 @@ pub const Interpreter = struct {
/// Prepare a call using a known runtime function type var.
/// Builds and inserts a cache entry on miss using the function's declared return var.
pub fn prepareCallWithFuncVar(self: *Interpreter, module_id: u32, func_id: u32, func_type_var: types.Var, args: []const types.Var) !PolyEntry {
const trace = tracy.trace(@src());
defer trace.end();
if (self.polyLookup(module_id, func_id, args)) |found| return found;
const func_resolved = self.runtime_types.resolveVar(func_type_var);
@ -10228,6 +10294,9 @@ pub const Interpreter = struct {
roc_ops: *RocOps,
expected_rt_var: ?types.Var,
) Error!StackValue {
const trace = tracy.trace(@src());
defer trace.end();
var work_stack = try WorkStack.init(self.allocator);
defer work_stack.deinit();
@ -10467,6 +10536,9 @@ pub const Interpreter = struct {
expected_rt_var: ?types.Var,
roc_ops: *RocOps,
) Error!void {
const trace = tracy.trace(@src());
defer trace.end();
const expr = self.env.store.getExpr(expr_idx);
switch (expr) {
@ -10980,6 +11052,8 @@ pub const Interpreter = struct {
// Conditionals
.e_if => |if_expr| {
const sched_trace = tracy.traceNamed(@src(), "sched.if");
defer sched_trace.end();
const branches = self.env.store.sliceIfBranches(if_expr.branches);
if (branches.len > 0) {
// Get first branch
@ -11008,6 +11082,8 @@ pub const Interpreter = struct {
// Blocks
.e_block => |blk| {
const sched_trace = tracy.traceNamed(@src(), "sched.block");
defer sched_trace.end();
const stmts = self.env.store.sliceStatements(blk.stmts);
const bindings_start = self.bindings.items.len;
@ -11043,6 +11119,8 @@ pub const Interpreter = struct {
// Tuples
.e_tuple => |tup| {
const sched_trace = tracy.traceNamed(@src(), "sched.tuple");
defer sched_trace.end();
const elems = self.env.store.sliceExpr(tup.elems);
if (elems.len == 0) {
// Empty tuple - create immediately
@ -11068,6 +11146,8 @@ pub const Interpreter = struct {
// Lists
.e_list => |list_expr| {
const sched_trace = tracy.traceNamed(@src(), "sched.list");
defer sched_trace.end();
const elems = self.env.store.sliceExpr(list_expr.elems);
// Get list type variable
@ -11108,6 +11188,8 @@ pub const Interpreter = struct {
// Records
.e_record => |rec| {
const sched_trace = tracy.traceNamed(@src(), "sched.record");
defer sched_trace.end();
const ct_var = can.ModuleEnv.varFrom(expr_idx);
const rt_var = try self.translateTypeVar(self.env, ct_var);
const fields = self.env.store.sliceRecordFields(rec.fields);
@ -11286,6 +11368,8 @@ pub const Interpreter = struct {
},
.e_return => |ret| {
const sched_trace = tracy.traceNamed(@src(), "sched.return");
defer sched_trace.end();
// Schedule the early return continuation after evaluating the inner expression
const inner_ct_var = can.ModuleEnv.varFrom(ret.expr);
const inner_rt_var = try self.translateTypeVar(self.env, inner_ct_var);
@ -11299,6 +11383,8 @@ pub const Interpreter = struct {
// Tag unions with payloads
.e_tag => |tag| {
const sched_trace = tracy.traceNamed(@src(), "sched.tag");
defer sched_trace.end();
// Determine runtime type and tag index.
// Use expected_rt_var if it's resolved to something concrete (structure or alias).
// If expected_rt_var is flex (unresolved), fall back to ct_var translation.
@ -11444,6 +11530,8 @@ pub const Interpreter = struct {
// Pattern matching
.e_match => |m| {
const sched_trace = tracy.traceNamed(@src(), "sched.match");
defer sched_trace.end();
// Get type info for scrutinee and result
const scrutinee_ct_var = can.ModuleEnv.varFrom(m.cond);
const scrutinee_rt_var = try self.translateTypeVar(self.env, scrutinee_ct_var);
@ -11496,6 +11584,8 @@ pub const Interpreter = struct {
},
.e_for => |for_expr| {
const sched_trace = tracy.traceNamed(@src(), "sched.for");
defer sched_trace.end();
// For expression: first evaluate the list, then set up iteration
const expr_ct_var = can.ModuleEnv.varFrom(for_expr.expr);
const expr_rt_var = try self.translateTypeVar(self.env, expr_ct_var);
@ -11533,12 +11623,17 @@ pub const Interpreter = struct {
// Function calls
.e_call => |call| {
const sched_trace = tracy.traceNamed(@src(), "sched.call");
defer sched_trace.end();
const func_idx = call.func;
const arg_indices = self.env.store.sliceExpr(call.args);
// Check if the function is an anno-only lookup that will crash
const func_expr_check = self.env.store.getExpr(func_idx);
if (func_expr_check == .e_lookup_local) {
const anno_trace = tracy.traceNamed(@src(), "sched.call.anno_check");
defer anno_trace.end();
const lookup = func_expr_check.e_lookup_local;
const all_defs = self.env.store.sliceDefs(self.env.all_defs);
for (all_defs) |def_idx| {
@ -11609,6 +11704,8 @@ pub const Interpreter = struct {
var saved_rigid_subst: ?std.AutoHashMap(types.Var, types.Var) = null;
if (should_instantiate) {
const clone_trace = tracy.traceNamed(@src(), "sched.call.rigid_clone");
defer clone_trace.end();
saved_rigid_subst = try self.rigid_subst.clone();
}
errdefer {
@ -11624,6 +11721,9 @@ pub const Interpreter = struct {
// If we instantiated, update rigid_subst and empty_scope (will be restored in cleanup)
if (should_instantiate) {
const setup_trace = tracy.traceNamed(@src(), "sched.call.instantiate_setup");
defer setup_trace.end();
// Ensure we have at least one scope level
if (self.empty_scope.scopes.items.len == 0) {
try self.empty_scope.scopes.append(types.VarMap.init(self.allocator));
@ -11831,6 +11931,9 @@ pub const Interpreter = struct {
expected_rt_var: ?types.Var,
num_lit: @TypeOf(@as(can.CIR.Expr, undefined).e_num),
) Error!StackValue {
const trace = tracy.trace(@src());
defer trace.end();
// Get the layout type variable - use expected_rt_var if provided for layout determination
const layout_rt_var = expected_rt_var orelse blk: {
const ct_var = can.ModuleEnv.varFrom(expr_idx);
@ -12179,6 +12282,9 @@ pub const Interpreter = struct {
zero: @TypeOf(@as(can.CIR.Expr, undefined).e_zero_argument_tag),
roc_ops: *RocOps,
) Error!StackValue {
const trace = tracy.trace(@src());
defer trace.end();
var rt_var = expected_rt_var orelse blk: {
const ct_var = can.ModuleEnv.varFrom(expr_idx);
break :blk try self.translateTypeVar(self.env, ct_var);
@ -12388,6 +12494,9 @@ pub const Interpreter = struct {
lam: @TypeOf(@as(can.CIR.Expr, undefined).e_lambda),
roc_ops: *RocOps,
) Error!StackValue {
const trace = tracy.trace(@src());
defer trace.end();
// Build a closure value with empty captures using the runtime layout for the lambda's type
const rt_var = if (expected_rt_var) |provided_var|
provided_var
@ -12489,6 +12598,9 @@ pub const Interpreter = struct {
cls: @TypeOf(@as(can.CIR.Expr, undefined).e_closure),
roc_ops: *RocOps,
) Error!StackValue {
const trace = tracy.trace(@src());
defer trace.end();
const lam_expr = self.env.store.getExpr(cls.lambda_idx);
if (lam_expr != .e_lambda) {
self.triggerCrash("e_closure: lambda_idx does not point to e_lambda", false, roc_ops);
@ -12662,6 +12774,9 @@ pub const Interpreter = struct {
expected_rt_var: ?types.Var,
roc_ops: *RocOps,
) Error!StackValue {
const trace = tracy.trace(@src());
defer trace.end();
// Search bindings in reverse
var i: usize = self.bindings.items.len;
while (i > 0) {
@ -12786,6 +12901,9 @@ pub const Interpreter = struct {
expected_rt_var: ?types.Var,
roc_ops: *RocOps,
) Error!StackValue {
const trace = tracy.trace(@src());
defer trace.end();
const other_env = self.import_envs.get(lookup.module_idx) orelse {
self.triggerCrash("e_lookup_external: import_envs missing entry for module", false, roc_ops);
return error.Crash;
@ -13144,22 +13262,35 @@ pub const Interpreter = struct {
cont: Continuation,
roc_ops: *RocOps,
) Error!bool {
// Increased quota needed: 40+ tracy.traceNamed() calls generate comptime structs
@setEvalBranchQuota(5000);
const trace = tracy.trace(@src());
defer trace.end();
switch (cont) {
.return_result => {
const cont_trace = tracy.traceNamed(@src(), "cont.return_result");
defer cont_trace.end();
// Signal to exit the main loop - the result is on the value stack
return false;
},
.decref_value => |dv| {
const cont_trace = tracy.traceNamed(@src(), "cont.decref_value");
defer cont_trace.end();
// Decrement reference count of the value
dv.value.decref(&self.runtime_layout_store, roc_ops);
return true;
},
.trim_bindings => |tb| {
const cont_trace = tracy.traceNamed(@src(), "cont.trim_bindings");
defer cont_trace.end();
// Restore bindings to a previous length
self.trimBindingList(&self.bindings, tb.target_len, roc_ops);
return true;
},
.and_short_circuit => |sc| {
const cont_trace = tracy.traceNamed(@src(), "cont.and_short_circuit");
defer cont_trace.end();
// Pop LHS value from stack
const lhs = value_stack.pop() orelse return error.Crash;
defer lhs.decref(&self.runtime_layout_store, roc_ops);
@ -13178,6 +13309,8 @@ pub const Interpreter = struct {
return true;
},
.or_short_circuit => |sc| {
const cont_trace = tracy.traceNamed(@src(), "cont.or_short_circuit");
defer cont_trace.end();
// Pop LHS value from stack
const lhs = value_stack.pop() orelse return error.Crash;
defer lhs.decref(&self.runtime_layout_store, roc_ops);
@ -13196,6 +13329,8 @@ pub const Interpreter = struct {
return true;
},
.if_branch => |ib| {
const cont_trace = tracy.traceNamed(@src(), "cont.if_branch");
defer cont_trace.end();
// Pop condition value from stack
const cond = value_stack.pop() orelse return error.Crash;
defer cond.decref(&self.runtime_layout_store, roc_ops);
@ -13233,6 +13368,8 @@ pub const Interpreter = struct {
return true;
},
.block_continue => |bc| {
const cont_trace = tracy.traceNamed(@src(), "cont.block_continue");
defer cont_trace.end();
// For s_expr statements, we need to pop and discard the value
// Only pop if should_discard_value is set (meaning this was scheduled after an s_expr)
if (bc.should_discard_value) {
@ -13254,6 +13391,8 @@ pub const Interpreter = struct {
return true;
},
.bind_decl => |bd| {
const cont_trace = tracy.traceNamed(@src(), "cont.bind_decl");
defer cont_trace.end();
// Pop evaluated value from stack
const val = value_stack.pop() orelse return error.Crash;
if (comptime trace_refcount and builtin.os.tag != .freestanding) {
@ -13322,6 +13461,8 @@ pub const Interpreter = struct {
return true;
},
.tuple_collect => |tc| {
const cont_trace = tracy.traceNamed(@src(), "cont.tuple_collect");
defer cont_trace.end();
// Tuple collection works by evaluating elements one at a time
// and tracking how many we've collected
if (tc.remaining_elems.len > 0) {
@ -13351,6 +13492,7 @@ pub const Interpreter = struct {
try value_stack.push(tuple_val);
} else {
// Gather layouts and values
const alloc_trace = tracy.traceNamed(@src(), "tuple_collect.alloc_temps");
var elem_layouts = try self.allocator.alloc(Layout, total_count);
defer self.allocator.free(elem_layouts);
@ -13362,6 +13504,7 @@ pub const Interpreter = struct {
// Collect element rt_vars for constructing tuple type
var elem_rt_vars = try self.allocator.alloc(types.Var, total_count);
defer self.allocator.free(elem_rt_vars);
alloc_trace.end();
// Pop values in reverse order (last evaluated is on top)
var i: usize = total_count;
@ -13391,8 +13534,12 @@ pub const Interpreter = struct {
}
// Decref temporary values after they've been copied into the tuple
for (values) |val| {
val.decref(&self.runtime_layout_store, roc_ops);
{
const decref_trace = tracy.traceNamed(@src(), "tuple_collect.decref_elements");
defer decref_trace.end();
for (values) |val| {
val.decref(&self.runtime_layout_store, roc_ops);
}
}
try value_stack.push(dest);
@ -13401,6 +13548,8 @@ pub const Interpreter = struct {
return true;
},
.list_collect => |lc| {
const cont_trace = tracy.traceNamed(@src(), "cont.list_collect");
defer cont_trace.end();
// List collection works by evaluating elements one at a time
// and tracking how many we've collected
if (lc.remaining_elems.len > 0) {
@ -13441,8 +13590,10 @@ pub const Interpreter = struct {
try value_stack.push(dest);
} else {
// Pop all collected values from the value stack
const alloc_trace = tracy.traceNamed(@src(), "list_collect.alloc_temps");
var values = try self.allocator.alloc(StackValue, total_count);
defer self.allocator.free(values);
alloc_trace.end();
// Pop values in reverse order (last evaluated is on top)
var i: usize = total_count;
@ -13496,8 +13647,12 @@ pub const Interpreter = struct {
header.* = runtime_list;
// Decref temporary values after they've been copied into the list
for (values) |val| {
val.decref(&self.runtime_layout_store, roc_ops);
{
const decref_trace = tracy.traceNamed(@src(), "list_collect.decref_elements");
defer decref_trace.end();
for (values) |val| {
val.decref(&self.runtime_layout_store, roc_ops);
}
}
// Set the runtime type variable so method dispatch works correctly.
@ -13521,6 +13676,8 @@ pub const Interpreter = struct {
return true;
},
.record_collect => |rc| {
const cont_trace = tracy.traceNamed(@src(), "cont.record_collect");
defer cont_trace.end();
// Record collection: evaluate extension (if any), then fields in order
if (rc.remaining_fields.len > 0) {
// More fields to evaluate - schedule next one
@ -13546,6 +13703,7 @@ pub const Interpreter = struct {
const total_field_values = rc.collected_count;
// Build layout info from collected values
const alloc_trace = tracy.traceNamed(@src(), "record_collect.alloc_temps");
var union_names = std.array_list.AlignedManaged(base_pkg.Ident.Idx, null).init(self.allocator);
defer union_names.deinit();
var union_layouts = std.array_list.AlignedManaged(layout.Layout, null).init(self.allocator);
@ -13556,6 +13714,7 @@ pub const Interpreter = struct {
// Pop field values from stack (in reverse order since last evaluated is on top)
var field_values = try self.allocator.alloc(StackValue, total_field_values);
defer self.allocator.free(field_values);
alloc_trace.end();
var i: usize = total_field_values;
while (i > 0) {
@ -13664,11 +13823,15 @@ pub const Interpreter = struct {
}
// Decref base value and field values after they've been copied
if (base_value_opt) |base_value| {
base_value.decref(&self.runtime_layout_store, roc_ops);
}
for (field_values) |val| {
val.decref(&self.runtime_layout_store, roc_ops);
{
const decref_trace = tracy.traceNamed(@src(), "record_collect.decref_fields");
defer decref_trace.end();
if (base_value_opt) |base_value| {
base_value.decref(&self.runtime_layout_store, roc_ops);
}
for (field_values) |val| {
val.decref(&self.runtime_layout_store, roc_ops);
}
}
try value_stack.push(dest);
@ -13676,6 +13839,8 @@ pub const Interpreter = struct {
return true;
},
.early_return => {
const cont_trace = tracy.traceNamed(@src(), "cont.early_return");
defer cont_trace.end();
// Pop the evaluated value and signal early return
const return_value = value_stack.pop() orelse return error.Crash;
self.early_return_value = return_value;
@ -13789,6 +13954,8 @@ pub const Interpreter = struct {
return true;
},
.tag_collect => |tc| {
const cont_trace = tracy.traceNamed(@src(), "cont.tag_collect");
defer cont_trace.end();
// Tag payload collection: evaluate each argument, then finalize tag
if (tc.remaining_args.len > 0) {
// More arguments to evaluate
@ -14080,6 +14247,8 @@ pub const Interpreter = struct {
return true;
},
.match_branches => |mb| {
const cont_trace = tracy.traceNamed(@src(), "cont.match_branches");
defer cont_trace.end();
// Scrutinee is on value stack - get it but keep it there for potential later use
const scrutinee_temp = value_stack.pop() orelse return error.Crash;
// Make a copy to protect from corruption
@ -14162,6 +14331,8 @@ pub const Interpreter = struct {
return error.Crash;
},
.match_guard => |mg| {
const cont_trace = tracy.traceNamed(@src(), "cont.match_guard");
defer cont_trace.end();
// Guard result is on value stack
const guard_val = value_stack.pop() orelse return error.Crash;
defer guard_val.decref(&self.runtime_layout_store, roc_ops);
@ -14205,11 +14376,15 @@ pub const Interpreter = struct {
return true;
},
.match_cleanup => |mc| {
const cont_trace = tracy.traceNamed(@src(), "cont.match_cleanup");
defer cont_trace.end();
// Result is on value stack - leave it there, just trim bindings
self.trimBindingList(&self.bindings, mc.bindings_start, roc_ops);
return true;
},
.expect_check => |ec| {
const cont_trace = tracy.traceNamed(@src(), "cont.expect_check");
defer cont_trace.end();
// Pop condition value from stack
const cond_val = value_stack.pop() orelse return error.Crash;
const succeeded = self.boolValueEquals(true, cond_val);
@ -14227,6 +14402,8 @@ pub const Interpreter = struct {
return error.Crash;
},
.dbg_print => |dp| {
const cont_trace = tracy.traceNamed(@src(), "cont.dbg_print");
defer cont_trace.end();
// Pop evaluated value from stack
const value = value_stack.pop() orelse return error.Crash;
defer value.decref(&self.runtime_layout_store, roc_ops);
@ -14242,6 +14419,8 @@ pub const Interpreter = struct {
return true;
},
.str_collect => |sc| {
const cont_trace = tracy.traceNamed(@src(), "cont.str_collect");
defer cont_trace.end();
// State machine for string interpolation:
// 1. If needs_conversion, convert top of value stack to string
// 2. If remaining segments, process next one
@ -14378,6 +14557,8 @@ pub const Interpreter = struct {
return true;
},
.call_collect_args => |cc| {
const cont_trace = tracy.traceNamed(@src(), "cont.call_collect_args");
defer cont_trace.end();
// Function call: collect arguments one by one
if (cc.remaining_args.len > 0) {
// More arguments to evaluate
@ -14400,6 +14581,8 @@ pub const Interpreter = struct {
return true;
},
.call_invoke_closure => |ci| {
const cont_trace = tracy.traceNamed(@src(), "cont.call_invoke_closure");
defer cont_trace.end();
// All arguments collected - pop them and the function, then invoke
// Stack state: [func_val, arg0, arg1, ...] (func at bottom, args on top)
var saved_rigid_subst = ci.saved_rigid_subst;
@ -14677,6 +14860,8 @@ pub const Interpreter = struct {
return error.Crash;
},
.call_cleanup => |cleanup| {
const cont_trace = tracy.traceNamed(@src(), "cont.call_cleanup");
defer cont_trace.end();
// Function body evaluated - cleanup and return result
// Check for early return
if (self.early_return_value) |return_val_in| {
@ -14761,6 +14946,8 @@ pub const Interpreter = struct {
return true;
},
.unary_op_apply => |ua| {
const cont_trace = tracy.traceNamed(@src(), "cont.unary_op_apply");
defer cont_trace.end();
// Unary operation: operand is on stack, apply method
const operand = value_stack.pop() orelse return error.Crash;
defer operand.decref(&self.runtime_layout_store, roc_ops);
@ -14873,6 +15060,8 @@ pub const Interpreter = struct {
return true;
},
.binop_eval_rhs => |be| {
const cont_trace = tracy.traceNamed(@src(), "cont.binop_eval_rhs");
defer cont_trace.end();
// Binary operation: LHS is on stack, now evaluate RHS
// We keep LHS on stack, push continuation to apply method after RHS is evaluated
try work_stack.push(.{ .apply_continuation = .{ .binop_apply = .{
@ -14888,6 +15077,8 @@ pub const Interpreter = struct {
return true;
},
.binop_apply => |ba| {
const cont_trace = tracy.traceNamed(@src(), "cont.binop_apply");
defer cont_trace.end();
// Binary operation: both operands on stack, apply method
// Stack: [lhs, rhs] - RHS on top
const rhs = value_stack.pop() orelse return error.Crash;
@ -15316,6 +15507,8 @@ pub const Interpreter = struct {
return true;
},
.dot_access_await_receiver => |da| {
const cont_trace = tracy.traceNamed(@src(), "cont.dot_access_await_receiver");
defer cont_trace.end();
// Pop the receiver from value stack (pushed by eval_expr for the receiver)
const receiver_value = value_stack.pop() orelse return error.Crash;
@ -15350,6 +15543,8 @@ pub const Interpreter = struct {
return true;
},
.dot_access_resolve => |da| {
const cont_trace = tracy.traceNamed(@src(), "cont.dot_access_resolve");
defer cont_trace.end();
// Dot access: receiver is carried in continuation to avoid value stack interleaving
const receiver_value = da.receiver_value;
@ -15761,6 +15956,8 @@ pub const Interpreter = struct {
return true;
},
.dot_access_collect_args => |dac| {
const cont_trace = tracy.traceNamed(@src(), "cont.dot_access_collect_args");
defer cont_trace.end();
// Dot access method call: collecting arguments
// Stack: [receiver, method_func, arg0, arg1, ...]
if (dac.remaining_args.len > 1) {
@ -16079,6 +16276,8 @@ pub const Interpreter = struct {
return true;
},
.type_var_dispatch_collect_args => |tvdc| {
const cont_trace = tracy.traceNamed(@src(), "cont.type_var_dispatch_collect_args");
defer cont_trace.end();
// Type var dispatch: collecting arguments
// Stack: [method_func, arg0, arg1, ...]
if (tvdc.remaining_args.len > 0) {
@ -16102,6 +16301,8 @@ pub const Interpreter = struct {
return true;
},
.type_var_dispatch_invoke => |tvdi| {
const cont_trace = tracy.traceNamed(@src(), "cont.type_var_dispatch_invoke");
defer cont_trace.end();
// Type var dispatch: all arguments collected, invoke the method
// Stack: [method_func, arg0, arg1, ...]
@ -16253,6 +16454,8 @@ pub const Interpreter = struct {
}
},
.for_iterate => |fl_in| {
const cont_trace = tracy.traceNamed(@src(), "cont.for_iterate");
defer cont_trace.end();
// For loop/expression iteration: list has been evaluated, start iterating
const list_value = value_stack.pop() orelse {
self.triggerCrash("for_iterate: value_stack empty", false, roc_ops);
@ -16357,6 +16560,8 @@ pub const Interpreter = struct {
return true;
},
.for_body_done => |fl| {
const cont_trace = tracy.traceNamed(@src(), "cont.for_body_done");
defer cont_trace.end();
// For loop/expression body completed, clean up and continue to next iteration
const body_result = value_stack.pop() orelse {
self.triggerCrash("for_body_done: value_stack empty", false, roc_ops);
@ -16426,6 +16631,8 @@ pub const Interpreter = struct {
return true;
},
.while_loop_check => |wl| {
const cont_trace = tracy.traceNamed(@src(), "cont.while_loop_check");
defer cont_trace.end();
// While loop: condition has been evaluated
const cond_value = value_stack.pop() orelse return error.Crash;
const cond_is_true = self.boolValueEquals(true, cond_value);
@ -16461,6 +16668,8 @@ pub const Interpreter = struct {
return true;
},
.while_loop_body_done => |wl| {
const cont_trace = tracy.traceNamed(@src(), "cont.while_loop_body_done");
defer cont_trace.end();
// While loop body completed, check condition again
const body_result = value_stack.pop() orelse return error.Crash;
body_result.decref(&self.runtime_layout_store, roc_ops);
@ -16484,6 +16693,8 @@ pub const Interpreter = struct {
return true;
},
.expect_check_stmt => |ec| {
const cont_trace = tracy.traceNamed(@src(), "cont.expect_check_stmt");
defer cont_trace.end();
// Expect statement: check condition result
const cond_val = value_stack.pop() orelse return error.Crash;
const is_true = self.boolValueEquals(true, cond_val);
@ -16504,6 +16715,8 @@ pub const Interpreter = struct {
return true;
},
.reassign_value => |rv| {
const cont_trace = tracy.traceNamed(@src(), "cont.reassign_value");
defer cont_trace.end();
// Reassign statement: update binding
const new_val = value_stack.pop() orelse {
self.triggerCrash("reassign_value: value_stack empty", false, roc_ops);
@ -16532,6 +16745,8 @@ pub const Interpreter = struct {
return true;
},
.dbg_print_stmt => |dp| {
const cont_trace = tracy.traceNamed(@src(), "cont.dbg_print_stmt");
defer cont_trace.end();
// Dbg statement: print value
const value = value_stack.pop() orelse return error.Crash;
defer value.decref(&self.runtime_layout_store, roc_ops);
@ -16551,6 +16766,8 @@ pub const Interpreter = struct {
return true;
},
.sort_compare_result => |sc_in| {
const cont_trace = tracy.traceNamed(@src(), "cont.sort_compare_result");
defer cont_trace.end();
var sc = sc_in;
var saved_rigid_subst = sc.saved_rigid_subst;
defer {
@ -16789,6 +17006,8 @@ pub const Interpreter = struct {
return true;
},
.negate_bool => {
const cont_trace = tracy.traceNamed(@src(), "cont.negate_bool");
defer cont_trace.end();
// Negate the boolean result on top of value stack (for != operator)
var result = value_stack.pop() orelse {
self.triggerCrash("negate_bool: expected value on stack", false, roc_ops);
@ -16801,6 +17020,8 @@ pub const Interpreter = struct {
return true;
},
.nominal_wrap => |nw| {
const cont_trace = tracy.traceNamed(@src(), "cont.nominal_wrap");
defer cont_trace.end();
// Wrap the backing expression result with the nominal type's rt_var.
// This ensures method dispatch can find methods defined on the nominal type.
var result = value_stack.pop() orelse {

View file

@ -14,6 +14,7 @@ const types = @import("types");
const collections = @import("collections");
const import_mapping_mod = types.import_mapping;
const eval = @import("eval");
const tracy = @import("tracy");
// Platform detection
const is_wasm32 = builtin.cpu.arch == .wasm32;
@ -33,8 +34,23 @@ const ipc = if (is_wasm32) struct {
};
} else @import("ipc");
// Allocator: wasm32 uses a simple arena, native uses page_allocator
const default_allocator = if (is_wasm32) wasm_allocator else std.heap.page_allocator;
// Debug allocator for native platforms (not wasm32) - provides leak detection in Debug/ReleaseSafe builds
var debug_allocator: if (is_wasm32) void else std.heap.DebugAllocator(.{}) =
if (is_wasm32) {} else .{ .backing_allocator = std.heap.c_allocator };
// Get the base allocator based on platform and build mode
fn getBaseAllocator() std.mem.Allocator {
if (is_wasm32) return wasm_allocator;
return switch (builtin.mode) {
.Debug, .ReleaseSafe => debug_allocator.allocator(),
.ReleaseFast, .ReleaseSmall => std.heap.c_allocator,
};
}
// TracyAllocator wrapping for allocation profiling
var tracy_allocator: tracy.TracyAllocator(null) = undefined;
var wrapped_allocator: std.mem.Allocator = undefined;
var allocator_initialized: bool = false;
// Wasm32 allocator - uses roc_alloc from host
const wasm_allocator = if (is_wasm32) std.mem.Allocator{
@ -73,7 +89,15 @@ extern fn roc_realloc(ptr: *anyopaque, new_size: usize, old_size: usize, alignme
extern fn roc_dealloc(ptr: *anyopaque, alignment: u32) callconv(.c) void;
// Static empty import mapping for shim (no type name resolution needed)
var shim_import_mapping = import_mapping_mod.ImportMapping.init(default_allocator);
// Lazy-initialized to use the properly wrapped allocator
var shim_import_mapping: ?import_mapping_mod.ImportMapping = null;
fn getShimImportMapping() *import_mapping_mod.ImportMapping {
if (shim_import_mapping == null) {
shim_import_mapping = import_mapping_mod.ImportMapping.init(wrapped_allocator);
}
return &shim_import_mapping.?;
}
const SharedMemoryAllocator = if (is_wasm32) struct {} else ipc.SharedMemoryAllocator;
@ -195,6 +219,9 @@ const ShimError = error{
/// Returns a RocStr to the caller
/// Expected format in shared memory: [u64 parent_address][u32 entry_count][ModuleEnv data][u32[] def_indices]
export fn roc_entrypoint(entry_idx: u32, ops: *builtins.host_abi.RocOps, ret_ptr: *anyopaque, arg_ptr: ?*anyopaque) callconv(.c) void {
const trace = tracy.trace(@src());
defer trace.end();
evaluateFromSharedMemory(entry_idx, ops, ret_ptr, arg_ptr) catch |err| {
// Only show this generic error if we haven't already crashed with a more specific message
// (errors like Crash and StackOverflow already triggered roc_crashed with details)
@ -208,6 +235,9 @@ export fn roc_entrypoint(entry_idx: u32, ops: *builtins.host_abi.RocOps, ret_ptr
/// Initialize shared memory and ModuleEnv once per process
fn initializeOnce(roc_ops: *RocOps) ShimError!void {
const trace = tracy.trace(@src());
defer trace.end();
// Fast path: if already initialized, return immediately
if (shared_memory_initialized.isSet()) return;
@ -218,7 +248,19 @@ fn initializeOnce(roc_ops: *RocOps) ShimError!void {
// Check again in case another thread initialized while we were waiting
if (shared_memory_initialized.isSet()) return;
const allocator = default_allocator;
// Set up allocator with optional TracyAllocator wrapping before any allocations
if (!allocator_initialized) {
const base_allocator = getBaseAllocator();
if (tracy.enable_allocation) {
tracy_allocator = tracy.tracyAllocator(base_allocator);
wrapped_allocator = tracy_allocator.allocator();
} else {
wrapped_allocator = base_allocator;
}
allocator_initialized = true;
}
const allocator = wrapped_allocator;
var buf: [256]u8 = undefined;
// IPC path only available on native platforms (not wasm32)
@ -276,6 +318,9 @@ fn initializeOnce(roc_ops: *RocOps) ShimError!void {
/// Cross-platform evaluation (works for both IPC and embedded modes)
fn evaluateFromSharedMemory(entry_idx: u32, roc_ops: *RocOps, ret_ptr: *anyopaque, arg_ptr: ?*anyopaque) ShimError!void {
const trace = tracy.trace(@src());
defer trace.end();
// Initialize shared memory once per process
try initializeOnce(roc_ops);
@ -346,9 +391,12 @@ const SetupResult = struct {
/// Works for both IPC mode (roc run) and embedded mode (roc build)
/// Detects portable serialized format (cross-architecture) via magic number
fn setupModuleEnv(roc_ops: *RocOps) ShimError!SetupResult {
const trace = tracy.trace(@src());
defer trace.end();
var buf: [256]u8 = undefined;
const base_ptr = roc__serialized_base_ptr.?;
const allocator = default_allocator;
const allocator = wrapped_allocator;
// Check for portable serialized format by looking at first 4 bytes
// The magic number is at the very start of the buffer (no FIRST_ALLOC_OFFSET for portable format)
@ -504,6 +552,9 @@ fn setupModuleEnv(roc_ops: *RocOps) ShimError!SetupResult {
/// Set up ModuleEnv from portable serialized format (cross-architecture builds)
/// This format uses ModuleEnv.Serialized with fixed-size types
fn setupModuleEnvFromSerialized(roc_ops: *RocOps, base_ptr: [*]align(1) u8, allocator: std.mem.Allocator) ShimError!SetupResult {
const trace = tracy.trace(@src());
defer trace.end();
var buf: [256]u8 = undefined;
// Read the serialized header (use unaligned reads since embedded data may not be aligned)
@ -616,7 +667,10 @@ fn setupModuleEnvFromSerialized(roc_ops: *RocOps, base_ptr: [*]align(1) u8, allo
/// Create and initialize interpreter with heap-allocated stable objects
fn createInterpreter(env_ptr: *ModuleEnv, app_env: ?*ModuleEnv, builtin_modules: *const eval.BuiltinModules, roc_ops: *RocOps) ShimError!Interpreter {
const allocator = default_allocator;
const trace = tracy.trace(@src());
defer trace.end();
const allocator = wrapped_allocator;
// Use builtin types from the loaded builtin modules
// This provides the actual definitions of plus, minus, times, etc.
@ -688,7 +742,7 @@ fn createInterpreter(env_ptr: *ModuleEnv, app_env: ?*ModuleEnv, builtin_modules:
};
}
var interpreter = eval.Interpreter.init(allocator, env_ptr, builtin_types, builtin_module_env, imported_envs, &shim_import_mapping, app_env) catch {
var interpreter = eval.Interpreter.init(allocator, env_ptr, builtin_types, builtin_module_env, imported_envs, getShimImportMapping(), app_env) catch {
roc_ops.crash("INTERPRETER SHIM: Interpreter initialization failed");
return error.InterpreterSetupFailed;
};

View file

@ -2,6 +2,7 @@
const std = @import("std");
const builtin = @import("builtin");
const tracy = @import("tracy");
const base = @import("base");
const types = @import("types");
const collections = @import("collections");
@ -260,6 +261,9 @@ pub const Store = struct {
field_layouts: []const Layout,
field_names: []const Ident.Idx,
) std.mem.Allocator.Error!Idx {
const trace = tracy.traceNamed(@src(), "layoutStore.putRecord");
defer trace.end();
var temp_fields = std.ArrayList(RecordField).empty;
defer temp_fields.deinit(self.env.gpa);
@ -338,6 +342,9 @@ pub const Store = struct {
/// Insert a tuple layout from concrete element layouts
pub fn putTuple(self: *Self, element_layouts: []const Layout) std.mem.Allocator.Error!Idx {
const trace = tracy.traceNamed(@src(), "layoutStore.putTuple");
defer trace.end();
// Collect fields
var temp_fields = std.ArrayList(TupleField).empty;
defer temp_fields.deinit(self.env.gpa);
@ -1765,6 +1772,9 @@ pub const Store = struct {
}
pub fn insertLayout(self: *Self, layout: Layout) std.mem.Allocator.Error!Idx {
const trace = tracy.traceNamed(@src(), "layoutStore.insertLayout");
defer trace.end();
// For scalar types, return the appropriate sentinel value instead of inserting
if (layout.tag == .scalar) {
const result = idxFromScalar(layout.data.scalar);

View file

@ -21,6 +21,7 @@ const repl = @import("repl");
const eval_mod = @import("eval");
const collections = @import("collections");
const compiled_builtins = @import("compiled_builtins");
const tracy = @import("tracy");
const Repl = repl.Repl;
const CrashContext = eval_mod.CrashContext;
@ -655,12 +656,19 @@ var debug_allocator: std.heap.DebugAllocator(.{}) = .{
/// cli entrypoint for snapshot tool
pub fn main() !void {
// Always use the debug allocator with the snapshot tool to help find allocation bugs.
const gpa = debug_allocator.allocator();
var gpa_tracy: tracy.TracyAllocator(null) = undefined;
var gpa = debug_allocator.allocator();
defer {
const mem_state = debug_allocator.deinit();
std.debug.assert(mem_state == .ok);
}
// Wrap with Tracy for allocation profiling when enabled
if (tracy.enable_allocation) {
gpa_tracy = tracy.tracyAllocator(gpa);
gpa = gpa_tracy.allocator();
}
const args = try std.process.argsAlloc(gpa);
defer std.process.argsFree(gpa, args);

View file

@ -2,6 +2,7 @@
//! Contains both Slot & Descriptor stores
const std = @import("std");
const tracy = @import("tracy");
const base = @import("base");
const collections = @import("collections");
const serialization = @import("serialization");
@ -143,6 +144,8 @@ pub const Store = struct {
/// Create a new unbound, flexible type variable without a name
/// Used in canonicalization when creating type slots
pub fn fresh(self: *Self) std.mem.Allocator.Error!Var {
const trace = tracy.traceNamed(@src(), "typesStore.fresh");
defer trace.end();
return try self.freshFromContent(Content{ .flex = Flex.init() });
}
@ -155,6 +158,8 @@ pub const Store = struct {
/// Create a new variable with the provided desc
/// Used in tests
pub fn freshFromContent(self: *Self, content: Content) std.mem.Allocator.Error!Var {
const trace = tracy.traceNamed(@src(), "typesStore.freshFromContent");
defer trace.end();
const desc_idx = try self.descs.insert(self.gpa, .{ .content = content, .rank = Rank.top_level, .mark = Mark.none });
const slot_idx = try self.slots.insert(self.gpa, .{ .root = desc_idx });
return Self.slotIdxToVar(slot_idx);
@ -468,6 +473,8 @@ pub const Store = struct {
/// Append a var to the backing list, returning the idx
pub fn appendVars(self: *Self, s: []const Var) std.mem.Allocator.Error!VarSafeList.Range {
const trace = tracy.traceNamed(@src(), "typesStore.appendVars");
defer trace.end();
return try self.vars.appendSlice(self.gpa, s);
}
@ -620,6 +627,8 @@ pub const Store = struct {
/// Given a type var, follow all redirects until finding the root descriptor
pub fn resolveVar(self: *const Self, initial_var: Var) ResolvedVarDesc {
const trace = tracy.traceNamed(@src(), "typesStore.resolveVar");
defer trace.end();
var redirected_slot_idx = Self.varToSlotIdx(initial_var);
var redirected_slot: Slot = self.slots.get(redirected_slot_idx);

View file

@ -9,7 +9,7 @@ Err(foo)??12>5*5 or 13+2<5 and 10-1>=16 or 12<=3/5
~~~
# EXPECTED
UNDEFINED VARIABLE - binop_omnibus__single__no_spaces.md:1:5:1:8
NOT IMPLEMENTED - :0:0:0:0
NOT IMPLEMENTED - binop_omnibus__single__no_spaces.md:1:1:1:13
MISSING METHOD - binop_omnibus__single__no_spaces.md:1:32:1:34
# PROBLEMS
**UNDEFINED VARIABLE**
@ -26,8 +26,15 @@ Err(foo)??12>5*5 or 13+2<5 and 10-1>=16 or 12<=3/5
**NOT IMPLEMENTED**
This feature is not yet implemented: unsupported operator
**binop_omnibus__single__no_spaces.md:1:1:1:13:**
```roc
Err(foo)??12>5*5 or 13+2<5 and 10-1>=16 or 12<=3/5
```
^^^^^^^^^^^^
This error doesn't have a proper diagnostic report yet. Let us know if you want to help improve Roc's error messages!
**MISSING METHOD**
This **from_numeral** method is being called on a value whose type doesn't have that method:
**binop_omnibus__single__no_spaces.md:1:32:1:34:**

View file

@ -9,7 +9,7 @@ Err(foo) ?? 12 > 5 * 5 or 13 + 2 < 5 and 10 - 1 >= 16 or 12 <= 3 / 5
~~~
# EXPECTED
UNDEFINED VARIABLE - binop_omnibus__singleline.md:1:5:1:8
NOT IMPLEMENTED - :0:0:0:0
NOT IMPLEMENTED - binop_omnibus__singleline.md:1:1:1:15
# PROBLEMS
**UNDEFINED VARIABLE**
Nothing is named `foo` in this scope.
@ -25,8 +25,15 @@ Err(foo) ?? 12 > 5 * 5 or 13 + 2 < 5 and 10 - 1 >= 16 or 12 <= 3 / 5
**NOT IMPLEMENTED**
This feature is not yet implemented: unsupported operator
**binop_omnibus__singleline.md:1:1:1:15:**
```roc
Err(foo) ?? 12 > 5 * 5 or 13 + 2 < 5 and 10 - 1 >= 16 or 12 <= 3 / 5
```
^^^^^^^^^^^^^^
This error doesn't have a proper diagnostic report yet. Let us know if you want to help improve Roc's error messages!
# TOKENS
~~~zig
UpperIdent,NoSpaceOpenRound,LowerIdent,CloseRound,OpDoubleQuestion,Int,OpGreaterThan,Int,OpStar,Int,OpOr,Int,OpPlus,Int,OpLessThan,Int,OpAnd,Int,OpBinaryMinus,Int,OpGreaterThanOrEq,Int,OpOr,Int,OpLessThanOrEq,Int,OpSlash,Int,

View file

@ -24,13 +24,20 @@ type=expr
)
~~~
# EXPECTED
NOT IMPLEMENTED - :0:0:0:0
NOT IMPLEMENTED - binops.md:16:5:16:14
# PROBLEMS
**NOT IMPLEMENTED**
This feature is not yet implemented: unsupported operator
**binops.md:16:5:16:14:**
```roc
None ?? 0,
```
^^^^^^^^^
This error doesn't have a proper diagnostic report yet. Let us know if you want to help improve Roc's error messages!
# TOKENS
~~~zig
OpenRound,

View file

@ -9,7 +9,7 @@ get_name!({}) ?? "Bob"
~~~
# EXPECTED
UNDEFINED VARIABLE - double_question_binop.md:1:1:1:10
NOT IMPLEMENTED - :0:0:0:0
NOT IMPLEMENTED - double_question_binop.md:1:1:1:23
# PROBLEMS
**UNDEFINED VARIABLE**
Nothing is named `get_name!` in this scope.
@ -25,8 +25,15 @@ get_name!({}) ?? "Bob"
**NOT IMPLEMENTED**
This feature is not yet implemented: unsupported operator
**double_question_binop.md:1:1:1:23:**
```roc
get_name!({}) ?? "Bob"
```
^^^^^^^^^^^^^^^^^^^^^^
This error doesn't have a proper diagnostic report yet. Let us know if you want to help improve Roc's error messages!
# TOKENS
~~~zig
LowerIdent,NoSpaceOpenRound,OpenCurly,CloseCurly,CloseRound,OpDoubleQuestion,StringStart,StringPart,StringEnd,

View file

@ -174,7 +174,7 @@ UNDEFINED VARIABLE - fuzz_crash_019.md:100:11:100:14
UNDEFINED VARIABLE - fuzz_crash_019.md:102:4:102:6
UNDEFINED VARIABLE - fuzz_crash_019.md:102:8:102:13
UNDEFINED VARIABLE - fuzz_crash_019.md:105:2:105:3
NOT IMPLEMENTED - :0:0:0:0
NOT IMPLEMENTED - fuzz_crash_019.md:105:2:105:8
UNDEFINED VARIABLE - fuzz_crash_019.md:105:55:105:59
UNDEFINED VARIABLE - fuzz_crash_019.md:105:60:105:64
UNDEFINED VARIABLE - fuzz_crash_019.md:108:4:108:5
@ -726,8 +726,15 @@ Is there an `import` or `exposing` missing up-top?
**NOT IMPLEMENTED**
This feature is not yet implemented: unsupported operator
**fuzz_crash_019.md:105:2:105:8:**
```roc
b?? 12 > 5 or 13 + 2 < 5 and 10 - 1 >= 16 or 12 <= 3 e_fn(arg1)?.od()?.ned()?.recd?
```
^^^^^^
This error doesn't have a proper diagnostic report yet. Let us know if you want to help improve Roc's error messages!
**UNDEFINED VARIABLE**
Nothing is named `e_fn` in this scope.
Is there an `import` or `exposing` missing up-top?

View file

@ -175,7 +175,7 @@ UNDEFINED VARIABLE - fuzz_crash_020.md:100:11:100:14
UNDEFINED VARIABLE - fuzz_crash_020.md:102:4:102:6
UNDEFINED VARIABLE - fuzz_crash_020.md:102:8:102:13
UNDEFINED VARIABLE - fuzz_crash_020.md:105:2:105:3
NOT IMPLEMENTED - :0:0:0:0
NOT IMPLEMENTED - fuzz_crash_020.md:105:2:105:8
UNDEFINED VARIABLE - fuzz_crash_020.md:105:55:105:59
UNDEFINED VARIABLE - fuzz_crash_020.md:105:60:105:64
UNDEFINED VARIABLE - fuzz_crash_020.md:108:4:108:5
@ -737,8 +737,15 @@ Is there an `import` or `exposing` missing up-top?
**NOT IMPLEMENTED**
This feature is not yet implemented: unsupported operator
**fuzz_crash_020.md:105:2:105:8:**
```roc
b?? 12 > 5 or 13 + 2 < 5 and 10 - 1 >= 16 or 12 <= 3 e_fn(arg1)?.od()?.ned()?.recd?
```
^^^^^^
This error doesn't have a proper diagnostic report yet. Let us know if you want to help improve Roc's error messages!
**UNDEFINED VARIABLE**
Nothing is named `e_fn` in this scope.
Is there an `import` or `exposing` missing up-top?

View file

@ -229,22 +229,22 @@ UNDECLARED TYPE - fuzz_crash_023.md:45:8:45:10
UNDECLARED TYPE - fuzz_crash_023.md:46:8:46:17
UNDECLARED TYPE - fuzz_crash_023.md:52:4:52:6
UNDECLARED TYPE - fuzz_crash_023.md:53:8:53:17
NOT IMPLEMENTED - :0:0:0:0
NOT IMPLEMENTED - fuzz_crash_023.md:6:1:12:4
MODULE NOT FOUND - fuzz_crash_023.md:16:1:16:27
MODULE NOT FOUND - fuzz_crash_023.md:17:1:20:20
UNDEFINED VARIABLE - fuzz_crash_023.md:72:4:72:13
UNUSED VARIABLE - fuzz_crash_023.md:97:3:97:8
UNUSED VARIABLE - fuzz_crash_023.md:1:1:1:1
NOT IMPLEMENTED - :0:0:0:0
NOT IMPLEMENTED - fuzz_crash_023.md:108:7:108:12
UNUSED VARIABLE - fuzz_crash_023.md:1:1:1:1
NOT IMPLEMENTED - :0:0:0:0
NOT IMPLEMENTED - fuzz_crash_023.md:111:4:111:9
UNUSED VARIABLE - fuzz_crash_023.md:1:1:1:1
NOT IMPLEMENTED - :0:0:0:0
NOT IMPLEMENTED - fuzz_crash_023.md:120:7:120:12
UNDEFINED VARIABLE - fuzz_crash_023.md:121:37:121:40
UNUSED VARIABLE - fuzz_crash_023.md:121:21:121:27
UNUSED VARIABLE - fuzz_crash_023.md:127:4:128:9
NOT IMPLEMENTED - :0:0:0:0
NOT IMPLEMENTED - :0:0:0:0
NOT IMPLEMENTED - fuzz_crash_023.md:130:18:130:23
NOT IMPLEMENTED - fuzz_crash_023.md:133:9:133:14
UNUSED VARIABLE - fuzz_crash_023.md:82:2:82:3
UNDEFINED VARIABLE - fuzz_crash_023.md:141:2:141:6
UNDECLARED TYPE - fuzz_crash_023.md:143:14:143:20
@ -259,7 +259,7 @@ UNDEFINED VARIABLE - fuzz_crash_023.md:179:42:179:48
UNDEFINED VARIABLE - fuzz_crash_023.md:183:3:183:7
UNDEFINED VARIABLE - fuzz_crash_023.md:185:4:185:10
UNDEFINED VARIABLE - fuzz_crash_023.md:188:22:188:25
NOT IMPLEMENTED - :0:0:0:0
NOT IMPLEMENTED - fuzz_crash_023.md:188:18:188:32
UNDEFINED VARIABLE - fuzz_crash_023.md:189:26:189:33
UNDEFINED VARIABLE - fuzz_crash_023.md:189:34:189:38
UNDEFINED VARIABLE - fuzz_crash_023.md:190:2:190:14
@ -449,8 +449,20 @@ This type is referenced here:
**NOT IMPLEMENTED**
This feature is not yet implemented: malformed import module name contains invalid control characters
**fuzz_crash_023.md:6:1:12:4:**
```roc
import # Comment after import keyword
pf # Comment after qualifier
.StdoutMultiline # Comment after ident
exposing [ # Comment after exposing open
line!, # Comment after exposed item
write!, # Another after exposed item
] # Comment after exposing close
```
This error doesn't have a proper diagnostic report yet. Let us know if you want to help improve Roc's error messages!
**MODULE NOT FOUND**
The module `BadName` was not found in this Roc project.
@ -513,8 +525,15 @@ The unused variable is declared here:
**NOT IMPLEMENTED**
This feature is not yet implemented: alternatives pattern outside match expression
**fuzz_crash_023.md:108:7:108:12:**
```roc
[1, 2 | 5, 3, .. as rest] => 123
```
^^^^^
This error doesn't have a proper diagnostic report yet. Let us know if you want to help improve Roc's error messages!
**UNUSED VARIABLE**
Variable `rest` is not used anywhere in your code.
@ -530,8 +549,15 @@ The unused variable is declared here:
**NOT IMPLEMENTED**
This feature is not yet implemented: alternatives pattern outside match expression
**fuzz_crash_023.md:111:4:111:9:**
```roc
2 | 5,
```
^^^^^
This error doesn't have a proper diagnostic report yet. Let us know if you want to help improve Roc's error messages!
**UNUSED VARIABLE**
Variable `rest` is not used anywhere in your code.
@ -547,8 +573,15 @@ The unused variable is declared here:
**NOT IMPLEMENTED**
This feature is not yet implemented: alternatives pattern outside match expression
**fuzz_crash_023.md:120:7:120:12:**
```roc
(1, 2 | 5, 3) => 123
```
^^^^^
This error doesn't have a proper diagnostic report yet. Let us know if you want to help improve Roc's error messages!
**UNDEFINED VARIABLE**
Nothing is named `add` in this scope.
Is there an `import` or `exposing` missing up-top?
@ -587,13 +620,27 @@ The unused variable is declared here:
**NOT IMPLEMENTED**
This feature is not yet implemented: alternatives pattern outside match expression
**fuzz_crash_023.md:130:18:130:23:**
```roc
{ foo: 1, bar: 2 | 7 } => 12
```
^^^^^
This error doesn't have a proper diagnostic report yet. Let us know if you want to help improve Roc's error messages!
**NOT IMPLEMENTED**
This feature is not yet implemented: alternatives pattern outside match expression
**fuzz_crash_023.md:133:9:133:14:**
```roc
bar: 2 | 7, # After last record field
```
^^^^^
This error doesn't have a proper diagnostic report yet. Let us know if you want to help improve Roc's error messages!
**UNUSED VARIABLE**
Variable `b` is not used anywhere in your code.
@ -751,8 +798,15 @@ Is there an `import` or `exposing` missing up-top?
**NOT IMPLEMENTED**
This feature is not yet implemented: unsupported operator
**fuzz_crash_023.md:188:18:188:32:**
```roc
bin_op_result = Err(foo) ?? 12 > 5 * 5 or 13 + 2 < 5 and 10 - 1 >= 16 or 12 <= 3 / 5
```
^^^^^^^^^^^^^^
This error doesn't have a proper diagnostic report yet. Let us know if you want to help improve Roc's error messages!
**UNDEFINED VARIABLE**
Nothing is named `some_fn` in this scope.
Is there an `import` or `exposing` missing up-top?

View file

@ -193,14 +193,14 @@ UNDEFINED VARIABLE - fuzz_crash_027.md:65:6:65:7
UNUSED VARIABLE - fuzz_crash_027.md:64:11:64:14
UNDEFINED VARIABLE - fuzz_crash_027.md:71:7:71:11
UNUSED VARIABLE - fuzz_crash_027.md:1:1:1:1
NOT IMPLEMENTED - :0:0:0:0
NOT IMPLEMENTED - fuzz_crash_027.md:74:7:74:12
UNUSED VARIABLE - fuzz_crash_027.md:1:1:1:1
UNUSED VARIABLE - fuzz_crash_027.md:76:1:76:4
NOT IMPLEMENTED - :0:0:0:0
NOT IMPLEMENTED - fuzz_crash_027.md:81:7:81:12
UNDEFINED VARIABLE - fuzz_crash_027.md:82:37:82:40
UNUSED VARIABLE - fuzz_crash_027.md:82:21:82:27
NOT IMPLEMENTED - :0:0:0:0
NOT IMPLEMENTED - :0:0:0:0
NOT IMPLEMENTED - fuzz_crash_027.md:88:4:88:6
NOT IMPLEMENTED - fuzz_crash_027.md:89:18:89:23
UNUSED VARIABLE - fuzz_crash_027.md:62:2:62:3
UNDEFINED VARIABLE - fuzz_crash_027.md:97:2:97:6
UNDECLARED TYPE - fuzz_crash_027.md:99:14:99:20
@ -212,7 +212,7 @@ UNDEFINED VARIABLE - fuzz_crash_027.md:132:42:132:48
UNDEFINED VARIABLE - fuzz_crash_027.md:136:3:136:7
UNDEFINED VARIABLE - fuzz_crash_027.md:138:4:138:10
UNDEFINED VARIABLE - fuzz_crash_027.md:141:14:141:17
NOT IMPLEMENTED - :0:0:0:0
NOT IMPLEMENTED - fuzz_crash_027.md:141:10:141:24
UNDEFINED VARIABLE - fuzz_crash_027.md:142:10:142:17
UNDEFINED VARIABLE - fuzz_crash_027.md:142:18:142:22
DOES NOT EXIST - fuzz_crash_027.md:145:4:145:13
@ -544,8 +544,15 @@ The unused variable is declared here:
**NOT IMPLEMENTED**
This feature is not yet implemented: alternatives pattern outside match expression
**fuzz_crash_027.md:74:7:74:12:**
```roc
[1, 2 | 5, 3, .. as rest] => 123
```
^^^^^
This error doesn't have a proper diagnostic report yet. Let us know if you want to help improve Roc's error messages!
**UNUSED VARIABLE**
Variable `rest` is not used anywhere in your code.
@ -573,8 +580,15 @@ ist
**NOT IMPLEMENTED**
This feature is not yet implemented: alternatives pattern outside match expression
**fuzz_crash_027.md:81:7:81:12:**
```roc
(1, 2 | 5, 3) => 123
```
^^^^^
This error doesn't have a proper diagnostic report yet. Let us know if you want to help improve Roc's error messages!
**UNDEFINED VARIABLE**
Nothing is named `add` in this scope.
Is there an `import` or `exposing` missing up-top?
@ -601,13 +615,27 @@ The unused variable is declared here:
**NOT IMPLEMENTED**
This feature is not yet implemented: report an error when unable to resolve field identifier
**fuzz_crash_027.md:88:4:88:6:**
```roc
..} => 12
```
^^
This error doesn't have a proper diagnostic report yet. Let us know if you want to help improve Roc's error messages!
**NOT IMPLEMENTED**
This feature is not yet implemented: alternatives pattern outside match expression
**fuzz_crash_027.md:89:18:89:23:**
```roc
{ foo: 1, bar: 2 | 7 } => 12
```
^^^^^
This error doesn't have a proper diagnostic report yet. Let us know if you want to help improve Roc's error messages!
**UNUSED VARIABLE**
Variable `b` is not used anywhere in your code.
@ -733,8 +761,15 @@ Is there an `import` or `exposing` missing up-top?
**NOT IMPLEMENTED**
This feature is not yet implemented: unsupported operator
**fuzz_crash_027.md:141:10:141:24:**
```roc
bsult = Err(foo) ?? 12 > 5 * 5 or 13 + 2 < 5 and 10 - 1 >= 16 or 12 <= 3 / 5
```
^^^^^^^^^^^^^^
This error doesn't have a proper diagnostic report yet. Let us know if you want to help improve Roc's error messages!
**UNDEFINED VARIABLE**
Nothing is named `some_fn` in this scope.
Is there an `import` or `exposing` missing up-top?

View file

@ -224,22 +224,22 @@ UNDECLARED TYPE - syntax_grab_bag.md:45:8:45:10
UNDECLARED TYPE - syntax_grab_bag.md:46:8:46:17
UNDECLARED TYPE - syntax_grab_bag.md:52:4:52:6
UNDECLARED TYPE - syntax_grab_bag.md:53:8:53:17
NOT IMPLEMENTED - :0:0:0:0
NOT IMPLEMENTED - syntax_grab_bag.md:6:1:12:4
MODULE NOT FOUND - syntax_grab_bag.md:16:1:16:27
MODULE NOT FOUND - syntax_grab_bag.md:17:1:20:20
UNDEFINED VARIABLE - syntax_grab_bag.md:72:4:72:13
UNUSED VARIABLE - syntax_grab_bag.md:97:3:97:8
UNUSED VARIABLE - syntax_grab_bag.md:1:1:1:1
NOT IMPLEMENTED - :0:0:0:0
NOT IMPLEMENTED - syntax_grab_bag.md:108:7:108:12
UNUSED VARIABLE - syntax_grab_bag.md:1:1:1:1
NOT IMPLEMENTED - :0:0:0:0
NOT IMPLEMENTED - syntax_grab_bag.md:111:4:111:9
UNUSED VARIABLE - syntax_grab_bag.md:1:1:1:1
NOT IMPLEMENTED - :0:0:0:0
NOT IMPLEMENTED - syntax_grab_bag.md:120:7:120:12
UNDEFINED VARIABLE - syntax_grab_bag.md:121:37:121:40
UNUSED VARIABLE - syntax_grab_bag.md:121:21:121:27
UNUSED VARIABLE - syntax_grab_bag.md:127:4:128:9
NOT IMPLEMENTED - :0:0:0:0
NOT IMPLEMENTED - :0:0:0:0
NOT IMPLEMENTED - syntax_grab_bag.md:130:18:130:23
NOT IMPLEMENTED - syntax_grab_bag.md:133:9:133:14
UNUSED VARIABLE - syntax_grab_bag.md:82:2:82:3
UNDEFINED VARIABLE - syntax_grab_bag.md:141:2:141:6
UNDECLARED TYPE - syntax_grab_bag.md:143:14:143:20
@ -251,7 +251,7 @@ UNDEFINED VARIABLE - syntax_grab_bag.md:179:42:179:48
UNDEFINED VARIABLE - syntax_grab_bag.md:183:3:183:7
UNDEFINED VARIABLE - syntax_grab_bag.md:185:4:185:10
UNDEFINED VARIABLE - syntax_grab_bag.md:188:22:188:25
NOT IMPLEMENTED - :0:0:0:0
NOT IMPLEMENTED - syntax_grab_bag.md:188:18:188:32
UNDEFINED VARIABLE - syntax_grab_bag.md:189:26:189:33
UNDEFINED VARIABLE - syntax_grab_bag.md:189:34:189:38
UNDEFINED VARIABLE - syntax_grab_bag.md:190:2:190:14
@ -384,8 +384,20 @@ This type is referenced here:
**NOT IMPLEMENTED**
This feature is not yet implemented: malformed import module name contains invalid control characters
**syntax_grab_bag.md:6:1:12:4:**
```roc
import # Comment after import keyword
pf # Comment after qualifier
.StdoutMultiline # Comment after ident
exposing [ # Comment after exposing open
line!, # Comment after exposed item
write!, # Another after exposed item
] # Comment after exposing close
```
This error doesn't have a proper diagnostic report yet. Let us know if you want to help improve Roc's error messages!
**MODULE NOT FOUND**
The module `BadName` was not found in this Roc project.
@ -448,8 +460,15 @@ The unused variable is declared here:
**NOT IMPLEMENTED**
This feature is not yet implemented: alternatives pattern outside match expression
**syntax_grab_bag.md:108:7:108:12:**
```roc
[1, 2 | 5, 3, .. as rest] => 123
```
^^^^^
This error doesn't have a proper diagnostic report yet. Let us know if you want to help improve Roc's error messages!
**UNUSED VARIABLE**
Variable `rest` is not used anywhere in your code.
@ -465,8 +484,15 @@ The unused variable is declared here:
**NOT IMPLEMENTED**
This feature is not yet implemented: alternatives pattern outside match expression
**syntax_grab_bag.md:111:4:111:9:**
```roc
2 | 5,
```
^^^^^
This error doesn't have a proper diagnostic report yet. Let us know if you want to help improve Roc's error messages!
**UNUSED VARIABLE**
Variable `rest` is not used anywhere in your code.
@ -482,8 +508,15 @@ The unused variable is declared here:
**NOT IMPLEMENTED**
This feature is not yet implemented: alternatives pattern outside match expression
**syntax_grab_bag.md:120:7:120:12:**
```roc
(1, 2 | 5, 3) => 123
```
^^^^^
This error doesn't have a proper diagnostic report yet. Let us know if you want to help improve Roc's error messages!
**UNDEFINED VARIABLE**
Nothing is named `add` in this scope.
Is there an `import` or `exposing` missing up-top?
@ -522,13 +555,27 @@ The unused variable is declared here:
**NOT IMPLEMENTED**
This feature is not yet implemented: alternatives pattern outside match expression
**syntax_grab_bag.md:130:18:130:23:**
```roc
{ foo: 1, bar: 2 | 7 } => 12
```
^^^^^
This error doesn't have a proper diagnostic report yet. Let us know if you want to help improve Roc's error messages!
**NOT IMPLEMENTED**
This feature is not yet implemented: alternatives pattern outside match expression
**syntax_grab_bag.md:133:9:133:14:**
```roc
bar: 2 | 7, # After last record field
```
^^^^^
This error doesn't have a proper diagnostic report yet. Let us know if you want to help improve Roc's error messages!
**UNUSED VARIABLE**
Variable `b` is not used anywhere in your code.
@ -654,8 +701,15 @@ Is there an `import` or `exposing` missing up-top?
**NOT IMPLEMENTED**
This feature is not yet implemented: unsupported operator
**syntax_grab_bag.md:188:18:188:32:**
```roc
bin_op_result = Err(foo) ?? 12 > 5 * 5 or 13 + 2 < 5 and 10 - 1 >= 16 or 12 <= 3 / 5
```
^^^^^^^^^^^^^^
This error doesn't have a proper diagnostic report yet. Let us know if you want to help improve Roc's error messages!
**UNDEFINED VARIABLE**
Nothing is named `some_fn` in this scope.
Is there an `import` or `exposing` missing up-top?