authorchloe caruso <git@paperclover.net> 2024-10-27 20:33:31-07:00
committerchloe caruso <git@paperclover.net> 2024-10-27 20:33:31-07:00
logee6d161658572b76eb31d23be33043f63be4f556
tree078a9377345cb661d277516ae79713dee297279d
parent9c9f440794d6c700dbbcf7bc410d954c694a36c1
signature Commit is signed but in an unrecognized format.

fix: rework InternPool.Key to not use slices

these pointers get invalidated after appends to InternPool, so they should store `Store.Slice(T)` instead. this introduces a memory leak since there is a genuine use case for using real slices (when the query is not in InternPool), but the fix for this is more convoluted and will be done later when some other InternPool organization is done.

14 files changed, 373 insertions(+), 301 deletions(-)

CHANGELOG.md+1
......@@ -11,6 +11,7 @@
1111- fix: coerce `break` operands and implicit breaks to result type
1212- fix: coerce results when `if` expression branches merge
1313- fix: ensure if branch results to a runtime value when the condition is not compile-time known
14- fix: coerce return value to a runtime value
1415- fix: inferred array type uses item type for items instead of the container type.
1516- fix(js): stop printing redundant parenthesis on ternary expressions
1617
README.md+2-2
......@@ -1,6 +1,6 @@
11# Ix
22
3Ix (`I`nferable E`x`pression) is a high-level, general purpose programming
3Ix (*I*nferable E*x*pression) is a high-level, general purpose programming
44language. It features a mix of Rust, Zig, and JavaScript's great points.
55
66For a guide on how to use Ix, see the manual included in the binary
......@@ -29,6 +29,6 @@ CLI to check spelling mistakes and [`dprint`][dprint] for code formatting. It is
2929recommended to setup editor integration with these two tools to prevent pushing
3030broken commits.
3131
32[ci]: https://buildkite.com/paperdave/compiler
32[ci]: https://buildkite.com/paperclover/compiler
3333[typos]: https://github.com/crate-ci/typos
3434[dprint]: https://dprint.dev
ci+16-14
......@@ -12,25 +12,27 @@ commit_short=$(echo "$commit" | cut -c -9)
1212typos
1313dprint check
1414
15if [ -n "$BUILDKITE" ]; then
15if [ -n "$BUILDKITE" ] || [ "$1" == "all" ]; then
1616 # perform the entire build
1717 ./build all --summary all
1818
19 pushd zig-out/package
20 zip -r compiler-$commit.zip *
21 buildkite-agent artifact upload compiler-$commit.zip
22 popd
19 if [ -n "$BUILDKITE" ]; then
20 pushd zig-out/package
21 zip -r compiler-$commit.zip *
22 buildkite-agent artifact upload compiler-$commit.zip
23 popd
2324
24 rm -fr zig-out/site
25 mkdir zig-out/site
26 cp zig-out/package/ix.html zig-out/site/index.html
27 branch="$BUILDKITE_BRANCH"
28 if [ "$branch" = "dev" ]; then
29 branch=main
25 rm -fr zig-out/site
26 mkdir zig-out/site
27 cp zig-out/package/ix.html zig-out/site/index.html
28 branch="$BUILDKITE_BRANCH"
29 if [ "$branch" = "dev" ]; then
30 branch=main
31 fi
32 CLOUDFLARE_API_TOKEN="$(buildkite-agent secret get CLOUDFLARE_API_TOKEN)" \
33 CLOUDFLARE_ACCOUNT_ID="$(buildkite-agent secret get CLOUDFLARE_ACCOUNT_ID)" \
34 wrangler pages deploy zig-out/site --branch "$branch" --commit-hash "$commit" --no-bundle --project-name language-manual
3035 fi
31 CLOUDFLARE_API_TOKEN="$(buildkite-agent secret get CLOUDFLARE_API_TOKEN)" \
32 CLOUDFLARE_ACCOUNT_ID="$(buildkite-agent secret get CLOUDFLARE_ACCOUNT_ID)" \
33 wrangler pages deploy zig-out/site --branch "$branch" --commit-hash "$commit" --no-bundle --project-name language-manual
3436else
3537 # perform only the tests, with a shorter summary
3638 ./build test --summary new
doc/language-manual.md+2-2
......@@ -179,7 +179,7 @@ it cannot be assigned to a `var` without an explicit type annotation. Since
179179float, but a compiler warning will be emitted.
180180
181181```lang
182var number = 0; // `number` is a `float`, but not explicit
182var number = 0; // `number` is `float`, but not explicit
183183var number: int = 0; // `number` is `int`
184184var number: float = 0; // `number` is `float`
185185```
......@@ -203,7 +203,7 @@ fn main {
203203
204204The `return` expression can be used within functions to return early.
205205
206```lang:run
206```lang
207207let print = @extern("console").log;
208208
209209fn something(a: int) -> bool {
src/core/Air.Dump.zig+15-14
......@@ -52,7 +52,7 @@ pub const State = struct {
5252 switch (tag) {
5353 .block => {
5454 const index_list: Air.IndexList = air.instData(.block, inst);
55 const insts = index_list.slice(air);
55 const insts = index_list.get(air);
5656 try s.dumpInstList(w, insts, '{', '}');
5757 },
5858 .arg => {
......@@ -127,7 +127,7 @@ pub const State = struct {
127127 air
128128 .typeOfIndex(field.base, s.ip)
129129 .toStructType(s.ip).?
130 .field_keys[field.field_index]
130 .field_keys.at(s.ip, field.field_index)
131131 .toSlice(s.ip),
132132 });
133133 try tty.setColor(w, .reset);
......@@ -149,7 +149,7 @@ pub const State = struct {
149149 try w.writeAll("(");
150150 try s.dumpRef(w, call.base);
151151 try w.writeAll(", ");
152 try s.dumpRefList(w, call_data.args.slice(air), '[', ']');
152 try s.dumpRefList(w, call_data.args.get(air), '[', ']');
153153 try w.writeAll(")");
154154 },
155155 .@"if" => {
......@@ -177,7 +177,7 @@ pub const State = struct {
177177 try s.dumpValue(w, struct_init.ty.value());
178178 try w.writeAll(", {");
179179 s.indent += 1;
180 for (struct_type.field_keys, struct_init.valuesPtr(air)) |key, ref| {
180 for (struct_type.field_keys.get(s.ip), struct_init.valuesPtr(air)) |key, ref| {
181181 try s.newline(w);
182182 try w.print("{}: ", .{key.fmt(s.ip)});
183183 try s.dumpRef(w, ref);
......@@ -192,7 +192,7 @@ pub const State = struct {
192192
193193 try w.writeAll("(");
194194 try s.dumpValue(w, array_type.item_type.value());
195 try s.dumpRefList(w, array_init.list.get(air).slice(air), '[', ']');
195 try s.dumpRefList(w, array_init.list.get(air).get(air), '[', ']');
196196 try w.writeAll(")");
197197 },
198198 .tuple_init => {
......@@ -203,6 +203,7 @@ pub const State = struct {
203203 // try s.dumpValue(w, array_type.item_type.value());
204204 // try s.dumpRefList(w, array_init.list.get(air).slice(air), '[', ']');
205205 // try w.writeAll(")");
206 @panic("TODO");
206207 },
207208 }
208209 }
......@@ -244,7 +245,7 @@ pub const State = struct {
244245 try tty.setColor(w, .blue);
245246 try w.writeAll("fn(");
246247 try tty.setColor(w, .reset);
247 for (ty.param_types, 0..) |param, i| {
248 for (ty.param_types.get(s.ip), 0..) |param, i| {
248249 if (i != 0) {
249250 try tty.setColor(w, .blue);
250251 try w.writeAll(", ");
......@@ -322,8 +323,8 @@ pub const State = struct {
322323 try w.writeAll(" ");
323324
324325 for (
325 struct_type.field_keys,
326 struct_type.field_types,
326 struct_type.field_keys.get(s.ip),
327 struct_type.field_types.get(s.ip),
327328 0..,
328329 ) |key, field_type, i| {
329330 if (i != 0)
......@@ -352,8 +353,8 @@ pub const State = struct {
352353 try w.writeAll(" ");
353354
354355 for (
355 struct_value.ty.toStructType(s.ip).?.field_keys,
356 struct_value.field_values,
356 struct_value.ty.toStructType(s.ip).?.field_keys.get(s.ip),
357 struct_value.field_values.get(s.ip),
357358 0..,
358359 ) |key, value, i| {
359360 if (i != 0)
......@@ -385,7 +386,7 @@ pub const State = struct {
385386 try tty.setColor(w, .reset);
386387 try w.writeAll("[");
387388
388 for (array_value.items, 0..) |value, i| {
389 for (array_value.items.get(s.ip), 0..) |value, i| {
389390 if (i != 0)
390391 try w.writeAll(", ");
391392 try s.dumpValue(w, value);
......@@ -398,7 +399,7 @@ pub const State = struct {
398399 },
399400 .external_value => |external_value| {
400401 try w.writeAll("external '");
401 for (external_value.key, 0..) |part, i| {
402 for (external_value.key.get(s.ip), 0..) |part, i| {
402403 if (i != 0) try w.writeAll(".");
403404 try w.writeAll(part.toSlice(s.ip));
404405 }
......@@ -406,7 +407,7 @@ pub const State = struct {
406407 },
407408 .tuple_type => |tuple_type| {
408409 try w.writeAll("(");
409 for (tuple_type.items, 0..) |item, i| {
410 for (tuple_type.items.get(s.ip), 0..) |item, i| {
410411 if (i != 0) try w.writeAll(", ");
411412 try s.dumpValue(w, item.value());
412413 }
......@@ -414,7 +415,7 @@ pub const State = struct {
414415 },
415416 .tuple_value => |tuple_value| {
416417 try w.writeAll("(");
417 for (tuple_value.items, 0..) |item, i| {
418 for (tuple_value.items.get(s.ip), 0..) |item, i| {
418419 if (i != 0) try w.writeAll(", ");
419420 try s.dumpValue(w, item);
420421 }
src/core/Air.zig+6-21
......@@ -1,5 +1,5 @@
11insts: Inst.List.Slice,
2extra: ExtraStore = .{},
2extra: ExtraStore,
33
44pub const ExtraStore = dod.ExtraStore(.air, .@"const");
55pub const EncodedData = dod.EncodedData(Inst.Tag, u64);
......@@ -201,23 +201,8 @@ pub const Flags = packed struct {
201201 };
202202};
203203
204pub const IndexList = struct {
205 start: u32,
206 len: u32,
207
208 pub fn slice(self: IndexList, air: *const Air) []const Inst.Index {
209 return @ptrCast(air.extra.list.items[self.start..][0..self.len]);
210 }
211};
212
213pub const RefList = struct {
214 start: u32,
215 len: u32,
216
217 pub fn slice(self: RefList, air: *const Air) []const Inst.Ref {
218 return @ptrCast(air.extra.list.items[self.start..][0..self.len]);
219 }
220};
204pub const IndexList = ExtraStore.Slice(Air.Inst.Index);
205pub const RefList = ExtraStore.Slice(Air.Inst.Ref);
221206
222207pub const Break = struct {
223208 block: Inst.Index,
......@@ -383,7 +368,7 @@ pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *const InternPool) In
383368 // TODO: taking the last instruction is likely wrong.
384369 // The last instruction is going to be a .break and be of type .never
385370 .block => {
386 const items = air.instData(.block, index).slice(air);
371 const items = air.instData(.block, index).get(air);
387372 assert(items.len > 0); // empty blocks should always be `Value.void`
388373 return air.typeOfIndex(items[items.len - 1], ip);
389374 },
......@@ -402,7 +387,7 @@ pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *const InternPool) In
402387 const inst = air.instData(.field_struct, index);
403388 const base_type = air.typeOfIndex(inst.base, ip)
404389 .toStructType(ip) orelse unreachable; // field_struct demands struct type
405 return base_type.field_types[inst.field_index];
390 return base_type.field_types.at(ip, inst.field_index);
406391 },
407392
408393 // Array accesses use the array they are accessing into.
......@@ -418,7 +403,7 @@ pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *const InternPool) In
418403 const inst = air.instData(.field_tuple, index);
419404 const base_type = air.typeOfIndex(inst.base, ip)
420405 .toTupleType(ip) orelse unreachable; // field_tuple demands tuple type
421 return base_type.items[inst.field_index];
406 return base_type.items.at(ip, inst.field_index);
422407 },
423408 };
424409}
src/core/Hir.zig+1-1
......@@ -13,7 +13,7 @@
1313
1414insts: Inst.List.Slice,
1515string_bytes: []const u8,
16extra: ExtraStore = .{},
16extra: ExtraStore,
1717report: Report,
1818
1919pub const ExtraStore = dod.ExtraStore(.hir, .@"const");
src/core/InternPool.zig+91-104
......@@ -21,9 +21,9 @@
2121///
2222/// The preferred way to access these this data through `.get()` and the methods
2323/// on `Value` and `Type`.
24map: std.AutoArrayHashMapUnmanaged(void, void) = .{},
25items: std.MultiArrayList(Item) = .{},
26extra: ExtraStore = .{},
24map: std.AutoArrayHashMapUnmanaged(void, void) = .empty,
25items: std.MultiArrayList(Item) = .empty,
26extra: Extra = .empty,
2727
2828/// In order to store references to strings in fewer bytes, we copy all
2929/// string bytes into here. String bytes can be null. It is up to whoever
......@@ -146,7 +146,7 @@ pub const Tag = enum(u8) {
146146 .int32 => i32,
147147 .opaque_value => Value,
148148
149 else => ExtraIndex(tag.Payload()),
149 else => Extra.Index(tag.Payload()),
150150 };
151151 }
152152
......@@ -270,18 +270,7 @@ pub const Value = enum(u32) {
270270 none = std.math.maxInt(u32),
271271 _,
272272
273 /// An array of `Value` existing within the `extra` array.
274 /// This type exists to provide a struct with lifetime that is
275 /// not invalidated when items are added to the `InternPool`.
276 // TODO: Replace with ExtraStore.Slice(Value)
277 pub const Slice = struct {
278 start: u32,
279 len: u32,
280
281 pub fn get(slice: Slice, ip: *const InternPool) []const Value {
282 return @ptrCast(ip.extra.list.items[slice.start..][0..slice.len]);
283 }
284 };
273 pub const Slice = Extra.Slice(Value);
285274
286275 /// Used for a map of `Value` values to the index within a list of `Value` values.
287276 const Adapter = struct {
......@@ -316,6 +305,8 @@ pub const Value = enum(u32) {
316305
317306 pub fn assertValid(value: Value, ip: *const InternPool) void {
318307 assert(@intFromEnum(value) < ip.items.len);
308 assert(value != .none);
309 assert(ip.items.items(.tag)[@intFromEnum(value)] != .removed);
319310 }
320311
321312 pub fn dump(value: Value, ip: *const InternPool) std.fmt.Formatter(Value.formatValue) {
......@@ -459,17 +450,7 @@ pub const Type = enum(u32) {
459450 tuple_type = @intFromEnum(InternPool.Tag.tuple_type),
460451 };
461452
462 /// An array of `Index` existing within the `extra` array.
463 /// This type exists to provide a struct with lifetime that is
464 /// not invalidated when items are added to the `InternPool`.
465 pub const Slice = struct {
466 start: u32,
467 len: u32,
468
469 pub fn get(slice: Slice, ip: *const InternPool) []Type {
470 return @ptrCast(ip.extra.list.items[slice.start..][0..slice.len]);
471 }
472 };
453 pub const Slice = Extra.Slice(Type);
473454
474455 pub fn value(ty: Type) Value {
475456 return @enumFromInt(@intFromEnum(ty));
......@@ -526,7 +507,7 @@ pub const Type = enum(u32) {
526507 => true,
527508 .tuple_type => {
528509 const tuple_type = ty.toTupleType(ip).?;
529 for (tuple_type.items) |item| {
510 for (tuple_type.items.get(ip)) |item| {
530511 if (!item.hasPossibleRepresentation(ip)) {
531512 return false;
532513 }
......@@ -599,7 +580,7 @@ pub const Type = enum(u32) {
599580 .function_type => {
600581 const function_type = ty.toUnresolvedFunctionPrototype(ip).?;
601582 try writer.writeAll("fn(");
602 for (function_type.param_types, 0..) |param, i| {
583 for (function_type.param_types.get(ip), 0..) |param, i| {
603584 if (i != 0) try writer.writeAll(", ");
604585 try writer.print("{}", .{param.displayName(ip)});
605586 }
......@@ -619,7 +600,7 @@ pub const Type = enum(u32) {
619600 },
620601 .tuple_type => {
621602 try writer.writeAll("(");
622 for (ty.toTupleType(ip).?.items, 0..) |item, i| {
603 for (ty.toTupleType(ip).?.items.get(ip), 0..) |item, i| {
623604 if (i != 0) try writer.writeAll(", ");
624605 try writer.print("{}", .{item.displayName(ip)});
625606 }
......@@ -651,9 +632,8 @@ pub const Item = struct {
651632 }
652633};
653634
654pub const ExtraStore = dod.ExtraStore(.intern_pool, .@"var");
635pub const Extra = dod.ExtraStore(.intern_pool, .@"var");
655636pub const EncodedData = dod.EncodedData(Tag, u32);
656pub const ExtraIndex = ExtraStore.Index;
657637
658638/// How many items in the InternPool are statically known.
659639/// This is specified with an integer literal and a corresponding comptime
......@@ -674,9 +654,9 @@ pub const static_keys = [_]Key{
674654 SimpleType.never.key(),
675655 SimpleType.type.key(),
676656 SimpleType.numeric_literal.key(),
677 .{ .array_type = .{ .item_type = Type.numeric_literal } },
678 .{ .array_type = .{ .item_type = Type.never } },
679 .{ .tuple_type = .{ .items = &.{} } },
657 .{ .array_type = .{ .item_type = .numeric_literal } },
658 .{ .array_type = .{ .item_type = .never } },
659 .{ .tuple_type = .{ .items = .empty } },
680660
681661 SimpleValue.void.key(),
682662 SimpleValue.true.key(),
......@@ -685,13 +665,13 @@ pub const static_keys = [_]Key{
685665 .{ .float = 0.0 },
686666 .{ .float = Float.pure_nan.decode() },
687667 .{ .array_value = .{
688 .type = Type.never_array,
689 .items = &.{},
668 .type = .never_array,
669 .items = .empty,
690670 } },
691671 .{ .string = "" },
692672 .{ .tuple_value = .{
693673 .type = .empty_tuple,
694 .items = &.{},
674 .items = .empty,
695675 } },
696676};
697677
......@@ -814,14 +794,7 @@ pub const NullTerminatedString = enum(u32) {
814794 return .{ .data = .{ .string = self, .ip = ip } };
815795 }
816796
817 pub const Slice = struct {
818 start: u32,
819 len: u32,
820
821 pub fn get(slice: Slice, ip: *const InternPool) []NullTerminatedString {
822 return @ptrCast(ip.extra.list.items[slice.start..][0..slice.len]);
823 }
824 };
797 pub const Slice = Extra.Slice(NullTerminatedString);
825798};
826799
827800pub const TrackedInst = extern struct {
......@@ -975,66 +948,74 @@ pub const Key = union(enum) {
975948 };
976949
977950 pub const FunctionType = struct {
978 param_types: []Type,
951 param_types: Type.Slice,
979952 /// If a return type is missing, it is inferred and not resolved yet.
980953 /// When analysis figures out a return type, a new `FunctionType` with
981954 /// the resolved return type.
982955 return_type: ?Type,
983956
984957 pub const Resolved = struct {
985 param_types: []Type,
958 param_types: Type.Slice,
986959 return_type: Type,
987960 };
988961
989 pub fn hash(self: FunctionType, hasher: *Hash) void {
962 pub fn hash(self: FunctionType, ip: *const InternPool, hasher: *Hash) void {
990963 const t = tracer.trace(@src());
991964 defer t.end();
992965
993 for (self.param_types) |param_type| {
966 for (self.param_types.get(ip)) |param_type| {
994967 std.hash.autoHash(hasher, param_type);
995968 }
996969 std.hash.autoHash(hasher, self.return_type);
997970 }
998971
999 pub fn eql(a: FunctionType, b: FunctionType) bool {
1000 return std.mem.eql(Type, a.param_types, b.param_types) and
972 pub fn eql(a: FunctionType, b: FunctionType, ip: *const InternPool) bool {
973 return std.mem.eql(Type, a.param_types.get(ip), b.param_types.get(ip)) and
1001974 a.return_type == b.return_type;
1002975 }
1003976 };
1004977
1005978 pub const StructType = struct {
1006 field_keys: []NullTerminatedString,
1007 field_types: []const Type,
979 field_keys: NullTerminatedString.Slice,
980 field_types: Type.Slice,
1008981
1009 pub fn hash(self: StructType, hasher: *Hash) void {
1010 // TODO: remove this function. structural typing is not used
1011 // this should be hashing it's location / decl, exactly like `Func`
1012 std.hash.autoHashStrat(hasher, self, .DeepRecursive);
982 /// TODO: store where the struct is declared to make this a nomial type
983 pub fn hash(self: StructType, ip: *const InternPool, hasher: *Hash) void {
984 for (self.field_keys.get(ip)) |value| {
985 std.hash.autoHash(hasher, value);
986 }
987 for (self.field_types.get(ip)) |value| {
988 std.hash.autoHash(hasher, value);
989 }
1013990 }
1014991 };
1015992
1016993 pub const StructValue = struct {
1017994 ty: Type,
1018 field_values: []const Value,
995 field_values: Value.Slice,
1019996
1020 pub fn hash(self: StructValue, hasher: *Hash) void {
997 pub fn hash(self: StructValue, ip: *const InternPool, hasher: *Hash) void {
1021998 std.hash.autoHash(hasher, self.ty);
1022 std.hash.autoHashStrat(hasher, self.field_values, .Deep);
999 for (self.field_values.get(ip)) |value| {
1000 std.hash.autoHash(hasher, value);
1001 }
10231002 }
10241003 };
10251004
10261005 pub const ArrayType = struct {
10271006 item_type: Type,
10281007
1029 pub fn hash(self: ArrayType, hasher: *Hash) void {
1008 pub fn hash(self: ArrayType, ip: *const InternPool, hasher: *Hash) void {
1009 _ = ip;
10301010 std.hash.autoHash(hasher, self.item_type);
10311011 }
10321012 };
10331013
10341014 pub const TupleType = struct {
1035 items: []const Type,
1015 items: Type.Slice,
10361016
1037 pub fn hash(self: TupleType, hasher: *Hash) void {
1017 pub fn hash(self: TupleType, ip: *const InternPool, hasher: *Hash) void {
1018 _ = ip;
10381019 std.hash.autoHashStrat(hasher, self.items, .Deep);
10391020 }
10401021 };
......@@ -1042,30 +1023,31 @@ pub const Key = union(enum) {
10421023 pub const ExternalValue = struct {
10431024 /// A list of strings to generate the property access
10441025 /// so `console.log` would be .{ "console", "log" }
1045 key: []const NullTerminatedString,
1026 key: NullTerminatedString.Slice,
10461027
1047 pub fn hash(self: ExternalValue, hasher: *Hash) void {
1048 std.hash.autoHashStrat(hasher, self.key, .Shallow);
1028 pub fn hash(self: ExternalValue, ip: *const InternPool, hasher: *Hash) void {
1029 std.hash.autoHashStrat(hasher, self.key.get(ip), .Shallow);
10491030 }
10501031 };
10511032
10521033 pub const ArrayValue = struct {
10531034 /// This is the array type, not the item type
10541035 type: Type,
1055 items: []const Value,
1036 items: Value.Slice,
10561037
1057 pub fn hash(self: ArrayValue, hasher: *Hash) void {
1038 pub fn hash(self: ArrayValue, ip: *const InternPool, hasher: *Hash) void {
10581039 std.hash.autoHash(hasher, self.type);
1059 std.hash.autoHashStrat(hasher, self.items, .Deep);
1040 std.hash.autoHashStrat(hasher, self.items.get(ip), .Deep);
10601041 }
10611042 };
10621043
10631044 pub const TupleValue = struct {
10641045 /// This is the tuple type, not the item type
10651046 type: Type,
1066 items: []const Value,
1047 items: Value.Slice,
10671048
1068 pub fn hash(self: TupleValue, hasher: *Hash) void {
1049 pub fn hash(self: TupleValue, ip: *const InternPool, hasher: *Hash) void {
1050 _ = ip;
10691051 std.hash.autoHash(hasher, self.type);
10701052 std.hash.autoHashStrat(hasher, self.items, .Deep);
10711053 }
......@@ -1075,9 +1057,10 @@ pub const Key = union(enum) {
10751057 ty: Type,
10761058 owner_decl: DeclIndex,
10771059 teg_body_inst: TrackedInst.Index,
1078 analysis: ExtraIndex(AnalysisState),
1060 analysis: Extra.Index(AnalysisState),
10791061
1080 pub fn hash(self: Func, hasher: *Hash) void {
1062 pub fn hash(self: Func, ip: *const InternPool, hasher: *Hash) void {
1063 _ = ip;
10811064 std.hash.autoHash(hasher, self.ty);
10821065 std.hash.autoHash(hasher, self.owner_decl);
10831066 std.hash.autoHash(hasher, self.teg_body_inst);
......@@ -1095,7 +1078,6 @@ pub const Key = union(enum) {
10951078 }
10961079
10971080 pub fn hash64(key: Key, ip: *const InternPool) u64 {
1098 _ = ip; // autofix
10991081 const t = tracer.trace(@src());
11001082 defer t.end();
11011083
......@@ -1114,8 +1096,8 @@ pub const Key = union(enum) {
11141096 .float, .comptime_float => |x| Hash.hash(seed, asBytes(&Float.assertPure(x))),
11151097 inline .function_type,
11161098 .func,
1117 .struct_type,
11181099 .struct_value,
1100 .struct_type,
11191101 .array_value,
11201102 .array_type,
11211103 .external_value,
......@@ -1123,14 +1105,13 @@ pub const Key = union(enum) {
11231105 .tuple_value,
11241106 => |x| {
11251107 var hasher = Hash.init(seed);
1126 x.hash(&hasher);
1108 x.hash(ip, &hasher);
11271109 return hasher.final();
11281110 },
11291111 };
11301112 }
11311113
11321114 pub fn eql(a: Key, b: Key, ip: *const InternPool) bool {
1133 _ = ip; // autofix
11341115 const t = tracer.trace(@src());
11351116 defer t.end();
11361117
......@@ -1148,7 +1129,7 @@ pub const Key = union(enum) {
11481129 => |x| std.mem.eql(u8, x, b.string),
11491130 .float => |x| Float.assertPure(x) == Float.assertPure(b.float),
11501131 .comptime_float => |x| Float.assertPure(x) == Float.assertPure(b.comptime_float),
1151 .function_type => |x| x.eql(b.function_type),
1132 .function_type => |x| x.eql(b.function_type, ip),
11521133 .func => |a_info| {
11531134 const b_info = b.func;
11541135 if (a_info.owner_decl != b_info.owner_decl)
......@@ -1165,7 +1146,7 @@ pub const Key = union(enum) {
11651146 .struct_value => |a_info| {
11661147 const b_info = b.struct_value;
11671148 return a_info.ty == b_info.ty and
1168 std.mem.eql(Value, a_info.field_values, b_info.field_values);
1149 std.mem.eql(Value, a_info.field_values.get(ip), b_info.field_values.get(ip));
11691150 },
11701151 .array_type => |a_info| {
11711152 return a_info.item_type == b.array_type.item_type;
......@@ -1173,20 +1154,21 @@ pub const Key = union(enum) {
11731154 .array_value => |a_info| {
11741155 const b_info = b.array_value;
11751156 return a_info.type == b_info.type and
1176 std.mem.eql(Value, a_info.items, b_info.items);
1157 std.mem.eql(Value, a_info.items.get(ip), b_info.items.get(ip));
11771158 },
11781159 .external_value => |a_info| {
11791160 const b_info = b.external_value;
1180 return std.mem.eql(NullTerminatedString, a_info.key, b_info.key);
1161 return std.mem.eql(NullTerminatedString, a_info.key.get(ip), b_info.key.get(ip));
11811162 },
11821163 .tuple_type => |a_info| {
11831164 const b_info = b.tuple_type;
1184 return a_info.items.len == b_info.items.len and std.mem.eql(Type, a_info.items, b_info.items);
1165 return a_info.items.len == b_info.items.len and
1166 std.mem.eql(Type, a_info.items.get(ip), b_info.items.get(ip));
11851167 },
11861168 .tuple_value => |a_info| {
11871169 const b_info = b.tuple_value;
11881170 return a_info.type == b_info.type and
1189 std.mem.eql(Value, a_info.items, b_info.items);
1171 std.mem.eql(Value, a_info.items.get(ip), b_info.items.get(ip));
11901172 },
11911173 };
11921174 }
......@@ -1438,8 +1420,8 @@ pub fn valueToKey(ip: *const InternPool, index: Value) Key {
14381420 data.decode(.struct_type, item.tag).getTrail(ip);
14391421
14401422 return .{ .struct_type = .{
1441 .field_keys = trail.readNullTerminatedStringSlice(payload.fields_len).get(ip),
1442 .field_types = trail.readTypeSlice(payload.fields_len).get(ip),
1423 .field_keys = trail.readNullTerminatedStringSlice(payload.fields_len),
1424 .field_types = trail.readTypeSlice(payload.fields_len),
14431425 } };
14441426 },
14451427 .struct_value => {
......@@ -1449,8 +1431,10 @@ pub fn valueToKey(ip: *const InternPool, index: Value) Key {
14491431 return .{ .struct_value = .{
14501432 .ty = payload.ty,
14511433 .field_values = trail.readValueSlice(
1452 payload.ty.value().valueData(ip, .struct_type).get(ip).fields_len,
1453 ).get(ip),
1434 payload.ty.value()
1435 .valueData(ip, .struct_type)
1436 .get(ip).fields_len,
1437 ),
14541438 } };
14551439 },
14561440 .array_type => {
......@@ -1463,31 +1447,34 @@ pub fn valueToKey(ip: *const InternPool, index: Value) Key {
14631447 const payload: Tag.ArrayValue, var trail = data.decode(.array_value, item.tag).getTrail(ip);
14641448 return .{ .array_value = .{
14651449 .type = payload.type,
1466 .items = trail.readValueSlice(payload.items_len).get(ip),
1450 .items = trail.readValueSlice(payload.items_len),
14671451 } };
14681452 },
14691453 .external_value => {
14701454 const payload: Tag.ExternalValue, var trail = data.decode(.external_value, item.tag).getTrail(ip);
14711455 return .{ .external_value = .{
1472 .key = trail.readNullTerminatedStringSlice(payload.key_count).get(ip),
1456 .key = trail.readNullTerminatedStringSlice(payload.key_count),
14731457 } };
14741458 },
14751459 .tuple_type => {
14761460 const payload: Tag.TupleType, var trail = data.decode(.tuple_type, item.tag).getTrail(ip);
14771461 return .{ .tuple_type = .{
1478 .items = trail.readTypeSlice(payload.items_len).get(ip),
1462 .items = trail.readTypeSlice(payload.items_len),
14791463 } };
14801464 },
14811465 .tuple_value => {
14821466 const payload: Tag.TupleValue, var trail = data.decode(.tuple_value, item.tag).getTrail(ip);
14831467 return .{ .tuple_value = .{
14841468 .type = payload.type,
1485 .items = trail.readValueSlice(payload.items_len).get(ip),
1469 .items = trail.readValueSlice(payload.items_len),
14861470 } };
14871471 },
14881472 };
14891473}
14901474
1475// TODO: this function currently has a soft leak as `Key` requires slices into
1476// InternPool, so querying for a something with a slice (function_type) will
1477// always append it to `.extra` even if it becomes unused.
14911478pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Value {
14921479 const t = tracer.traceFmt(@src(), "{s}", .{@tagName(key)});
14931480 defer t.end();
......@@ -1536,25 +1523,25 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Value {
15361523 break :brk Item.encode(.func, extra);
15371524 },
15381525 .function_type => |f| brk: {
1539 for (f.param_types) |ty| ty.assertValid(ip);
1526 for (f.param_types.get(ip)) |ty| ty.assertValid(ip);
15401527
15411528 const extra, var trail = try ip.extra.appendTrailing(gpa, Tag.FunctionType, .{
15421529 .params_len = @intCast(f.param_types.len),
15431530 .return_type = .init(f.return_type),
15441531 }, f.param_types.len);
15451532 defer trail.end();
1546 trail.writeSlice(f.param_types);
1533 trail.writeSlice(f.param_types.get(ip));
15471534 break :brk Item.encode(.function_type, extra);
15481535 },
15491536 .struct_type => |s| brk: {
1550 for (s.field_types) |ty| ty.assertValid(ip);
1537 for (s.field_types.get(ip)) |ty| ty.assertValid(ip);
15511538
15521539 assert(s.field_keys.len == s.field_types.len);
15531540 const extra, var trail = try ip.extra.appendTrailing(gpa, Tag.StructType, .{
15541541 .fields_len = @intCast(s.field_keys.len),
15551542 }, s.field_keys.len * 2);
1556 trail.writeSlice(s.field_keys);
1557 trail.writeSlice(s.field_types);
1543 trail.writeSlice(s.field_keys.get(ip));
1544 trail.writeSlice(s.field_types.get(ip));
15581545
15591546 break :brk Item.encode(.struct_type, extra);
15601547 },
......@@ -1563,7 +1550,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Value {
15631550 const extra, var trail = try ip.extra.appendTrailing(gpa, Tag.StructValue, .{
15641551 .ty = s.ty,
15651552 }, s.field_values.len);
1566 trail.writeSlice(s.field_values);
1553 trail.writeSlice(s.field_values.get(ip));
15671554 break :brk Item.encode(.struct_value, extra);
15681555 },
15691556 .array_type => |s| brk: {
......@@ -1576,21 +1563,21 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Value {
15761563 .type = s.type,
15771564 .items_len = @intCast(s.items.len),
15781565 }, s.items.len);
1579 trail.writeSlice(s.items);
1566 trail.writeSlice(s.items.get(ip));
15801567 break :brk Item.encode(.array_value, extra);
15811568 },
15821569 .external_value => |s| brk: {
15831570 const extra, var trail = try ip.extra.appendTrailing(gpa, Tag.ExternalValue, .{
15841571 .key_count = @intCast(s.key.len),
15851572 }, s.key.len);
1586 trail.writeSlice(s.key);
1573 trail.writeSlice(s.key.get(ip));
15871574 break :brk Item.encode(.external_value, extra);
15881575 },
15891576 .tuple_type => |s| brk: {
15901577 const extra, var trail = try ip.extra.appendTrailing(gpa, Tag.TupleType, .{
15911578 .items_len = @intCast(s.items.len),
15921579 }, s.items.len);
1593 trail.writeSlice(s.items);
1580 trail.writeSlice(s.items.get(ip));
15941581 break :brk Item.encode(.tuple_type, extra);
15951582 },
15961583 .tuple_value => |s| brk: {
......@@ -1598,7 +1585,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Value {
15981585 .type = s.type,
15991586 .items_len = @intCast(s.items.len),
16001587 }, s.items.len);
1601 trail.writeSlice(s.items);
1588 trail.writeSlice(s.items.get(ip));
16021589 break :brk Item.encode(.tuple_value, extra);
16031590 },
16041591 };
......@@ -1613,13 +1600,13 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Value {
16131600
16141601fn extraTypeFunction(
16151602 ip: *const InternPool,
1616 extra_index: ExtraIndex(Tag.FunctionType),
1603 extra_index: Extra.Index(Tag.FunctionType),
16171604) Key.FunctionType {
16181605 const function_type, var trail = extra_index.getTrail(ip);
16191606 const param_types = trail.readTypeSlice(function_type.params_len);
16201607 const result: Key.FunctionType = .{
16211608 .return_type = function_type.return_type.unwrap(),
1622 .param_types = param_types.get(ip),
1609 .param_types = param_types,
16231610 };
16241611 return result;
16251612}
src/core/Report.zig+6-7
......@@ -111,8 +111,7 @@ pub const Err = union(enum) {
111111 },
112112 no_main_func: struct {
113113 fn build(_: @This(), ctx: *MsgContext) !void {
114 // TODO: variant that includes file, but no location
115 try ctx.msgToken(0, "missing top-level function \"main\"", .{});
114 try ctx.msg(.{ .codepoint_eol = 0 }, "missing top-level function \"main\"", .{});
116115 }
117116 },
118117 unknown_identifier: struct {
......@@ -455,7 +454,8 @@ pub const Err = union(enum) {
455454 data.ty.displayName(ctx.ip()),
456455 formatId(
457456 data.ty.toStructType(ctx.ip()).?
458 .field_keys[data.field].toSlice(ctx.ip()),
457 .field_keys.at(ctx.ip(), data.field)
458 .toSlice(ctx.ip()),
459459 ),
460460 },
461461 );
......@@ -872,7 +872,7 @@ fn formatItem(
872872 try tty.setColor(writer, .reset);
873873 try tty.setColor(writer, prefix.color());
874874 try tty.setColor(writer, .bold);
875 try writer.writeBytesNTimes("━", at.slice.len);
875 try writer.writeBytesNTimes("━", @max(at.slice.len, 1));
876876 try tty.setColor(writer, .reset);
877877 try writer.writeAll("\n");
878878 }
......@@ -1074,11 +1074,10 @@ pub const Highlight = union(enum) {
10741074 .byte = b,
10751075 .slice = ast.utf8_source[b..][0..len],
10761076 .loc = .{
1077 // TODO:
10781077 .column = .start,
10791078 .line = .start,
1080 .line_start = 0,
1081 .line_end = @intCast(ast.utf8_source.len),
1079 .line_start = b,
1080 .line_end = @intCast(b + len),
10821081 },
10831082 };
10841083 },
src/core/Sema.zig+64-39
......@@ -547,7 +547,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
547547 return return_type.value().toAir();
548548 },
549549 else => return s.addRef(.arg, .{
550 .type = proto.param_types[param.data],
550 .type = proto.param_types.at(s.ip, param.data),
551551 .arg_number = param.data,
552552 }),
553553 }
......@@ -664,8 +664,8 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
664664 }
665665
666666 return try s.makeValueAir(.{ .struct_type = .{
667 .field_keys = scratch.items(.keys),
668 .field_types = scratch.items(.types),
667 .field_keys = try s.ip.extra.appendSlice(s.gpa, scratch.items(.keys)),
668 .field_types = try s.ip.extra.appendSlice(s.gpa, scratch.items(.types)),
669669 } });
670670 },
671671 .discard => {
......@@ -689,7 +689,10 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
689689 @panic("TODO: support strings with null here");
690690 };
691691 return try s.makeValueAir(.{ .external_value = .{
692 .key = &.{str},
692 .key = try s.ip.extra.appendSlice(
693 s.gpa,
694 @as([]const NullTerminatedString, &.{str}),
695 ),
693696 } });
694697 },
695698 .field => {
......@@ -708,13 +711,13 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
708711 const previous_key = value.toKey(s.ip).external_value.key;
709712
710713 const new_key = try std.mem.concat(s.arena(), NullTerminatedString, &.{
711 previous_key,
714 previous_key.get(s.ip),
712715 &.{field_key},
713716 });
714717 defer s.arena().free(new_key);
715718
716719 return s.makeValueAir(.{ .external_value = .{
717 .key = new_key,
720 .key = try s.ip.extra.appendSlice(s.gpa, new_key),
718721 } });
719722 }
720723 }
......@@ -764,7 +767,11 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
764767 }
765768
766769 // validate function args
767 for (proto.param_types, call.args.slice(&s.hir), 0..) |param, arg, i| {
770 for (
771 proto.param_types.get(s.ip),
772 call.args.slice(&s.hir),
773 0..,
774 ) |param, arg, i| {
768775 const ref = s.getRef(arg, .marked);
769776 const coerced = try s.coerceRef(
770777 s.lazyNode(.argument(@intCast(i))),
......@@ -838,19 +845,23 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
838845 for (scratch.slice(), scratch.sliceReinterpret(Value)) |ref, *value| {
839846 value.* = ref.decode().value;
840847 }
841 return try s.makeValueAir(.{ .array_value = .{
842 .type = ty,
843 .items = result_storage,
844 } });
848 return try s.makeValueAir(.{
849 .array_value = .{
850 .type = ty,
851 // TODO: do not clone memory here
852 .items = try s.ip.extra.appendSlice(s.gpa, result_storage),
853 },
854 });
845855 } else {
846856 // Create a runtime array instantiation
847857 try s.ensureAtRuntime(s.lazyNode(.main_node));
848858 return try s.addRef(.array_init, .{
849859 .ty = ty,
850 .list = try s.func.?.extra.append(s.gpa, Air.RefList, .{
851 .start = try s.func.?.extra.appendSlice(s.gpa, scratch.slice()),
852 .len = node.list.len,
853 }),
860 .list = try s.func.?.extra.append(
861 s.gpa,
862 Air.RefList,
863 try s.func.?.extra.appendSlice(s.gpa, scratch.slice()),
864 ),
854865 });
855866 }
856867 },
......@@ -1017,7 +1028,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
10171028 const brk: Hir.Break = s.frame.currentPayload(.@"break");
10181029 const operand = s.getRef(brk.operand, .marked);
10191030
1020 assert(s.frame.block_index == brk.block);
1031 if (s.frame.block_index != brk.block) @panic("TODO");
10211032
10221033 const mark = core.U32Stack.Mark{ .stack = &s.scratch, .index = s.frame.mark_index };
10231034
......@@ -1028,7 +1039,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
10281039 const coerced = if (proto.return_type) |return_coercion|
10291040 try s.coerceRef(s.lazyNode(.operand), operand, return_coercion)
10301041 else
1031 operand;
1042 try s.ensureRefRuntime(s.lazyNode(.operand), operand);
10321043 s.inst_map.add(s.frame.block_index, coerced);
10331044
10341045 const indexes = mark.slice(u32);
......@@ -1388,7 +1399,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
13881399 // may be different than the instantiation. The fields are visited in
13891400 // order of the instantiation.
13901401 for (node.keys(&s.hir), node.inits(&s.hir), 0..) |init_key, init_value, i| {
1391 const found_index = index: for (struct_type.field_keys, 0..) |decl_key, j| {
1402 const found_index = index: for (struct_type.field_keys.get(s.ip), 0..) |decl_key, j| {
13921403 if (decl_key.eqlSlice(init_key.slice(s.hir.string_bytes), s.ip))
13931404 break :index j;
13941405 } else {
......@@ -1410,7 +1421,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
14101421 const coerced = s.getCoercedRef(
14111422 s.lazyNode(.argument(@intCast(i))),
14121423 init_value,
1413 struct_type.field_types[found_index],
1424 struct_type.field_types.at(s.ip, found_index),
14141425 .marked,
14151426 ) catch |e| switch (e) {
14161427 error.AnalysisFail => {
......@@ -1452,7 +1463,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
14521463 }
14531464 return try s.makeValueAir(.{ .struct_value = .{
14541465 .ty = ty,
1455 .field_values = result_storage,
1466 .field_values = try s.ip.extra.appendSlice(s.gpa, result_storage),
14561467 } });
14571468 } else {
14581469 try s.ensureAtRuntime(s.lazyNode(.main_node));
......@@ -1460,7 +1471,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
14601471 const value_index = try s.func.?.extra.appendSlice(s.gpa, scratch.slice());
14611472 return try s.addRef(.struct_init, .{
14621473 .ty = ty,
1463 .field_values = value_index,
1474 .field_values = value_index.start,
14641475 });
14651476 }
14661477 },
......@@ -1481,7 +1492,9 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
14811492 dst.* = try s.getType(s.lazyNode(.argument(@intCast(i))), src);
14821493 }
14831494
1484 return s.makeValueAir(.{ .tuple_type = .{ .items = scratch.slice() } });
1495 return s.makeValueAir(.{ .tuple_type = .{
1496 .items = try s.ip.extra.appendSlice(s.gpa, scratch.slice()),
1497 } });
14851498 },
14861499
14871500 .tuple_init => {
......@@ -1515,7 +1528,12 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
15151528 ty.* = s.typeOfRef(val);
15161529 }
15171530
1518 break :ty try s.makeType(.{ .tuple_type = .{ .items = type_scratch.slice() } });
1531 break :ty try s.makeType(.{
1532 .tuple_type = .{
1533 // TODO: memory leak
1534 .items = try s.ip.extra.appendSlice(s.gpa, type_scratch.slice()),
1535 },
1536 });
15191537 };
15201538
15211539 if (is_const) {
......@@ -1525,14 +1543,17 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
15251543 value.* = ref.decode().value;
15261544 }
15271545
1528 return try s.makeValueAir(.{ .tuple_value = .{
1529 .items = result_storage,
1530 .type = ty,
1531 } });
1546 return try s.makeValueAir(.{
1547 .tuple_value = .{
1548 // TODO: memory leak
1549 .items = try s.ip.extra.appendSlice(s.gpa, result_storage),
1550 .type = ty,
1551 },
1552 });
15321553 } else {
15331554 const value_index = try s.func.?.extra.appendSlice(s.gpa, scratch.slice());
15341555 return try s.addRef(.struct_init, .{
1535 .field_values = value_index,
1556 .field_values = value_index.start,
15361557 .ty = ty,
15371558 });
15381559 }
......@@ -1550,7 +1571,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
15501571 if (result.argument >= func.param_types.len)
15511572 return Value.opaque_type.toAir();
15521573
1553 return func.param_types[result.argument].value().toAir();
1574 return func.param_types.at(s.ip, result.argument).value().toAir();
15541575 },
15551576
15561577 .result_type_array_value => {
......@@ -1575,7 +1596,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
15751596
15761597 _ = ty;
15771598
1578 @panic("TODO: tuple result type resolution"); // tuples are not implemented
1599 @panic("TODO: tuple result type resolution");
15791600 },
15801601
15811602 .result_type_struct_field => {
......@@ -1589,7 +1610,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
15891610 return Value.opaque_type.toAir();
15901611
15911612 const to_match = result.field.slice(s.hir.string_bytes);
1592 for (struct_type.field_keys, struct_type.field_types) |k, v| {
1613 for (struct_type.field_keys.get(s.ip), struct_type.field_types.get(s.ip)) |k, v| {
15931614 if (k.eqlSlice(to_match, s.ip)) {
15941615 return v.value().toAir();
15951616 }
......@@ -1857,9 +1878,14 @@ fn coerceRef(s: *Sema, src: LazyNode, ref: Air.Inst.Ref, to: Type) !Air.Inst.Ref
18571878/// Same as `coerceRef` but on a compile-time known value
18581879fn coerceValue(s: *Sema, src: LazyNode, value: Value, to: Type) Error!Value {
18591880 const from = value.typeOf(s.ip);
1881
1882 from.assertValid(s.ip);
1883 to.assertValid(s.ip);
1884
18601885 if (from == to) {
18611886 return value;
18621887 }
1888
18631889 switch (to) {
18641890 .@"opaque" => {
18651891 return try s.makeValue(.{ .opaque_value = value });
......@@ -2069,7 +2095,7 @@ fn coerceArrayValue(s: *Sema, src: LazyNode, value: Value, item_type: Type) !Val
20692095
20702096 return try s.makeValue(.{ .array_value = .{
20712097 .type = try s.makeType(.{ .array_type = .{ .item_type = item_type } }),
2072 .items = scratch.slice(),
2098 .items = try s.ip.extra.appendSlice(s.gpa, scratch.slice()),
20732099 } });
20742100}
20752101
......@@ -2096,8 +2122,8 @@ fn coerceTupleValue(
20962122
20972123 // This function will append new items to the intern pool, invalidating
20982124 // existing ones. Copy all data into a stable slice first.
2099 @memcpy(scratch.items(.values), tuple_value.items);
2100 @memcpy(scratch.items(.types), target_key.items);
2125 @memcpy(scratch.items(.values), tuple_value.items.get(s.ip));
2126 @memcpy(scratch.items(.types), target_key.items.get(s.ip));
21012127
21022128 for (0..len) |i| {
21032129 // `s.scratch` can be invalidated by having a tuple of tuples and coercing it.
......@@ -2107,7 +2133,7 @@ fn coerceTupleValue(
21072133
21082134 return try s.makeValue(.{ .tuple_value = .{
21092135 .type = target_type,
2110 .items = scratch.items(.values),
2136 .items = try s.ip.extra.appendSlice(s.gpa, scratch.items(.values)),
21112137 } });
21122138}
21132139
......@@ -2205,7 +2231,7 @@ fn fieldAccessStruct(
22052231 else => |e| return e,
22062232 };
22072233
2208 break :found_index for (struct_type.field_keys, 0..) |key, i| {
2234 break :found_index for (struct_type.field_keys.get(s.ip), 0..) |key, i| {
22092235 if (key == lookup)
22102236 break @as(u32, @intCast(i));
22112237 } else null;
......@@ -2341,7 +2367,7 @@ fn fieldAccessTuple(
23412367
23422368 switch (lhs.decode()) {
23432369 .value => |value| {
2344 return value.toKey(s.ip).tuple_value.items[index].toAir();
2370 return value.toKey(s.ip).tuple_value.items.at(s.ip, index).toAir();
23452371 },
23462372 .index => |lhs_index| {
23472373 try s.ensureAtRuntime(s.lazyNode(.lhs));
......@@ -2359,11 +2385,10 @@ fn postVisitFunctionPrototype(s: *Sema, reserve: FunctionReserve, return_type: ?
23592385 const tracked_inst = try s.ip.trackInst(s.gpa, s.file, s.frame.currentIndex());
23602386 const func_type = try s.makeType(.{
23612387 .function_type = .{
2362 .param_types = reserve.items(.params),
2388 .param_types = try s.ip.extra.appendSlice(s.gpa, reserve.items(.params)),
23632389 .return_type = return_type,
23642390 },
23652391 });
2366 // TODO: make a dedicated function to insert a new function
23672392 const func_value = try s.makeValue(.{
23682393 .func = .{
23692394 .ty = func_type,
src/core/array.zig+122-72
......@@ -81,24 +81,14 @@ pub const StoreKind = enum {
8181 air,
8282 js_tree,
8383
84 pub fn resolveStoreConst(
84 pub fn resolveStore(
8585 comptime kind: StoreKind,
8686 owner: anytype,
87 ) *const kind.ResolvedStore(@TypeOf(owner)) {
87 ) kind.ResolvedStorePtr(@TypeOf(owner)) {
8888 return &owner.extra;
8989 }
9090
91 pub fn resolveStoreMut(
92 comptime kind: StoreKind,
93 owner: anytype,
94 ) *kind.ResolvedStore(@TypeOf(owner)) {
95 return &owner.extra;
96 }
97
98 pub fn ResolvedStore(
99 comptime kind: StoreKind,
100 comptime Owner: type,
101 ) type {
91 pub fn ResolvedStore(kind: StoreKind, Owner: type) type {
10292 const ptr = @typeInfo(Owner).pointer;
10393 assert(ptr.size == .One);
10494 const mutability = brk: for (@typeInfo(ptr.child).@"struct".fields) |field| {
......@@ -108,42 +98,32 @@ pub const StoreKind = enum {
10898 } else unreachable;
10999 return ExtraStore(kind, mutability);
110100 }
111};
112
113fn ExtraWrap(comptime kind: StoreKind) type {
114 return struct {
115 pub fn Index(comptime T: type) type {
116 return enum(u32) {
117 _,
118101
119 pub fn get(index: @This(), owner: anytype) T {
120 return kind.resolveStoreConst(owner).get(T, @intFromEnum(index));
121 }
122
123 pub fn set(index: @This(), owner: anytype, payload: T) void {
124 return kind.resolveStoreMut(owner).set(T, @intFromEnum(index), payload);
125 }
126
127 /// Returns data with a trailing reader to read data stored immediately after
128 /// the main data structure. What is stored should be documented on `T`
129 pub fn getTrail(index: @This(), owner: anytype) struct {
130 T,
131 kind.ResolvedStore(@TypeOf(owner)).TrailReader,
132 } {
133 const advance = comptime extraSizeOf(T);
134 return .{
135 index.get(owner),
136 .{ .index = @intFromEnum(index) + advance },
137 };
138 }
102 pub fn ResolvedStorePtr(kind: StoreKind, Owner: type) type {
103 return kind.ItemPointer(Owner, .One, kind.ResolvedStore(Owner));
104 }
139105
140 pub fn jsonStringify(index: @This(), jw: anytype) !void {
141 try jw.write(@intFromEnum(index));
142 }
143 };
144 }
145 };
146}
106 pub fn ItemPointer(
107 kind: StoreKind,
108 Owner: type,
109 size: std.builtin.Type.Pointer.Size,
110 child: type,
111 ) type {
112 const ptr = @typeInfo(Owner).pointer;
113 return @Type(.{
114 .pointer = .{
115 .size = size,
116 .is_const = ptr.is_const or ResolvedStore(kind, Owner).mutability == .@"const",
117 .is_volatile = false,
118 .is_allowzero = false,
119 .alignment = @alignOf(child),
120 .address_space = .generic,
121 .child = child,
122 .sentinel = null,
123 },
124 });
125 }
126};
147127
148128pub fn EncodedData(comptime Tag: type, backing_type: type) type {
149129 return enum(backing_type) {
......@@ -230,23 +210,89 @@ pub inline fn extraSizeOf(comptime T: type) usize {
230210 };
231211}
232212
233// TODO: rename to Store
234pub fn ExtraStore(comptime set_kind: StoreKind, comptime set_mutability: Mutability) type {
213pub const ExtraStore = Store;
214
215/// A data structure to manage a `[]u32` with mixed data types. Provides
216/// `.Index` and `.Slice` to keep strongly typed indices to items within the
217/// store.
218pub fn Store(set_kind: StoreKind, set_mutability: Mutability) type {
219 // Separate struct to avoid capturing set_mutability
220 const wrappers = struct {
221 pub const kind = set_kind;
222
223 pub fn Index(T: type) type {
224 return enum(u32) {
225 _,
226
227 pub fn get(index: @This(), owner: anytype) T {
228 return kind.resolveStore(owner).get(T, @intFromEnum(index));
229 }
230
231 pub fn set(index: @This(), owner: anytype, payload: T) void {
232 return kind.resolveStore(owner).set(T, @intFromEnum(index), payload);
233 }
234
235 /// Returns data with a trailing reader to read data stored immediately after
236 /// the main data structure. What is stored should be documented on `T`
237 pub fn getTrail(index: @This(), owner: anytype) struct {
238 T,
239 kind.ResolvedStore(@TypeOf(owner)).TrailReader,
240 } {
241 const advance = comptime extraSizeOf(T);
242 return .{
243 index.get(owner),
244 .{ .index = @intFromEnum(index) + advance },
245 };
246 }
247
248 pub fn jsonStringify(index: @This(), jw: anytype) !void {
249 try jw.write(@intFromEnum(index));
250 }
251 };
252 }
253
254 /// An array of `T` existing within the `extra` array.
255 /// This type exists to provide a struct with lifetime that is
256 /// not invalidated when items are added to the `InternPool`.
257 pub fn Slice(T: type) type {
258 return struct {
259 start: u32,
260 len: u32,
261
262 pub const empty: @This() = .{
263 .start = 0,
264 .len = 0,
265 };
266
267 pub fn get(slice: @This(), owner: anytype) kind.ItemPointer(@TypeOf(owner), .Slice, T) {
268 return @ptrCast(kind.resolveStore(owner).list.items[slice.start..][0..slice.len]);
269 }
270
271 pub fn at(slice: @This(), owner: anytype, index: usize) T {
272 return slice.get(owner)[index];
273 }
274 };
275 }
276 };
277
235278 return struct {
236 list: List = .{},
279 const Self = @This();
280
281 list: Inner,
237282
238 pub const empty: @This() = .{};
283 pub const empty: @This() = .{ .list = .empty };
239284
240285 pub const kind = set_kind;
241286 pub const mutability = set_mutability;
242287
243 const Store = @This();
244
245 pub const Index = ExtraWrap(kind).Index;
288 pub const Index = wrappers.Index;
289 pub const Slice = wrappers.Slice;
246290
247 pub const List = switch (mutability) {
291 pub const Inner = switch (mutability) {
248292 .@"const" => struct {
249 items: []const u32 = &.{},
293 items: []const u32,
294
295 pub const empty = .{ .items = &.{} };
250296
251297 pub fn deinit(slice: *@This(), gpa: Allocator) void {
252298 gpa.free(slice.items);
......@@ -255,7 +301,7 @@ pub fn ExtraStore(comptime set_kind: StoreKind, comptime set_mutability: Mutabil
255301 .@"var" => std.ArrayListUnmanaged(u32),
256302 };
257303
258 pub fn deinit(store: *Store, gpa: Allocator) void {
304 pub fn deinit(store: *Self, gpa: Allocator) void {
259305 store.list.deinit(gpa);
260306 store.* = undefined;
261307 }
......@@ -263,12 +309,12 @@ pub fn ExtraStore(comptime set_kind: StoreKind, comptime set_mutability: Mutabil
263309 pub const TrailReader = struct {
264310 index: usize,
265311
266 pub fn read(trail: *TrailReader, ip: *const Store, comptime T: type) T {
312 pub fn read(trail: *TrailReader, ip: *const Self, comptime T: type) T {
267313 defer trail.index += comptime extraSizeOf(T);
268314 return ip.get(T, trail.index);
269315 }
270316
271 pub fn at(trail: *const TrailReader, ip: *const Store, comptime T: type, index: u32) T {
317 pub fn at(trail: *const TrailReader, ip: *const Self, comptime T: type, index: u32) T {
272318 return ip.get(T, trail.index + index);
273319 }
274320
......@@ -301,10 +347,10 @@ pub fn ExtraStore(comptime set_kind: StoreKind, comptime set_mutability: Mutabil
301347 };
302348
303349 pub const TrailWriter = struct {
304 store: *Store,
350 store: *Self,
305351 leftover: usize,
306352
307 pub fn init(store: *Store, len: usize) TrailWriter {
353 pub fn init(store: *Self, len: usize) TrailWriter {
308354 return .{ .store = store, .leftover = len };
309355 }
310356
......@@ -332,13 +378,13 @@ pub fn ExtraStore(comptime set_kind: StoreKind, comptime set_mutability: Mutabil
332378 }
333379 };
334380
335 pub fn append(store: *Store, gpa: Allocator, comptime T: type, payload: T) Allocator.Error!Index(T) {
381 pub fn append(store: *Self, gpa: Allocator, comptime T: type, payload: T) Allocator.Error!Index(T) {
336382 comptime assert(mutability == .@"var");
337383 try store.list.ensureUnusedCapacity(gpa, extraSizeOf(@TypeOf(payload)));
338384 return store.appendAssumeCapacity(T, payload);
339385 }
340386
341 pub fn appendAssumeCapacity(ip: *Store, comptime T: type, payload: T) Index(T) {
387 pub fn appendAssumeCapacity(ip: *Self, comptime T: type, payload: T) Index(T) {
342388 comptime assert(mutability == .@"var");
343389 const extra_index: u32 = @intCast(ip.list.items.len);
344390 ip.list.items.len += extraSizeOf(@TypeOf(payload));
......@@ -347,7 +393,7 @@ pub fn ExtraStore(comptime set_kind: StoreKind, comptime set_mutability: Mutabil
347393 }
348394
349395 pub fn appendTrailing(
350 store: *Store,
396 store: *Self,
351397 gpa: Allocator,
352398 comptime T: type,
353399 payload: T,
......@@ -365,32 +411,34 @@ pub fn ExtraStore(comptime set_kind: StoreKind, comptime set_mutability: Mutabil
365411 }
366412
367413 // TODO: make setAsU32 allow any type
368 pub fn setU32(store: *Store, index: usize, payload: u32) void {
414 pub fn setU32(store: *Self, index: usize, payload: u32) void {
369415 comptime assert(mutability == .@"var");
370416 store.list.items[index] = payload;
371417 }
372418
373 pub fn set(store: *Store, comptime T: type, index: usize, payload: T) void {
419 pub fn set(store: *Self, comptime T: type, index: usize, payload: T) void {
374420 comptime assert(mutability == .@"var");
375421 setAsU32(store.list.items, T, index, payload);
376422 }
377423
378 pub fn get(store: *const Store, comptime T: type, index: usize) T {
424 pub fn get(store: *const Self, comptime T: type, index: usize) T {
379425 return getAsU32(store.list.items, T, index);
380426 }
381427
382 pub fn toOwnedStore(store: *Store, gpa: Allocator) !ExtraStore(set_kind, .@"const") {
428 pub fn toOwnedStore(store: *Self, gpa: Allocator) !ExtraStore(set_kind, .@"const") {
383429 comptime assert(mutability == .@"var");
384430 return .{ .list = .{ .items = try store.list.toOwnedSlice(gpa) } };
385431 }
386432
387 pub fn constant(store: *const Store) ExtraStore(set_kind, .@"const") {
433 /// Returns a `const` store pointing at the mutable's data.
434 /// Invalidated when the mutable store is mutated.
435 pub fn constant(store: *const Self) ExtraStore(set_kind, .@"const") {
388436 return .{ .list = .{ .items = store.list.items } };
389437 }
390438
391439 // TODO: Add some safety to the Index returned from this
392440 /// Allocate a number of u32s into this store, but they are left uninitialized.
393 pub fn alloc(store: *Store, gpa: Allocator, len: usize) !u32 {
441 pub fn alloc(store: *Self, gpa: Allocator, len: usize) !u32 {
394442 comptime assert(mutability == .@"var");
395443 const idx = store.list.items.len;
396444 try store.list.ensureUnusedCapacity(gpa, len);
......@@ -398,13 +446,15 @@ pub fn ExtraStore(comptime set_kind: StoreKind, comptime set_mutability: Mutabil
398446 return @intCast(idx);
399447 }
400448
401 pub fn appendSlice(store: *Store, gpa: Allocator, data: anytype) !u32 {
449 pub fn appendSlice(store: *Self, gpa: Allocator, data: anytype) !Slice(std.meta.Child(@TypeOf(data))) {
402450 const idx = store.list.items.len;
451 comptime assert(@typeInfo(@TypeOf(data)).pointer.size == .Slice);
452 comptime assert(@typeInfo(@TypeOf(data)).pointer.alignment == @alignOf(u32));
403453 comptime assert(@sizeOf(@TypeOf(data[0])) == @sizeOf(u32));
404454 comptime assert(@alignOf(@TypeOf(data[0])) == @alignOf(u32));
405455 try store.list.appendSlice(gpa, @ptrCast(data));
406456 store.list.items.len += data.len;
407 return @intCast(idx);
457 return .{ .start = @intCast(idx), .len = @intCast(data.len) };
408458 }
409459 };
410460}
src/core/js/Link.zig+17-8
......@@ -284,8 +284,9 @@ fn printValue(link: *Link, value: InternPool.Value, level: Level, writer: anytyp
284284 try writer.writeAll("{");
285285
286286 for (
287 struct_value.ty.toStructType(&link.comp.intern_pool).?.field_keys,
288 struct_value.field_values,
287 struct_value.ty.toStructType(&link.comp.intern_pool).?
288 .field_keys.get(&link.comp.intern_pool),
289 struct_value.field_values.get(&link.comp.intern_pool),
289290 0..,
290291 ) |key, inner_value, i| {
291292 if (i != 0)
......@@ -305,7 +306,7 @@ fn printValue(link: *Link, value: InternPool.Value, level: Level, writer: anytyp
305306 .array_value => |array_value| {
306307 try writer.writeAll("[");
307308
308 for (array_value.items, 0..) |inner_value, i| {
309 for (array_value.items.get(&link.comp.intern_pool), 0..) |inner_value, i| {
309310 if (i != 0)
310311 try writer.writeAll(",");
311312
......@@ -317,7 +318,7 @@ fn printValue(link: *Link, value: InternPool.Value, level: Level, writer: anytyp
317318 .tuple_value => |tuple_value| {
318319 try writer.writeAll("[");
319320
320 for (tuple_value.items, 0..) |inner_value, i| {
321 for (tuple_value.items.get(&link.comp.intern_pool), 0..) |inner_value, i| {
321322 if (i != 0)
322323 try writer.writeAll(",");
323324
......@@ -327,7 +328,7 @@ fn printValue(link: *Link, value: InternPool.Value, level: Level, writer: anytyp
327328 },
328329
329330 .external_value => |external_value| {
330 for (external_value.key, 0..) |part, i| {
331 for (external_value.key.get(&link.comp.intern_pool), 0..) |part, i| {
331332 if (i != 0) try writer.writeAll(".");
332333 try writer.writeAll(part.toSlice(&link.comp.intern_pool));
333334 }
......@@ -477,11 +478,15 @@ fn printExprLevel(
477478 },
478479
479480 .comma_chain => {
481 if (Level.comma.needsParens(level))
482 try writer.writeAll("(");
480483 const bin: Tree.IndexList = tree.nodeData(.comma_chain, node);
481484 for (bin.slice(tree), 0..) |expr, i| {
482485 if (i != 0) try writer.writeAll(", ");
483486 try link.printExprLevel(tree, expr, .assignment, writer);
484487 }
488 if (Level.comma.needsParens(level))
489 try writer.writeAll(")");
485490 },
486491
487492 inline .negate,
......@@ -503,9 +508,9 @@ fn printExprLevel(
503508 try writer.writeAll("(");
504509 try link.printExprLevel(tree, ternary.cond, .logical_or, writer);
505510 try writer.writeAll(" ? ");
506 try link.printExpr(tree, data.yes, writer);
511 try link.printExprLevel(tree, data.yes, .assignment, writer);
507512 try writer.writeAll(" : ");
508 try link.printExpr(tree, data.no, writer);
513 try link.printExprLevel(tree, data.no, .assignment, writer);
509514 if (wrap)
510515 try writer.writeAll(")");
511516 },
......@@ -518,7 +523,11 @@ fn printExprLevel(
518523 const k = tree.nodeData(.plain_value, call.base).value.toKey(&link.comp.intern_pool);
519524 break :brk k == .external_value and
520525 k.external_value.key.len == 1 and
521 std.mem.eql(u8, k.external_value.key[0].toSlice(&link.comp.intern_pool), "eval");
526 std.mem.eql(
527 u8,
528 k.external_value.key.at(&link.comp.intern_pool, 0).toSlice(&link.comp.intern_pool),
529 "eval",
530 );
522531 }) {
523532 @branchHint(.unlikely);
524533 try writer.writeAll("(0, eval)");
src/core/js/NodeGen.zig+19-14
......@@ -47,8 +47,8 @@ pub fn init(gpa: Allocator, arena: Allocator, ip: *InternPool, air: Air) !NodeGe
4747 .extern_symbols = .{},
4848 .top_level_value_deps = .{},
4949 .air_node_map = air_node_map,
50 .extra = .{},
51 .scratch = .{},
50 .extra = .empty,
51 .scratch = .empty,
5252 .next_id = param_count,
5353 .next_label = 0,
5454 };
......@@ -100,7 +100,7 @@ pub fn build(c: *NodeGen) !void {
100100 defer t.end();
101101
102102 assert(c.air.instTag(.main_block) == .block); // expected Air to start with block
103 const statements = c.air.instData(.block, .main_block).slice(&c.air);
103 const statements = c.air.instData(.block, .main_block).get(&c.air);
104104
105105 const scratch_top = c.scratch.items.len;
106106 defer c.scratch.shrinkRetainingCapacity(scratch_top);
......@@ -301,7 +301,7 @@ fn codeGenInst(c: *NodeGen, inst: Air.Inst.Index) Error!void {
301301 .field = field_name: {
302302 break :field_name c.air.typeOfIndex(data.base, c.ip)
303303 .toStructType(c.ip).?
304 .field_keys[data.field_index];
304 .field_keys.at(c.ip, data.field_index);
305305 },
306306 });
307307 try c.markExpression(inst, node);
......@@ -338,7 +338,7 @@ fn codeGenInst(c: *NodeGen, inst: Air.Inst.Index) Error!void {
338338
339339 const items = c.extra.list.items[start..][0..call_data.args.len];
340340
341 for (call_data.args.slice(&c.air), items) |arg, *dest| {
341 for (call_data.args.get(&c.air), items) |arg, *dest| {
342342 dest.* = @intFromEnum(try c.fetchExpression(arg));
343343 }
344344
......@@ -457,7 +457,7 @@ fn codeGenInst(c: *NodeGen, inst: Air.Inst.Index) Error!void {
457457 //
458458 // This is also required for the main function, which cannot return
459459 // anything. We don't want to emit return instructions here.
460 const main_insts = c.air.instData(.block, .main_block).slice(&c.air);
460 const main_insts = c.air.instData(.block, .main_block).get(&c.air);
461461 if (main_insts[main_insts.len - 1] == inst) {
462462 return;
463463 }
......@@ -472,7 +472,7 @@ fn codeGenInst(c: *NodeGen, inst: Air.Inst.Index) Error!void {
472472 const operand = try c.fetchExpression(brk.value);
473473 const block = &c.air_node_map[@intFromEnum(brk.block)].block;
474474
475 const block_insts = c.air.instData(.block, brk.block).slice(&c.air);
475 const block_insts = c.air.instData(.block, brk.block).get(&c.air);
476476 if (block_insts[block_insts.len - 1] != inst) {
477477 block.used = true;
478478 }
......@@ -499,7 +499,7 @@ fn codeGenInst(c: *NodeGen, inst: Air.Inst.Index) Error!void {
499499 const store_offset = try c.extra.alloc(c.gpa, property_count * 2);
500500
501501 for (
502 struct_type.field_keys,
502 struct_type.field_keys.get(c.ip),
503503 struct_init.valuesPtr(&c.air),
504504 store_offset..,
505505 store_offset + property_count..,
......@@ -520,7 +520,7 @@ fn codeGenInst(c: *NodeGen, inst: Air.Inst.Index) Error!void {
520520 .array_init => {
521521 const array_init: Air.ArrayInit = c.air.instData(.array_init, inst);
522522
523 const items = array_init.list.get(&c.air).slice(&c.air);
523 const items = array_init.list.get(&c.air).get(&c.air);
524524 const store_offset = try c.extra.alloc(c.gpa, items.len);
525525
526526 for (
......@@ -653,7 +653,12 @@ fn valueToExpression(c: *NodeGen, v: Value) !Node.Index {
653653
654654 .external_value => {
655655 const external = v.toKey(c.ip).external_value;
656 try c.extern_symbols.put(c.gpa, external.key[0].toString().withLen(external.key[0].length(c.ip)), {});
656 const first_key = external.key.at(c.ip, 0);
657 try c.extern_symbols.put(
658 c.gpa,
659 first_key.toString().withLen(first_key.length(c.ip)),
660 {},
661 );
657662 return try c.add(.plain_value, .{ .value = v });
658663 },
659664
......@@ -730,7 +735,7 @@ fn codeGenBranch(c: *NodeGen, inst: Air.Inst.Ref, temporary: ?Node.Index) !?Bran
730735 });
731736
732737 const block: Air.IndexList = c.air.instData(.block, i);
733 for (block.slice(&c.air)) |item| {
738 for (block.get(&c.air)) |item| {
734739 try c.codeGenInst(item);
735740 }
736741
......@@ -781,7 +786,7 @@ fn codeGenBlock(c: *NodeGen, inst: Air.Inst.Index) !void {
781786 };
782787 const block: Air.IndexList = c.air.instData(.block, inst);
783788
784 for (block.slice(&c.air)) |item| {
789 for (block.get(&c.air)) |item| {
785790 try c.codeGenInst(item);
786791 }
787792
......@@ -814,7 +819,7 @@ fn codeGenBlockAsExpression(c: *NodeGen, inst: Air.Inst.Index) !Node.Index {
814819 .block = .{ .index = @intCast(scratch_top) },
815820 };
816821 const block: Air.IndexList = c.air.instData(.block, inst);
817 const instructions = block.slice(&c.air);
822 const instructions = block.get(&c.air);
818823 for (instructions[0 .. instructions.len - 1]) |item| {
819824 try c.codeGenInst(item);
820825 }
......@@ -885,7 +890,7 @@ fn canLowerToExpression(c: *const NodeGen, inst: Air.Inst.Ref) bool {
885890 // are lowerable. The break at the end just becomes the result.
886891 .block => {
887892 const block: Air.IndexList = c.air.instData(.block, index);
888 const items = block.slice(&c.air);
893 const items = block.get(&c.air);
889894 for (items[0 .. items.len - 1]) |item| {
890895 if (c.air.instFlags(item).uses == .multi)
891896 return false;
src/manual/generate_manual.zig+11-3
......@@ -70,7 +70,7 @@ pub fn main() !void {
7070 .contents = contents.items,
7171 .navigation = header.data.items,
7272 .nav_h1 = "Ix Language",
73 .repository = "https://github.com/paperdave/wl",
73 .repository = "https://github.com/paperdave/ix",
7474 .style = minified_style,
7575 });
7676
......@@ -83,7 +83,7 @@ pub fn main() !void {
8383 std.debug.lockStdErr();
8484 std.debug.unlockStdErr();
8585
86 std.process.exit(0);
86 std.process.exit(if (header.had_signaled) 1 else 0);
8787}
8888
8989const BlockType = enum {
......@@ -190,6 +190,8 @@ const HeaderWriter = struct {
190190
191191 has_closed_li: bool = true,
192192
193 had_signaled: bool = false,
194
193195 fn add(header: *HeaderWriter, alloc: Allocator, name: []const u8, id: []const u8, level: u8) !void {
194196 const w = header.data.writer(alloc);
195197
......@@ -440,6 +442,10 @@ fn processMarkdown(
440442
441443 try build.collectOutput(&out, &err, std.math.maxInt(usize));
442444 const result = try build.wait();
445 if (result == .Signal) {
446 std.debug.print("{s}\n", .{err.items});
447 header.had_signaled = true;
448 }
443449 if (result != .Exited or result.Exited != 0) {
444450 try err.writer().print("[Process {s} with {d}]", .{
445451 switch (result) {
......@@ -530,7 +536,9 @@ fn processMarkdown(
530536 }
531537 return e;
532538 };
533
539 if (run_result == .Signal) {
540 header.had_signaled = true;
541 }
534542 if (run_result != .Exited or run_result.Exited != 0) {
535543 try run_err.writer().print("[Process {s} with {d}]", .{
536544 switch (run_result) {