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 @@...@@ -11,6 +11,7 @@
11- fix: coerce `break` operands and implicit breaks to result type11- fix: coerce `break` operands and implicit breaks to result type
12- fix: coerce results when `if` expression branches merge12- fix: coerce results when `if` expression branches merge
13- fix: ensure if branch results to a runtime value when the condition is not compile-time known13- 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
14- fix: inferred array type uses item type for items instead of the container type.15- fix: inferred array type uses item type for items instead of the container type.
15- fix(js): stop printing redundant parenthesis on ternary expressions16- fix(js): stop printing redundant parenthesis on ternary expressions
1617
README.md+2-2
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1# Ix1# Ix
22
3Ix (`I`nferable E`x`pression) is a high-level, general purpose programming3Ix (*I*nferable E*x*pression) is a high-level, general purpose programming
4language. It features a mix of Rust, Zig, and JavaScript's great points.4language. It features a mix of Rust, Zig, and JavaScript's great points.
55
6For a guide on how to use Ix, see the manual included in the binary6For 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...@@ -29,6 +29,6 @@ CLI to check spelling mistakes and [`dprint`][dprint] for code formatting. It is
29recommended to setup editor integration with these two tools to prevent pushing29recommended to setup editor integration with these two tools to prevent pushing
30broken commits.30broken commits.
3131
32[ci]: https://buildkite.com/paperdave/compiler32[ci]: https://buildkite.com/paperclover/compiler
33[typos]: https://github.com/crate-ci/typos33[typos]: https://github.com/crate-ci/typos
34[dprint]: https://dprint.dev34[dprint]: https://dprint.dev
ci+16-14
...@@ -12,25 +12,27 @@ commit_short=$(echo "$commit" | cut -c -9)...@@ -12,25 +12,27 @@ commit_short=$(echo "$commit" | cut -c -9)
12typos12typos
13dprint check13dprint check
1414
15if [ -n "$BUILDKITE" ]; then15if [ -n "$BUILDKITE" ] || [ "$1" == "all" ]; then
16 # perform the entire build16 # perform the entire build
17 ./build all --summary all17 ./build all --summary all
1818
19 pushd zig-out/package19 if [ -n "$BUILDKITE" ]; then
20 zip -r compiler-$commit.zip *20 pushd zig-out/package
21 buildkite-agent artifact upload compiler-$commit.zip21 zip -r compiler-$commit.zip *
22 popd22 buildkite-agent artifact upload compiler-$commit.zip
23 popd
2324
24 rm -fr zig-out/site25 rm -fr zig-out/site
25 mkdir zig-out/site26 mkdir zig-out/site
26 cp zig-out/package/ix.html zig-out/site/index.html27 cp zig-out/package/ix.html zig-out/site/index.html
27 branch="$BUILDKITE_BRANCH"28 branch="$BUILDKITE_BRANCH"
28 if [ "$branch" = "dev" ]; then29 if [ "$branch" = "dev" ]; then
29 branch=main30 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
30 fi35 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
34else36else
35 # perform only the tests, with a shorter summary37 # perform only the tests, with a shorter summary
36 ./build test --summary new38 ./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...@@ -179,7 +179,7 @@ it cannot be assigned to a `var` without an explicit type annotation. Since
179float, but a compiler warning will be emitted.179float, but a compiler warning will be emitted.
180180
181```lang181```lang
182var number = 0; // `number` is a `float`, but not explicit182var number = 0; // `number` is `float`, but not explicit
183var number: int = 0; // `number` is `int`183var number: int = 0; // `number` is `int`
184var number: float = 0; // `number` is `float`184var number: float = 0; // `number` is `float`
185```185```
...@@ -203,7 +203,7 @@ fn main {...@@ -203,7 +203,7 @@ fn main {
203203
204The `return` expression can be used within functions to return early.204The `return` expression can be used within functions to return early.
205205
206```lang:run206```lang
207let print = @extern("console").log;207let print = @extern("console").log;
208208
209fn something(a: int) -> bool {209fn something(a: int) -> bool {
src/core/Air.Dump.zig+15-14
...@@ -52,7 +52,7 @@ pub const State = struct {...@@ -52,7 +52,7 @@ pub const State = struct {
52 switch (tag) {52 switch (tag) {
53 .block => {53 .block => {
54 const index_list: Air.IndexList = air.instData(.block, inst);54 const index_list: Air.IndexList = air.instData(.block, inst);
55 const insts = index_list.slice(air);55 const insts = index_list.get(air);
56 try s.dumpInstList(w, insts, '{', '}');56 try s.dumpInstList(w, insts, '{', '}');
57 },57 },
58 .arg => {58 .arg => {
...@@ -127,7 +127,7 @@ pub const State = struct {...@@ -127,7 +127,7 @@ pub const State = struct {
127 air127 air
128 .typeOfIndex(field.base, s.ip)128 .typeOfIndex(field.base, s.ip)
129 .toStructType(s.ip).?129 .toStructType(s.ip).?
130 .field_keys[field.field_index]130 .field_keys.at(s.ip, field.field_index)
131 .toSlice(s.ip),131 .toSlice(s.ip),
132 });132 });
133 try tty.setColor(w, .reset);133 try tty.setColor(w, .reset);
...@@ -149,7 +149,7 @@ pub const State = struct {...@@ -149,7 +149,7 @@ pub const State = struct {
149 try w.writeAll("(");149 try w.writeAll("(");
150 try s.dumpRef(w, call.base);150 try s.dumpRef(w, call.base);
151 try w.writeAll(", ");151 try w.writeAll(", ");
152 try s.dumpRefList(w, call_data.args.slice(air), '[', ']');152 try s.dumpRefList(w, call_data.args.get(air), '[', ']');
153 try w.writeAll(")");153 try w.writeAll(")");
154 },154 },
155 .@"if" => {155 .@"if" => {
...@@ -177,7 +177,7 @@ pub const State = struct {...@@ -177,7 +177,7 @@ pub const State = struct {
177 try s.dumpValue(w, struct_init.ty.value());177 try s.dumpValue(w, struct_init.ty.value());
178 try w.writeAll(", {");178 try w.writeAll(", {");
179 s.indent += 1;179 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| {
181 try s.newline(w);181 try s.newline(w);
182 try w.print("{}: ", .{key.fmt(s.ip)});182 try w.print("{}: ", .{key.fmt(s.ip)});
183 try s.dumpRef(w, ref);183 try s.dumpRef(w, ref);
...@@ -192,7 +192,7 @@ pub const State = struct {...@@ -192,7 +192,7 @@ pub const State = struct {
192192
193 try w.writeAll("(");193 try w.writeAll("(");
194 try s.dumpValue(w, array_type.item_type.value());194 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), '[', ']');
196 try w.writeAll(")");196 try w.writeAll(")");
197 },197 },
198 .tuple_init => {198 .tuple_init => {
...@@ -203,6 +203,7 @@ pub const State = struct {...@@ -203,6 +203,7 @@ pub const State = struct {
203 // try s.dumpValue(w, array_type.item_type.value());203 // try s.dumpValue(w, array_type.item_type.value());
204 // try s.dumpRefList(w, array_init.list.get(air).slice(air), '[', ']');204 // try s.dumpRefList(w, array_init.list.get(air).slice(air), '[', ']');
205 // try w.writeAll(")");205 // try w.writeAll(")");
206 @panic("TODO");
206 },207 },
207 }208 }
208 }209 }
...@@ -244,7 +245,7 @@ pub const State = struct {...@@ -244,7 +245,7 @@ pub const State = struct {
244 try tty.setColor(w, .blue);245 try tty.setColor(w, .blue);
245 try w.writeAll("fn(");246 try w.writeAll("fn(");
246 try tty.setColor(w, .reset);247 try tty.setColor(w, .reset);
247 for (ty.param_types, 0..) |param, i| {248 for (ty.param_types.get(s.ip), 0..) |param, i| {
248 if (i != 0) {249 if (i != 0) {
249 try tty.setColor(w, .blue);250 try tty.setColor(w, .blue);
250 try w.writeAll(", ");251 try w.writeAll(", ");
...@@ -322,8 +323,8 @@ pub const State = struct {...@@ -322,8 +323,8 @@ pub const State = struct {
322 try w.writeAll(" ");323 try w.writeAll(" ");
323324
324 for (325 for (
325 struct_type.field_keys,326 struct_type.field_keys.get(s.ip),
326 struct_type.field_types,327 struct_type.field_types.get(s.ip),
327 0..,328 0..,
328 ) |key, field_type, i| {329 ) |key, field_type, i| {
329 if (i != 0)330 if (i != 0)
...@@ -352,8 +353,8 @@ pub const State = struct {...@@ -352,8 +353,8 @@ pub const State = struct {
352 try w.writeAll(" ");353 try w.writeAll(" ");
353354
354 for (355 for (
355 struct_value.ty.toStructType(s.ip).?.field_keys,356 struct_value.ty.toStructType(s.ip).?.field_keys.get(s.ip),
356 struct_value.field_values,357 struct_value.field_values.get(s.ip),
357 0..,358 0..,
358 ) |key, value, i| {359 ) |key, value, i| {
359 if (i != 0)360 if (i != 0)
...@@ -385,7 +386,7 @@ pub const State = struct {...@@ -385,7 +386,7 @@ pub const State = struct {
385 try tty.setColor(w, .reset);386 try tty.setColor(w, .reset);
386 try w.writeAll("[");387 try w.writeAll("[");
387388
388 for (array_value.items, 0..) |value, i| {389 for (array_value.items.get(s.ip), 0..) |value, i| {
389 if (i != 0)390 if (i != 0)
390 try w.writeAll(", ");391 try w.writeAll(", ");
391 try s.dumpValue(w, value);392 try s.dumpValue(w, value);
...@@ -398,7 +399,7 @@ pub const State = struct {...@@ -398,7 +399,7 @@ pub const State = struct {
398 },399 },
399 .external_value => |external_value| {400 .external_value => |external_value| {
400 try w.writeAll("external '");401 try w.writeAll("external '");
401 for (external_value.key, 0..) |part, i| {402 for (external_value.key.get(s.ip), 0..) |part, i| {
402 if (i != 0) try w.writeAll(".");403 if (i != 0) try w.writeAll(".");
403 try w.writeAll(part.toSlice(s.ip));404 try w.writeAll(part.toSlice(s.ip));
404 }405 }
...@@ -406,7 +407,7 @@ pub const State = struct {...@@ -406,7 +407,7 @@ pub const State = struct {
406 },407 },
407 .tuple_type => |tuple_type| {408 .tuple_type => |tuple_type| {
408 try w.writeAll("(");409 try w.writeAll("(");
409 for (tuple_type.items, 0..) |item, i| {410 for (tuple_type.items.get(s.ip), 0..) |item, i| {
410 if (i != 0) try w.writeAll(", ");411 if (i != 0) try w.writeAll(", ");
411 try s.dumpValue(w, item.value());412 try s.dumpValue(w, item.value());
412 }413 }
...@@ -414,7 +415,7 @@ pub const State = struct {...@@ -414,7 +415,7 @@ pub const State = struct {
414 },415 },
415 .tuple_value => |tuple_value| {416 .tuple_value => |tuple_value| {
416 try w.writeAll("(");417 try w.writeAll("(");
417 for (tuple_value.items, 0..) |item, i| {418 for (tuple_value.items.get(s.ip), 0..) |item, i| {
418 if (i != 0) try w.writeAll(", ");419 if (i != 0) try w.writeAll(", ");
419 try s.dumpValue(w, item);420 try s.dumpValue(w, item);
420 }421 }
src/core/Air.zig+6-21
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1insts: Inst.List.Slice,1insts: Inst.List.Slice,
2extra: ExtraStore = .{},2extra: ExtraStore,
33
4pub const ExtraStore = dod.ExtraStore(.air, .@"const");4pub const ExtraStore = dod.ExtraStore(.air, .@"const");
5pub const EncodedData = dod.EncodedData(Inst.Tag, u64);5pub const EncodedData = dod.EncodedData(Inst.Tag, u64);
...@@ -201,23 +201,8 @@ pub const Flags = packed struct {...@@ -201,23 +201,8 @@ pub const Flags = packed struct {
201 };201 };
202};202};
203203
204pub const IndexList = struct {204pub const IndexList = ExtraStore.Slice(Air.Inst.Index);
205 start: u32,205pub const RefList = ExtraStore.Slice(Air.Inst.Ref);
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};
221206
222pub const Break = struct {207pub const Break = struct {
223 block: Inst.Index,208 block: Inst.Index,
...@@ -383,7 +368,7 @@ pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *const InternPool) In...@@ -383,7 +368,7 @@ pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *const InternPool) In
383 // TODO: taking the last instruction is likely wrong.368 // TODO: taking the last instruction is likely wrong.
384 // The last instruction is going to be a .break and be of type .never369 // The last instruction is going to be a .break and be of type .never
385 .block => {370 .block => {
386 const items = air.instData(.block, index).slice(air);371 const items = air.instData(.block, index).get(air);
387 assert(items.len > 0); // empty blocks should always be `Value.void`372 assert(items.len > 0); // empty blocks should always be `Value.void`
388 return air.typeOfIndex(items[items.len - 1], ip);373 return air.typeOfIndex(items[items.len - 1], ip);
389 },374 },
...@@ -402,7 +387,7 @@ pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *const InternPool) In...@@ -402,7 +387,7 @@ pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *const InternPool) In
402 const inst = air.instData(.field_struct, index);387 const inst = air.instData(.field_struct, index);
403 const base_type = air.typeOfIndex(inst.base, ip)388 const base_type = air.typeOfIndex(inst.base, ip)
404 .toStructType(ip) orelse unreachable; // field_struct demands struct type389 .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);
406 },391 },
407392
408 // Array accesses use the array they are accessing into.393 // 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...@@ -418,7 +403,7 @@ pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *const InternPool) In
418 const inst = air.instData(.field_tuple, index);403 const inst = air.instData(.field_tuple, index);
419 const base_type = air.typeOfIndex(inst.base, ip)404 const base_type = air.typeOfIndex(inst.base, ip)
420 .toTupleType(ip) orelse unreachable; // field_tuple demands tuple type405 .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);
422 },407 },
423 };408 };
424}409}
src/core/Hir.zig+1-1
...@@ -13,7 +13,7 @@...@@ -13,7 +13,7 @@
1313
14insts: Inst.List.Slice,14insts: Inst.List.Slice,
15string_bytes: []const u8,15string_bytes: []const u8,
16extra: ExtraStore = .{},16extra: ExtraStore,
17report: Report,17report: Report,
1818
19pub const ExtraStore = dod.ExtraStore(.hir, .@"const");19pub const ExtraStore = dod.ExtraStore(.hir, .@"const");
src/core/InternPool.zig+91-104
...@@ -21,9 +21,9 @@...@@ -21,9 +21,9 @@
21///21///
22/// The preferred way to access these this data through `.get()` and the methods22/// The preferred way to access these this data through `.get()` and the methods
23/// on `Value` and `Type`.23/// on `Value` and `Type`.
24map: std.AutoArrayHashMapUnmanaged(void, void) = .{},24map: std.AutoArrayHashMapUnmanaged(void, void) = .empty,
25items: std.MultiArrayList(Item) = .{},25items: std.MultiArrayList(Item) = .empty,
26extra: ExtraStore = .{},26extra: Extra = .empty,
2727
28/// In order to store references to strings in fewer bytes, we copy all28/// In order to store references to strings in fewer bytes, we copy all
29/// string bytes into here. String bytes can be null. It is up to whoever29/// string bytes into here. String bytes can be null. It is up to whoever
...@@ -146,7 +146,7 @@ pub const Tag = enum(u8) {...@@ -146,7 +146,7 @@ pub const Tag = enum(u8) {
146 .int32 => i32,146 .int32 => i32,
147 .opaque_value => Value,147 .opaque_value => Value,
148148
149 else => ExtraIndex(tag.Payload()),149 else => Extra.Index(tag.Payload()),
150 };150 };
151 }151 }
152152
...@@ -270,18 +270,7 @@ pub const Value = enum(u32) {...@@ -270,18 +270,7 @@ pub const Value = enum(u32) {
270 none = std.math.maxInt(u32),270 none = std.math.maxInt(u32),
271 _,271 _,
272272
273 /// An array of `Value` existing within the `extra` array.273 pub const Slice = Extra.Slice(Value);
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 };
285274
286 /// Used for a map of `Value` values to the index within a list of `Value` values.275 /// Used for a map of `Value` values to the index within a list of `Value` values.
287 const Adapter = struct {276 const Adapter = struct {
...@@ -316,6 +305,8 @@ pub const Value = enum(u32) {...@@ -316,6 +305,8 @@ pub const Value = enum(u32) {
316305
317 pub fn assertValid(value: Value, ip: *const InternPool) void {306 pub fn assertValid(value: Value, ip: *const InternPool) void {
318 assert(@intFromEnum(value) < ip.items.len);307 assert(@intFromEnum(value) < ip.items.len);
308 assert(value != .none);
309 assert(ip.items.items(.tag)[@intFromEnum(value)] != .removed);
319 }310 }
320311
321 pub fn dump(value: Value, ip: *const InternPool) std.fmt.Formatter(Value.formatValue) {312 pub fn dump(value: Value, ip: *const InternPool) std.fmt.Formatter(Value.formatValue) {
...@@ -459,17 +450,7 @@ pub const Type = enum(u32) {...@@ -459,17 +450,7 @@ pub const Type = enum(u32) {
459 tuple_type = @intFromEnum(InternPool.Tag.tuple_type),450 tuple_type = @intFromEnum(InternPool.Tag.tuple_type),
460 };451 };
461452
462 /// An array of `Index` existing within the `extra` array.453 pub const Slice = Extra.Slice(Type);
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 };
473454
474 pub fn value(ty: Type) Value {455 pub fn value(ty: Type) Value {
475 return @enumFromInt(@intFromEnum(ty));456 return @enumFromInt(@intFromEnum(ty));
...@@ -526,7 +507,7 @@ pub const Type = enum(u32) {...@@ -526,7 +507,7 @@ pub const Type = enum(u32) {
526 => true,507 => true,
527 .tuple_type => {508 .tuple_type => {
528 const tuple_type = ty.toTupleType(ip).?;509 const tuple_type = ty.toTupleType(ip).?;
529 for (tuple_type.items) |item| {510 for (tuple_type.items.get(ip)) |item| {
530 if (!item.hasPossibleRepresentation(ip)) {511 if (!item.hasPossibleRepresentation(ip)) {
531 return false;512 return false;
532 }513 }
...@@ -599,7 +580,7 @@ pub const Type = enum(u32) {...@@ -599,7 +580,7 @@ pub const Type = enum(u32) {
599 .function_type => {580 .function_type => {
600 const function_type = ty.toUnresolvedFunctionPrototype(ip).?;581 const function_type = ty.toUnresolvedFunctionPrototype(ip).?;
601 try writer.writeAll("fn(");582 try writer.writeAll("fn(");
602 for (function_type.param_types, 0..) |param, i| {583 for (function_type.param_types.get(ip), 0..) |param, i| {
603 if (i != 0) try writer.writeAll(", ");584 if (i != 0) try writer.writeAll(", ");
604 try writer.print("{}", .{param.displayName(ip)});585 try writer.print("{}", .{param.displayName(ip)});
605 }586 }
...@@ -619,7 +600,7 @@ pub const Type = enum(u32) {...@@ -619,7 +600,7 @@ pub const Type = enum(u32) {
619 },600 },
620 .tuple_type => {601 .tuple_type => {
621 try writer.writeAll("(");602 try writer.writeAll("(");
622 for (ty.toTupleType(ip).?.items, 0..) |item, i| {603 for (ty.toTupleType(ip).?.items.get(ip), 0..) |item, i| {
623 if (i != 0) try writer.writeAll(", ");604 if (i != 0) try writer.writeAll(", ");
624 try writer.print("{}", .{item.displayName(ip)});605 try writer.print("{}", .{item.displayName(ip)});
625 }606 }
...@@ -651,9 +632,8 @@ pub const Item = struct {...@@ -651,9 +632,8 @@ pub const Item = struct {
651 }632 }
652};633};
653634
654pub const ExtraStore = dod.ExtraStore(.intern_pool, .@"var");635pub const Extra = dod.ExtraStore(.intern_pool, .@"var");
655pub const EncodedData = dod.EncodedData(Tag, u32);636pub const EncodedData = dod.EncodedData(Tag, u32);
656pub const ExtraIndex = ExtraStore.Index;
657637
658/// How many items in the InternPool are statically known.638/// How many items in the InternPool are statically known.
659/// This is specified with an integer literal and a corresponding comptime639/// This is specified with an integer literal and a corresponding comptime
...@@ -674,9 +654,9 @@ pub const static_keys = [_]Key{...@@ -674,9 +654,9 @@ pub const static_keys = [_]Key{
674 SimpleType.never.key(),654 SimpleType.never.key(),
675 SimpleType.type.key(),655 SimpleType.type.key(),
676 SimpleType.numeric_literal.key(),656 SimpleType.numeric_literal.key(),
677 .{ .array_type = .{ .item_type = Type.numeric_literal } },657 .{ .array_type = .{ .item_type = .numeric_literal } },
678 .{ .array_type = .{ .item_type = Type.never } },658 .{ .array_type = .{ .item_type = .never } },
679 .{ .tuple_type = .{ .items = &.{} } },659 .{ .tuple_type = .{ .items = .empty } },
680660
681 SimpleValue.void.key(),661 SimpleValue.void.key(),
682 SimpleValue.true.key(),662 SimpleValue.true.key(),
...@@ -685,13 +665,13 @@ pub const static_keys = [_]Key{...@@ -685,13 +665,13 @@ pub const static_keys = [_]Key{
685 .{ .float = 0.0 },665 .{ .float = 0.0 },
686 .{ .float = Float.pure_nan.decode() },666 .{ .float = Float.pure_nan.decode() },
687 .{ .array_value = .{667 .{ .array_value = .{
688 .type = Type.never_array,668 .type = .never_array,
689 .items = &.{},669 .items = .empty,
690 } },670 } },
691 .{ .string = "" },671 .{ .string = "" },
692 .{ .tuple_value = .{672 .{ .tuple_value = .{
693 .type = .empty_tuple,673 .type = .empty_tuple,
694 .items = &.{},674 .items = .empty,
695 } },675 } },
696};676};
697677
...@@ -814,14 +794,7 @@ pub const NullTerminatedString = enum(u32) {...@@ -814,14 +794,7 @@ pub const NullTerminatedString = enum(u32) {
814 return .{ .data = .{ .string = self, .ip = ip } };794 return .{ .data = .{ .string = self, .ip = ip } };
815 }795 }
816796
817 pub const Slice = struct {797 pub const Slice = Extra.Slice(NullTerminatedString);
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 };
825};798};
826799
827pub const TrackedInst = extern struct {800pub const TrackedInst = extern struct {
...@@ -975,66 +948,74 @@ pub const Key = union(enum) {...@@ -975,66 +948,74 @@ pub const Key = union(enum) {
975 };948 };
976949
977 pub const FunctionType = struct {950 pub const FunctionType = struct {
978 param_types: []Type,951 param_types: Type.Slice,
979 /// If a return type is missing, it is inferred and not resolved yet.952 /// If a return type is missing, it is inferred and not resolved yet.
980 /// When analysis figures out a return type, a new `FunctionType` with953 /// When analysis figures out a return type, a new `FunctionType` with
981 /// the resolved return type.954 /// the resolved return type.
982 return_type: ?Type,955 return_type: ?Type,
983956
984 pub const Resolved = struct {957 pub const Resolved = struct {
985 param_types: []Type,958 param_types: Type.Slice,
986 return_type: Type,959 return_type: Type,
987 };960 };
988961
989 pub fn hash(self: FunctionType, hasher: *Hash) void {962 pub fn hash(self: FunctionType, ip: *const InternPool, hasher: *Hash) void {
990 const t = tracer.trace(@src());963 const t = tracer.trace(@src());
991 defer t.end();964 defer t.end();
992965
993 for (self.param_types) |param_type| {966 for (self.param_types.get(ip)) |param_type| {
994 std.hash.autoHash(hasher, param_type);967 std.hash.autoHash(hasher, param_type);
995 }968 }
996 std.hash.autoHash(hasher, self.return_type);969 std.hash.autoHash(hasher, self.return_type);
997 }970 }
998971
999 pub fn eql(a: FunctionType, b: FunctionType) bool {972 pub fn eql(a: FunctionType, b: FunctionType, ip: *const InternPool) bool {
1000 return std.mem.eql(Type, a.param_types, b.param_types) and973 return std.mem.eql(Type, a.param_types.get(ip), b.param_types.get(ip)) and
1001 a.return_type == b.return_type;974 a.return_type == b.return_type;
1002 }975 }
1003 };976 };
1004977
1005 pub const StructType = struct {978 pub const StructType = struct {
1006 field_keys: []NullTerminatedString,979 field_keys: NullTerminatedString.Slice,
1007 field_types: []const Type,980 field_types: Type.Slice,
1008981
1009 pub fn hash(self: StructType, hasher: *Hash) void {982 /// TODO: store where the struct is declared to make this a nomial type
1010 // TODO: remove this function. structural typing is not used983 pub fn hash(self: StructType, ip: *const InternPool, hasher: *Hash) void {
1011 // this should be hashing it's location / decl, exactly like `Func`984 for (self.field_keys.get(ip)) |value| {
1012 std.hash.autoHashStrat(hasher, self, .DeepRecursive);985 std.hash.autoHash(hasher, value);
986 }
987 for (self.field_types.get(ip)) |value| {
988 std.hash.autoHash(hasher, value);
989 }
1013 }990 }
1014 };991 };
1015992
1016 pub const StructValue = struct {993 pub const StructValue = struct {
1017 ty: Type,994 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 {
1021 std.hash.autoHash(hasher, self.ty);998 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 }
1023 }1002 }
1024 };1003 };
10251004
1026 pub const ArrayType = struct {1005 pub const ArrayType = struct {
1027 item_type: Type,1006 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;
1030 std.hash.autoHash(hasher, self.item_type);1010 std.hash.autoHash(hasher, self.item_type);
1031 }1011 }
1032 };1012 };
10331013
1034 pub const TupleType = struct {1014 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;
1038 std.hash.autoHashStrat(hasher, self.items, .Deep);1019 std.hash.autoHashStrat(hasher, self.items, .Deep);
1039 }1020 }
1040 };1021 };
...@@ -1042,30 +1023,31 @@ pub const Key = union(enum) {...@@ -1042,30 +1023,31 @@ pub const Key = union(enum) {
1042 pub const ExternalValue = struct {1023 pub const ExternalValue = struct {
1043 /// A list of strings to generate the property access1024 /// A list of strings to generate the property access
1044 /// so `console.log` would be .{ "console", "log" }1025 /// 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 {1028 pub fn hash(self: ExternalValue, ip: *const InternPool, hasher: *Hash) void {
1048 std.hash.autoHashStrat(hasher, self.key, .Shallow);1029 std.hash.autoHashStrat(hasher, self.key.get(ip), .Shallow);
1049 }1030 }
1050 };1031 };
10511032
1052 pub const ArrayValue = struct {1033 pub const ArrayValue = struct {
1053 /// This is the array type, not the item type1034 /// This is the array type, not the item type
1054 type: Type,1035 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 {
1058 std.hash.autoHash(hasher, self.type);1039 std.hash.autoHash(hasher, self.type);
1059 std.hash.autoHashStrat(hasher, self.items, .Deep);1040 std.hash.autoHashStrat(hasher, self.items.get(ip), .Deep);
1060 }1041 }
1061 };1042 };
10621043
1063 pub const TupleValue = struct {1044 pub const TupleValue = struct {
1064 /// This is the tuple type, not the item type1045 /// This is the tuple type, not the item type
1065 type: Type,1046 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;
1069 std.hash.autoHash(hasher, self.type);1051 std.hash.autoHash(hasher, self.type);
1070 std.hash.autoHashStrat(hasher, self.items, .Deep);1052 std.hash.autoHashStrat(hasher, self.items, .Deep);
1071 }1053 }
...@@ -1075,9 +1057,10 @@ pub const Key = union(enum) {...@@ -1075,9 +1057,10 @@ pub const Key = union(enum) {
1075 ty: Type,1057 ty: Type,
1076 owner_decl: DeclIndex,1058 owner_decl: DeclIndex,
1077 teg_body_inst: TrackedInst.Index,1059 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;
1081 std.hash.autoHash(hasher, self.ty);1064 std.hash.autoHash(hasher, self.ty);
1082 std.hash.autoHash(hasher, self.owner_decl);1065 std.hash.autoHash(hasher, self.owner_decl);
1083 std.hash.autoHash(hasher, self.teg_body_inst);1066 std.hash.autoHash(hasher, self.teg_body_inst);
...@@ -1095,7 +1078,6 @@ pub const Key = union(enum) {...@@ -1095,7 +1078,6 @@ pub const Key = union(enum) {
1095 }1078 }
10961079
1097 pub fn hash64(key: Key, ip: *const InternPool) u64 {1080 pub fn hash64(key: Key, ip: *const InternPool) u64 {
1098 _ = ip; // autofix
1099 const t = tracer.trace(@src());1081 const t = tracer.trace(@src());
1100 defer t.end();1082 defer t.end();
11011083
...@@ -1114,8 +1096,8 @@ pub const Key = union(enum) {...@@ -1114,8 +1096,8 @@ pub const Key = union(enum) {
1114 .float, .comptime_float => |x| Hash.hash(seed, asBytes(&Float.assertPure(x))),1096 .float, .comptime_float => |x| Hash.hash(seed, asBytes(&Float.assertPure(x))),
1115 inline .function_type,1097 inline .function_type,
1116 .func,1098 .func,
1117 .struct_type,
1118 .struct_value,1099 .struct_value,
1100 .struct_type,
1119 .array_value,1101 .array_value,
1120 .array_type,1102 .array_type,
1121 .external_value,1103 .external_value,
...@@ -1123,14 +1105,13 @@ pub const Key = union(enum) {...@@ -1123,14 +1105,13 @@ pub const Key = union(enum) {
1123 .tuple_value,1105 .tuple_value,
1124 => |x| {1106 => |x| {
1125 var hasher = Hash.init(seed);1107 var hasher = Hash.init(seed);
1126 x.hash(&hasher);1108 x.hash(ip, &hasher);
1127 return hasher.final();1109 return hasher.final();
1128 },1110 },
1129 };1111 };
1130 }1112 }
11311113
1132 pub fn eql(a: Key, b: Key, ip: *const InternPool) bool {1114 pub fn eql(a: Key, b: Key, ip: *const InternPool) bool {
1133 _ = ip; // autofix
1134 const t = tracer.trace(@src());1115 const t = tracer.trace(@src());
1135 defer t.end();1116 defer t.end();
11361117
...@@ -1148,7 +1129,7 @@ pub const Key = union(enum) {...@@ -1148,7 +1129,7 @@ pub const Key = union(enum) {
1148 => |x| std.mem.eql(u8, x, b.string),1129 => |x| std.mem.eql(u8, x, b.string),
1149 .float => |x| Float.assertPure(x) == Float.assertPure(b.float),1130 .float => |x| Float.assertPure(x) == Float.assertPure(b.float),
1150 .comptime_float => |x| Float.assertPure(x) == Float.assertPure(b.comptime_float),1131 .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),
1152 .func => |a_info| {1133 .func => |a_info| {
1153 const b_info = b.func;1134 const b_info = b.func;
1154 if (a_info.owner_decl != b_info.owner_decl)1135 if (a_info.owner_decl != b_info.owner_decl)
...@@ -1165,7 +1146,7 @@ pub const Key = union(enum) {...@@ -1165,7 +1146,7 @@ pub const Key = union(enum) {
1165 .struct_value => |a_info| {1146 .struct_value => |a_info| {
1166 const b_info = b.struct_value;1147 const b_info = b.struct_value;
1167 return a_info.ty == b_info.ty and1148 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));
1169 },1150 },
1170 .array_type => |a_info| {1151 .array_type => |a_info| {
1171 return a_info.item_type == b.array_type.item_type;1152 return a_info.item_type == b.array_type.item_type;
...@@ -1173,20 +1154,21 @@ pub const Key = union(enum) {...@@ -1173,20 +1154,21 @@ pub const Key = union(enum) {
1173 .array_value => |a_info| {1154 .array_value => |a_info| {
1174 const b_info = b.array_value;1155 const b_info = b.array_value;
1175 return a_info.type == b_info.type and1156 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));
1177 },1158 },
1178 .external_value => |a_info| {1159 .external_value => |a_info| {
1179 const b_info = b.external_value;1160 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));
1181 },1162 },
1182 .tuple_type => |a_info| {1163 .tuple_type => |a_info| {
1183 const b_info = b.tuple_type;1164 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));
1185 },1167 },
1186 .tuple_value => |a_info| {1168 .tuple_value => |a_info| {
1187 const b_info = b.tuple_value;1169 const b_info = b.tuple_value;
1188 return a_info.type == b_info.type and1170 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));
1190 },1172 },
1191 };1173 };
1192 }1174 }
...@@ -1438,8 +1420,8 @@ pub fn valueToKey(ip: *const InternPool, index: Value) Key {...@@ -1438,8 +1420,8 @@ pub fn valueToKey(ip: *const InternPool, index: Value) Key {
1438 data.decode(.struct_type, item.tag).getTrail(ip);1420 data.decode(.struct_type, item.tag).getTrail(ip);
14391421
1440 return .{ .struct_type = .{1422 return .{ .struct_type = .{
1441 .field_keys = trail.readNullTerminatedStringSlice(payload.fields_len).get(ip),1423 .field_keys = trail.readNullTerminatedStringSlice(payload.fields_len),
1442 .field_types = trail.readTypeSlice(payload.fields_len).get(ip),1424 .field_types = trail.readTypeSlice(payload.fields_len),
1443 } };1425 } };
1444 },1426 },
1445 .struct_value => {1427 .struct_value => {
...@@ -1449,8 +1431,10 @@ pub fn valueToKey(ip: *const InternPool, index: Value) Key {...@@ -1449,8 +1431,10 @@ pub fn valueToKey(ip: *const InternPool, index: Value) Key {
1449 return .{ .struct_value = .{1431 return .{ .struct_value = .{
1450 .ty = payload.ty,1432 .ty = payload.ty,
1451 .field_values = trail.readValueSlice(1433 .field_values = trail.readValueSlice(
1452 payload.ty.value().valueData(ip, .struct_type).get(ip).fields_len,1434 payload.ty.value()
1453 ).get(ip),1435 .valueData(ip, .struct_type)
1436 .get(ip).fields_len,
1437 ),
1454 } };1438 } };
1455 },1439 },
1456 .array_type => {1440 .array_type => {
...@@ -1463,31 +1447,34 @@ pub fn valueToKey(ip: *const InternPool, index: Value) Key {...@@ -1463,31 +1447,34 @@ pub fn valueToKey(ip: *const InternPool, index: Value) Key {
1463 const payload: Tag.ArrayValue, var trail = data.decode(.array_value, item.tag).getTrail(ip);1447 const payload: Tag.ArrayValue, var trail = data.decode(.array_value, item.tag).getTrail(ip);
1464 return .{ .array_value = .{1448 return .{ .array_value = .{
1465 .type = payload.type,1449 .type = payload.type,
1466 .items = trail.readValueSlice(payload.items_len).get(ip),1450 .items = trail.readValueSlice(payload.items_len),
1467 } };1451 } };
1468 },1452 },
1469 .external_value => {1453 .external_value => {
1470 const payload: Tag.ExternalValue, var trail = data.decode(.external_value, item.tag).getTrail(ip);1454 const payload: Tag.ExternalValue, var trail = data.decode(.external_value, item.tag).getTrail(ip);
1471 return .{ .external_value = .{1455 return .{ .external_value = .{
1472 .key = trail.readNullTerminatedStringSlice(payload.key_count).get(ip),1456 .key = trail.readNullTerminatedStringSlice(payload.key_count),
1473 } };1457 } };
1474 },1458 },
1475 .tuple_type => {1459 .tuple_type => {
1476 const payload: Tag.TupleType, var trail = data.decode(.tuple_type, item.tag).getTrail(ip);1460 const payload: Tag.TupleType, var trail = data.decode(.tuple_type, item.tag).getTrail(ip);
1477 return .{ .tuple_type = .{1461 return .{ .tuple_type = .{
1478 .items = trail.readTypeSlice(payload.items_len).get(ip),1462 .items = trail.readTypeSlice(payload.items_len),
1479 } };1463 } };
1480 },1464 },
1481 .tuple_value => {1465 .tuple_value => {
1482 const payload: Tag.TupleValue, var trail = data.decode(.tuple_value, item.tag).getTrail(ip);1466 const payload: Tag.TupleValue, var trail = data.decode(.tuple_value, item.tag).getTrail(ip);
1483 return .{ .tuple_value = .{1467 return .{ .tuple_value = .{
1484 .type = payload.type,1468 .type = payload.type,
1485 .items = trail.readValueSlice(payload.items_len).get(ip),1469 .items = trail.readValueSlice(payload.items_len),
1486 } };1470 } };
1487 },1471 },
1488 };1472 };
1489}1473}
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.
1491pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Value {1478pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Value {
1492 const t = tracer.traceFmt(@src(), "{s}", .{@tagName(key)});1479 const t = tracer.traceFmt(@src(), "{s}", .{@tagName(key)});
1493 defer t.end();1480 defer t.end();
...@@ -1536,25 +1523,25 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Value {...@@ -1536,25 +1523,25 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Value {
1536 break :brk Item.encode(.func, extra);1523 break :brk Item.encode(.func, extra);
1537 },1524 },
1538 .function_type => |f| brk: {1525 .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
1541 const extra, var trail = try ip.extra.appendTrailing(gpa, Tag.FunctionType, .{1528 const extra, var trail = try ip.extra.appendTrailing(gpa, Tag.FunctionType, .{
1542 .params_len = @intCast(f.param_types.len),1529 .params_len = @intCast(f.param_types.len),
1543 .return_type = .init(f.return_type),1530 .return_type = .init(f.return_type),
1544 }, f.param_types.len);1531 }, f.param_types.len);
1545 defer trail.end();1532 defer trail.end();
1546 trail.writeSlice(f.param_types);1533 trail.writeSlice(f.param_types.get(ip));
1547 break :brk Item.encode(.function_type, extra);1534 break :brk Item.encode(.function_type, extra);
1548 },1535 },
1549 .struct_type => |s| brk: {1536 .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
1552 assert(s.field_keys.len == s.field_types.len);1539 assert(s.field_keys.len == s.field_types.len);
1553 const extra, var trail = try ip.extra.appendTrailing(gpa, Tag.StructType, .{1540 const extra, var trail = try ip.extra.appendTrailing(gpa, Tag.StructType, .{
1554 .fields_len = @intCast(s.field_keys.len),1541 .fields_len = @intCast(s.field_keys.len),
1555 }, s.field_keys.len * 2);1542 }, s.field_keys.len * 2);
1556 trail.writeSlice(s.field_keys);1543 trail.writeSlice(s.field_keys.get(ip));
1557 trail.writeSlice(s.field_types);1544 trail.writeSlice(s.field_types.get(ip));
15581545
1559 break :brk Item.encode(.struct_type, extra);1546 break :brk Item.encode(.struct_type, extra);
1560 },1547 },
...@@ -1563,7 +1550,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Value {...@@ -1563,7 +1550,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Value {
1563 const extra, var trail = try ip.extra.appendTrailing(gpa, Tag.StructValue, .{1550 const extra, var trail = try ip.extra.appendTrailing(gpa, Tag.StructValue, .{
1564 .ty = s.ty,1551 .ty = s.ty,
1565 }, s.field_values.len);1552 }, s.field_values.len);
1566 trail.writeSlice(s.field_values);1553 trail.writeSlice(s.field_values.get(ip));
1567 break :brk Item.encode(.struct_value, extra);1554 break :brk Item.encode(.struct_value, extra);
1568 },1555 },
1569 .array_type => |s| brk: {1556 .array_type => |s| brk: {
...@@ -1576,21 +1563,21 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Value {...@@ -1576,21 +1563,21 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Value {
1576 .type = s.type,1563 .type = s.type,
1577 .items_len = @intCast(s.items.len),1564 .items_len = @intCast(s.items.len),
1578 }, s.items.len);1565 }, s.items.len);
1579 trail.writeSlice(s.items);1566 trail.writeSlice(s.items.get(ip));
1580 break :brk Item.encode(.array_value, extra);1567 break :brk Item.encode(.array_value, extra);
1581 },1568 },
1582 .external_value => |s| brk: {1569 .external_value => |s| brk: {
1583 const extra, var trail = try ip.extra.appendTrailing(gpa, Tag.ExternalValue, .{1570 const extra, var trail = try ip.extra.appendTrailing(gpa, Tag.ExternalValue, .{
1584 .key_count = @intCast(s.key.len),1571 .key_count = @intCast(s.key.len),
1585 }, s.key.len);1572 }, s.key.len);
1586 trail.writeSlice(s.key);1573 trail.writeSlice(s.key.get(ip));
1587 break :brk Item.encode(.external_value, extra);1574 break :brk Item.encode(.external_value, extra);
1588 },1575 },
1589 .tuple_type => |s| brk: {1576 .tuple_type => |s| brk: {
1590 const extra, var trail = try ip.extra.appendTrailing(gpa, Tag.TupleType, .{1577 const extra, var trail = try ip.extra.appendTrailing(gpa, Tag.TupleType, .{
1591 .items_len = @intCast(s.items.len),1578 .items_len = @intCast(s.items.len),
1592 }, s.items.len);1579 }, s.items.len);
1593 trail.writeSlice(s.items);1580 trail.writeSlice(s.items.get(ip));
1594 break :brk Item.encode(.tuple_type, extra);1581 break :brk Item.encode(.tuple_type, extra);
1595 },1582 },
1596 .tuple_value => |s| brk: {1583 .tuple_value => |s| brk: {
...@@ -1598,7 +1585,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Value {...@@ -1598,7 +1585,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Value {
1598 .type = s.type,1585 .type = s.type,
1599 .items_len = @intCast(s.items.len),1586 .items_len = @intCast(s.items.len),
1600 }, s.items.len);1587 }, s.items.len);
1601 trail.writeSlice(s.items);1588 trail.writeSlice(s.items.get(ip));
1602 break :brk Item.encode(.tuple_value, extra);1589 break :brk Item.encode(.tuple_value, extra);
1603 },1590 },
1604 };1591 };
...@@ -1613,13 +1600,13 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Value {...@@ -1613,13 +1600,13 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Value {
16131600
1614fn extraTypeFunction(1601fn extraTypeFunction(
1615 ip: *const InternPool,1602 ip: *const InternPool,
1616 extra_index: ExtraIndex(Tag.FunctionType),1603 extra_index: Extra.Index(Tag.FunctionType),
1617) Key.FunctionType {1604) Key.FunctionType {
1618 const function_type, var trail = extra_index.getTrail(ip);1605 const function_type, var trail = extra_index.getTrail(ip);
1619 const param_types = trail.readTypeSlice(function_type.params_len);1606 const param_types = trail.readTypeSlice(function_type.params_len);
1620 const result: Key.FunctionType = .{1607 const result: Key.FunctionType = .{
1621 .return_type = function_type.return_type.unwrap(),1608 .return_type = function_type.return_type.unwrap(),
1622 .param_types = param_types.get(ip),1609 .param_types = param_types,
1623 };1610 };
1624 return result;1611 return result;
1625}1612}
src/core/Report.zig+6-7
...@@ -111,8 +111,7 @@ pub const Err = union(enum) {...@@ -111,8 +111,7 @@ pub const Err = union(enum) {
111 },111 },
112 no_main_func: struct {112 no_main_func: struct {
113 fn build(_: @This(), ctx: *MsgContext) !void {113 fn build(_: @This(), ctx: *MsgContext) !void {
114 // TODO: variant that includes file, but no location114 try ctx.msg(.{ .codepoint_eol = 0 }, "missing top-level function \"main\"", .{});
115 try ctx.msgToken(0, "missing top-level function \"main\"", .{});
116 }115 }
117 },116 },
118 unknown_identifier: struct {117 unknown_identifier: struct {
...@@ -455,7 +454,8 @@ pub const Err = union(enum) {...@@ -455,7 +454,8 @@ pub const Err = union(enum) {
455 data.ty.displayName(ctx.ip()),454 data.ty.displayName(ctx.ip()),
456 formatId(455 formatId(
457 data.ty.toStructType(ctx.ip()).?456 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()),
459 ),459 ),
460 },460 },
461 );461 );
...@@ -872,7 +872,7 @@ fn formatItem(...@@ -872,7 +872,7 @@ fn formatItem(
872 try tty.setColor(writer, .reset);872 try tty.setColor(writer, .reset);
873 try tty.setColor(writer, prefix.color());873 try tty.setColor(writer, prefix.color());
874 try tty.setColor(writer, .bold);874 try tty.setColor(writer, .bold);
875 try writer.writeBytesNTimes("━", at.slice.len);875 try writer.writeBytesNTimes("━", @max(at.slice.len, 1));
876 try tty.setColor(writer, .reset);876 try tty.setColor(writer, .reset);
877 try writer.writeAll("\n");877 try writer.writeAll("\n");
878 }878 }
...@@ -1074,11 +1074,10 @@ pub const Highlight = union(enum) {...@@ -1074,11 +1074,10 @@ pub const Highlight = union(enum) {
1074 .byte = b,1074 .byte = b,
1075 .slice = ast.utf8_source[b..][0..len],1075 .slice = ast.utf8_source[b..][0..len],
1076 .loc = .{1076 .loc = .{
1077 // TODO:
1078 .column = .start,1077 .column = .start,
1079 .line = .start,1078 .line = .start,
1080 .line_start = 0,1079 .line_start = b,
1081 .line_end = @intCast(ast.utf8_source.len),1080 .line_end = @intCast(b + len),
1082 },1081 },
1083 };1082 };
1084 },1083 },
src/core/Sema.zig+64-39
...@@ -547,7 +547,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)...@@ -547,7 +547,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
547 return return_type.value().toAir();547 return return_type.value().toAir();
548 },548 },
549 else => return s.addRef(.arg, .{549 else => return s.addRef(.arg, .{
550 .type = proto.param_types[param.data],550 .type = proto.param_types.at(s.ip, param.data),
551 .arg_number = param.data,551 .arg_number = param.data,
552 }),552 }),
553 }553 }
...@@ -664,8 +664,8 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)...@@ -664,8 +664,8 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
664 }664 }
665665
666 return try s.makeValueAir(.{ .struct_type = .{666 return try s.makeValueAir(.{ .struct_type = .{
667 .field_keys = scratch.items(.keys),667 .field_keys = try s.ip.extra.appendSlice(s.gpa, scratch.items(.keys)),
668 .field_types = scratch.items(.types),668 .field_types = try s.ip.extra.appendSlice(s.gpa, scratch.items(.types)),
669 } });669 } });
670 },670 },
671 .discard => {671 .discard => {
...@@ -689,7 +689,10 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)...@@ -689,7 +689,10 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
689 @panic("TODO: support strings with null here");689 @panic("TODO: support strings with null here");
690 };690 };
691 return try s.makeValueAir(.{ .external_value = .{691 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 ),
693 } });696 } });
694 },697 },
695 .field => {698 .field => {
...@@ -708,13 +711,13 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)...@@ -708,13 +711,13 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
708 const previous_key = value.toKey(s.ip).external_value.key;711 const previous_key = value.toKey(s.ip).external_value.key;
709712
710 const new_key = try std.mem.concat(s.arena(), NullTerminatedString, &.{713 const new_key = try std.mem.concat(s.arena(), NullTerminatedString, &.{
711 previous_key,714 previous_key.get(s.ip),
712 &.{field_key},715 &.{field_key},
713 });716 });
714 defer s.arena().free(new_key);717 defer s.arena().free(new_key);
715718
716 return s.makeValueAir(.{ .external_value = .{719 return s.makeValueAir(.{ .external_value = .{
717 .key = new_key,720 .key = try s.ip.extra.appendSlice(s.gpa, new_key),
718 } });721 } });
719 }722 }
720 }723 }
...@@ -764,7 +767,11 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)...@@ -764,7 +767,11 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
764 }767 }
765768
766 // validate function args769 // 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| {
768 const ref = s.getRef(arg, .marked);775 const ref = s.getRef(arg, .marked);
769 const coerced = try s.coerceRef(776 const coerced = try s.coerceRef(
770 s.lazyNode(.argument(@intCast(i))),777 s.lazyNode(.argument(@intCast(i))),
...@@ -838,19 +845,23 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)...@@ -838,19 +845,23 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
838 for (scratch.slice(), scratch.sliceReinterpret(Value)) |ref, *value| {845 for (scratch.slice(), scratch.sliceReinterpret(Value)) |ref, *value| {
839 value.* = ref.decode().value;846 value.* = ref.decode().value;
840 }847 }
841 return try s.makeValueAir(.{ .array_value = .{848 return try s.makeValueAir(.{
842 .type = ty,849 .array_value = .{
843 .items = result_storage,850 .type = ty,
844 } });851 // TODO: do not clone memory here
852 .items = try s.ip.extra.appendSlice(s.gpa, result_storage),
853 },
854 });
845 } else {855 } else {
846 // Create a runtime array instantiation856 // Create a runtime array instantiation
847 try s.ensureAtRuntime(s.lazyNode(.main_node));857 try s.ensureAtRuntime(s.lazyNode(.main_node));
848 return try s.addRef(.array_init, .{858 return try s.addRef(.array_init, .{
849 .ty = ty,859 .ty = ty,
850 .list = try s.func.?.extra.append(s.gpa, Air.RefList, .{860 .list = try s.func.?.extra.append(
851 .start = try s.func.?.extra.appendSlice(s.gpa, scratch.slice()),861 s.gpa,
852 .len = node.list.len,862 Air.RefList,
853 }),863 try s.func.?.extra.appendSlice(s.gpa, scratch.slice()),
864 ),
854 });865 });
855 }866 }
856 },867 },
...@@ -1017,7 +1028,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)...@@ -1017,7 +1028,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
1017 const brk: Hir.Break = s.frame.currentPayload(.@"break");1028 const brk: Hir.Break = s.frame.currentPayload(.@"break");
1018 const operand = s.getRef(brk.operand, .marked);1029 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
1022 const mark = core.U32Stack.Mark{ .stack = &s.scratch, .index = s.frame.mark_index };1033 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)...@@ -1028,7 +1039,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
1028 const coerced = if (proto.return_type) |return_coercion|1039 const coerced = if (proto.return_type) |return_coercion|
1029 try s.coerceRef(s.lazyNode(.operand), operand, return_coercion)1040 try s.coerceRef(s.lazyNode(.operand), operand, return_coercion)
1030 else1041 else
1031 operand;1042 try s.ensureRefRuntime(s.lazyNode(.operand), operand);
1032 s.inst_map.add(s.frame.block_index, coerced);1043 s.inst_map.add(s.frame.block_index, coerced);
10331044
1034 const indexes = mark.slice(u32);1045 const indexes = mark.slice(u32);
...@@ -1388,7 +1399,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)...@@ -1388,7 +1399,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
1388 // may be different than the instantiation. The fields are visited in1399 // may be different than the instantiation. The fields are visited in
1389 // order of the instantiation.1400 // order of the instantiation.
1390 for (node.keys(&s.hir), node.inits(&s.hir), 0..) |init_key, init_value, i| {1401 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| {
1392 if (decl_key.eqlSlice(init_key.slice(s.hir.string_bytes), s.ip))1403 if (decl_key.eqlSlice(init_key.slice(s.hir.string_bytes), s.ip))
1393 break :index j;1404 break :index j;
1394 } else {1405 } else {
...@@ -1410,7 +1421,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)...@@ -1410,7 +1421,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
1410 const coerced = s.getCoercedRef(1421 const coerced = s.getCoercedRef(
1411 s.lazyNode(.argument(@intCast(i))),1422 s.lazyNode(.argument(@intCast(i))),
1412 init_value,1423 init_value,
1413 struct_type.field_types[found_index],1424 struct_type.field_types.at(s.ip, found_index),
1414 .marked,1425 .marked,
1415 ) catch |e| switch (e) {1426 ) catch |e| switch (e) {
1416 error.AnalysisFail => {1427 error.AnalysisFail => {
...@@ -1452,7 +1463,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)...@@ -1452,7 +1463,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
1452 }1463 }
1453 return try s.makeValueAir(.{ .struct_value = .{1464 return try s.makeValueAir(.{ .struct_value = .{
1454 .ty = ty,1465 .ty = ty,
1455 .field_values = result_storage,1466 .field_values = try s.ip.extra.appendSlice(s.gpa, result_storage),
1456 } });1467 } });
1457 } else {1468 } else {
1458 try s.ensureAtRuntime(s.lazyNode(.main_node));1469 try s.ensureAtRuntime(s.lazyNode(.main_node));
...@@ -1460,7 +1471,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)...@@ -1460,7 +1471,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
1460 const value_index = try s.func.?.extra.appendSlice(s.gpa, scratch.slice());1471 const value_index = try s.func.?.extra.appendSlice(s.gpa, scratch.slice());
1461 return try s.addRef(.struct_init, .{1472 return try s.addRef(.struct_init, .{
1462 .ty = ty,1473 .ty = ty,
1463 .field_values = value_index,1474 .field_values = value_index.start,
1464 });1475 });
1465 }1476 }
1466 },1477 },
...@@ -1481,7 +1492,9 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)...@@ -1481,7 +1492,9 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
1481 dst.* = try s.getType(s.lazyNode(.argument(@intCast(i))), src);1492 dst.* = try s.getType(s.lazyNode(.argument(@intCast(i))), src);
1482 }1493 }
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 } });
1485 },1498 },
14861499
1487 .tuple_init => {1500 .tuple_init => {
...@@ -1515,7 +1528,12 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)...@@ -1515,7 +1528,12 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
1515 ty.* = s.typeOfRef(val);1528 ty.* = s.typeOfRef(val);
1516 }1529 }
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 });
1519 };1537 };
15201538
1521 if (is_const) {1539 if (is_const) {
...@@ -1525,14 +1543,17 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)...@@ -1525,14 +1543,17 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
1525 value.* = ref.decode().value;1543 value.* = ref.decode().value;
1526 }1544 }
15271545
1528 return try s.makeValueAir(.{ .tuple_value = .{1546 return try s.makeValueAir(.{
1529 .items = result_storage,1547 .tuple_value = .{
1530 .type = ty,1548 // TODO: memory leak
1531 } });1549 .items = try s.ip.extra.appendSlice(s.gpa, result_storage),
1550 .type = ty,
1551 },
1552 });
1532 } else {1553 } else {
1533 const value_index = try s.func.?.extra.appendSlice(s.gpa, scratch.slice());1554 const value_index = try s.func.?.extra.appendSlice(s.gpa, scratch.slice());
1534 return try s.addRef(.struct_init, .{1555 return try s.addRef(.struct_init, .{
1535 .field_values = value_index,1556 .field_values = value_index.start,
1536 .ty = ty,1557 .ty = ty,
1537 });1558 });
1538 }1559 }
...@@ -1550,7 +1571,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)...@@ -1550,7 +1571,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
1550 if (result.argument >= func.param_types.len)1571 if (result.argument >= func.param_types.len)
1551 return Value.opaque_type.toAir();1572 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();
1554 },1575 },
15551576
1556 .result_type_array_value => {1577 .result_type_array_value => {
...@@ -1575,7 +1596,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)...@@ -1575,7 +1596,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
15751596
1576 _ = ty;1597 _ = ty;
15771598
1578 @panic("TODO: tuple result type resolution"); // tuples are not implemented1599 @panic("TODO: tuple result type resolution");
1579 },1600 },
15801601
1581 .result_type_struct_field => {1602 .result_type_struct_field => {
...@@ -1589,7 +1610,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)...@@ -1589,7 +1610,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag)
1589 return Value.opaque_type.toAir();1610 return Value.opaque_type.toAir();
15901611
1591 const to_match = result.field.slice(s.hir.string_bytes);1612 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| {
1593 if (k.eqlSlice(to_match, s.ip)) {1614 if (k.eqlSlice(to_match, s.ip)) {
1594 return v.value().toAir();1615 return v.value().toAir();
1595 }1616 }
...@@ -1857,9 +1878,14 @@ fn coerceRef(s: *Sema, src: LazyNode, ref: Air.Inst.Ref, to: Type) !Air.Inst.Ref...@@ -1857,9 +1878,14 @@ fn coerceRef(s: *Sema, src: LazyNode, ref: Air.Inst.Ref, to: Type) !Air.Inst.Ref
1857/// Same as `coerceRef` but on a compile-time known value1878/// Same as `coerceRef` but on a compile-time known value
1858fn coerceValue(s: *Sema, src: LazyNode, value: Value, to: Type) Error!Value {1879fn coerceValue(s: *Sema, src: LazyNode, value: Value, to: Type) Error!Value {
1859 const from = value.typeOf(s.ip);1880 const from = value.typeOf(s.ip);
1881
1882 from.assertValid(s.ip);
1883 to.assertValid(s.ip);
1884
1860 if (from == to) {1885 if (from == to) {
1861 return value;1886 return value;
1862 }1887 }
1888
1863 switch (to) {1889 switch (to) {
1864 .@"opaque" => {1890 .@"opaque" => {
1865 return try s.makeValue(.{ .opaque_value = value });1891 return try s.makeValue(.{ .opaque_value = value });
...@@ -2069,7 +2095,7 @@ fn coerceArrayValue(s: *Sema, src: LazyNode, value: Value, item_type: Type) !Val...@@ -2069,7 +2095,7 @@ fn coerceArrayValue(s: *Sema, src: LazyNode, value: Value, item_type: Type) !Val
20692095
2070 return try s.makeValue(.{ .array_value = .{2096 return try s.makeValue(.{ .array_value = .{
2071 .type = try s.makeType(.{ .array_type = .{ .item_type = item_type } }),2097 .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()),
2073 } });2099 } });
2074}2100}
20752101
...@@ -2096,8 +2122,8 @@ fn coerceTupleValue(...@@ -2096,8 +2122,8 @@ fn coerceTupleValue(
20962122
2097 // This function will append new items to the intern pool, invalidating2123 // This function will append new items to the intern pool, invalidating
2098 // existing ones. Copy all data into a stable slice first.2124 // existing ones. Copy all data into a stable slice first.
2099 @memcpy(scratch.items(.values), tuple_value.items);2125 @memcpy(scratch.items(.values), tuple_value.items.get(s.ip));
2100 @memcpy(scratch.items(.types), target_key.items);2126 @memcpy(scratch.items(.types), target_key.items.get(s.ip));
21012127
2102 for (0..len) |i| {2128 for (0..len) |i| {
2103 // `s.scratch` can be invalidated by having a tuple of tuples and coercing it.2129 // `s.scratch` can be invalidated by having a tuple of tuples and coercing it.
...@@ -2107,7 +2133,7 @@ fn coerceTupleValue(...@@ -2107,7 +2133,7 @@ fn coerceTupleValue(
21072133
2108 return try s.makeValue(.{ .tuple_value = .{2134 return try s.makeValue(.{ .tuple_value = .{
2109 .type = target_type,2135 .type = target_type,
2110 .items = scratch.items(.values),2136 .items = try s.ip.extra.appendSlice(s.gpa, scratch.items(.values)),
2111 } });2137 } });
2112}2138}
21132139
...@@ -2205,7 +2231,7 @@ fn fieldAccessStruct(...@@ -2205,7 +2231,7 @@ fn fieldAccessStruct(
2205 else => |e| return e,2231 else => |e| return e,
2206 };2232 };
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| {
2209 if (key == lookup)2235 if (key == lookup)
2210 break @as(u32, @intCast(i));2236 break @as(u32, @intCast(i));
2211 } else null;2237 } else null;
...@@ -2341,7 +2367,7 @@ fn fieldAccessTuple(...@@ -2341,7 +2367,7 @@ fn fieldAccessTuple(
23412367
2342 switch (lhs.decode()) {2368 switch (lhs.decode()) {
2343 .value => |value| {2369 .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();
2345 },2371 },
2346 .index => |lhs_index| {2372 .index => |lhs_index| {
2347 try s.ensureAtRuntime(s.lazyNode(.lhs));2373 try s.ensureAtRuntime(s.lazyNode(.lhs));
...@@ -2359,11 +2385,10 @@ fn postVisitFunctionPrototype(s: *Sema, reserve: FunctionReserve, return_type: ?...@@ -2359,11 +2385,10 @@ fn postVisitFunctionPrototype(s: *Sema, reserve: FunctionReserve, return_type: ?
2359 const tracked_inst = try s.ip.trackInst(s.gpa, s.file, s.frame.currentIndex());2385 const tracked_inst = try s.ip.trackInst(s.gpa, s.file, s.frame.currentIndex());
2360 const func_type = try s.makeType(.{2386 const func_type = try s.makeType(.{
2361 .function_type = .{2387 .function_type = .{
2362 .param_types = reserve.items(.params),2388 .param_types = try s.ip.extra.appendSlice(s.gpa, reserve.items(.params)),
2363 .return_type = return_type,2389 .return_type = return_type,
2364 },2390 },
2365 });2391 });
2366 // TODO: make a dedicated function to insert a new function
2367 const func_value = try s.makeValue(.{2392 const func_value = try s.makeValue(.{
2368 .func = .{2393 .func = .{
2369 .ty = func_type,2394 .ty = func_type,
src/core/array.zig+122-72
...@@ -81,24 +81,14 @@ pub const StoreKind = enum {...@@ -81,24 +81,14 @@ pub const StoreKind = enum {
81 air,81 air,
82 js_tree,82 js_tree,
8383
84 pub fn resolveStoreConst(84 pub fn resolveStore(
85 comptime kind: StoreKind,85 comptime kind: StoreKind,
86 owner: anytype,86 owner: anytype,
87 ) *const kind.ResolvedStore(@TypeOf(owner)) {87 ) kind.ResolvedStorePtr(@TypeOf(owner)) {
88 return &owner.extra;88 return &owner.extra;
89 }89 }
9090
91 pub fn resolveStoreMut(91 pub fn ResolvedStore(kind: StoreKind, Owner: type) type {
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 {
102 const ptr = @typeInfo(Owner).pointer;92 const ptr = @typeInfo(Owner).pointer;
103 assert(ptr.size == .One);93 assert(ptr.size == .One);
104 const mutability = brk: for (@typeInfo(ptr.child).@"struct".fields) |field| {94 const mutability = brk: for (@typeInfo(ptr.child).@"struct".fields) |field| {
...@@ -108,42 +98,32 @@ pub const StoreKind = enum {...@@ -108,42 +98,32 @@ pub const StoreKind = enum {
108 } else unreachable;98 } else unreachable;
109 return ExtraStore(kind, mutability);99 return ExtraStore(kind, mutability);
110 }100 }
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 {102 pub fn ResolvedStorePtr(kind: StoreKind, Owner: type) type {
120 return kind.resolveStoreConst(owner).get(T, @intFromEnum(index));103 return kind.ItemPointer(Owner, .One, kind.ResolvedStore(Owner));
121 }104 }
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 }
139105
140 pub fn jsonStringify(index: @This(), jw: anytype) !void {106 pub fn ItemPointer(
141 try jw.write(@intFromEnum(index));107 kind: StoreKind,
142 }108 Owner: type,
143 };109 size: std.builtin.Type.Pointer.Size,
144 }110 child: type,
145 };111 ) type {
146}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
148pub fn EncodedData(comptime Tag: type, backing_type: type) type {128pub fn EncodedData(comptime Tag: type, backing_type: type) type {
149 return enum(backing_type) {129 return enum(backing_type) {
...@@ -230,23 +210,89 @@ pub inline fn extraSizeOf(comptime T: type) usize {...@@ -230,23 +210,89 @@ pub inline fn extraSizeOf(comptime T: type) usize {
230 };210 };
231}211}
232212
233// TODO: rename to Store213pub const ExtraStore = Store;
234pub fn ExtraStore(comptime set_kind: StoreKind, comptime set_mutability: Mutability) type {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
235 return struct {278 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
240 pub const kind = set_kind;285 pub const kind = set_kind;
241 pub const mutability = set_mutability;286 pub const mutability = set_mutability;
242287
243 const Store = @This();288 pub const Index = wrappers.Index;
244289 pub const Slice = wrappers.Slice;
245 pub const Index = ExtraWrap(kind).Index;
246290
247 pub const List = switch (mutability) {291 pub const Inner = switch (mutability) {
248 .@"const" => struct {292 .@"const" => struct {
249 items: []const u32 = &.{},293 items: []const u32,
294
295 pub const empty = .{ .items = &.{} };
250296
251 pub fn deinit(slice: *@This(), gpa: Allocator) void {297 pub fn deinit(slice: *@This(), gpa: Allocator) void {
252 gpa.free(slice.items);298 gpa.free(slice.items);
...@@ -255,7 +301,7 @@ pub fn ExtraStore(comptime set_kind: StoreKind, comptime set_mutability: Mutabil...@@ -255,7 +301,7 @@ pub fn ExtraStore(comptime set_kind: StoreKind, comptime set_mutability: Mutabil
255 .@"var" => std.ArrayListUnmanaged(u32),301 .@"var" => std.ArrayListUnmanaged(u32),
256 };302 };
257303
258 pub fn deinit(store: *Store, gpa: Allocator) void {304 pub fn deinit(store: *Self, gpa: Allocator) void {
259 store.list.deinit(gpa);305 store.list.deinit(gpa);
260 store.* = undefined;306 store.* = undefined;
261 }307 }
...@@ -263,12 +309,12 @@ pub fn ExtraStore(comptime set_kind: StoreKind, comptime set_mutability: Mutabil...@@ -263,12 +309,12 @@ pub fn ExtraStore(comptime set_kind: StoreKind, comptime set_mutability: Mutabil
263 pub const TrailReader = struct {309 pub const TrailReader = struct {
264 index: usize,310 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 {
267 defer trail.index += comptime extraSizeOf(T);313 defer trail.index += comptime extraSizeOf(T);
268 return ip.get(T, trail.index);314 return ip.get(T, trail.index);
269 }315 }
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 {
272 return ip.get(T, trail.index + index);318 return ip.get(T, trail.index + index);
273 }319 }
274320
...@@ -301,10 +347,10 @@ pub fn ExtraStore(comptime set_kind: StoreKind, comptime set_mutability: Mutabil...@@ -301,10 +347,10 @@ pub fn ExtraStore(comptime set_kind: StoreKind, comptime set_mutability: Mutabil
301 };347 };
302348
303 pub const TrailWriter = struct {349 pub const TrailWriter = struct {
304 store: *Store,350 store: *Self,
305 leftover: usize,351 leftover: usize,
306352
307 pub fn init(store: *Store, len: usize) TrailWriter {353 pub fn init(store: *Self, len: usize) TrailWriter {
308 return .{ .store = store, .leftover = len };354 return .{ .store = store, .leftover = len };
309 }355 }
310356
...@@ -332,13 +378,13 @@ pub fn ExtraStore(comptime set_kind: StoreKind, comptime set_mutability: Mutabil...@@ -332,13 +378,13 @@ pub fn ExtraStore(comptime set_kind: StoreKind, comptime set_mutability: Mutabil
332 }378 }
333 };379 };
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) {
336 comptime assert(mutability == .@"var");382 comptime assert(mutability == .@"var");
337 try store.list.ensureUnusedCapacity(gpa, extraSizeOf(@TypeOf(payload)));383 try store.list.ensureUnusedCapacity(gpa, extraSizeOf(@TypeOf(payload)));
338 return store.appendAssumeCapacity(T, payload);384 return store.appendAssumeCapacity(T, payload);
339 }385 }
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) {
342 comptime assert(mutability == .@"var");388 comptime assert(mutability == .@"var");
343 const extra_index: u32 = @intCast(ip.list.items.len);389 const extra_index: u32 = @intCast(ip.list.items.len);
344 ip.list.items.len += extraSizeOf(@TypeOf(payload));390 ip.list.items.len += extraSizeOf(@TypeOf(payload));
...@@ -347,7 +393,7 @@ pub fn ExtraStore(comptime set_kind: StoreKind, comptime set_mutability: Mutabil...@@ -347,7 +393,7 @@ pub fn ExtraStore(comptime set_kind: StoreKind, comptime set_mutability: Mutabil
347 }393 }
348394
349 pub fn appendTrailing(395 pub fn appendTrailing(
350 store: *Store,396 store: *Self,
351 gpa: Allocator,397 gpa: Allocator,
352 comptime T: type,398 comptime T: type,
353 payload: T,399 payload: T,
...@@ -365,32 +411,34 @@ pub fn ExtraStore(comptime set_kind: StoreKind, comptime set_mutability: Mutabil...@@ -365,32 +411,34 @@ pub fn ExtraStore(comptime set_kind: StoreKind, comptime set_mutability: Mutabil
365 }411 }
366412
367 // TODO: make setAsU32 allow any type413 // 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 {
369 comptime assert(mutability == .@"var");415 comptime assert(mutability == .@"var");
370 store.list.items[index] = payload;416 store.list.items[index] = payload;
371 }417 }
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 {
374 comptime assert(mutability == .@"var");420 comptime assert(mutability == .@"var");
375 setAsU32(store.list.items, T, index, payload);421 setAsU32(store.list.items, T, index, payload);
376 }422 }
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 {
379 return getAsU32(store.list.items, T, index);425 return getAsU32(store.list.items, T, index);
380 }426 }
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") {
383 comptime assert(mutability == .@"var");429 comptime assert(mutability == .@"var");
384 return .{ .list = .{ .items = try store.list.toOwnedSlice(gpa) } };430 return .{ .list = .{ .items = try store.list.toOwnedSlice(gpa) } };
385 }431 }
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") {
388 return .{ .list = .{ .items = store.list.items } };436 return .{ .list = .{ .items = store.list.items } };
389 }437 }
390438
391 // TODO: Add some safety to the Index returned from this439 // TODO: Add some safety to the Index returned from this
392 /// Allocate a number of u32s into this store, but they are left uninitialized.440 /// 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 {
394 comptime assert(mutability == .@"var");442 comptime assert(mutability == .@"var");
395 const idx = store.list.items.len;443 const idx = store.list.items.len;
396 try store.list.ensureUnusedCapacity(gpa, len);444 try store.list.ensureUnusedCapacity(gpa, len);
...@@ -398,13 +446,15 @@ pub fn ExtraStore(comptime set_kind: StoreKind, comptime set_mutability: Mutabil...@@ -398,13 +446,15 @@ pub fn ExtraStore(comptime set_kind: StoreKind, comptime set_mutability: Mutabil
398 return @intCast(idx);446 return @intCast(idx);
399 }447 }
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))) {
402 const idx = store.list.items.len;450 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));
403 comptime assert(@sizeOf(@TypeOf(data[0])) == @sizeOf(u32));453 comptime assert(@sizeOf(@TypeOf(data[0])) == @sizeOf(u32));
404 comptime assert(@alignOf(@TypeOf(data[0])) == @alignOf(u32));454 comptime assert(@alignOf(@TypeOf(data[0])) == @alignOf(u32));
405 try store.list.appendSlice(gpa, @ptrCast(data));455 try store.list.appendSlice(gpa, @ptrCast(data));
406 store.list.items.len += data.len;456 store.list.items.len += data.len;
407 return @intCast(idx);457 return .{ .start = @intCast(idx), .len = @intCast(data.len) };
408 }458 }
409 };459 };
410}460}
src/core/js/Link.zig+17-8
...@@ -284,8 +284,9 @@ fn printValue(link: *Link, value: InternPool.Value, level: Level, writer: anytyp...@@ -284,8 +284,9 @@ fn printValue(link: *Link, value: InternPool.Value, level: Level, writer: anytyp
284 try writer.writeAll("{");284 try writer.writeAll("{");
285285
286 for (286 for (
287 struct_value.ty.toStructType(&link.comp.intern_pool).?.field_keys,287 struct_value.ty.toStructType(&link.comp.intern_pool).?
288 struct_value.field_values,288 .field_keys.get(&link.comp.intern_pool),
289 struct_value.field_values.get(&link.comp.intern_pool),
289 0..,290 0..,
290 ) |key, inner_value, i| {291 ) |key, inner_value, i| {
291 if (i != 0)292 if (i != 0)
...@@ -305,7 +306,7 @@ fn printValue(link: *Link, value: InternPool.Value, level: Level, writer: anytyp...@@ -305,7 +306,7 @@ fn printValue(link: *Link, value: InternPool.Value, level: Level, writer: anytyp
305 .array_value => |array_value| {306 .array_value => |array_value| {
306 try writer.writeAll("[");307 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| {
309 if (i != 0)310 if (i != 0)
310 try writer.writeAll(",");311 try writer.writeAll(",");
311312
...@@ -317,7 +318,7 @@ fn printValue(link: *Link, value: InternPool.Value, level: Level, writer: anytyp...@@ -317,7 +318,7 @@ fn printValue(link: *Link, value: InternPool.Value, level: Level, writer: anytyp
317 .tuple_value => |tuple_value| {318 .tuple_value => |tuple_value| {
318 try writer.writeAll("[");319 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| {
321 if (i != 0)322 if (i != 0)
322 try writer.writeAll(",");323 try writer.writeAll(",");
323324
...@@ -327,7 +328,7 @@ fn printValue(link: *Link, value: InternPool.Value, level: Level, writer: anytyp...@@ -327,7 +328,7 @@ fn printValue(link: *Link, value: InternPool.Value, level: Level, writer: anytyp
327 },328 },
328329
329 .external_value => |external_value| {330 .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| {
331 if (i != 0) try writer.writeAll(".");332 if (i != 0) try writer.writeAll(".");
332 try writer.writeAll(part.toSlice(&link.comp.intern_pool));333 try writer.writeAll(part.toSlice(&link.comp.intern_pool));
333 }334 }
...@@ -477,11 +478,15 @@ fn printExprLevel(...@@ -477,11 +478,15 @@ fn printExprLevel(
477 },478 },
478479
479 .comma_chain => {480 .comma_chain => {
481 if (Level.comma.needsParens(level))
482 try writer.writeAll("(");
480 const bin: Tree.IndexList = tree.nodeData(.comma_chain, node);483 const bin: Tree.IndexList = tree.nodeData(.comma_chain, node);
481 for (bin.slice(tree), 0..) |expr, i| {484 for (bin.slice(tree), 0..) |expr, i| {
482 if (i != 0) try writer.writeAll(", ");485 if (i != 0) try writer.writeAll(", ");
483 try link.printExprLevel(tree, expr, .assignment, writer);486 try link.printExprLevel(tree, expr, .assignment, writer);
484 }487 }
488 if (Level.comma.needsParens(level))
489 try writer.writeAll(")");
485 },490 },
486491
487 inline .negate,492 inline .negate,
...@@ -503,9 +508,9 @@ fn printExprLevel(...@@ -503,9 +508,9 @@ fn printExprLevel(
503 try writer.writeAll("(");508 try writer.writeAll("(");
504 try link.printExprLevel(tree, ternary.cond, .logical_or, writer);509 try link.printExprLevel(tree, ternary.cond, .logical_or, writer);
505 try writer.writeAll(" ? ");510 try writer.writeAll(" ? ");
506 try link.printExpr(tree, data.yes, writer);511 try link.printExprLevel(tree, data.yes, .assignment, writer);
507 try writer.writeAll(" : ");512 try writer.writeAll(" : ");
508 try link.printExpr(tree, data.no, writer);513 try link.printExprLevel(tree, data.no, .assignment, writer);
509 if (wrap)514 if (wrap)
510 try writer.writeAll(")");515 try writer.writeAll(")");
511 },516 },
...@@ -518,7 +523,11 @@ fn printExprLevel(...@@ -518,7 +523,11 @@ fn printExprLevel(
518 const k = tree.nodeData(.plain_value, call.base).value.toKey(&link.comp.intern_pool);523 const k = tree.nodeData(.plain_value, call.base).value.toKey(&link.comp.intern_pool);
519 break :brk k == .external_value and524 break :brk k == .external_value and
520 k.external_value.key.len == 1 and525 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 );
522 }) {531 }) {
523 @branchHint(.unlikely);532 @branchHint(.unlikely);
524 try writer.writeAll("(0, eval)");533 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...@@ -47,8 +47,8 @@ pub fn init(gpa: Allocator, arena: Allocator, ip: *InternPool, air: Air) !NodeGe
47 .extern_symbols = .{},47 .extern_symbols = .{},
48 .top_level_value_deps = .{},48 .top_level_value_deps = .{},
49 .air_node_map = air_node_map,49 .air_node_map = air_node_map,
50 .extra = .{},50 .extra = .empty,
51 .scratch = .{},51 .scratch = .empty,
52 .next_id = param_count,52 .next_id = param_count,
53 .next_label = 0,53 .next_label = 0,
54 };54 };
...@@ -100,7 +100,7 @@ pub fn build(c: *NodeGen) !void {...@@ -100,7 +100,7 @@ pub fn build(c: *NodeGen) !void {
100 defer t.end();100 defer t.end();
101101
102 assert(c.air.instTag(.main_block) == .block); // expected Air to start with block102 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
105 const scratch_top = c.scratch.items.len;105 const scratch_top = c.scratch.items.len;
106 defer c.scratch.shrinkRetainingCapacity(scratch_top);106 defer c.scratch.shrinkRetainingCapacity(scratch_top);
...@@ -301,7 +301,7 @@ fn codeGenInst(c: *NodeGen, inst: Air.Inst.Index) Error!void {...@@ -301,7 +301,7 @@ fn codeGenInst(c: *NodeGen, inst: Air.Inst.Index) Error!void {
301 .field = field_name: {301 .field = field_name: {
302 break :field_name c.air.typeOfIndex(data.base, c.ip)302 break :field_name c.air.typeOfIndex(data.base, c.ip)
303 .toStructType(c.ip).?303 .toStructType(c.ip).?
304 .field_keys[data.field_index];304 .field_keys.at(c.ip, data.field_index);
305 },305 },
306 });306 });
307 try c.markExpression(inst, node);307 try c.markExpression(inst, node);
...@@ -338,7 +338,7 @@ fn codeGenInst(c: *NodeGen, inst: Air.Inst.Index) Error!void {...@@ -338,7 +338,7 @@ fn codeGenInst(c: *NodeGen, inst: Air.Inst.Index) Error!void {
338338
339 const items = c.extra.list.items[start..][0..call_data.args.len];339 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| {
342 dest.* = @intFromEnum(try c.fetchExpression(arg));342 dest.* = @intFromEnum(try c.fetchExpression(arg));
343 }343 }
344344
...@@ -457,7 +457,7 @@ fn codeGenInst(c: *NodeGen, inst: Air.Inst.Index) Error!void {...@@ -457,7 +457,7 @@ fn codeGenInst(c: *NodeGen, inst: Air.Inst.Index) Error!void {
457 //457 //
458 // This is also required for the main function, which cannot return458 // This is also required for the main function, which cannot return
459 // anything. We don't want to emit return instructions here.459 // 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);
461 if (main_insts[main_insts.len - 1] == inst) {461 if (main_insts[main_insts.len - 1] == inst) {
462 return;462 return;
463 }463 }
...@@ -472,7 +472,7 @@ fn codeGenInst(c: *NodeGen, inst: Air.Inst.Index) Error!void {...@@ -472,7 +472,7 @@ fn codeGenInst(c: *NodeGen, inst: Air.Inst.Index) Error!void {
472 const operand = try c.fetchExpression(brk.value);472 const operand = try c.fetchExpression(brk.value);
473 const block = &c.air_node_map[@intFromEnum(brk.block)].block;473 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);
476 if (block_insts[block_insts.len - 1] != inst) {476 if (block_insts[block_insts.len - 1] != inst) {
477 block.used = true;477 block.used = true;
478 }478 }
...@@ -499,7 +499,7 @@ fn codeGenInst(c: *NodeGen, inst: Air.Inst.Index) Error!void {...@@ -499,7 +499,7 @@ fn codeGenInst(c: *NodeGen, inst: Air.Inst.Index) Error!void {
499 const store_offset = try c.extra.alloc(c.gpa, property_count * 2);499 const store_offset = try c.extra.alloc(c.gpa, property_count * 2);
500500
501 for (501 for (
502 struct_type.field_keys,502 struct_type.field_keys.get(c.ip),
503 struct_init.valuesPtr(&c.air),503 struct_init.valuesPtr(&c.air),
504 store_offset..,504 store_offset..,
505 store_offset + property_count..,505 store_offset + property_count..,
...@@ -520,7 +520,7 @@ fn codeGenInst(c: *NodeGen, inst: Air.Inst.Index) Error!void {...@@ -520,7 +520,7 @@ fn codeGenInst(c: *NodeGen, inst: Air.Inst.Index) Error!void {
520 .array_init => {520 .array_init => {
521 const array_init: Air.ArrayInit = c.air.instData(.array_init, inst);521 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);
524 const store_offset = try c.extra.alloc(c.gpa, items.len);524 const store_offset = try c.extra.alloc(c.gpa, items.len);
525525
526 for (526 for (
...@@ -653,7 +653,12 @@ fn valueToExpression(c: *NodeGen, v: Value) !Node.Index {...@@ -653,7 +653,12 @@ fn valueToExpression(c: *NodeGen, v: Value) !Node.Index {
653653
654 .external_value => {654 .external_value => {
655 const external = v.toKey(c.ip).external_value;655 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 );
657 return try c.add(.plain_value, .{ .value = v });662 return try c.add(.plain_value, .{ .value = v });
658 },663 },
659664
...@@ -730,7 +735,7 @@ fn codeGenBranch(c: *NodeGen, inst: Air.Inst.Ref, temporary: ?Node.Index) !?Bran...@@ -730,7 +735,7 @@ fn codeGenBranch(c: *NodeGen, inst: Air.Inst.Ref, temporary: ?Node.Index) !?Bran
730 });735 });
731736
732 const block: Air.IndexList = c.air.instData(.block, i);737 const block: Air.IndexList = c.air.instData(.block, i);
733 for (block.slice(&c.air)) |item| {738 for (block.get(&c.air)) |item| {
734 try c.codeGenInst(item);739 try c.codeGenInst(item);
735 }740 }
736741
...@@ -781,7 +786,7 @@ fn codeGenBlock(c: *NodeGen, inst: Air.Inst.Index) !void {...@@ -781,7 +786,7 @@ fn codeGenBlock(c: *NodeGen, inst: Air.Inst.Index) !void {
781 };786 };
782 const block: Air.IndexList = c.air.instData(.block, inst);787 const block: Air.IndexList = c.air.instData(.block, inst);
783788
784 for (block.slice(&c.air)) |item| {789 for (block.get(&c.air)) |item| {
785 try c.codeGenInst(item);790 try c.codeGenInst(item);
786 }791 }
787792
...@@ -814,7 +819,7 @@ fn codeGenBlockAsExpression(c: *NodeGen, inst: Air.Inst.Index) !Node.Index {...@@ -814,7 +819,7 @@ fn codeGenBlockAsExpression(c: *NodeGen, inst: Air.Inst.Index) !Node.Index {
814 .block = .{ .index = @intCast(scratch_top) },819 .block = .{ .index = @intCast(scratch_top) },
815 };820 };
816 const block: Air.IndexList = c.air.instData(.block, inst);821 const block: Air.IndexList = c.air.instData(.block, inst);
817 const instructions = block.slice(&c.air);822 const instructions = block.get(&c.air);
818 for (instructions[0 .. instructions.len - 1]) |item| {823 for (instructions[0 .. instructions.len - 1]) |item| {
819 try c.codeGenInst(item);824 try c.codeGenInst(item);
820 }825 }
...@@ -885,7 +890,7 @@ fn canLowerToExpression(c: *const NodeGen, inst: Air.Inst.Ref) bool {...@@ -885,7 +890,7 @@ fn canLowerToExpression(c: *const NodeGen, inst: Air.Inst.Ref) bool {
885 // are lowerable. The break at the end just becomes the result.890 // are lowerable. The break at the end just becomes the result.
886 .block => {891 .block => {
887 const block: Air.IndexList = c.air.instData(.block, index);892 const block: Air.IndexList = c.air.instData(.block, index);
888 const items = block.slice(&c.air);893 const items = block.get(&c.air);
889 for (items[0 .. items.len - 1]) |item| {894 for (items[0 .. items.len - 1]) |item| {
890 if (c.air.instFlags(item).uses == .multi)895 if (c.air.instFlags(item).uses == .multi)
891 return false;896 return false;
src/manual/generate_manual.zig+11-3
...@@ -70,7 +70,7 @@ pub fn main() !void {...@@ -70,7 +70,7 @@ pub fn main() !void {
70 .contents = contents.items,70 .contents = contents.items,
71 .navigation = header.data.items,71 .navigation = header.data.items,
72 .nav_h1 = "Ix Language",72 .nav_h1 = "Ix Language",
73 .repository = "https://github.com/paperdave/wl",73 .repository = "https://github.com/paperdave/ix",
74 .style = minified_style,74 .style = minified_style,
75 });75 });
7676
...@@ -83,7 +83,7 @@ pub fn main() !void {...@@ -83,7 +83,7 @@ pub fn main() !void {
83 std.debug.lockStdErr();83 std.debug.lockStdErr();
84 std.debug.unlockStdErr();84 std.debug.unlockStdErr();
8585
86 std.process.exit(0);86 std.process.exit(if (header.had_signaled) 1 else 0);
87}87}
8888
89const BlockType = enum {89const BlockType = enum {
...@@ -190,6 +190,8 @@ const HeaderWriter = struct {...@@ -190,6 +190,8 @@ const HeaderWriter = struct {
190190
191 has_closed_li: bool = true,191 has_closed_li: bool = true,
192192
193 had_signaled: bool = false,
194
193 fn add(header: *HeaderWriter, alloc: Allocator, name: []const u8, id: []const u8, level: u8) !void {195 fn add(header: *HeaderWriter, alloc: Allocator, name: []const u8, id: []const u8, level: u8) !void {
194 const w = header.data.writer(alloc);196 const w = header.data.writer(alloc);
195197
...@@ -440,6 +442,10 @@ fn processMarkdown(...@@ -440,6 +442,10 @@ fn processMarkdown(
440442
441 try build.collectOutput(&out, &err, std.math.maxInt(usize));443 try build.collectOutput(&out, &err, std.math.maxInt(usize));
442 const result = try build.wait();444 const result = try build.wait();
445 if (result == .Signal) {
446 std.debug.print("{s}\n", .{err.items});
447 header.had_signaled = true;
448 }
443 if (result != .Exited or result.Exited != 0) {449 if (result != .Exited or result.Exited != 0) {
444 try err.writer().print("[Process {s} with {d}]", .{450 try err.writer().print("[Process {s} with {d}]", .{
445 switch (result) {451 switch (result) {
...@@ -530,7 +536,9 @@ fn processMarkdown(...@@ -530,7 +536,9 @@ fn processMarkdown(
530 }536 }
531 return e;537 return e;
532 };538 };
533539 if (run_result == .Signal) {
540 header.had_signaled = true;
541 }
534 if (run_result != .Exited or run_result.Exited != 0) {542 if (run_result != .Exited or run_result.Exited != 0) {
535 try run_err.writer().print("[Process {s} with {d}]", .{543 try run_err.writer().print("[Process {s} with {d}]", .{
536 switch (run_result) {544 switch (run_result) {