mirror of
https://github.com/roc-lang/roc.git
synced 2025-12-23 08:48:03 +00:00
Merge remote-tracking branch 'remote/main' into implement-box
This commit is contained in:
commit
79c0cbb04b
23 changed files with 675 additions and 63 deletions
80
build.zig
80
build.zig
|
|
@ -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(©_step.step);
|
||||
}
|
||||
|
|
@ -1192,6 +1203,8 @@ fn setupTestPlatforms(
|
|||
cross_target.name,
|
||||
optimize,
|
||||
roc_modules,
|
||||
strip,
|
||||
omit_frame_pointer,
|
||||
);
|
||||
clear_cache_step.dependOn(©_step.step);
|
||||
}
|
||||
|
|
@ -1207,6 +1220,8 @@ fn setupTestPlatforms(
|
|||
"wasm32",
|
||||
optimize,
|
||||
roc_modules,
|
||||
strip,
|
||||
omit_frame_pointer,
|
||||
);
|
||||
clear_cache_step.dependOn(©_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(©_step.step);
|
||||
}
|
||||
|
|
@ -2042,6 +2085,8 @@ fn addMainExe(
|
|||
cross_target.name,
|
||||
optimize,
|
||||
roc_modules,
|
||||
strip,
|
||||
omit_frame_pointer,
|
||||
);
|
||||
b.getInstallStep().dependOn(©_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(©_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,
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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 },
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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: {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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:**
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
|
|
@ -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?
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue