mirror of
https://github.com/roc-lang/roc.git
synced 2025-12-23 08:48:03 +00:00
Document literal rendering improvements
This commit is contained in:
parent
b92b3eed08
commit
0acbcdb94f
4 changed files with 138 additions and 39 deletions
17
PROGRESS.md
17
PROGRESS.md
|
|
@ -49,14 +49,19 @@
|
|||
The goal is not full semantics yet, but enough to run end‑to‑end Roc tests and exercise the type‑carrying pieces.
|
||||
|
||||
- Implemented expressions:
|
||||
- Strings: `e_str`, `e_str_segment` (create `RocStr` with `RocOps`), REPL‑style string rendering.
|
||||
- Integers: `e_int`, and `e_binop` with `+` (reads/writes using runtime‑chosen layout), REPL‑style integer
|
||||
- Strings: `e_str`, `e_str_segment` (create `RocStr` with `RocOps`), REPL-style string rendering.
|
||||
- Integers: `e_int`, and `e_binop` with `+` (reads/writes using runtime-chosen layout), REPL-style integer
|
||||
rendering.
|
||||
- Floats & decimals: `e_frac_f32`, `e_frac_f64`, `e_frac_dec`, `e_dec_small` evaluate and render (`3.25f64`
|
||||
→ `3.25`, `0.125` → `0.125`).
|
||||
- Tuples: `e_tuple` (allocate and fill via layout store accessors), REPL‑style rendering `(a, b, ...)`.
|
||||
- Records: `e_record` (allocate and fill by field name via accessor), REPL‑style rendering `{ x: 1, y: 2 }`.
|
||||
- Lambdas: `e_lambda` as minimal placeholder; `e_call` supports a one‑arg lambda by binding the parameter to the
|
||||
- Records: `e_record` (allocate and fill by field name via accessor), REPL-style rendering `{ x: 1, y: 2 }`.
|
||||
- Empty record literal `e_empty_record` and expect-success unit result `{}` (zero-sized values stay purely logical).
|
||||
- Lambdas: `e_lambda` as minimal placeholder; `e_call` supports a one-arg lambda by binding the parameter to the
|
||||
evaluated argument and evaluating the body; `e_lookup_local` finds values in a simple binding stack.
|
||||
- Nominal wrappers: `e_nominal` / `e_nominal_external` delegate evaluation to the backing expression.
|
||||
- Crash & expect: `e_crash`, `s_crash`, and `e_expect`/`s_expect` invoke `roc_crashed`/`roc_expect_failed`, stash
|
||||
crash messages, and surface deterministic Roc-style error strings.
|
||||
|
||||
- Not implemented in minimal path (intentionally deferred): booleans, `if`, `match` tag destructuring, guards, tag
|
||||
unions, lists, boxes, effects, and most operators. (See Roadmap.)
|
||||
|
|
@ -72,11 +77,13 @@
|
|||
### 7) Roc‑syntax tests (begin/end with Roc code)
|
||||
- New file: `src/eval/test/interpreter2_style_test.zig`.
|
||||
- Tests parse and canonicalize with early failure (using helpers) to surface syntax or type issues immediately.
|
||||
- Tests then exercise Interpreter2 minimal eval and assert on REPL‑style rendered results for readability:
|
||||
- Tests then exercise Interpreter2 minimal eval and assert on REPL-style rendered results for readability:
|
||||
- `(|x| x)("Hello")` → `"Hello"`
|
||||
- `(|n| n + 1)(41)` → `42`
|
||||
- `(1, 2)` → `(1, 2)`
|
||||
- `{ x: 1, y: 2 }` → `{ x: 1, y: 2 }`
|
||||
- `0.125` → `0.125`, `3.25f64` → `3.25`
|
||||
- `expect 1 == 1` → `{}` while failures crash with trimmed `Expect failed: …` messages.
|
||||
|
||||
## Design Summary
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@ const std = @import("std");
|
|||
const types = @import("types");
|
||||
const can = @import("can");
|
||||
const layout = @import("layout");
|
||||
const builtins = @import("builtins");
|
||||
const StackValue = @import("StackValue.zig");
|
||||
const RocDec = builtins.dec.RocDec;
|
||||
|
||||
pub const RenderCtx = struct {
|
||||
allocator: std.mem.Allocator,
|
||||
|
|
@ -133,21 +135,18 @@ pub fn renderValueRocWithType(ctx: *RenderCtx, value: StackValue, rt_var: types.
|
|||
pub fn renderValueRoc(ctx: *RenderCtx, value: StackValue) ![]u8 {
|
||||
const gpa = ctx.allocator;
|
||||
if (value.layout.tag == .scalar) {
|
||||
switch (value.layout.data.scalar.tag) {
|
||||
const scalar = value.layout.data.scalar;
|
||||
switch (scalar.tag) {
|
||||
.str => {
|
||||
const rs: *const @import("builtins").str.RocStr = @ptrCast(@alignCast(value.ptr.?));
|
||||
const rs: *const builtins.str.RocStr = @ptrCast(@alignCast(value.ptr.?));
|
||||
const s = rs.asSlice();
|
||||
var buf = std.ArrayList(u8).init(gpa);
|
||||
errdefer buf.deinit();
|
||||
try buf.append('"');
|
||||
for (s) |ch| {
|
||||
switch (ch) {
|
||||
'\\' => {
|
||||
try buf.appendSlice("\\\\");
|
||||
},
|
||||
'"' => {
|
||||
try buf.appendSlice("\\\"");
|
||||
},
|
||||
'\\' => try buf.appendSlice("\\\\"),
|
||||
'"' => try buf.appendSlice("\\\""),
|
||||
else => try buf.append(ch),
|
||||
}
|
||||
}
|
||||
|
|
@ -158,6 +157,23 @@ pub fn renderValueRoc(ctx: *RenderCtx, value: StackValue) ![]u8 {
|
|||
const i = value.asI128();
|
||||
return try std.fmt.allocPrint(gpa, "{d}", .{i});
|
||||
},
|
||||
.frac => {
|
||||
std.debug.assert(value.ptr != null);
|
||||
return switch (scalar.data.frac) {
|
||||
.f32 => {
|
||||
const ptr = @as(*const f32, @ptrCast(@alignCast(value.ptr.?)));
|
||||
return try std.fmt.allocPrint(gpa, "{d}", .{@as(f64, ptr.*)});
|
||||
},
|
||||
.f64 => {
|
||||
const ptr = @as(*const f64, @ptrCast(@alignCast(value.ptr.?)));
|
||||
return try std.fmt.allocPrint(gpa, "{d}", .{ptr.*});
|
||||
},
|
||||
.dec => {
|
||||
const ptr = @as(*const RocDec, @ptrCast(@alignCast(value.ptr.?)));
|
||||
return try renderDecimal(gpa, ptr.*);
|
||||
},
|
||||
};
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
|
@ -181,8 +197,12 @@ pub fn renderValueRoc(ctx: *RenderCtx, value: StackValue) ![]u8 {
|
|||
if (value.layout.tag == .record) {
|
||||
var out = std.ArrayList(u8).init(gpa);
|
||||
errdefer out.deinit();
|
||||
try out.appendSlice("{ ");
|
||||
const rec_data = ctx.layout_store.getRecordData(value.layout.data.record.idx);
|
||||
if (rec_data.fields.count == 0) {
|
||||
try out.appendSlice("{}");
|
||||
return out.toOwnedSlice();
|
||||
}
|
||||
try out.appendSlice("{ ");
|
||||
const fields = ctx.layout_store.record_fields.sliceRange(rec_data.getFields());
|
||||
var i: usize = 0;
|
||||
while (i < fields.len) : (i += 1) {
|
||||
|
|
@ -205,3 +225,50 @@ pub fn renderValueRoc(ctx: *RenderCtx, value: StackValue) ![]u8 {
|
|||
}
|
||||
return try std.fmt.allocPrint(gpa, "<unsupported>", .{});
|
||||
}
|
||||
|
||||
fn renderDecimal(gpa: std.mem.Allocator, dec: RocDec) ![]u8 {
|
||||
if (dec.num == 0) {
|
||||
return try gpa.dupe(u8, "0.0");
|
||||
}
|
||||
|
||||
var out = std.ArrayList(u8).init(gpa);
|
||||
errdefer out.deinit();
|
||||
|
||||
var num = dec.num;
|
||||
if (num < 0) {
|
||||
try out.append('-');
|
||||
num = -num;
|
||||
}
|
||||
|
||||
const one = RocDec.one_point_zero_i128;
|
||||
const integer_part = @divTrunc(num, one);
|
||||
const fractional_part = @rem(num, one);
|
||||
|
||||
try std.fmt.format(out.writer(), "{d}", .{integer_part});
|
||||
|
||||
if (fractional_part == 0) {
|
||||
try out.writer().writeAll(".0");
|
||||
return out.toOwnedSlice();
|
||||
}
|
||||
|
||||
try out.writer().writeByte('.');
|
||||
|
||||
const decimal_places: usize = @as(usize, RocDec.decimal_places);
|
||||
var digits: [decimal_places]u8 = undefined;
|
||||
@memset(digits[0..], '0');
|
||||
var remaining = fractional_part;
|
||||
var idx: usize = decimal_places;
|
||||
while (idx > 0) : (idx -= 1) {
|
||||
const digit: u8 = @intCast(@mod(remaining, 10));
|
||||
digits[idx - 1] = digit + '0';
|
||||
remaining = @divTrunc(remaining, 10);
|
||||
}
|
||||
|
||||
var end: usize = decimal_places;
|
||||
while (end > 1 and digits[end - 1] == '0') {
|
||||
end -= 1;
|
||||
}
|
||||
|
||||
try out.writer().writeAll(digits[0..end]);
|
||||
return out.toOwnedSlice();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,10 +65,9 @@ fn testRocCrashed(crashed_args: *const RocCrashed, _: *anyopaque) callconv(.C) v
|
|||
@panic("Roc crashed");
|
||||
}
|
||||
|
||||
fn makeOps(alloc: std.mem.Allocator) RocOps {
|
||||
var host = TestHost{ .allocator = alloc };
|
||||
fn makeOps(host: *TestHost) RocOps {
|
||||
return RocOps{
|
||||
.env = @ptrCast(&host),
|
||||
.env = @ptrCast(host),
|
||||
.roc_alloc = testRocAlloc,
|
||||
.roc_dealloc = testRocDealloc,
|
||||
.roc_realloc = testRocRealloc,
|
||||
|
|
@ -90,7 +89,8 @@ test "interpreter2 poly: return a function then call (int)" {
|
|||
var interp2 = try Interpreter2.init(std.testing.allocator, resources.module_env);
|
||||
defer interp2.deinit();
|
||||
|
||||
var ops = makeOps(std.testing.allocator);
|
||||
var host = TestHost{ .allocator = std.testing.allocator };
|
||||
var ops = makeOps(&host);
|
||||
const result = try interp2.evalMinimal(resources.expr_idx, &ops);
|
||||
const ct_var_ok = can.ModuleEnv.varFrom(resources.expr_idx);
|
||||
const rt_var_ok = try interp2.translateTypeVar(resources.module_env, ct_var_ok);
|
||||
|
|
@ -110,7 +110,8 @@ test "interpreter2 poly: return a function then call (string)" {
|
|||
var interp2 = try Interpreter2.init(std.testing.allocator, resources.module_env);
|
||||
defer interp2.deinit();
|
||||
|
||||
var ops = makeOps(std.testing.allocator);
|
||||
var host = TestHost{ .allocator = std.testing.allocator };
|
||||
var ops = makeOps(&host);
|
||||
const result = try interp2.evalMinimal(resources.expr_idx, &ops);
|
||||
const ct_var_point = can.ModuleEnv.varFrom(resources.expr_idx);
|
||||
const rt_var_point = try interp2.translateTypeVar(resources.module_env, ct_var_point);
|
||||
|
|
@ -133,7 +134,8 @@ test "interpreter2 captures (monomorphic): adder" {
|
|||
var interp2 = try Interpreter2.init(std.testing.allocator, resources.module_env);
|
||||
defer interp2.deinit();
|
||||
|
||||
var ops = makeOps(std.testing.allocator);
|
||||
var host = TestHost{ .allocator = std.testing.allocator };
|
||||
var ops = makeOps(&host);
|
||||
const result = try interp2.evalMinimal(resources.expr_idx, &ops);
|
||||
const ct_var_ok = can.ModuleEnv.varFrom(resources.expr_idx);
|
||||
const rt_var_ok = try interp2.translateTypeVar(resources.module_env, ct_var_ok);
|
||||
|
|
@ -153,7 +155,8 @@ test "interpreter2 captures (monomorphic): constant function" {
|
|||
var interp2 = try Interpreter2.init(std.testing.allocator, resources.module_env);
|
||||
defer interp2.deinit();
|
||||
|
||||
var ops = makeOps(std.testing.allocator);
|
||||
var host = TestHost{ .allocator = std.testing.allocator };
|
||||
var ops = makeOps(&host);
|
||||
const result = try interp2.evalMinimal(resources.expr_idx, &ops);
|
||||
const ct_var_point = can.ModuleEnv.varFrom(resources.expr_idx);
|
||||
const rt_var_point = try interp2.translateTypeVar(resources.module_env, ct_var_point);
|
||||
|
|
@ -176,7 +179,8 @@ test "interpreter2 captures (polymorphic): capture id and apply to int" {
|
|||
var interp2 = try Interpreter2.init(std.testing.allocator, resources.module_env);
|
||||
defer interp2.deinit();
|
||||
|
||||
var ops = makeOps(std.testing.allocator);
|
||||
var host = TestHost{ .allocator = std.testing.allocator };
|
||||
var ops = makeOps(&host);
|
||||
const result = try interp2.evalMinimal(resources.expr_idx, &ops);
|
||||
const ct_var_ok = can.ModuleEnv.varFrom(resources.expr_idx);
|
||||
const rt_var_ok = try interp2.translateTypeVar(resources.module_env, ct_var_ok);
|
||||
|
|
@ -196,7 +200,8 @@ test "interpreter2 captures (polymorphic): capture id and apply to string" {
|
|||
var interp2 = try Interpreter2.init(std.testing.allocator, resources.module_env);
|
||||
defer interp2.deinit();
|
||||
|
||||
var ops = makeOps(std.testing.allocator);
|
||||
var host = TestHost{ .allocator = std.testing.allocator };
|
||||
var ops = makeOps(&host);
|
||||
const result = try interp2.evalMinimal(resources.expr_idx, &ops);
|
||||
const ct_var_point = can.ModuleEnv.varFrom(resources.expr_idx);
|
||||
const rt_var_point = try interp2.translateTypeVar(resources.module_env, ct_var_point);
|
||||
|
|
@ -219,7 +224,8 @@ test "interpreter2 captures (polymorphic): same captured id used at two types" {
|
|||
var interp2 = try Interpreter2.init(std.testing.allocator, resources.module_env);
|
||||
defer interp2.deinit();
|
||||
|
||||
var ops = makeOps(std.testing.allocator);
|
||||
var host = TestHost{ .allocator = std.testing.allocator };
|
||||
var ops = makeOps(&host);
|
||||
const result = try interp2.evalMinimal(resources.expr_idx, &ops);
|
||||
const rendered = try interp2.renderValueRoc(result);
|
||||
defer std.testing.allocator.free(rendered);
|
||||
|
|
@ -241,7 +247,8 @@ test "interpreter2 higher-order: apply f then call with 41" {
|
|||
var interp2 = try Interpreter2.init(std.testing.allocator, resources.module_env);
|
||||
defer interp2.deinit();
|
||||
|
||||
var ops = makeOps(std.testing.allocator);
|
||||
var host = TestHost{ .allocator = std.testing.allocator };
|
||||
var ops = makeOps(&host);
|
||||
const result = try interp2.evalMinimal(resources.expr_idx, &ops);
|
||||
const rendered = try interp2.renderValueRoc(result);
|
||||
defer std.testing.allocator.free(rendered);
|
||||
|
|
@ -260,7 +267,8 @@ test "interpreter2 higher-order: apply f twice" {
|
|||
var interp2 = try Interpreter2.init(std.testing.allocator, resources.module_env);
|
||||
defer interp2.deinit();
|
||||
|
||||
var ops = makeOps(std.testing.allocator);
|
||||
var host = TestHost{ .allocator = std.testing.allocator };
|
||||
var ops = makeOps(&host);
|
||||
const result = try interp2.evalMinimal(resources.expr_idx, &ops);
|
||||
const rendered = try interp2.renderValueRoc(result);
|
||||
defer std.testing.allocator.free(rendered);
|
||||
|
|
@ -279,7 +287,8 @@ test "interpreter2 higher-order: pass constructed closure and apply" {
|
|||
var interp2 = try Interpreter2.init(std.testing.allocator, resources.module_env);
|
||||
defer interp2.deinit();
|
||||
|
||||
var ops = makeOps(std.testing.allocator);
|
||||
var host = TestHost{ .allocator = std.testing.allocator };
|
||||
var ops = makeOps(&host);
|
||||
const result = try interp2.evalMinimal(resources.expr_idx, &ops);
|
||||
const rendered = try interp2.renderValueRoc(result);
|
||||
defer std.testing.allocator.free(rendered);
|
||||
|
|
@ -298,7 +307,8 @@ test "interpreter2 higher-order: construct then pass then call" {
|
|||
var interp2 = try Interpreter2.init(std.testing.allocator, resources.module_env);
|
||||
defer interp2.deinit();
|
||||
|
||||
var ops = makeOps(std.testing.allocator);
|
||||
var host = TestHost{ .allocator = std.testing.allocator };
|
||||
var ops = makeOps(&host);
|
||||
const result = try interp2.evalMinimal(resources.expr_idx, &ops);
|
||||
const rendered = try interp2.renderValueRoc(result);
|
||||
defer std.testing.allocator.free(rendered);
|
||||
|
|
@ -317,7 +327,8 @@ test "interpreter2 higher-order: compose id with +1" {
|
|||
var interp2 = try Interpreter2.init(std.testing.allocator, resources.module_env);
|
||||
defer interp2.deinit();
|
||||
|
||||
var ops = makeOps(std.testing.allocator);
|
||||
var host = TestHost{ .allocator = std.testing.allocator };
|
||||
var ops = makeOps(&host);
|
||||
const result = try interp2.evalMinimal(resources.expr_idx, &ops);
|
||||
const rendered = try interp2.renderValueRoc(result);
|
||||
defer std.testing.allocator.free(rendered);
|
||||
|
|
@ -336,7 +347,8 @@ test "interpreter2 higher-order: return poly fn using captured +n" {
|
|||
var interp2 = try Interpreter2.init(std.testing.allocator, resources.module_env);
|
||||
defer interp2.deinit();
|
||||
|
||||
var ops = makeOps(std.testing.allocator);
|
||||
var host = TestHost{ .allocator = std.testing.allocator };
|
||||
var ops = makeOps(&host);
|
||||
const result = try interp2.evalMinimal(resources.expr_idx, &ops);
|
||||
const rendered = try interp2.renderValueRoc(result);
|
||||
defer std.testing.allocator.free(rendered);
|
||||
|
|
@ -355,7 +367,8 @@ test "interpreter2 recursion: simple countdown" {
|
|||
var interp2 = try Interpreter2.init(std.testing.allocator, resources.module_env);
|
||||
defer interp2.deinit();
|
||||
|
||||
var ops = makeOps(std.testing.allocator);
|
||||
var host = TestHost{ .allocator = std.testing.allocator };
|
||||
var ops = makeOps(&host);
|
||||
const result = try interp2.evalMinimal(resources.expr_idx, &ops);
|
||||
const rendered = try interp2.renderValueRoc(result);
|
||||
defer std.testing.allocator.free(rendered);
|
||||
|
|
@ -373,7 +386,8 @@ test "interpreter2 if: else-if chain selects middle branch" {
|
|||
var interp2 = try Interpreter2.init(std.testing.allocator, resources.module_env);
|
||||
defer interp2.deinit();
|
||||
|
||||
var ops = makeOps(std.testing.allocator);
|
||||
var host = TestHost{ .allocator = std.testing.allocator };
|
||||
var ops = makeOps(&host);
|
||||
const result = try interp2.evalMinimal(resources.expr_idx, &ops);
|
||||
const rendered = try interp2.renderValueRoc(result);
|
||||
defer std.testing.allocator.free(rendered);
|
||||
|
|
@ -394,7 +408,8 @@ test "interpreter2 var and reassign" {
|
|||
var interp2 = try Interpreter2.init(std.testing.allocator, resources.module_env);
|
||||
defer interp2.deinit();
|
||||
|
||||
var ops = makeOps(std.testing.allocator);
|
||||
var host = TestHost{ .allocator = std.testing.allocator };
|
||||
var ops = makeOps(&host);
|
||||
const result = try interp2.evalMinimal(resources.expr_idx, &ops);
|
||||
const rendered = try interp2.renderValueRoc(result);
|
||||
defer std.testing.allocator.free(rendered);
|
||||
|
|
@ -412,7 +427,8 @@ test "interpreter2 logical or is short-circuiting" {
|
|||
var interp2 = try Interpreter2.init(std.testing.allocator, resources.module_env);
|
||||
defer interp2.deinit();
|
||||
|
||||
var ops = makeOps(std.testing.allocator);
|
||||
var host = TestHost{ .allocator = std.testing.allocator };
|
||||
var ops = makeOps(&host);
|
||||
const result = try interp2.evalMinimal(resources.expr_idx, &ops);
|
||||
const rendered = try interp2.renderValueRoc(result);
|
||||
defer std.testing.allocator.free(rendered);
|
||||
|
|
@ -433,7 +449,8 @@ test "interpreter2 logical and is short-circuiting" {
|
|||
var interp2 = try Interpreter2.init(std.testing.allocator, resources.module_env);
|
||||
defer interp2.deinit();
|
||||
|
||||
var ops = makeOps(std.testing.allocator);
|
||||
var host = TestHost{ .allocator = std.testing.allocator };
|
||||
var ops = makeOps(&host);
|
||||
const result = try interp2.evalMinimal(resources.expr_idx, &ops);
|
||||
const rendered = try interp2.renderValueRoc(result);
|
||||
defer std.testing.allocator.free(rendered);
|
||||
|
|
@ -454,7 +471,8 @@ test "interpreter2 recursion: factorial 5 -> 120" {
|
|||
var interp2 = try Interpreter2.init(std.testing.allocator, resources.module_env);
|
||||
defer interp2.deinit();
|
||||
|
||||
var ops = makeOps(std.testing.allocator);
|
||||
var host = TestHost{ .allocator = std.testing.allocator };
|
||||
var ops = makeOps(&host);
|
||||
const result = try interp2.evalMinimal(resources.expr_idx, &ops);
|
||||
const rendered = try interp2.renderValueRoc(result);
|
||||
defer std.testing.allocator.free(rendered);
|
||||
|
|
@ -476,7 +494,8 @@ test "interpreter2 recursion: fibonacci 5 -> 5" {
|
|||
var interp2 = try Interpreter2.init(std.testing.allocator, resources.module_env);
|
||||
defer interp2.deinit();
|
||||
|
||||
var ops = makeOps(std.testing.allocator);
|
||||
var host = TestHost{ .allocator = std.testing.allocator };
|
||||
var ops = makeOps(&host);
|
||||
const result = try interp2.evalMinimal(resources.expr_idx, &ops);
|
||||
const rendered = try interp2.renderValueRoc(result);
|
||||
defer std.testing.allocator.free(rendered);
|
||||
|
|
@ -496,7 +515,8 @@ test "interpreter2 tag union: one-arg tag Ok(42)" {
|
|||
var interp2 = try Interpreter2.init(std.testing.allocator, resources.module_env);
|
||||
defer interp2.deinit();
|
||||
|
||||
var ops = makeOps(std.testing.allocator);
|
||||
var host = TestHost{ .allocator = std.testing.allocator };
|
||||
var ops = makeOps(&host);
|
||||
const result = try interp2.evalMinimal(resources.expr_idx, &ops);
|
||||
const ct_var = can.ModuleEnv.varFrom(resources.expr_idx);
|
||||
const rt_var = try interp2.translateTypeVar(resources.module_env, ct_var);
|
||||
|
|
@ -519,7 +539,8 @@ test "interpreter2 tag union: multi-arg tag Point(1, 2)" {
|
|||
var interp2 = try Interpreter2.init(std.testing.allocator, resources.module_env);
|
||||
defer interp2.deinit();
|
||||
|
||||
var ops = makeOps(std.testing.allocator);
|
||||
var host = TestHost{ .allocator = std.testing.allocator };
|
||||
var ops = makeOps(&host);
|
||||
const result = try interp2.evalMinimal(resources.expr_idx, &ops);
|
||||
const ct_var = can.ModuleEnv.varFrom(resources.expr_idx);
|
||||
const rt_var = try interp2.translateTypeVar(resources.module_env, ct_var);
|
||||
|
|
|
|||
|
|
@ -438,6 +438,10 @@ pub const Store = struct {
|
|||
return try self.insertLayout(empty_record_layout);
|
||||
}
|
||||
|
||||
pub fn ensureEmptyRecordLayout(self: *Self) !Idx {
|
||||
return self.getEmptyRecordLayout();
|
||||
}
|
||||
|
||||
/// Get the size in bytes of a layout, given the store's target usize.
|
||||
pub fn layoutSize(self: *const Self, layout: Layout) u32 {
|
||||
// TODO change this to SizeAlign (just return both since they're packed into 4B anyway)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue