authorgravatar for me@paperdave.netdave caruso <me@paperdave.net> 2024-05-25 02:35:49-07:00
committergravatar for me@paperdave.netdave caruso <me@paperdave.net> 2024-05-25 02:35:49-07:00
log2c270c7666f2ab4fab17392bffe2c2f64ef782a5
tree6daf797485f1a83f62305003a12c84e8aac1c071
parent4cd49040184a9da68e9584b71ac21f9e19723d59
signature Commit is signed but in an unrecognized format.

split InternPool.Index into Type + Value

this ends up regressing a lot of the compiler's ability to work, but i have found many many many cases where a comptime value should have only ever been a type, but we previously allowed any value. also a revelation that `validateType` is not going to cut it- we need to have a Teg ref for any type validation, and it should be a *coersion*. the difference is these new coersion functions return !Value or !Air.Inst.Ref instead of just a !void (error being a coersion error)

20 files changed, 683 insertions(+), 416 deletions(-)

README.md+6-6
...@@ -46,7 +46,7 @@ let hello = hello * world;...@@ -46,7 +46,7 @@ let hello = hello * world;
46@js("console").log(hello);46@js("console").log(hello);
47```47```
4848
49`var` bindings create mutable memory locations at runtime. This means they can be re-assigned to in arbitrary ways.49`var` bindings create mutable memory locations at runtime. This means they can be re-assigned to:
5050
51```51```
52var message = "first message";52var message = "first message";
...@@ -58,7 +58,7 @@ if @js("Math").random() > 0.5 {...@@ -58,7 +58,7 @@ if @js("Math").random() > 0.5 {
58@js("console").log(message);58@js("console").log(message);
59```59```
6060
61`let` is preferred whenever possible, as it will lead to more readable code, and the compiler is able to optimize it better. The above can be rewritten as:61Using `let` is preferred whenever possible, as it will lead to more readable code, and the compiler is able to optimize it better. The above can be rewritten as:
6262
63```63```
64let message = if @js("Math").random() > 0.5 {64let message = if @js("Math").random() > 0.5 {
...@@ -70,10 +70,10 @@ let message = if @js("Math").random() > 0.5 {...@@ -70,10 +70,10 @@ let message = if @js("Math").random() > 0.5 {
70@js("console").log(message);70@js("console").log(message);
71```71```
7272
73The initializer for a `let` and `var` are always required, but the type annotations can be omitted when the data type can be inferred. For `let`, this is always the case. `var`, being runtime-mutable memory, only supports runtime representable data types. This means for numerical literals, an explicit type annotation is needed to determine weather to store an integer or a floating point number.73It should be noted that numeric literals are a comptime-only data type, meaning it cannot be assigned to a `var` without an explicit type annotation. Since `int` is a strict subset of valid `float`s, the coersion will implicitly be a float, but a compiler warning will be emitted.
7474
75```75```
76var a = 5; // error76var number = 0; // `number` is a `float`, but not explicit
77var b: int = 5; // ok77var number: int = 0; // `number` is `int`
78var c: float = 5; // ok78var number: float = 0; // `number` is `float`
79```79```
demo.wl created+1
...@@ -0,0 +1 @@
1let x: int = 1.5;
notes created+19
...@@ -0,0 +1,19 @@
10.1.2
2- teg: useless discard
3- teg: dangling identifier
4- teg: remove `let _ = ` error
5- sema: .as instruction
6- sema: binary op type resolution (float + num_literal -> float)
70.1.3
8- parse/teg/sema: implement the comptime keyword
9- implement all the binary operators
10- implement all the unary operators
11- implement string escapes
12- implement proper float printing
13- js/link: add parenthesis when needed
140.1.4
15- parse: impl module, struct define, struct init, defer, and optionals
16- teg: impl the above, except anonymous struct initializers
17- sema: implement some built-in functions on floats
18 - float.intTruncate() to perform lossy int conversion
19
src/compiler/Air.Dump.zig+9-10
...@@ -2,7 +2,7 @@...@@ -2,7 +2,7 @@
2air: Air,2air: Air,
3ip: *const InternPool,3ip: *const InternPool,
44
5const State = struct {5pub const State = struct {
6 arena: std.mem.Allocator,6 arena: std.mem.Allocator,
7 air: *const Air,7 air: *const Air,
8 ip: *const InternPool,8 ip: *const InternPool,
...@@ -67,7 +67,7 @@ const State = struct {...@@ -67,7 +67,7 @@ const State = struct {
67 try w.print("{d}", .{arg.arg_number});67 try w.print("{d}", .{arg.arg_number});
68 try tty.setColor(w, .reset);68 try tty.setColor(w, .reset);
69 try w.writeAll(": ");69 try w.writeAll(": ");
70 try s.dumpValue(w, arg.type);70 try s.dumpValue(w, arg.type.value());
71 },71 },
72 .@"break" => {72 .@"break" => {
73 const brk: Air.Break = air.instData(.@"break", inst);73 const brk: Air.Break = air.instData(.@"break", inst);
...@@ -113,7 +113,7 @@ const State = struct {...@@ -113,7 +113,7 @@ const State = struct {
113 try w.writeAll("(");113 try w.writeAll("(");
114 try s.dumpRef(w, memory.init);114 try s.dumpRef(w, memory.init);
115 try w.writeAll(", type: ");115 try w.writeAll(", type: ");
116 try s.dumpValue(w, memory.ty);116 try s.dumpValue(w, memory.ty.value());
117 try w.writeAll(")");117 try w.writeAll(")");
118 },118 },
119 .field => {119 .field => {
...@@ -175,7 +175,7 @@ const State = struct {...@@ -175,7 +175,7 @@ const State = struct {
175 try s.tty.setColor(w, .reset);175 try s.tty.setColor(w, .reset);
176 }176 }
177177
178 fn dumpValue(s: *State, w: anytype, val: Value) !void {178 pub fn dumpValue(s: *State, w: anytype, val: Value) !void {
179 const tty = s.tty;179 const tty = s.tty;
180 switch (val.toKey(s.ip)) {180 switch (val.toKey(s.ip)) {
181 .simple_type => |t| {181 .simple_type => |t| {
...@@ -198,14 +198,14 @@ const State = struct {...@@ -198,14 +198,14 @@ const State = struct {
198 try w.writeAll(",");198 try w.writeAll(",");
199 try tty.setColor(w, .reset);199 try tty.setColor(w, .reset);
200 }200 }
201 try s.dumpValue(w, Value.fromInterned(param));201 try s.dumpValue(w, param.value());
202 }202 }
203 try tty.setColor(w, .blue);203 try tty.setColor(w, .blue);
204 try w.writeAll(") -> ");204 try w.writeAll(") -> ");
205 try tty.setColor(w, .reset);205 try tty.setColor(w, .reset);
206 try s.dumpValue(w, Value.fromInterned(ty.return_type));206 try s.dumpValue(w, ty.return_type.value());
207 },207 },
208 inline .float, .int32 => |data, tag| {208 inline .float, .int32, .comptime_float => |data, tag| {
209 try tty.setColor(w, .bright_black);209 try tty.setColor(w, .bright_black);
210 try w.writeAll("<");210 try w.writeAll("<");
211 try tty.setColor(w, .blue);211 try tty.setColor(w, .blue);
...@@ -235,7 +235,7 @@ const State = struct {...@@ -235,7 +235,7 @@ const State = struct {
235 .func => |func| {235 .func => |func| {
236 try tty.setColor(w, .bright_black);236 try tty.setColor(w, .bright_black);
237 try w.writeAll("<");237 try w.writeAll("<");
238 try s.dumpValue(w, Value.fromInterned(func.ty));238 try s.dumpValue(w, func.ty);
239 try tty.setColor(w, .bright_black);239 try tty.setColor(w, .bright_black);
240 try w.writeAll(", ");240 try w.writeAll(", ");
241 const decl_name = s.ip.declPtrConst(func.owner_decl).name.toSlice(s.ip);241 const decl_name = s.ip.declPtrConst(func.owner_decl).name.toSlice(s.ip);
...@@ -310,8 +310,7 @@ const assert = std.debug.assert;...@@ -310,8 +310,7 @@ const assert = std.debug.assert;
310const Air = @import("Air.zig");310const Air = @import("Air.zig");
311const Inst = Air.Inst;311const Inst = Air.Inst;
312312
313const Value = @import("Value.zig");
314
315const InternPool = @import("InternPool.zig");313const InternPool = @import("InternPool.zig");
314const Value = InternPool.Value;
316315
317const detectTTYFromWriter = @import("util.zig").detectTTYFromWriter;316const detectTTYFromWriter = @import("util.zig").detectTTYFromWriter;
src/compiler/Air.zig+22-21
...@@ -77,7 +77,7 @@ pub const Inst = struct {...@@ -77,7 +77,7 @@ pub const Inst = struct {
7777
78 pub fn decode(ref: Ref) Decoded {78 pub fn decode(ref: Ref) Decoded {
79 return switch (ref.kind) {79 return switch (ref.kind) {
80 .value => .{ .value = Value.fromInterned(@enumFromInt(ref.data)) },80 .value => .{ .value = @enumFromInt(ref.data) },
81 .inst => .{ .inst = @enumFromInt(ref.data) },81 .inst => .{ .inst = @enumFromInt(ref.data) },
82 };82 };
83 }83 }
...@@ -97,7 +97,7 @@ pub const Inst = struct {...@@ -97,7 +97,7 @@ pub const Inst = struct {
9797
98 pub fn isVoid(ref: Ref) bool {98 pub fn isVoid(ref: Ref) bool {
99 return ref.kind == .value and99 return ref.kind == .value and
100 ref.decode().value.toIntern() == .void_value;100 ref.decode().value == .void;
101 }101 }
102102
103 pub fn eql(ref: Ref, other: Ref) bool {103 pub fn eql(ref: Ref, other: Ref) bool {
...@@ -203,7 +203,7 @@ pub const Call = struct {...@@ -203,7 +203,7 @@ pub const Call = struct {
203};203};
204204
205pub const Arg = struct {205pub const Arg = struct {
206 type: Value,206 type: Type,
207 arg_number: u32,207 arg_number: u32,
208};208};
209209
...@@ -214,13 +214,13 @@ pub const If = struct {...@@ -214,13 +214,13 @@ pub const If = struct {
214 pub const Data = struct {214 pub const Data = struct {
215 yes: Inst.Ref,215 yes: Inst.Ref,
216 no: Inst.Ref,216 no: Inst.Ref,
217 union_ty: Value,217 union_ty: Type,
218 };218 };
219};219};
220220
221pub const Memory = struct {221pub const Memory = struct {
222 init: Inst.Ref,222 init: Inst.Ref,
223 ty: Value,223 ty: Type,
224};224};
225225
226pub fn deinit(air: *Air, gpa: std.mem.Allocator) void {226pub fn deinit(air: *Air, gpa: std.mem.Allocator) void {
...@@ -249,16 +249,16 @@ pub fn instPayload(air: *const Air, comptime tag: Inst.Tag, index: Inst.Index) t...@@ -249,16 +249,16 @@ pub fn instPayload(air: *const Air, comptime tag: Inst.Tag, index: Inst.Index) t
249 return air.instData(tag, index).extra_index.get(air);249 return air.instData(tag, index).extra_index.get(air);
250}250}
251251
252pub fn typeOf(air: *const Air, ref: Inst.Ref, ip: *InternPool) InternPool.Index {252pub fn typeOf(air: *const Air, ref: Inst.Ref, ip: *InternPool) InternPool.Type {
253 return switch (ref.decode()) {253 return switch (ref.decode()) {
254 .value => |v| v.type(ip).toIntern(),254 .value => |v| v.typeOf(ip),
255 .inst => |i| air.typeOfIndex(i, ip),255 .inst => |i| air.typeOfIndex(i, ip),
256 };256 };
257}257}
258258
259pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *InternPool) InternPool.Index {259pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *InternPool) InternPool.Type {
260 return switch (air.instTag(index)) {260 return switch (air.instTag(index)) {
261 .js_global_ref => .opaque_type,261 .js_global_ref => .@"opaque",
262262
263 .block => {263 .block => {
264 const items = air.instData(.block, index).slice(air);264 const items = air.instData(.block, index).slice(air);
...@@ -267,28 +267,28 @@ pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *InternPool) InternPo...@@ -267,28 +267,28 @@ pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *InternPool) InternPo
267267
268 inline .add, .sub, .mul, .div => |t| air.typeOf(air.instData(t, index).lhs, ip),268 inline .add, .sub, .mul, .div => |t| air.typeOf(air.instData(t, index).lhs, ip),
269269
270 .lt, .gt, .eq, .bool_not => .bool_type,270 .lt, .gt, .eq, .bool_not => .bool,
271271
272 .arg => air.instData(.arg, index).type.toIntern(),272 .arg => air.instData(.arg, index).type,
273273
274 .negate => air.typeOf(air.instData(.negate, index).operand, ip),274 .negate => air.typeOf(air.instData(.negate, index).operand, ip),
275275
276 .@"break" => .noreturn_type,276 .@"break" => .noreturn,
277277
278 // todo:278 // todo:
279 .field => .opaque_type,279 .field => .@"opaque",
280280
281 .call => {281 .call => {
282 const base_type = air.typeOf(air.instData(.call, index).base, ip);282 const base_type = air.typeOf(air.instData(.call, index).base, ip);
283 if (base_type == .opaque_type) return .opaque_type;283 if (base_type == .@"opaque") return .@"opaque";
284 return base_type.toKey(ip).type_function.return_type;284 return base_type.value().toKey(ip).type_function.return_type;
285 },285 },
286286
287 .memory => air.instData(.memory, index).ty.toIntern(),287 .memory => air.instData(.memory, index).ty,
288288
289 .store => air.instData(.memory, air.instData(.store, index).memory).ty.toIntern(),289 .store => air.instData(.memory, air.instData(.store, index).memory).ty,
290290
291 .@"if" => air.instData(.@"if", index).data.get(air).union_ty.toIntern(),291 .@"if" => air.instData(.@"if", index).data.get(air).union_ty,
292 };292 };
293}293}
294294
...@@ -310,10 +310,11 @@ const std = @import("std");...@@ -310,10 +310,11 @@ const std = @import("std");
310const mem = std.mem;310const mem = std.mem;
311const assert = std.debug.assert;311const assert = std.debug.assert;
312312
313const Teg = @import("Teg.zig");
314const InternPool = @import("InternPool.zig");313const InternPool = @import("InternPool.zig");
314const Value = InternPool.Value;
315const Type = InternPool.Type;
316
317const Teg = @import("Teg.zig");
315const dod = @import("dod.zig");318const dod = @import("dod.zig");
316319
317const Unused = enum(u32) { zero = 0 };320const Unused = enum(u32) { zero = 0 };
318
319const Value = @import("Value.zig");
src/compiler/Comp.zig+1-2
...@@ -214,7 +214,7 @@ pub const File = struct {...@@ -214,7 +214,7 @@ pub const File = struct {
214214
215pub const Decl = struct {215pub const Decl = struct {
216 name: InternPool.NullTerminatedString,216 name: InternPool.NullTerminatedString,
217 val: Value,217 val: InternPool.Value,
218 /// The direct parent namespace of the Decl. In the case of the Decl218 /// The direct parent namespace of the Decl. In the case of the Decl
219 /// corresponding to a file, this is the namespace of the struct, since219 /// corresponding to a file, this is the namespace of the struct, since
220 /// there is no parent.220 /// there is no parent.
...@@ -432,7 +432,6 @@ const Ast = @import("Ast.zig");...@@ -432,7 +432,6 @@ const Ast = @import("Ast.zig");
432const Air = @import("Air.zig");432const Air = @import("Air.zig");
433const Teg = @import("Teg.zig");433const Teg = @import("Teg.zig");
434const Cache = @import("Cache.zig");434const Cache = @import("Cache.zig");
435const Value = @import("Value.zig");
436const Sema = @import("Sema.zig");435const Sema = @import("Sema.zig");
437const Transform = @import("Transform.zig");436const Transform = @import("Transform.zig");
438const JsNodeGen = @import("JsNodeGen.zig");437const JsNodeGen = @import("JsNodeGen.zig");
src/compiler/InternPool.zig+156-41
...@@ -78,21 +78,25 @@ pub const Tag = enum(u8) {...@@ -78,21 +78,25 @@ pub const Tag = enum(u8) {
78 /// A function type78 /// A function type
79 /// data is an extra index into a `FuncType`79 /// data is an extra index into a `FuncType`
80 type_function,80 type_function,
81 /// A type that can be represented with only an enum tag.
82 /// data is SimpleType enum value.
83 simple_type,
8184
82 // --- before this are types ---85 // --- before this are types ---
83 // --- past this are values ---86 // --- past this are values ---
8487
85 /// A type that can be represented with only an enum tag.
86 /// data is SimpleType enum value.
87 simple_type,
88 /// A value that can be represented with only an enum tag.88 /// A value that can be represented with only an enum tag.
89 /// data is SimpleValue enum value.89 /// data is SimpleValue enum value.
90 simple_value,90 simple_value,
91 /// A numeric literal that can be represented as a float.
92 /// Integers greater than 2^53 known at compile time are currently not supported.
93 /// data is an extra index into a `Float`
94 comptime_float,
91 /// An int32 value95 /// An int32 value
92 /// data is i3296 /// data is i32
93 int32,97 int32,
94 /// A float value98 /// A float value
95 /// data is an extra index into an `Float`99 /// data is an extra index into a `Float`
96 float,100 float,
97 /// A function101 /// A function
98 /// data is an extra index into a `FuncDecl`102 /// data is an extra index into a `FuncDecl`
...@@ -122,7 +126,7 @@ pub const Tag = enum(u8) {...@@ -122,7 +126,7 @@ pub const Tag = enum(u8) {
122 .simple_value,126 .simple_value,
123 .int32,127 .int32,
124 => unreachable, // does not have a payload128 => unreachable, // does not have a payload
125 .float => Float,129 .float, .comptime_float => Float,
126 .func => FuncDecl,130 .func => FuncDecl,
127 .type_function => TypeFunction,131 .type_function => TypeFunction,
128 .string => String.WithLen,132 .string => String.WithLen,
...@@ -133,7 +137,7 @@ pub const Tag = enum(u8) {...@@ -133,7 +137,7 @@ pub const Tag = enum(u8) {
133 pub const FuncDecl = struct {137 pub const FuncDecl = struct {
134 analysis: FuncAnalysis,138 analysis: FuncAnalysis,
135 owner_decl: DeclIndex,139 owner_decl: DeclIndex,
136 ty: Index,140 ty: Value,
137 teg_body_inst: TrackedInst.Index,141 teg_body_inst: TrackedInst.Index,
138 };142 };
139143
...@@ -141,26 +145,26 @@ pub const Tag = enum(u8) {...@@ -141,26 +145,26 @@ pub const Tag = enum(u8) {
141 /// 0. param_type: Index for each params_len145 /// 0. param_type: Index for each params_len
142 pub const TypeFunction = struct {146 pub const TypeFunction = struct {
143 params_len: u32,147 params_len: u32,
144 return_type: Index,148 return_type: Type,
145 };149 };
146};150};
147151
148pub const Index = enum(u32) {152pub const Value = enum(u32) {
149 pub const first_type: Index = .opaque_type;153 pub const first_type: Value = .opaque_type;
150 pub const last_type: Index = .noreturn_type;154 pub const last_type: Value = .noreturn_type;
151 pub const first_value: Index = .void_value;155 pub const first_value: Value = .void;
152 pub const last_value: Index = .empty_string;156 pub const last_value: Value = .empty_string;
153157
154 opaque_type,158 opaque_type,
155 bool_type,159 bool_type,
156 int32_type,160 int32_type,
157 float_type,161 float_type,
158 string_type,162 string_type,
159 void_type,
160 noreturn_type,163 noreturn_type,
161 type_type,164 type_type,
165 numeric_literal_type,
162166
163 void_value,167 void,
164 bool_true,168 bool_true,
165 bool_false,169 bool_false,
166 int32_zero,170 int32_zero,
...@@ -178,36 +182,140 @@ pub const Index = enum(u32) {...@@ -178,36 +182,140 @@ pub const Index = enum(u32) {
178 start: u32,182 start: u32,
179 len: u32,183 len: u32,
180184
181 pub fn get(slice: Slice, ip: *const InternPool) []Index {185 pub fn get(slice: Slice, ip: *const InternPool) []Value {
182 return @ptrCast(ip.extra.list.items[slice.start..][0..slice.len]);186 return @ptrCast(ip.extra.list.items[slice.start..][0..slice.len]);
183 }187 }
184 };188 };
185189
186 /// Used for a map of `Index` values to the index within a list of `Index` values.190 /// Used for a map of `Index` values to the index within a list of `Index` values.
187 const Adapter = struct {191 const Adapter = struct {
188 indexes: []const Index,192 indexes: []const Value,
189193
190 pub fn eql(ctx: @This(), a: Index, b_void: void, b_map_index: usize) bool {194 pub fn eql(ctx: @This(), a: Value, b_void: void, b_map_index: usize) bool {
191 _ = b_void;195 _ = b_void;
192 return a == ctx.indexes[b_map_index];196 return a == ctx.indexes[b_map_index];
193 }197 }
194198
195 pub fn hash(ctx: @This(), a: Index) u32 {199 pub fn hash(ctx: @This(), a: Value) u32 {
196 _ = ctx;200 _ = ctx;
197 return std.hash.uint32(@intFromEnum(a));201 return std.hash.uint32(@intFromEnum(a));
198 }202 }
199 };203 };
200204
201 pub fn toAir(index: Index) Air.Inst.Ref {205 pub fn valueTag(value: Value, ip: *const InternPool) Tag {
202 return .{ .kind = .value, .data = @intCast(@intFromEnum(index)) };206 return ip.items.items(.tag)[@intFromEnum(value)];
207 }
208
209 pub fn valueData(value: Value, ip: *const InternPool, comptime tag: Tag) tag.Data() {
210 return ip.items.items(.data)[@intFromEnum(value)].decode(tag, value.valueTag(ip));
211 }
212
213 pub fn toAir(value: Value) Air.Inst.Ref {
214 return .{ .kind = .value, .data = @intCast(@intFromEnum(value)) };
215 }
216
217 pub fn toKey(value: Value, ip: *const InternPool) Key {
218 return ip.indexToKey(value);
219 }
220
221 pub fn dump(value: Value, ip: *const InternPool) std.fmt.Formatter(Value.formatValue) {
222 return .{ .data = .{ .val = value, .ip = ip } };
223 }
224
225 fn formatValue(
226 ctx: struct { val: Value, ip: *const InternPool },
227 comptime _: []const u8,
228 _: std.fmt.FormatOptions,
229 writer: anytype,
230 ) !void {
231 // TODO: move the formatter out of Air.Dump
232 var state: Air.Dump.State = undefined;
233 state.ip = ctx.ip;
234 state.tty = @import("util.zig").detectTTYFromWriter(writer);
235 try Air.Dump.State.dumpValue(&state, writer, ctx.val);
236 }
237
238 pub fn typeOf(value: Value, ip: *const InternPool) Type {
239 return switch (value.valueTag(ip)) {
240 .removed => unreachable, // UAF
241
242 .type_function => .type,
243 .simple_type => .type,
244
245 .simple_value => switch (value.valueData(ip, .simple_value)) {
246 .true => .bool,
247 .false => .bool,
248 .void => .void,
249 },
250
251 .comptime_float => .numeric_literal,
252 .int32 => .int32,
253 .float => .float,
254 .string => .string,
255
256 .func => @panic("TODO"),
257 };
258 }
259
260 /// Try to re-interpret this `Value` as a `Type`.
261 /// Returns `null` if the value is not a type.
262 pub fn toType(value: Value, ip: *const InternPool) ?Type {
263 return switch (value.valueTag(ip)) {
264 .removed => unreachable, // UAF
265
266 .type_function,
267 .simple_type,
268 => @enumFromInt(@intFromEnum(value)),
269
270 // exception: void is a value AND a type
271 .simple_value => if (value == .void) .void else null,
272
273 else => null,
274 };
275 }
276
277 pub fn asString(val: Value, ip: *const InternPool) InternPool.String.WithLen {
278 return val.valueData(ip, .string).get(ip);
279 }
280
281 pub fn toFloat(val: Value, ip: *const InternPool) ?f64 {
282 return switch (val.valueTag(ip)) {
283 inline .comptime_float, .float => |tag| val.valueData(ip, tag).get(ip).decode(),
284 else => null,
285 };
203 }286 }
287};
288
289pub const Type = enum(u32) {
290 @"opaque" = @intFromEnum(Value.opaque_type),
291 bool = @intFromEnum(Value.bool_type),
292 int32 = @intFromEnum(Value.int32_type),
293 float = @intFromEnum(Value.float_type),
294 string = @intFromEnum(Value.string_type),
295 noreturn = @intFromEnum(Value.noreturn_type),
296 type = @intFromEnum(Value.type_type),
297 numeric_literal = @intFromEnum(Value.numeric_literal_type),
298 void = @intFromEnum(Value.void),
299 _,
204300
205 pub fn toValue(index: Index) @import("Value.zig") {301 /// An array of `Index` existing within the `extra` array.
206 return .{ .ip_index = index };302 /// This type exists to provide a struct with lifetime that is
303 /// not invalidated when items are added to the `InternPool`.
304 pub const Slice = struct {
305 start: u32,
306 len: u32,
307
308 pub fn get(slice: Slice, ip: *const InternPool) []Type {
309 return @ptrCast(ip.extra.list.items[slice.start..][0..slice.len]);
310 }
311 };
312
313 pub fn value(ty: Type) Value {
314 return @enumFromInt(@intFromEnum(ty));
207 }315 }
208316
209 pub fn toKey(index: Index, ip: *const InternPool) Key {317 pub fn dump(ty: Type, ip: *const InternPool) std.fmt.Formatter(Value.formatValue) {
210 return ip.indexToKey(index);318 return ty.value().dump(ip);
211 }319 }
212};320};
213321
...@@ -217,9 +325,9 @@ pub const static_keys = [_]Key{...@@ -217,9 +325,9 @@ pub const static_keys = [_]Key{
217 SimpleType.int32.key(),325 SimpleType.int32.key(),
218 SimpleType.float.key(),326 SimpleType.float.key(),
219 SimpleType.string.key(),327 SimpleType.string.key(),
220 SimpleType.void.key(),
221 SimpleType.noreturn.key(),328 SimpleType.noreturn.key(),
222 SimpleType.type.key(),329 SimpleType.type.key(),
330 SimpleType.numeric_literal.key(),
223331
224 SimpleValue.void.key(),332 SimpleValue.void.key(),
225 SimpleValue.true.key(),333 SimpleValue.true.key(),
...@@ -461,11 +569,11 @@ pub const NamespaceIndex = enum(u32) {...@@ -461,11 +569,11 @@ pub const NamespaceIndex = enum(u32) {
461/// * comptime-known value (where we store the value)569/// * comptime-known value (where we store the value)
462/// * decl val (so that we can analyze the value lazily)570/// * decl val (so that we can analyze the value lazily)
463/// * decl ref (so that we can analyze the reference lazily)571/// * decl ref (so that we can analyze the reference lazily)
464pub const CaptureValue = packed struct(u32) {572pub const Capture = packed struct(u32) {
465 tag: enum(u2) { @"comptime", runtime, decl_val, decl_ref },573 tag: enum(u2) { @"comptime", runtime, decl_val, decl_ref },
466 idx: u30,574 idx: u30,
467575
468 pub fn wrap(val: Unwrapped) CaptureValue {576 pub fn wrap(val: Unwrapped) Capture {
469 return switch (val) {577 return switch (val) {
470 .@"comptime" => |i| .{ .tag = .@"comptime", .idx = @intCast(@intFromEnum(i)) },578 .@"comptime" => |i| .{ .tag = .@"comptime", .idx = @intCast(@intFromEnum(i)) },
471 .runtime => |i| .{ .tag = .runtime, .idx = @intCast(@intFromEnum(i)) },579 .runtime => |i| .{ .tag = .runtime, .idx = @intCast(@intFromEnum(i)) },
...@@ -473,7 +581,7 @@ pub const CaptureValue = packed struct(u32) {...@@ -473,7 +581,7 @@ pub const CaptureValue = packed struct(u32) {
473 .decl_ref => |i| .{ .tag = .decl_ref, .idx = @intCast(@intFromEnum(i)) },581 .decl_ref => |i| .{ .tag = .decl_ref, .idx = @intCast(@intFromEnum(i)) },
474 };582 };
475 }583 }
476 pub fn unwrap(val: CaptureValue) Unwrapped {584 pub fn unwrap(val: Capture) Unwrapped {
477 return switch (val.tag) {585 return switch (val.tag) {
478 .@"comptime" => .{ .@"comptime" = @enumFromInt(val.idx) },586 .@"comptime" => .{ .@"comptime" = @enumFromInt(val.idx) },
479 .runtime => .{ .runtime = @enumFromInt(val.idx) },587 .runtime => .{ .runtime = @enumFromInt(val.idx) },
...@@ -484,9 +592,9 @@ pub const CaptureValue = packed struct(u32) {...@@ -484,9 +592,9 @@ pub const CaptureValue = packed struct(u32) {
484592
485 pub const Unwrapped = union(enum) {593 pub const Unwrapped = union(enum) {
486 /// Index refers to the value.594 /// Index refers to the value.
487 @"comptime": Index,595 @"comptime": Value,
488 /// Index refers to the type.596 /// Index refers to the type.
489 runtime: Index,597 runtime: Value,
490 decl_val: DeclIndex,598 decl_val: DeclIndex,
491 decl_ref: DeclIndex,599 decl_ref: DeclIndex,
492 };600 };
...@@ -494,7 +602,7 @@ pub const CaptureValue = packed struct(u32) {...@@ -494,7 +602,7 @@ pub const CaptureValue = packed struct(u32) {
494 pub const Slice = struct {602 pub const Slice = struct {
495 start: u32,603 start: u32,
496 len: u32,604 len: u32,
497 pub fn get(slice: Slice, ip: *const InternPool) []CaptureValue {605 pub fn get(slice: Slice, ip: *const InternPool) []Capture {
498 return @ptrCast(ip.extra.items[slice.start..][0..slice.len]);606 return @ptrCast(ip.extra.items[slice.start..][0..slice.len]);
499 }607 }
500 };608 };
...@@ -516,9 +624,9 @@ const SimpleType = enum {...@@ -516,9 +624,9 @@ const SimpleType = enum {
516 float,624 float,
517 string,625 string,
518 bool,626 bool,
519 void,
520 noreturn,627 noreturn,
521 type,628 type,
629 numeric_literal,
522630
523 pub fn key(self: SimpleType) Key {631 pub fn key(self: SimpleType) Key {
524 return .{ .simple_type = self };632 return .{ .simple_type = self };
...@@ -526,6 +634,7 @@ const SimpleType = enum {...@@ -526,6 +634,7 @@ const SimpleType = enum {
526};634};
527635
528pub const Key = union(enum) {636pub const Key = union(enum) {
637 comptime_float: f64,
529 int32: i32,638 int32: i32,
530 float: f64,639 float: f64,
531 string: []const u8,640 string: []const u8,
...@@ -549,8 +658,8 @@ pub const Key = union(enum) {...@@ -549,8 +658,8 @@ pub const Key = union(enum) {
549 };658 };
550659
551 pub const TypeFunction = struct {660 pub const TypeFunction = struct {
552 param_types: []Index,661 param_types: []Type,
553 return_type: Index,662 return_type: Type,
554663
555 pub fn hash(self: TypeFunction, hasher: *Hash) void {664 pub fn hash(self: TypeFunction, hasher: *Hash) void {
556 const t = tracer.trace(@src());665 const t = tracer.trace(@src());
...@@ -563,13 +672,13 @@ pub const Key = union(enum) {...@@ -563,13 +672,13 @@ pub const Key = union(enum) {
563 }672 }
564673
565 pub fn eql(a: TypeFunction, b: TypeFunction) bool {674 pub fn eql(a: TypeFunction, b: TypeFunction) bool {
566 return std.mem.eql(Index, a.param_types, b.param_types) and675 return std.mem.eql(Type, a.param_types, b.param_types) and
567 a.return_type == b.return_type;676 a.return_type == b.return_type;
568 }677 }
569 };678 };
570679
571 pub const Func = struct {680 pub const Func = struct {
572 ty: Index,681 ty: Value,
573 owner_decl: DeclIndex,682 owner_decl: DeclIndex,
574 teg_body_inst: TrackedInst.Index,683 teg_body_inst: TrackedInst.Index,
575684
...@@ -600,7 +709,7 @@ pub const Key = union(enum) {...@@ -600,7 +709,7 @@ pub const Key = union(enum) {
600 => |x| Hash.hash(seed, asBytes(&x)),709 => |x| Hash.hash(seed, asBytes(&x)),
601 .string,710 .string,
602 => |x| Hash.hash(seed, x),711 => |x| Hash.hash(seed, x),
603 .float => |x| Hash.hash(seed, asBytes(&Float.assertPure(x))),712 .float, .comptime_float => |x| Hash.hash(seed, asBytes(&Float.assertPure(x))),
604 .type_function => |x| {713 .type_function => |x| {
605 var hasher = Hash.init(seed);714 var hasher = Hash.init(seed);
606 x.hash(&hasher);715 x.hash(&hasher);
...@@ -631,6 +740,7 @@ pub const Key = union(enum) {...@@ -631,6 +740,7 @@ pub const Key = union(enum) {
631 .string,740 .string,
632 => |x| std.mem.eql(u8, x, b.string),741 => |x| std.mem.eql(u8, x, b.string),
633 .float => |x| Float.assertPure(x) == Float.assertPure(b.float),742 .float => |x| Float.assertPure(x) == Float.assertPure(b.float),
743 .comptime_float => |x| Float.assertPure(x) == Float.assertPure(b.comptime_float),
634 .type_function => |x| x.eql(b.type_function),744 .type_function => |x| x.eql(b.type_function),
635 .func => |a_info| {745 .func => |a_info| {
636 const b_info = b.func;746 const b_info = b.func;
...@@ -747,7 +857,7 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {...@@ -747,7 +857,7 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {
747 ip.* = undefined;857 ip.* = undefined;
748}858}
749859
750pub fn indexToKey(ip: *const InternPool, index: Index) Key {860pub fn indexToKey(ip: *const InternPool, index: Value) Key {
751 assert(index != .none);861 assert(index != .none);
752 const item: Item = ip.items.get(@intFromEnum(index));862 const item: Item = ip.items.get(@intFromEnum(index));
753 const data = item.data;863 const data = item.data;
...@@ -762,6 +872,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -762,6 +872,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
762 .simple_value => .{ .simple_value = data.decode(.simple_value, item.tag) },872 .simple_value => .{ .simple_value = data.decode(.simple_value, item.tag) },
763 .int32 => .{ .int32 = data.decode(.int32, item.tag) },873 .int32 => .{ .int32 = data.decode(.int32, item.tag) },
764 .float => .{ .float = data.decode(.float, item.tag).get(ip).decode() },874 .float => .{ .float = data.decode(.float, item.tag).get(ip).decode() },
875 .comptime_float => .{ .comptime_float = data.decode(.comptime_float, item.tag).get(ip).decode() },
765 .string => .{ .string = data.decode(.string, item.tag).get(ip).toSlice(ip) },876 .string => .{ .string = data.decode(.string, item.tag).get(ip).toSlice(ip) },
766 .func => {877 .func => {
767 const func = data.decode(.func, item.tag).get(ip);878 const func = data.decode(.func, item.tag).get(ip);
...@@ -774,7 +885,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -774,7 +885,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
774 };885 };
775}886}
776887
777pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Index {888pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Value {
778 const t = tracer.traceFmt(@src(), "{s}", .{@tagName(key)});889 const t = tracer.traceFmt(@src(), "{s}", .{@tagName(key)});
779 defer t.end();890 defer t.end();
780891
...@@ -806,6 +917,10 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Index {...@@ -806,6 +917,10 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Index {
806 .float,917 .float,
807 try ip.extra.append(gpa, Float, Float.encode(f)),918 try ip.extra.append(gpa, Float, Float.encode(f)),
808 ),919 ),
920 .comptime_float => |f| Item.encode(
921 .comptime_float,
922 try ip.extra.append(gpa, Float, Float.encode(f)),
923 ),
809 .func => |f| brk: {924 .func => |f| brk: {
810 const extra = try ip.extra.append(gpa, Tag.FuncDecl, .{925 const extra = try ip.extra.append(gpa, Tag.FuncDecl, .{
811 .analysis = .{926 .analysis = .{
...@@ -829,7 +944,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Index {...@@ -829,7 +944,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Index {
829 },944 },
830 };945 };
831 ip.items.appendAssumeCapacity(item);946 ip.items.appendAssumeCapacity(item);
832 const index: Index = @enumFromInt(ip.items.len - 1);947 const index: Value = @enumFromInt(ip.items.len - 1);
833 if (std.debug.runtime_safety) {948 if (std.debug.runtime_safety) {
834 assert(ip.indexToKey(index).eql(key, ip));949 assert(ip.indexToKey(index).eql(key, ip));
835 }950 }
...@@ -841,7 +956,7 @@ fn extraTypeFunction(...@@ -841,7 +956,7 @@ fn extraTypeFunction(
841 extra_index: ExtraIndex(Tag.TypeFunction),956 extra_index: ExtraIndex(Tag.TypeFunction),
842) Key.TypeFunction {957) Key.TypeFunction {
843 const type_function, var trail = extra_index.getTrail(ip);958 const type_function, var trail = extra_index.getTrail(ip);
844 const param_types = trail.readInternPoolIndexSlice(type_function.params_len);959 const param_types = trail.readTypeSlice(type_function.params_len);
845 const result: Key.TypeFunction = .{960 const result: Key.TypeFunction = .{
846 .return_type = type_function.return_type,961 .return_type = type_function.return_type,
847 .param_types = param_types.get(ip),962 .param_types = param_types.get(ip),
src/compiler/JsLink.zig+2
...@@ -221,6 +221,8 @@ fn printExpr(link: *JsLink, tree: *const JsTree, node: Node.Index, writer: anyty...@@ -221,6 +221,8 @@ fn printExpr(link: *JsLink, tree: *const JsTree, node: Node.Index, writer: anyty
221 // TODO: escapes221 // TODO: escapes
222 .string => |val| try writer.print("\"{s}\"", .{val}),222 .string => |val| try writer.print("\"{s}\"", .{val}),
223223
224 .comptime_float => unreachable, // was not lowered to float
225
224 else => unreachable, // this value is not a plain_value226 else => unreachable, // this value is not a plain_value
225 }227 }
226 },228 },
src/compiler/JsNodeGen.zig+29-25
...@@ -198,23 +198,23 @@ fn codeGenInst(c: *JsNodeGen, inst: Air.Inst.Index) Error!void {...@@ -198,23 +198,23 @@ fn codeGenInst(c: *JsNodeGen, inst: Air.Inst.Index) Error!void {
198 if ((tag == .add or tag == .sub) and198 if ((tag == .add or tag == .sub) and
199 inner_data.rhs.kind == .value)199 inner_data.rhs.kind == .value)
200 {200 {
201 if (inner_data.rhs.decode().value.toFloat(c.ip)) |f| {201 // if (inner_data.rhs.decode().value.toFloat(c.ip)) |f| {
202 if (f == 1) {202 // if (f == 1) {
203 // convert this into ++ or --203 // // convert this into ++ or --
204 const node = try c.add(204 // const node = try c.add(
205 if (tag == .add)205 // if (tag == .add)
206 .pre_inc206 // .pre_inc
207 else207 // else
208 .pre_dec,208 // .pre_dec,
209 .{209 // .{
210 .operand = target,210 // .operand = target,
211 },211 // },
212 );212 // );
213 try c.markExpression(inst, node);213 // try c.markExpression(inst, node);
214214
215 return;215 // return;
216 }216 // }
217 }217 // }
218 }218 }
219219
220 // convert into a compound assignment220 // convert into a compound assignment
...@@ -442,15 +442,20 @@ fn valueToExpression(c: *JsNodeGen, v: Value) !Node.Index {...@@ -442,15 +442,20 @@ fn valueToExpression(c: *JsNodeGen, v: Value) !Node.Index {
442 const t = tracer.trace(@src());442 const t = tracer.trace(@src());
443 defer t.end();443 defer t.end();
444444
445 const intern_tag = c.ip.items.items(.tag)[@intFromEnum(v.toIntern())];445 const intern_tag = v.valueTag(c.ip);
446 switch (intern_tag) {446 switch (intern_tag) {
447 .removed => unreachable, // UAF447 .removed => unreachable, // UAF
448448
449 .type_function, .simple_type => unreachable, // Type values are not allowed here449 .type_function,
450 .simple_type,
451 => unreachable, // Type values are not allowed here
450452
451 .int32, .float, .string, .simple_value => {453 .int32,
452 return try c.add(.plain_value, .{ .value = v });454 .float,
453 },455 .comptime_float,
456 .string,
457 .simple_value,
458 => return try c.add(.plain_value, .{ .value = v }),
454459
455 // funcs always point to decls460 // funcs always point to decls
456 .func => {461 .func => {
...@@ -493,7 +498,7 @@ fn codeGenBranch(c: *JsNodeGen, inst: Air.Inst.Ref, temporary: ?Node.Index) !?Br...@@ -493,7 +498,7 @@ fn codeGenBranch(c: *JsNodeGen, inst: Air.Inst.Ref, temporary: ?Node.Index) !?Br
493 var requires_label = false;498 var requires_label = false;
494 var items = switch (inst.decode()) {499 var items = switch (inst.decode()) {
495 .value => |v| items: {500 .value => |v| items: {
496 if (v.ip_index == .void_value)501 if (v == .void)
497 return null;502 return null;
498 if (temporary) |temp| {503 if (temporary) |temp| {
499 const node = try c.valueToExpression(v);504 const node = try c.valueToExpression(v);
...@@ -678,6 +683,7 @@ const assert = std.debug.assert;...@@ -678,6 +683,7 @@ const assert = std.debug.assert;
678const Allocator = std.mem.Allocator;683const Allocator = std.mem.Allocator;
679684
680const InternPool = @import("InternPool.zig");685const InternPool = @import("InternPool.zig");
686const Value = InternPool.Value;
681const NullTerminatedString = InternPool.NullTerminatedString;687const NullTerminatedString = InternPool.NullTerminatedString;
682688
683const Comp = @import("Comp.zig");689const Comp = @import("Comp.zig");
...@@ -690,7 +696,5 @@ const LocalIndex = JsTree.LocalIndex;...@@ -690,7 +696,5 @@ const LocalIndex = JsTree.LocalIndex;
690696
691const Air = @import("Air.zig");697const Air = @import("Air.zig");
692698
693const Value = @import("Value.zig");
694
695const dod = @import("dod.zig");699const dod = @import("dod.zig");
696const tracer = @import("tracer");700const tracer = @import("tracer");
src/compiler/JsTree.zig+2-2
...@@ -244,6 +244,8 @@ const std = @import("std");...@@ -244,6 +244,8 @@ const std = @import("std");
244const assert = std.debug.assert;244const assert = std.debug.assert;
245245
246const InternPool = @import("InternPool.zig");246const InternPool = @import("InternPool.zig");
247const Value = InternPool.Value;
248
247const NullTerminatedString = InternPool.NullTerminatedString;249const NullTerminatedString = InternPool.NullTerminatedString;
248const String = InternPool.String;250const String = InternPool.String;
249251
...@@ -252,6 +254,4 @@ const Decl = Comp.Decl;...@@ -252,6 +254,4 @@ const Decl = Comp.Decl;
252254
253const dod = @import("dod.zig");255const dod = @import("dod.zig");
254256
255const Value = @import("Value.zig");
256
257const Unused = @import("Ast.zig").Unused;257const Unused = @import("Ast.zig").Unused;
src/compiler/Parse.zig+4-1
...@@ -265,7 +265,10 @@ fn parseFnDecl(p: *Parse) Error!NodeIndex {...@@ -265,7 +265,10 @@ fn parseFnDecl(p: *Parse) Error!NodeIndex {
265 const params = try p.parseParamList();265 const params = try p.parseParamList();
266266
267 const return_type = if (p.eatToken(.minus_lt)) |_|267 const return_type = if (p.eatToken(.minus_lt)) |_|
268 try p.parseExpression(false)268 if (!p.isExpressionStart())
269 return p.failUnexpectedToken(.expression)
270 else
271 try p.parseExpression(false)
269 else272 else
270 null;273 null;
271274
src/compiler/Report.zig+108-56
...@@ -24,62 +24,6 @@ pub const Item = struct {...@@ -24,62 +24,6 @@ pub const Item = struct {
24 pub const Type = enum { @"error", warn };24 pub const Type = enum { @"error", warn };
25};25};
2626
27/// A variant of std.builtin.StackTrace that stores it's data within itself
28/// instead of being a pointer. This allows capturing the stack trace and
29/// saving it for later printing.
30pub const StoredTrace = struct {
31 data: [32]usize,
32 index: usize,
33
34 pub const empty = .{
35 .data = .{0} ** 32,
36 .index = 0,
37 };
38
39 fn trace(stored: *StoredTrace) std.builtin.StackTrace {
40 return .{
41 .index = stored.index,
42 .instruction_addresses = &stored.data,
43 };
44 }
45
46 pub fn capture(begin: ?usize) StoredTrace {
47 var stored: StoredTrace = undefined;
48 var frame = stored.trace();
49 std.debug.captureStackTrace(begin orelse @returnAddress(), &frame);
50 stored.index = frame.index;
51 return stored;
52 }
53
54 pub fn from(stack_trace: ?*std.builtin.StackTrace) StoredTrace {
55 if (stack_trace) |stack| {
56 var data: [32]usize = undefined;
57 @memset(&data, 0);
58 const items = @min(stack.instruction_addresses.len, 32);
59 @memcpy(data[0..items], stack.instruction_addresses[0..items]);
60 return .{
61 .data = data,
62 .index = @min(items, stack.index),
63 };
64 } else {
65 return empty;
66 }
67 }
68};
69
70pub const DebugStoredTrace = if (builtin.mode == .Debug)
71 StoredTrace
72else
73 struct {
74 pub fn capture() @This() {
75 return .{};
76 }
77
78 pub fn from(_: ?*std.builtin.StackTrace) @This() {
79 return .{};
80 }
81 };
82
83pub const Err = union(enum) {27pub const Err = union(enum) {
84 pub const FieldEnum = std.meta.FieldEnum(Err);28 pub const FieldEnum = std.meta.FieldEnum(Err);
8529
...@@ -189,6 +133,15 @@ pub const Err = union(enum) {...@@ -189,6 +133,15 @@ pub const Err = union(enum) {
189 );133 );
190 }134 }
191 },135 },
136 comptime_float_to_int: struct {
137 val: f64,
138 src: LazyNode,
139
140 fn build(data: @This(), ctx: *MsgContext) !void {
141 const node = try data.src.get(ctx);
142 try ctx.msgNode(node, "numeric literal \"{d}\" cannot be coerced to \"int\"", .{data.val});
143 }
144 },
192};145};
193146
194pub const Warn = union(enum) {147pub const Warn = union(enum) {
...@@ -221,8 +174,74 @@ pub const Warn = union(enum) {...@@ -221,8 +174,74 @@ pub const Warn = union(enum) {
221 try ctx.msgAlone("if this was intentional, discard it with \"_ = {s};\"", .{id});174 try ctx.msgAlone("if this was intentional, discard it with \"_ = {s};\"", .{id});
222 }175 }
223 },176 },
177 numeric_int_var_ambiguity: struct {
178 node: LazyNode,
179
180 fn build(data: @This(), ctx: *MsgContext) !void {
181 const var_decl_node = try data.node.get(ctx);
182 const init_node = ctx.ast.nodeData(var_decl_node).var_decl.init;
183 try ctx.msgNode(init_node, "constant integer in a \"var\" has an unknown type, assuming \"float\"", .{});
184 try ctx.msgAlone("add \": float\" or \": int\" after the variable name to set the type", .{});
185 }
186 },
224};187};
225188
189/// A variant of std.builtin.StackTrace that stores it's data within itself
190/// instead of being a pointer. This allows capturing the stack trace and
191/// saving it for later printing.
192pub const StoredTrace = struct {
193 data: [32]usize,
194 index: usize,
195
196 pub const empty = .{
197 .data = .{0} ** 32,
198 .index = 0,
199 };
200
201 fn trace(stored: *StoredTrace) std.builtin.StackTrace {
202 return .{
203 .index = stored.index,
204 .instruction_addresses = &stored.data,
205 };
206 }
207
208 pub fn capture(begin: ?usize) StoredTrace {
209 var stored: StoredTrace = undefined;
210 var frame = stored.trace();
211 std.debug.captureStackTrace(begin orelse @returnAddress(), &frame);
212 stored.index = frame.index;
213 return stored;
214 }
215
216 pub fn from(stack_trace: ?*std.builtin.StackTrace) StoredTrace {
217 if (stack_trace) |stack| {
218 var data: [32]usize = undefined;
219 @memset(&data, 0);
220 const items = @min(stack.instruction_addresses.len, 32);
221 @memcpy(data[0..items], stack.instruction_addresses[0..items]);
222 return .{
223 .data = data,
224 .index = @min(items, stack.index),
225 };
226 } else {
227 return empty;
228 }
229 }
230};
231
232pub const DebugStoredTrace = if (builtin.mode == .Debug)
233 StoredTrace
234else
235 struct {
236 pub fn capture() @This() {
237 return .{};
238 }
239
240 pub fn from(_: ?*std.builtin.StackTrace) @This() {
241 return .{};
242 }
243 };
244
226pub const UnusedKind = enum {245pub const UnusedKind = enum {
227 param,246 param,
228 constant,247 constant,
...@@ -509,6 +528,7 @@ pub const Builder = struct {...@@ -509,6 +528,7 @@ pub const Builder = struct {
509 pub fn deinit(b: *Builder) void {528 pub fn deinit(b: *Builder) void {
510 b.errors.deinit(b.gpa);529 b.errors.deinit(b.gpa);
511 b.warnings.deinit(b.gpa);530 b.warnings.deinit(b.gpa);
531 b.string_bytes.deinit(b.gpa);
512 }532 }
513533
514 pub fn finalize(b: *Builder) !Report {534 pub fn finalize(b: *Builder) !Report {
...@@ -592,6 +612,38 @@ pub const MsgContext = struct {...@@ -592,6 +612,38 @@ pub const MsgContext = struct {
592 }612 }
593};613};
594614
615pub const LazyNode = struct {
616 decl: Comp.Decl.Index,
617 node_offset: i32,
618
619 pub fn get(lazy: LazyNode, ctx: *MsgContext) !NodeIndex {
620 const decl = ctx.comp.intern_pool.declPtrConst(lazy.decl);
621 const ns = ctx.comp.intern_pool.namespacePtr(decl.src_namespace);
622
623 // TODO: This might change if we have errors like
624 // - function arguments not matching at <callsite>
625 // - function declared <definition>
626 // And they are both in different files.
627 // To resolve this, `Component` needs to store which file it is in.
628 assert(ns.file_scope == ctx.file);
629
630 if (ns.parent.unwrap() != null) {
631 @panic("TODO: LazyNode.get when the decl is in a nested namespace");
632 }
633
634 const teg = &(ctx.file.teg orelse
635 // this will be required once incremental compilation hits
636 @panic("TODO: teg was unloaded"));
637
638 const decl_inst = decl.teg_decl_index.unwrap() orelse
639 unreachable; // file was not analyzed, yet teg loaded?
640
641 const teg_decl = teg.instData(.declaration, decl_inst.resolve(&ctx.comp.intern_pool));
642
643 return @intCast(teg_decl.src_node - lazy.node_offset);
644 }
645};
646
595const Report = @This();647const Report = @This();
596const std = @import("std");648const std = @import("std");
597const ArrayListUnmanaged = std.ArrayListUnmanaged;649const ArrayListUnmanaged = std.ArrayListUnmanaged;
src/compiler/Sema.zig+224-121
...@@ -16,9 +16,10 @@ inst_map: InstMap = undefined,...@@ -16,9 +16,10 @@ inst_map: InstMap = undefined,
16/// scratch memory. can be used in any place you might temporarily allocate an arraylist16/// scratch memory. can be used in any place you might temporarily allocate an arraylist
17/// this is most notably used to store block contents before the block is finalized17/// this is most notably used to store block contents before the block is finalized
18scratch: std.ArrayListUnmanaged(u32) = .{},18scratch: std.ArrayListUnmanaged(u32) = .{},
19params: []InternPool.Index = undefined,19params: []Type = undefined,
2020
21// outputs21// outputs
22report: Report.Builder = undefined,
22air_instructions: std.MultiArrayList(Air.Inst) = .{},23air_instructions: std.MultiArrayList(Air.Inst) = .{},
23air_extra: dod.ExtraStore(.air, .@"var") = .{},24air_extra: dod.ExtraStore(.air, .@"var") = .{},
2425
...@@ -27,6 +28,8 @@ pub const Error = error{...@@ -27,6 +28,8 @@ pub const Error = error{
27 AnalysisFail,28 AnalysisFail,
28 /// This analysis is waiting on other dependencies to finish29 /// This analysis is waiting on other dependencies to finish
29 Interrupt,30 Interrupt,
31
32 OutOfMemory,
30};33};
3134
32/// Instead of using a hash map for this, just pre-allocate a list long enough to hold everything.35/// Instead of using a hash map for this, just pre-allocate a list long enough to hold everything.
...@@ -74,6 +77,11 @@ pub fn init(s: *Sema) !void {...@@ -74,6 +77,11 @@ pub fn init(s: *Sema) !void {
74 const t = tracer.trace(@src());77 const t = tracer.trace(@src());
75 defer t.end();78 defer t.end();
7679
80 s.report = .{
81 .gpa = s.gpa,
82 .current_file = s.ip.namespacePtr(s.namespace_index).file_scope,
83 };
84
77 try s.comp.current_compile_decls.append(s.gpa, s.decl_index);85 try s.comp.current_compile_decls.append(s.gpa, s.decl_index);
7886
79 s.inst_map = try InstMap.init(87 s.inst_map = try InstMap.init(
...@@ -87,6 +95,10 @@ pub fn deinit(s: *Sema) void {...@@ -87,6 +95,10 @@ pub fn deinit(s: *Sema) void {
87 const t = tracer.trace(@src());95 const t = tracer.trace(@src());
88 defer t.end();96 defer t.end();
8997
98 const report = s.report.finalize() catch @panic("OOM");
99 report.dumpToStdErr(s.comp) catch @panic("Error");
100 report.deinit(s.gpa);
101
90 defer s.* = undefined;102 defer s.* = undefined;
91 s.inst_map.deinit(s.arena);103 s.inst_map.deinit(s.arena);
92 s.scratch.deinit(s.arena);104 s.scratch.deinit(s.arena);
...@@ -121,14 +133,14 @@ pub fn analyzeDeclaration(s: *Sema) anyerror!Value {...@@ -121,14 +133,14 @@ pub fn analyzeDeclaration(s: *Sema) anyerror!Value {
121 const decl, const fn_decl = s.code.fullFuncDecl(s.inst_map.start);133 const decl, const fn_decl = s.code.fullFuncDecl(s.inst_map.start);
122 assert(decl.kind == .function);134 assert(decl.kind == .function);
123135
124 s.params = try s.gpa.alloc(InternPool.Index, fn_decl.params.len);136 s.params = try s.gpa.alloc(Type, fn_decl.params.len);
125 defer s.gpa.free(s.params);137 defer s.gpa.free(s.params);
126138
127 for (fn_decl.params.slice(&s.code), 0..) |param, i| {139 for (fn_decl.params.slice(&s.code), 0..) |param, i| {
128 s.params[i] = (try s.resolveRefComptime(param)).toIntern();140 s.params[i] = (try s.resolveRefComptime(param)).toType(s.ip).?;
129 }141 }
130142
131 const return_type = try s.resolveRefComptime(fn_decl.return_type);143 const return_type = (try s.resolveRefComptime(fn_decl.return_type)).toType(s.ip).?;
132144
133 const root_block = fn_decl.body.toIndex() orelse145 const root_block = fn_decl.body.toIndex() orelse
134 @panic("TODO: please change this to Index. Ref is not allowed here anymore");146 @panic("TODO: please change this to Index. Ref is not allowed here anymore");
...@@ -143,17 +155,16 @@ pub fn analyzeDeclaration(s: *Sema) anyerror!Value {...@@ -143,17 +155,16 @@ pub fn analyzeDeclaration(s: *Sema) anyerror!Value {
143 const func_prototype = try s.ip.get(s.gpa, .{155 const func_prototype = try s.ip.get(s.gpa, .{
144 .type_function = .{156 .type_function = .{
145 .param_types = s.params,157 .param_types = s.params,
146 .return_type = return_type.toIntern(),158 .return_type = return_type,
147 },159 },
148 });160 });
149 const func_value = try s.ip.get(s.gpa, .{161 const value = try s.ip.get(s.gpa, .{
150 .func = .{162 .func = .{
151 .ty = func_prototype,163 .ty = func_prototype,
152 .owner_decl = s.decl_index,164 .owner_decl = s.decl_index,
153 .teg_body_inst = s.decl.teg_decl_index.unwrap().?,165 .teg_body_inst = s.decl.teg_decl_index.unwrap().?,
154 },166 },
155 });167 });
156 const value = Value.fromInterned(func_value);
157 s.decl.val = value;168 s.decl.val = value;
158 return value;169 return value;
159}170}
...@@ -221,11 +232,12 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref {...@@ -221,11 +232,12 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref {
221 },232 },
222 .number => {233 .number => {
223 const number: dod.Float = s.code.instPayload(.number, in);234 const number: dod.Float = s.code.instPayload(.number, in);
224 return s.makeValueAir(.{ .float = number.decode() });235 return s.makeValueAir(.{ .comptime_float = number.decode() });
225 },236 },
226 .js => {237 .js => {
227 const operand = try s.resolveRefComptime(s.code.instData(.js, in).operand);238 const operand_ref = s.code.instData(.js, in).operand;
228 try s.validateType(operand.type(s.ip), .string_type);239 const operand = try s.resolveRefComptime(operand_ref);
240 // const operand_str = try s.coerceValue(operand_ref.toIndex().?, operand, .string);
229 return s.addInstRef(.js_global_ref, operand.asString(s.ip));241 return s.addInstRef(.js_global_ref, operand.asString(s.ip));
230 },242 },
231 .field => {243 .field => {
...@@ -233,12 +245,12 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref {...@@ -233,12 +245,12 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref {
233 const base = try s.resolveRefRuntime(field.lhs);245 const base = try s.resolveRefRuntime(field.lhs);
234 const rhs = try s.resolveRefComptime(field.rhs);246 const rhs = try s.resolveRefComptime(field.rhs);
235247
236 try s.validateType(rhs.type(s.ip), .string_type);248 // try s.validateType(rhs.type(s.ip), .string_type);
237 const string = rhs.asString(s.ip);249 const string = rhs.asString(s.ip);
238250
239 const base_type = s.typeOfRef(base);251 const base_type = s.typeOfRef(base);
240 switch (base_type) {252 switch (base_type) {
241 .opaque_type => {253 .@"opaque" => {
242 return s.addInstRef(.field, .{254 return s.addInstRef(.field, .{
243 .base = base,255 .base = base,
244 .field = try string.tryToNullTerminatedString(s.ip, s.gpa),256 .field = try string.tryToNullTerminatedString(s.ip, s.gpa),
...@@ -259,12 +271,12 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref {...@@ -259,12 +271,12 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref {
259 return error.AnalysisFail;271 return error.AnalysisFail;
260 };272 };
261 const resolved = try s.resolveDecl(decl_index);273 const resolved = try s.resolveDecl(decl_index);
262 return resolved.toIntern().toAir();274 return resolved.toAir();
263 },275 },
264 .param => {276 .param => {
265 const param: Teg.Inst.DataNode = s.code.instData(.param, in);277 const param: Teg.Inst.DataNode = s.code.instData(.param, in);
266 return s.addInstRef(.arg, .{278 return s.addInstRef(.arg, .{
267 .type = Value.fromInterned(s.params[param.data]),279 .type = s.params[param.data],
268 .arg_number = param.data,280 .arg_number = param.data,
269 });281 });
270 },282 },
...@@ -325,83 +337,86 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref {...@@ -325,83 +337,86 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref {
325 });337 });
326 },338 },
327 .call => {339 .call => {
328 const call: Teg.Inst.Call = s.code.instPayload(.call, in);340 @panic("TODO: re-implement .call");
329 const base = try s.resolveRefRuntime(call.base);341 // const call: Teg.Inst.Call = s.code.instPayload(.call, in);
330 const base_type = s.typeOfRef(base).toKey(s.ip);342 // const base = try s.resolveRefRuntime(call.base);
331343 // const base_type = s.typeOfRef(base).toKey(s.ip);
332 const is_opaque = base_type == .simple_type and base_type.simple_type == .@"opaque";344
333345 // const is_opaque = base_type == .simple_type and base_type.simple_type == .@"opaque";
334 const scratch = try s.arena.alloc(Air.Inst.Ref, call.args.len);346
335 defer s.arena.free(scratch);347 // const scratch = try s.arena.alloc(Air.Inst.Ref, call.args.len);
336 if (!is_opaque) {348 // defer s.arena.free(scratch);
337 if (base_type != .type_function) {349 // if (!is_opaque) {
338 std.debug.print("Attempt to call non-function {}", .{base_type});350 // if (base_type != .type_function) {
339 return error.AnalysisFail;351 // std.debug.print("Attempt to call non-function {}", .{base_type});
340 }352 // return error.AnalysisFail;
341353 // }
342 const proto = base_type.type_function;354
343 if (proto.param_types.len != call.args.len) {355 // const proto = base_type.type_function;
344 std.debug.print("Incorrect args. Expect {d}, Got {d}", .{356 // if (proto.param_types.len != call.args.len) {
345 proto.param_types.len,357 // std.debug.print("Incorrect args. Expect {d}, Got {d}", .{
346 call.args.len,358 // proto.param_types.len,
347 });359 // call.args.len,
348 return error.AnalysisFail;360 // });
349 }361 // return error.AnalysisFail;
350362 // }
351 // validate function args363
352 for (proto.param_types, call.args.slice(&s.code), 0..) |param, arg, i| {364 // // validate function args
353 const ref = try s.resolveRefRuntime(arg);365 // for (proto.param_types, call.args.slice(&s.code), 0..) |param, arg, i| {
354 scratch[i] = ref;366 // const ref = try s.resolveRefRuntime(arg);
355 try s.validateType(367 // scratch[i] = ref;
356 Value.fromInterned(s.typeOfRef(ref)),368 // _ = param;
357 param,369 // // try s.validateType(
358 );370 // // Value.fromInterned(s.typeOfRef(ref)),
359 }371 // // param,
360 } else {372 // // );
361 // just copy the args in without checking373 // }
362 for (call.args.slice(&s.code), 0..) |arg, i| {374 // } else {
363 const ref = try s.resolveRefRuntime(arg);375 // // just copy the args in without checking
364 scratch[i] = ref;376 // for (call.args.slice(&s.code), 0..) |arg, i| {
365 }377 // const ref = try s.resolveRefRuntime(arg);
366 }378 // scratch[i] = ref;
367379 // }
368 const start = s.air_extra.list.items.len;380 // }
369 try s.air_extra.list.appendSlice(s.gpa, @ptrCast(scratch));381
370382 // const start = s.air_extra.list.items.len;
371 return s.addInstRef(.call, .{383 // try s.air_extra.list.appendSlice(s.gpa, @ptrCast(scratch));
372 .base = base,384
373 .call_data = try s.air_extra.append(s.gpa, Air.Call.Data, .{385 // return s.addInstRef(.call, .{
374 .args = .{386 // .base = base,
375 .start = @intCast(start),387 // .call_data = try s.air_extra.append(s.gpa, Air.Call.Data, .{
376 .len = @intCast(scratch.len),388 // .args = .{
377 },389 // .start = @intCast(start),
378 }),390 // .len = @intCast(scratch.len),
379 });391 // },
392 // }),
393 // });
380 },394 },
381 .ensure_void => {395 .ensure_void => {
382 const operand = try s.resolveRefRuntimeExtra(s.code.instData(.ensure_void, in).operand, false);396 const operand = try s.resolveRefRuntimeExtra(s.code.instData(.ensure_void, in).operand, false);
383 const t = Value.fromInterned(s.typeOfRef(operand));397 const t = s.typeOfRef(operand);
384 if (!t.isEnsureVoid(s.ip)) {398 _ = t;
385 std.debug.print("oh no, we are discarding {} on accident\n", .{399 // if (!t.isEnsureVoid(s.ip)) {
386 t.fmt(s.ip),400 // std.debug.print("oh no, we are discarding {} on accident\n", .{
387 });401 // t.fmt(s.ip),
388 }402 // });
389 return InternPool.Index.void_value.toAir();403 // }
404 return InternPool.Value.void.toAir();
390 },405 },
391 .discard => {406 .discard => {
392 const operand = try s.resolveRefRuntimeExtra(s.code.instData(.discard, in).operand, false);407 const operand = try s.resolveRefRuntimeExtra(s.code.instData(.discard, in).operand, false);
393 const t = Value.fromInterned(s.typeOfRef(operand));408 const t = s.typeOfRef(operand);
394 if (t.ip_index == .void_value) {409 if (t == .void) {
395 std.debug.print("oh no, we have a useless _ = void;\n", .{});410 std.debug.print("oh no, we have a useless _ = void;\n", .{});
396 }411 }
397 return InternPool.Index.void_value.toAir();412 return InternPool.Value.void.toAir();
398 },413 },
399 .@"if" => {414 .@"if" => {
400 const data: Teg.Inst.If = s.code.instData(.@"if", in).extra_index.get(&s.code);415 const data: Teg.Inst.If = s.code.instData(.@"if", in).extra_index.get(&s.code);
401416
402 const cond = try s.resolveRefRuntime(data.cond);417 const cond = try s.resolveRefRuntime(data.cond);
403418
404 try s.validateType(Value.fromInterned(s.typeOfRef(cond)), .bool_type);419 // try s.validateType(s.typeOfRef(cond), .bool_type);
405420
406 // If known at comptime, only analyze the taken path421 // If known at comptime, only analyze the taken path
407 if (cond.kind == .value) {422 if (cond.kind == .value) {
...@@ -417,7 +432,7 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref {...@@ -417,7 +432,7 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref {
417 .data = try s.air_extra.append(s.gpa, Air.If.Data, .{432 .data = try s.air_extra.append(s.gpa, Air.If.Data, .{
418 .yes = yes_block,433 .yes = yes_block,
419 .no = no_block,434 .no = no_block,
420 .union_ty = s.unionType(Value.fromInterned(s.typeOfRef(yes_block)), Value.fromInterned(s.typeOfRef(no_block))),435 .union_ty = s.unionType(s.typeOfRef(yes_block), s.typeOfRef(no_block)),
421 }),436 }),
422 });437 });
423 },438 },
...@@ -434,11 +449,24 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref {...@@ -434,11 +449,24 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref {
434 .memory => {449 .memory => {
435 const data = s.code.instData(.memory, in);450 const data = s.code.instData(.memory, in);
436451
437 const initial_value = try s.resolveRefRuntime(data.operand);452 var initial_value = try s.resolveRefRuntime(data.operand);
453
454 switch (initial_value.decode()) {
455 .value => |v| switch (v.toKey(s.ip)) {
456 .comptime_float => |val| {
457 try s.report.warn(.numeric_int_var_ambiguity, .{
458 .node = s.nodeLoc(in),
459 });
460 initial_value = (try s.makeValue(.{ .float = val })).toAir();
461 },
462 else => {},
463 },
464 else => {},
465 }
438466
439 return try s.addInstRef(.memory, .{467 return try s.addInstRef(.memory, .{
440 .init = initial_value,468 .init = initial_value,
441 .ty = s.typeOfRef(initial_value).toValue(),469 .ty = s.typeOfRef(initial_value),
442 });470 });
443 },471 },
444 .store => {472 .store => {
...@@ -448,16 +476,22 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref {...@@ -448,16 +476,22 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) !Air.Inst.Ref {
448 const location = s.mapTeg(data.memory.toRef()).decode().inst;476 const location = s.mapTeg(data.memory.toRef()).decode().inst;
449 const operand = try s.resolveRefRuntime(data.operand);477 const operand = try s.resolveRefRuntime(data.operand);
450478
451 try s.validateType(479 // try s.validateType(
452 s.typeOfRef(operand).toValue(),480 // s.typeOfRef(operand).toValue(),
453 s.tempAir().instData(.memory, location).ty.ip_index,481 // s.tempAir().instData(.memory, location).ty.ip_index,
454 );482 // );
455483
456 return try s.addInstRef(.store, .{484 return try s.addInstRef(.store, .{
457 .memory = location,485 .memory = location,
458 .operand = operand,486 .operand = operand,
459 });487 });
460 },488 },
489 .as => {
490 const as: Teg.Inst.As = s.code.instPayload(.as, in);
491 const coerce_to = try s.resolveRefComptime(as.type);
492 const operand = try s.resolveRefRuntime(as.operand);
493 return try s.coerceRef(in, operand, coerce_to.toType(s.ip).?);
494 },
461 else => |tag| std.debug.panic("TODO: analyze of .{s}", .{@tagName(tag)}),495 else => |tag| std.debug.panic("TODO: analyze of .{s}", .{@tagName(tag)}),
462 }496 }
463}497}
...@@ -498,7 +532,7 @@ fn analyzeRefToBlock(s: *Sema, in: Teg.Inst.Ref) anyerror!Air.Inst.Ref {...@@ -498,7 +532,7 @@ fn analyzeRefToBlock(s: *Sema, in: Teg.Inst.Ref) anyerror!Air.Inst.Ref {
498532
499fn resolveRefRuntimeExtra(s: *Sema, ref: Teg.Inst.Ref, mark: bool) anyerror!Air.Inst.Ref {533fn resolveRefRuntimeExtra(s: *Sema, ref: Teg.Inst.Ref, mark: bool) anyerror!Air.Inst.Ref {
500 const index = ref.toIndex() orelse {534 const index = ref.toIndex() orelse {
501 return ref.toInterned().?.toAir();535 return ref.toValue().?.toAir();
502 };536 };
503537
504 if (s.inst_map.get(index)) |air| {538 if (s.inst_map.get(index)) |air| {
...@@ -519,20 +553,21 @@ fn resolveRefRuntime(s: *Sema, ref: Teg.Inst.Ref) anyerror!Air.Inst.Ref {...@@ -519,20 +553,21 @@ fn resolveRefRuntime(s: *Sema, ref: Teg.Inst.Ref) anyerror!Air.Inst.Ref {
519}553}
520554
521fn resolveRefComptime(s: *Sema, ref: Teg.Inst.Ref) !Value {555fn resolveRefComptime(s: *Sema, ref: Teg.Inst.Ref) !Value {
522 const in = ref.toIndex() orelse {556 const index = switch (ref.decode()) {
523 return Value{ .ip_index = ref.toInterned().? };557 .value => |value| return value,
558 .index => |index| index,
524 };559 };
525560
526 if (s.inst_map.get(in)) |air| {561 if (s.inst_map.get(index)) |air| {
527 switch (air.decode()) {562 switch (air.decode()) {
528 .value => |value| return value,563 .value => |value| return value,
529 else => {},564 else => {},
530 }565 }
531 }566 }
532567
533 switch (s.code.instTag(in)) {568 switch (s.code.instTag(index)) {
534 .string => {569 .string => {
535 const string: Teg.SlicedString = s.code.instPayload(.string, in);570 const string: Teg.SlicedString = s.code.instPayload(.string, index);
536 return s.makeValue(.{ .string = string.slice(s.code.string_bytes) });571 return s.makeValue(.{ .string = string.slice(s.code.string_bytes) });
537 },572 },
538573
...@@ -540,6 +575,70 @@ fn resolveRefComptime(s: *Sema, ref: Teg.Inst.Ref) !Value {...@@ -540,6 +575,70 @@ fn resolveRefComptime(s: *Sema, ref: Teg.Inst.Ref) !Value {
540 }575 }
541}576}
542577
578/// Coerce `value` runtime ref to `coerce_type`, and emit an error at `teg_ref`'s location
579fn coerceRef(
580 s: *Sema,
581 teg_ref: Teg.Inst.Index,
582 value: Air.Inst.Ref,
583 coerce_to: Type,
584) !Air.Inst.Ref {
585 _ = teg_ref;
586 _ = s;
587 _ = value;
588 _ = coerce_to;
589 // const value_type = s.typeOfRef(value);
590 // switch (coerce_type.toKey(s.ip)) {
591 // .simple_type => |simple_type| switch (simple_type) {
592 // // .@"opaque",
593 // .int32 => {
594 // switch (value_type.toKey(s.ip)) {
595 // .simple_type => switch (simple_type) {
596 // // .int32 => return value,
597 // // .numeric_literal => {
598 // // const val = value.decode().value.toKey(s.ip).comptime_float;
599 // // std.debug.print("buh {d}\n", .{val});
600 // // if (!math.isFinite(val) or
601 // // val < math.minInt(i32) or
602 // // val > math.maxInt(i32))
603 // // {
604 // // try s.fail(.comptime_float_to_int, .{
605 // // .val = val,
606 // // .src = s.nodeLoc(teg_ref),
607 // // });
608 // // }
609 // // return (try s.makeValue(.{ .int32 = @intFromFloat(val) })).toAir();
610 // // },
611 // else => |tag| std.debug.panic("TODO: coerceTo value_type simple_type .{s}", .{@tagName(tag)}),
612 // },
613 // else => |tag| std.debug.panic("TODO: coerceTo value_type .{s}", .{@tagName(tag)}),
614 // }
615 // },
616 // // .float,
617 // // .string,
618 // // .bool,
619 // // .noreturn,
620 // // .type,
621 // // .numeric_literal,
622 // else => |tag| std.debug.panic("TODO: coerceTo coerce_type .simple_type = .{s}", .{@tagName(tag)}),
623 // },
624 // else => |tag| std.debug.panic("TODO: coerceTo coerce_type .{s}", .{@tagName(tag)}),
625 // }
626 @panic("TODO");
627}
628
629fn coerceValue(
630 s: *Sema,
631 teg_ref: Teg.Inst.Index,
632 value: Value,
633 coerce_to: Type,
634) !Value {
635 _ = s;
636 _ = teg_ref;
637 _ = value;
638 _ = coerce_to;
639 @panic("TODO");
640}
641
543fn resolveDecl(s: *Sema, decl_index: Decl.Index) !Value {642fn resolveDecl(s: *Sema, decl_index: Decl.Index) !Value {
544 const decl = s.ip.declPtr(decl_index);643 const decl = s.ip.declPtr(decl_index);
545 switch (decl.analysis) {644 switch (decl.analysis) {
...@@ -579,27 +678,22 @@ fn resolveDecl(s: *Sema, decl_index: Decl.Index) !Value {...@@ -579,27 +678,22 @@ fn resolveDecl(s: *Sema, decl_index: Decl.Index) !Value {
579 }678 }
580}679}
581680
582fn unionType(s: *Sema, a: Value, b: Value) Value {681fn unionType(s: *Sema, a: Type, b: Type) Type {
583 if (std.debug.runtime_safety) {682 if (a == b) {
584 assert(a.type(s.ip).toIntern() == .type_type);
585 assert(b.type(s.ip).toIntern() == .type_type);
586 }
587
588 if (a.ip_index == b.ip_index) {
589 return a;683 return a;
590 }684 }
591685
592 if (a.ip_index == .noreturn_type)686 if (a == .noreturn)
593 return b;687 return b;
594688
595 if (b.ip_index == .noreturn_type)689 if (b == .noreturn)
596 return a;690 return a;
597691
598 std.debug.panic(692 std.debug.panic(
599 "TODO: when two non-equal types implicitly merge (if/match), this should generate a union type.\na: {}\nb: {}",693 "TODO: when two non-equal types implicitly merge (if/match), this should generate a union type.\na: {}\nb: {}",
600 .{694 .{
601 a.fmt(s.ip),695 a.dump(s.ip),
602 b.fmt(s.ip),696 b.dump(s.ip),
603 },697 },
604 );698 );
605 // return s.ip.get(s.gpa, .{ .@"union" = &.{ a, b } });699 // return s.ip.get(s.gpa, .{ .@"union" = &.{ a, b } });
...@@ -650,7 +744,7 @@ fn comptimeBin(s: *Sema, op: BinaryOp, lhs: Value, rhs: Value) !Air.Inst.Ref {...@@ -650,7 +744,7 @@ fn comptimeBin(s: *Sema, op: BinaryOp, lhs: Value, rhs: Value) !Air.Inst.Ref {
650 else => comptime unreachable,744 else => comptime unreachable,
651 };745 };
652 return @as(746 return @as(
653 InternPool.Index,747 InternPool.Value,
654 if (result) .bool_true else .bool_false,748 if (result) .bool_true else .bool_false,
655 ).toAir();749 ).toAir();
656 },750 },
...@@ -660,7 +754,7 @@ fn comptimeBin(s: *Sema, op: BinaryOp, lhs: Value, rhs: Value) !Air.Inst.Ref {...@@ -660,7 +754,7 @@ fn comptimeBin(s: *Sema, op: BinaryOp, lhs: Value, rhs: Value) !Air.Inst.Ref {
660 const r = rhs.toFloat(s.ip) orelse @panic("TODO: typecheck / non-numeric eq");754 const r = rhs.toFloat(s.ip) orelse @panic("TODO: typecheck / non-numeric eq");
661 const result = l == r;755 const result = l == r;
662 return @as(756 return @as(
663 InternPool.Index,757 InternPool.Value,
664 if (result) .bool_true else .bool_false,758 if (result) .bool_true else .bool_false,
665 ).toAir();759 ).toAir();
666 },760 },
...@@ -709,15 +803,15 @@ fn setInstData(...@@ -709,15 +803,15 @@ fn setInstData(
709}803}
710804
711fn makeValue(s: *Sema, key: InternPool.Key) !Value {805fn makeValue(s: *Sema, key: InternPool.Key) !Value {
712 return .{ .ip_index = try s.ip.get(s.gpa, key) };806 return try s.ip.get(s.gpa, key);
713}807}
714808
715fn makeValueAir(s: *Sema, key: InternPool.Key) !Air.Inst.Ref {809fn makeValueAir(s: *Sema, key: InternPool.Key) !Air.Inst.Ref {
716 return (try s.makeValue(key)).ip_index.toAir();810 return (try s.makeValue(key)).toAir();
717}811}
718812
719fn mapTeg(s: *Sema, inst: Teg.Inst.Ref) Air.Inst.Ref {813fn mapTeg(s: *Sema, inst: Teg.Inst.Ref) Air.Inst.Ref {
720 if (inst.toInterned()) |interned| {814 if (inst.toValue()) |interned| {
721 return interned.toAir();815 return interned.toAir();
722 }816 }
723 const index = inst.toIndex().?;817 const index = inst.toIndex().?;
...@@ -729,13 +823,6 @@ fn mapTeg(s: *Sema, inst: Teg.Inst.Ref) Air.Inst.Ref {...@@ -729,13 +823,6 @@ fn mapTeg(s: *Sema, inst: Teg.Inst.Ref) Air.Inst.Ref {
729 };823 };
730}824}
731825
732fn validateType(s: *Sema, checked_type: Value, wanted_type: InternPool.Index) !void {
733 _ = s; // autofix
734 if (checked_type.toIntern() != wanted_type) {
735 return error.TypeCheckFailed;
736 }
737}
738
739fn scratchToIndexList(s: *Sema, scratch_top: usize) !Air.IndexList {826fn scratchToIndexList(s: *Sema, scratch_top: usize) !Air.IndexList {
740 const items = s.scratch.items[scratch_top..];827 const items = s.scratch.items[scratch_top..];
741 const extra_top = s.air_extra.list.items.len;828 const extra_top = s.air_extra.list.items.len;
...@@ -753,7 +840,7 @@ fn tempAir(s: *const Sema) Air {...@@ -753,7 +840,7 @@ fn tempAir(s: *const Sema) Air {
753 };840 };
754}841}
755842
756fn typeOfRef(s: *Sema, ref: Air.Inst.Ref) InternPool.Index {843fn typeOfRef(s: *Sema, ref: Air.Inst.Ref) InternPool.Type {
757 return s.tempAir().typeOf(ref, s.ip);844 return s.tempAir().typeOf(ref, s.ip);
758}845}
759846
...@@ -769,10 +856,28 @@ fn lookupDecl(s: *Sema, name: NullTerminatedString) ?InternPool.DeclIndex {...@@ -769,10 +856,28 @@ fn lookupDecl(s: *Sema, name: NullTerminatedString) ?InternPool.DeclIndex {
769 }856 }
770}857}
771858
859fn nodeLoc(s: *const Sema, in: Teg.Inst.Index) Report.LazyNode {
860 return s.code.instSrcLoc(in, s.decl_index);
861}
862
863pub fn addWarn(s: *Sema, comptime kind: Report.Err.FieldEnum, data: std.meta.FieldType(Report.Err, kind)) !void {
864 try s.report.warn(kind, data);
865}
866
867pub fn addError(s: *Sema, comptime kind: Report.Err.FieldEnum, data: std.meta.FieldType(Report.Err, kind)) !void {
868 try s.report.err(kind, data);
869}
870
871pub fn fail(s: *Sema, comptime kind: Report.Err.FieldEnum, data: std.meta.FieldType(Report.Err, kind)) Error!void {
872 try s.report.err(kind, data);
873 return Error.AnalysisFail;
874}
875
772const Sema = @This();876const Sema = @This();
773877
774const std = @import("std");878const std = @import("std");
775const mem = std.mem;879const mem = std.mem;
880const math = std.math;
776const Allocator = std.mem.Allocator;881const Allocator = std.mem.Allocator;
777const assert = std.debug.assert;882const assert = std.debug.assert;
778const log = std.log.scoped(.sema);883const log = std.log.scoped(.sema);
...@@ -791,14 +896,12 @@ const Decl = Comp.Decl;...@@ -791,14 +896,12 @@ const Decl = Comp.Decl;
791const Namespace = Comp.Namespace;896const Namespace = Comp.Namespace;
792897
793const Air = @import("Air.zig");898const Air = @import("Air.zig");
794
795const Teg = @import("Teg.zig");899const Teg = @import("Teg.zig");
900const Report = @import("Report.zig");
901const dod = @import("dod.zig");
902const tracer = @import("tracer");
796903
797const Value = @import("Value.zig");
798const InternPool = @import("InternPool.zig");904const InternPool = @import("InternPool.zig");
905const Value = InternPool.Value;
906const Type = InternPool.Type;
799const NullTerminatedString = InternPool.NullTerminatedString;907const NullTerminatedString = InternPool.NullTerminatedString;
800const dod = @import("dod.zig");
801
802const Report = @import("Report.zig");
803
804const tracer = @import("tracer");
src/compiler/Teg.Dump.zig+8
...@@ -22,6 +22,14 @@ const State = struct {...@@ -22,6 +22,14 @@ const State = struct {
2222
23 const tag = s.teg.instTag(inst);23 const tag = s.teg.instTag(inst);
2424
25 try tty.setColor(writer, .bright_black);
26 const node_offset = teg.instSrcLoc(inst, @enumFromInt(0)).node_offset;
27 try writer.print("{c}{d} ", .{
28 @as(u8, if (node_offset >= 0) '+' else '-'),
29 @abs(node_offset),
30 });
31 try tty.setColor(writer, .reset);
32
25 try tty.setColor(writer, .cyan);33 try tty.setColor(writer, .cyan);
26 try writer.print("{s}", .{@tagName(tag)});34 try writer.print("{s}", .{@tagName(tag)});
27 try tty.setColor(writer, .reset);35 try tty.setColor(writer, .reset);
src/compiler/Teg.zig+42-14
...@@ -209,11 +209,11 @@ pub const Inst = struct {...@@ -209,11 +209,11 @@ pub const Inst = struct {
209 int32_type,209 int32_type,
210 float_type,210 float_type,
211 string_type,211 string_type,
212 void_type,
213 noreturn_type,212 noreturn_type,
214 type_type,213 type_type,
214 numeric_literal_type,
215215
216 void_value,216 void,
217 bool_true,217 bool_true,
218 bool_false,218 bool_false,
219 int32_zero,219 int32_zero,
...@@ -227,9 +227,22 @@ pub const Inst = struct {...@@ -227,9 +227,22 @@ pub const Inst = struct {
227227
228 _,228 _,
229229
230 pub fn toIndex(inst: Ref) ?Index {230 pub const Decoded = union(enum) {
231 assert(inst != .none);231 value: InternPool.Value,
232 const ref_int = @intFromEnum(inst);232 index: Teg.Inst.Index,
233 };
234
235 pub fn decode(ref: Ref) Decoded {
236 const ref_int = @intFromEnum(ref);
237 return if (ref_int >= Index.static_len)
238 .{ .index = @enumFromInt(ref_int - Index.static_len) }
239 else
240 .{ .value = @enumFromInt(ref_int) };
241 }
242
243 pub fn toIndex(ref: Ref) ?Index {
244 assert(ref != .none);
245 const ref_int = @intFromEnum(ref);
233 if (ref_int >= Index.static_len) {246 if (ref_int >= Index.static_len) {
234 return @enumFromInt(ref_int - Index.static_len);247 return @enumFromInt(ref_int - Index.static_len);
235 } else {248 } else {
...@@ -242,7 +255,7 @@ pub const Inst = struct {...@@ -242,7 +255,7 @@ pub const Inst = struct {
242 return toIndex(inst);255 return toIndex(inst);
243 }256 }
244257
245 pub fn toInterned(inst: Ref) ?InternPool.Index {258 pub fn toValue(inst: Ref) ?InternPool.Value {
246 const ref_int = @intFromEnum(inst);259 const ref_int = @intFromEnum(inst);
247260
248 // todo: is this > or >=261 // todo: is this > or >=
...@@ -383,18 +396,30 @@ pub fn declData(teg: *const Teg, index: Inst.Index) Inst.Decl {...@@ -383,18 +396,30 @@ pub fn declData(teg: *const Teg, index: Inst.Index) Inst.Decl {
383 return teg.instData(.declaration, index).extra_index.get(teg);396 return teg.instData(.declaration, index).extra_index.get(teg);
384}397}
385398
399pub fn instSrcLoc(teg: *const Teg, inst: Inst.Index, decl: Comp.Decl.Index) LazyNode {
400 switch (teg.instTag(inst)) {
401 inline else => |tag| {
402 const data = teg.instData(tag, inst);
403 return .{
404 .node_offset = data.src_node,
405 .decl = decl,
406 };
407 },
408 }
409}
410
386pub fn moduleDeclarations(teg: *const Teg, module_index: Inst.Index) []const Inst.Index {411pub fn moduleDeclarations(teg: *const Teg, module_index: Inst.Index) []const Inst.Index {
387 const module = teg.instData(.module, module_index);412 const module = teg.instData(.module, module_index);
388 const module_data: IndexList = module.extra_index.get(teg);413 const module_data: IndexList = module.extra_index.get(teg);
389 const slice = module_data.slice(teg);414 const slice = module_data.slice(teg);
390 // if (std.debug.runtime_safety) {415 if (std.debug.runtime_safety) {
391 // for (slice) |item| {416 for (slice) |item| {
392 // if (teg.instTag(item) != .declaration) {417 if (teg.instTag(item) != .declaration) {
393 // std.debug.print("\ngot unknown tag {s}\n", .{@tagName(teg.instTag(item))});418 std.debug.print("\ngot unknown tag {s}\n", .{@tagName(teg.instTag(item))});
394 // unreachable;419 unreachable;
395 // }420 }
396 // }421 }
397 // }422 }
398 return slice;423 return slice;
399}424}
400425
...@@ -441,4 +466,7 @@ const InternPool = @import("InternPool.zig");...@@ -441,4 +466,7 @@ const InternPool = @import("InternPool.zig");
441466
442const Air = @import("Air.zig");467const Air = @import("Air.zig");
443468
469const Comp = @import("Comp.zig");
470
444const Report = @import("Report.zig");471const Report = @import("Report.zig");
472const LazyNode = Report.LazyNode;
src/compiler/Tokenizer.zig+1-1
...@@ -192,7 +192,7 @@ pub const Token = struct {...@@ -192,7 +192,7 @@ pub const Token = struct {
192 .pipe_pipe => "||",192 .pipe_pipe => "||",
193 .percent => "%",193 .percent => "%",
194 .plus => "+",194 .plus => "+",
195 .minus_lt => "<",195 .minus_lt => "->",
196 .semi => ";",196 .semi => ";",
197 .slash => "/",197 .slash => "/",
198 .star => "*",198 .star => "*",
src/compiler/Transform.zig+18-18
...@@ -202,7 +202,7 @@ const BlockContext = struct {...@@ -202,7 +202,7 @@ const BlockContext = struct {
202const Liveness = enum { alive, dead };202const Liveness = enum { alive, dead };
203203
204const BuiltInIds = std.ComptimeStringMap(Inst.Ref, .{204const BuiltInIds = std.ComptimeStringMap(Inst.Ref, .{
205 .{ "void", .void_value },205 .{ "void", .void },
206 .{ "true", .bool_true },206 .{ "true", .bool_true },
207 .{ "false", .bool_false },207 .{ "false", .bool_false },
208 .{ "int", .int32_type },208 .{ "int", .int32_type },
...@@ -289,7 +289,7 @@ fn transformModule(t: *Transform, module_node: NodeIndex) Allocator.Error!Inst.I...@@ -289,7 +289,7 @@ fn transformModule(t: *Transform, module_node: NodeIndex) Allocator.Error!Inst.I
289289
290 trail.writeStruct(Inst.DeclFn, .{290 trail.writeStruct(Inst.DeclFn, .{
291 .params = .{ .start = 0, .len = 0 },291 .params = .{ .start = 0, .len = 0 },
292 .return_type = Inst.Ref.void_type,292 .return_type = Inst.Ref.void,
293 .body = block.toRef(),293 .body = block.toRef(),
294 });294 });
295295
...@@ -378,7 +378,7 @@ fn transformFunction(t: *Transform, outer_decl: BlockContext, node: NodeIndex) A...@@ -378,7 +378,7 @@ fn transformFunction(t: *Transform, outer_decl: BlockContext, node: NodeIndex) A
378 const return_type = if (fn_decl.return_type) |return_type_node|378 const return_type = if (fn_decl.return_type) |return_type_node|
379 try t.transformExpressionToBlock(decl, return_type_node, false)379 try t.transformExpressionToBlock(decl, return_type_node, false)
380 else380 else
381 Inst.Ref.void_type;381 Inst.Ref.void;
382382
383 const body = try t.transformExpressionToBlock(decl, fn_decl.body, true);383 const body = try t.transformExpressionToBlock(decl, fn_decl.body, true);
384384
...@@ -528,7 +528,7 @@ fn transformParamDecl(t: *Transform, decl: BlockContext, param: NodeIndex) Alloc...@@ -528,7 +528,7 @@ fn transformParamDecl(t: *Transform, decl: BlockContext, param: NodeIndex) Alloc
528 .node = param,528 .node = param,
529 .prev = sym.value_ptr.node,529 .prev = sym.value_ptr.node,
530 });530 });
531 return .void_value;531 return .void;
532 }532 }
533533
534 sym.value_ptr.* = .{534 sym.value_ptr.* = .{
...@@ -558,7 +558,7 @@ const Builtin = enum {...@@ -558,7 +558,7 @@ const Builtin = enum {
558558
559 if (args.len != 1) {559 if (args.len != 1) {
560 // try t.report.err(.invalid_builtin_args, .{ .id = "js" });560 // try t.report.err(.invalid_builtin_args, .{ .id = "js" });
561 return .void_value;561 return .void;
562 }562 }
563563
564 const source = try t.transformExpression(decl, args[0]) orelse return null;564 const source = try t.transformExpression(decl, args[0]) orelse return null;
...@@ -600,7 +600,7 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc...@@ -600,7 +600,7 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc
600600
601 const lookup = t.lookupId(id) orelse {601 const lookup = t.lookupId(id) orelse {
602 try t.report.err(.unknown_identifier, .{ .node = node });602 try t.report.err(.unknown_identifier, .{ .node = node });
603 return .void_value;603 return .void;
604 };604 };
605605
606 lookup.used = true;606 lookup.used = true;
...@@ -815,7 +815,7 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc...@@ -815,7 +815,7 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc
815 => |tag| {815 => |tag| {
816 const statements = t.ast.nodeStatements(node);816 const statements = t.ast.nodeStatements(node);
817817
818 var last: Inst.Ref = .void_value;818 var last: Inst.Ref = .void;
819 for (statements, 1..) |statement, i| {819 for (statements, 1..) |statement, i| {
820 const is_last = i == statements.len;820 const is_last = i == statements.len;
821 last = try t.transformBlockStatement(821 last = try t.transformBlockStatement(
...@@ -827,14 +827,14 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc...@@ -827,14 +827,14 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc
827 };827 };
828 }828 }
829829
830 return if (tag == .block_implicit_return) last else .void_value;830 return if (tag == .block_implicit_return) last else .void;
831 },831 },
832832
833 .builtin_call,833 .builtin_call,
834 => {834 => {
835 const builtin = Builtin.map.get(t.ast.basicNodeSlice(node)[1..]) orelse {835 const builtin = Builtin.map.get(t.ast.basicNodeSlice(node)[1..]) orelse {
836 try t.report.err(.invalid_builtin, .{ .node = node });836 try t.report.err(.invalid_builtin, .{ .node = node });
837 return .void_value;837 return .void;
838 };838 };
839839
840 const base = t.ast.nodeData(node).list;840 const base = t.ast.nodeData(node).list;
...@@ -939,9 +939,9 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc...@@ -939,9 +939,9 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc
939 false,939 false,
940 )940 )
941 else941 else
942 Inst.Ref.void_value;942 Inst.Ref.void;
943943
944 if (yes == .void_value and no == .void_value) {944 if (yes == .void and no == .void) {
945 // when both branches do nothing, we can omit the branch,945 // when both branches do nothing, we can omit the branch,
946 // however we still need to type-check the condition operand946 // however we still need to type-check the condition operand
947 _ = try t.addInstRef(.{947 _ = try t.addInstRef(.{
...@@ -951,7 +951,7 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc...@@ -951,7 +951,7 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc
951 .operand = cond,951 .operand = cond,
952 }),952 }),
953 });953 });
954 return .void_value;954 return .void;
955 }955 }
956956
957 return try t.addInstRef(.{957 return try t.addInstRef(.{
...@@ -990,7 +990,7 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc...@@ -990,7 +990,7 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc
990 try t.transformExpression(decl.withReturn(null), expr) orelse990 try t.transformExpression(decl.withReturn(null), expr) orelse
991 return null991 return null
992 else992 else
993 .void_value;993 .void;
994994
995 _ = try t.addInstRef(.{995 _ = try t.addInstRef(.{
996 .tag = .@"break",996 .tag = .@"break",
...@@ -1022,7 +1022,7 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc...@@ -1022,7 +1022,7 @@ fn transformExpression(t: *Transform, decl: BlockContext, node: NodeIndex) Alloc
1022 try t.transformExpression(decl.withReturn(null), expr) orelse1022 try t.transformExpression(decl.withReturn(null), expr) orelse
1023 return null1023 return null
1024 else1024 else
1025 .void_value;1025 .void;
10261026
1027 _ = try t.addInstRef(.{1027 _ = try t.addInstRef(.{
1028 .tag = .@"break",1028 .tag = .@"break",
...@@ -1063,12 +1063,12 @@ fn transformBlockStatement(...@@ -1063,12 +1063,12 @@ fn transformBlockStatement(
1063 if (mem.eql(u8, var_decl.id, "_")) {1063 if (mem.eql(u8, var_decl.id, "_")) {
1064 // TODO: relax this restriction into just creating a discard node1064 // TODO: relax this restriction into just creating a discard node
1065 try t.report.err(.invalid_discard, .{ .node = node });1065 try t.report.err(.invalid_discard, .{ .node = node });
1066 return .void_value;1066 return .void;
1067 }1067 }
10681068
1069 if (BuiltInIds.has(var_decl.id)) {1069 if (BuiltInIds.has(var_decl.id)) {
1070 try t.report.err(.shadow_builtin_variable, .{ .node = node });1070 try t.report.err(.shadow_builtin_variable, .{ .node = node });
1071 return .void_value;1071 return .void;
1072 }1072 }
10731073
1074 const type_ref = if (var_decl.type) |data_type|1074 const type_ref = if (var_decl.type) |data_type|
...@@ -1132,7 +1132,7 @@ fn transformBlockStatement(...@@ -1132,7 +1132,7 @@ fn transformBlockStatement(
1132 },1132 },
1133 };1133 };
11341134
1135 return .void_value;1135 return .void;
1136 },1136 },
11371137
1138 .fn_decl,1138 .fn_decl,
...@@ -1188,7 +1188,7 @@ fn transformBlockStatement(...@@ -1188,7 +1188,7 @@ fn transformBlockStatement(
1188 const result = try t.transformExpression(decl, node) orelse1188 const result = try t.transformExpression(decl, node) orelse
1189 return null;1189 return null;
11901190
1191 if (!is_implicit_return_expression and result != .void_value) {1191 if (!is_implicit_return_expression and result != .void) {
1192 return try t.addInstRef(.{1192 return try t.addInstRef(.{
1193 .tag = .ensure_void,1193 .tag = .ensure_void,
1194 .data = EncodedData.encode(.ensure_void, .{1194 .data = EncodedData.encode(.ensure_void, .{
src/compiler/Value.zig deleted-96
...@@ -1,96 +0,0 @@
1ip_index: InternPool.Index,
2
3pub fn fromInterned(i: InternPool.Index) Value {
4 assert(i != .none);
5 return .{ .ip_index = i };
6}
7
8pub fn toIntern(val: Value) InternPool.Index {
9 assert(val.ip_index != .none);
10 return val.ip_index;
11}
12
13pub fn toKey(val: Value, ip: *const InternPool) InternPool.Key {
14 return val.toIntern().toKey(ip);
15}
16
17pub fn asBool(val: Value) i32 {
18 return switch (val.toIntern()) {
19 .bool_true => true,
20 .bool_false => false,
21 else => unreachable,
22 };
23}
24
25pub fn asString(val: Value, ip: *const InternPool) InternPool.String.WithLen {
26 const index = val.toIntern();
27 return ip.items.items(.data)[@intFromEnum(index)].decode(
28 .string,
29 ip.items.items(.tag)[@intFromEnum(index)],
30 )
31 .get(ip);
32}
33
34pub fn @"type"(val: Value, ip: *const InternPool) Value {
35 const v: InternPool.Index = switch (val.toKey(ip)) {
36 .simple_type, .type_function => .type_type,
37
38 .int32 => .int32_type,
39 .float => .float_type,
40 .string => .string_type,
41 .simple_value => |v| switch (v) {
42 .true, .false => .bool_type,
43 .void => .void_type,
44 },
45 .func => |f| f.ty,
46 };
47 return Value.fromInterned(v);
48}
49
50pub fn toFloat(val: Value, ip: *const InternPool) ?f64 {
51 return switch (val.toKey(ip)) {
52 .int32 => |i| @floatFromInt(i),
53 .float => |f| f,
54 else => null,
55 };
56}
57
58/// used for validating ensure_void instructions
59pub fn isEnsureVoid(val: Value, ip: *const InternPool) bool {
60 const intern = val.toIntern();
61 const i = @intFromEnum(intern);
62
63 return switch (ip.items.items(.tag)[i]) {
64 .simple_type => switch (ip.items.items(.data)[i].decode(.simple_type, .simple_type)) {
65 .@"opaque", .void => true,
66 else => true,
67 },
68 else => false,
69 };
70}
71
72const Value = @This();
73
74const std = @import("std");
75const assert = std.debug.assert;
76
77pub const InternPool = @import("InternPool.zig");
78
79pub fn fmt(v: Value, ip: *InternPool) Format {
80 return .{ .value = v, .ip = ip };
81}
82
83pub const Format = struct {
84 value: Value,
85 ip: *InternPool,
86
87 pub fn format(
88 self: Format,
89 comptime unused_fmt_str: []const u8,
90 _: std.fmt.FormatOptions,
91 writer: anytype,
92 ) !void {
93 comptime assert(unused_fmt_str.len == 0);
94 try writer.print("{any}", .{self.value.toKey(self.ip)});
95 }
96};
src/compiler/dod.zig+9-1
...@@ -240,7 +240,15 @@ pub fn ExtraStore(comptime set_kind: StoreKind, comptime set_mutability: Mutabil...@@ -240,7 +240,15 @@ pub fn ExtraStore(comptime set_kind: StoreKind, comptime set_mutability: Mutabil
240 return ip.get(T, trail.index);240 return ip.get(T, trail.index);
241 }241 }
242242
243 pub fn readInternPoolIndexSlice(trail: *TrailReader, len: u32) @import("InternPool.zig").Index.Slice {243 pub fn readValueSlice(trail: *TrailReader, len: u32) @import("InternPool.zig").Value.Slice {
244 defer trail.index += len;
245 return .{
246 .start = @intCast(trail.index),
247 .len = len,
248 };
249 }
250
251 pub fn readTypeSlice(trail: *TrailReader, len: u32) @import("InternPool.zig").Type.Slice {
244 defer trail.index += len;252 defer trail.index += len;
245 return .{253 return .{
246 .start = @intCast(trail.index),254 .start = @intCast(trail.index),
src/compiler/util.zig+22-1
...@@ -1,4 +1,3 @@...@@ -1,4 +1,3 @@
1/// TODO: move to io utility file
2pub fn detectTTYFromWriter(writer: anytype) std.io.tty.Config {1pub fn detectTTYFromWriter(writer: anytype) std.io.tty.Config {
3 if (@hasField(@TypeOf(writer), "unbuffered_writer")) {2 if (@hasField(@TypeOf(writer), "unbuffered_writer")) {
4 return detectTTYFromWriter(writer.unbuffered_writer);3 return detectTTYFromWriter(writer.unbuffered_writer);
...@@ -17,4 +16,26 @@ pub fn detectTTYFromWriter(writer: anytype) std.io.tty.Config {...@@ -17,4 +16,26 @@ pub fn detectTTYFromWriter(writer: anytype) std.io.tty.Config {
17 return .no_color;16 return .no_color;
18}17}
1918
19pub fn Ordinal(Int: type) type {
20 comptime assert(@typeInfo(Int).Int.signedness == .unsigned);
21 return enum(Int) {
22 _,
23 pub fn fromZeroBased(int: Int) @This() {
24 assert(int != std.math.maxInt(Int));
25 return @enumFromInt(int);
26 }
27 pub fn fromOneBased(int: Int) @This() {
28 assert(int > 0);
29 return @enumFromInt(int - 1);
30 }
31 pub fn zeroBased(ord: @This()) Int {
32 return @intFromEnum(ord);
33 }
34 pub fn oneBased(ord: @This()) Int {
35 return @intFromEnum(ord) + 1;
36 }
37 };
38}
39
20const std = @import("std");40const std = @import("std");
41const assert = std.debug.assert;