authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-21 00:56:30-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-21 00:56:30-04:00
log4c7507ccebc8b1c03643219dfa45ece668c62993
treea81a6c2ff09574d44ac409f810b7be0ba417ba21
parentcc1c2bd5684a6195e9535fff38ca54ffb70ebe5a

ir: semantic analysis skeleton


4 files changed, 315 insertions(+), 135 deletions(-)

src-self-hosted/ir.zig+197-81
......@@ -8,106 +8,221 @@ const text = @import("ir/text.zig");
88
99/// These are in-memory, analyzed instructions. See `text.Inst` for the representation
1010/// of instructions that correspond to the ZIR text format.
11/// This struct owns the `Value` and `Type` memory. When the struct is deallocated,
12/// so are the `Value` and `Type`. The value of a constant must be copied into
13/// a memory location for the value to survive after a const instruction.
1114pub const Inst = struct {
12 pub fn ty(base: *Inst) ?Type {
13 switch (base.tag) {
14 .constant => return base.cast(Constant).?.ty,
15 .@"asm" => return base.cast(Assembly).?.ty,
16 .@"fn" => return base.cast(Fn).?.ty,
17
18 .ptrtoint => return Type.initTag(.@"usize"),
19 .@"unreachable" => return Type.initTag(.@"noreturn"),
20 .@"export" => return Type.initTag(.@"void"),
21 .fntype, .primitive => return Type.initTag(.@"type"),
22
23 .fieldptr,
24 .deref,
25 => return null,
26 }
15 tag: Tag,
16 ty: Type,
17 src_offset: usize,
18
19 pub const Tag = enum {
20 unreach,
21 constant,
22 assembly,
23 };
24
25 pub fn cast(base: *Inst, comptime T: type) ?*T {
26 if (base.tag != T.base_tag)
27 return null;
28
29 return @fieldParentPtr(T, "base", base);
2730 }
2831
29 /// This struct owns the `Value` memory. When the struct is deallocated,
30 /// so is the `Value`. The value of a constant must be copied into
31 /// a memory location for the value to survive after a const instruction.
3232 pub const Constant = struct {
33 base: Inst = Inst{ .tag = .constant },
34 ty: Type,
33 pub const base_tag = Tag.constant;
34 base: Inst,
3535
36 positionals: struct {
37 value: Value,
38 },
39 kw_args: struct {},
36 val: Value,
37 };
38
39 pub const Assembly = struct {
40 pub const base_tag = Tag.assembly;
41 base: Inst,
42
43 asm_source: []const u8,
44 is_volatile: bool,
45 output: []const u8,
46 inputs: []const []const u8,
47 clobbers: []const []const u8,
48 args: []const []const u8,
4049 };
4150};
4251
43const Analyze = struct {
44 allocator: *Allocator,
45 old_tree: *const Module,
46 errors: std.ArrayList(ErrorMsg),
47 decls: std.ArrayList(*Inst),
52const TypedValue = struct {
53 ty: Type,
54 val: Value,
55};
4856
49 const NewInst = struct {
50 ptr: *Inst,
57pub const Module = struct {
58 exports: []Export,
59 errors: []ErrorMsg,
60 arena: std.heap.ArenaAllocator,
61
62 pub const Export = struct {
63 name: []const u8,
64 typed_value: TypedValue,
5165 };
66
67 pub fn deinit(self: *Module, allocator: *Allocator) void {
68 allocator.free(self.exports);
69 allocator.free(self.errors);
70 self.arena.deinit();
71 self.* = undefined;
72 }
73
74 pub fn emit_zir(self: Module, allocator: *Allocator) !text.Module {
75 return error.TodoImplementEmitToZIR;
76 }
5277};
5378
54pub fn analyze(allocator: *Allocator, old_tree: Module) !Module {
79pub const ErrorMsg = struct {
80 byte_offset: usize,
81 msg: []const u8,
82};
83
84pub fn analyze(allocator: *Allocator, old_module: text.Module) !Module {
5585 var ctx = Analyze{
5686 .allocator = allocator,
57 .old_tree = &old_tree,
58 .decls = std.ArrayList(*Inst).init(allocator),
87 .arena = std.heap.ArenaAllocator.init(allocator),
88 .old_module = &old_module,
5989 .errors = std.ArrayList(ErrorMsg).init(allocator),
60 .inst_table = std.HashMap(*Inst, Analyze.InstData).init(allocator),
90 .inst_table = std.AutoHashMap(*text.Inst, Analyze.NewInst).init(allocator),
91 .exports = std.ArrayList(Module.Export).init(allocator),
6192 };
62 defer ctx.decls.deinit();
6393 defer ctx.errors.deinit();
64 defer inst_table.deinit();
94 defer ctx.inst_table.deinit();
95 defer ctx.exports.deinit();
6596
66 analyzeRoot(&ctx) catch |err| switch (err) {
67 error.AnalyzeFailure => {
97 ctx.analyzeRoot() catch |err| switch (err) {
98 error.AnalysisFail => {
6899 assert(ctx.errors.items.len != 0);
69100 },
70101 else => |e| return e,
71102 };
72103 return Module{
73 .decls = ctx.decls.toOwnedSlice(),
104 .exports = ctx.exports.toOwnedSlice(),
74105 .errors = ctx.errors.toOwnedSlice(),
106 .arena = ctx.arena,
75107 };
76108}
77109
78fn analyzeRoot(ctx: *Analyze) !void {
79 for (old_tree.decls) |decl| {
80 if (decl.cast(Inst.Export)) |export_inst| {
81 try analyzeExport(ctx, export_inst);
110const Analyze = struct {
111 allocator: *Allocator,
112 arena: std.heap.ArenaAllocator,
113 old_module: *const text.Module,
114 errors: std.ArrayList(ErrorMsg),
115 inst_table: std.AutoHashMap(*text.Inst, NewInst),
116 exports: std.ArrayList(Module.Export),
117
118 const NewInst = struct {
119 /// null means a semantic analysis error happened
120 ptr: ?*Inst,
121 };
122
123 const InnerError = error{ OutOfMemory, AnalysisFail };
124
125 fn analyzeRoot(self: *Analyze) !void {
126 for (self.old_module.decls) |decl| {
127 if (decl.cast(text.Inst.Export)) |export_inst| {
128 try analyzeExport(self, export_inst);
129 }
82130 }
83131 }
84}
85132
86fn analyzeExport(ctx: *Analyze, export_inst: *Inst.Export) !void {
87 const old_decl = export_inst.positionals.value;
88 const new_info = ctx.inst_table.get(old_exp_target) orelse blk: {
89 const new_decl = try analyzeDecl(ctx, old_decl);
90 const new_info: Analyze.NewInst = .{ .ptr = new_decl };
91 try ctx.inst_table.put(old_decl, new_info);
92 break :blk new_info;
93 };
133 fn resolveInst(self: *Analyze, old_inst: *text.Inst) InnerError!*Inst {
134 if (self.inst_table.get(old_inst)) |kv| {
135 return kv.value.ptr orelse return error.AnalysisFail;
136 } else {
137 const new_inst = self.analyzeDecl(old_inst) catch |err| switch (err) {
138 error.AnalysisFail => {
139 try self.inst_table.putNoClobber(old_inst, .{ .ptr = null });
140 return error.AnalysisFail;
141 },
142 else => |e| return e,
143 };
144 try self.inst_table.putNoClobber(old_inst, .{ .ptr = new_inst });
145 return new_inst;
146 }
147 }
94148
95 //const exp_type = new_info.ptr.ty();
96 //switch (exp_type.zigTypeTag()) {
97 // .Fn => {
98 // if () |kv| {
99 // kv.value
100 // }
101 // return analyzeExportFn(ctx, exp_target.cast(Inst.,
102 // },
103 // else => return ctx.fail("unable to export type '{}'", .{exp_type}),
104 //}
105}
149 fn resolveInstConst(self: *Analyze, old_inst: *text.Inst) InnerError!TypedValue {
150 const new_inst = try self.resolveInst(old_inst);
151 const val = try self.resolveConstValue(new_inst);
152 return TypedValue{
153 .ty = new_inst.ty,
154 .val = val,
155 };
156 }
157
158 fn resolveConstValue(self: *Analyze, base: *Inst) !Value {
159 const const_inst = base.cast(Inst.Constant) orelse
160 return self.fail(base.src_offset, "unable to resolve comptime value", .{});
161 return const_inst.val;
162 }
163
164 fn resolveConstString(self: *Analyze, old_inst: *text.Inst) ![]u8 {
165 const new_inst = try self.resolveInst(old_inst);
166 const wanted_type = Type.initTag(.const_slice_u8);
167 const coerced_inst = try self.coerce(wanted_type, new_inst);
168 const val = try self.resolveConstValue(coerced_inst);
169 return val.toAllocatedBytes(&self.arena.allocator);
170 }
171
172 fn analyzeExport(self: *Analyze, export_inst: *text.Inst.Export) !void {
173 const symbol_name = try self.resolveConstString(export_inst.positionals.symbol_name);
174 const typed_value = try self.resolveInstConst(export_inst.positionals.value);
175
176 switch (typed_value.ty.zigTypeTag()) {
177 .Fn => {},
178 else => return self.fail(
179 export_inst.positionals.value.src_offset,
180 "unable to export type '{}'",
181 .{typed_value.ty},
182 ),
183 }
184 try self.exports.append(.{
185 .name = symbol_name,
186 .typed_value = typed_value,
187 });
188 }
189
190 fn analyzeDecl(self: *Analyze, old_inst: *text.Inst) !*Inst {
191 switch (old_inst.tag) {
192 .str => return self.fail(old_inst.src_offset, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
193 .int => return self.fail(old_inst.src_offset, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
194 .ptrtoint => return self.fail(old_inst.src_offset, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
195 .fieldptr => return self.fail(old_inst.src_offset, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
196 .deref => return self.fail(old_inst.src_offset, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
197 .as => return self.fail(old_inst.src_offset, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
198 .@"asm" => return self.fail(old_inst.src_offset, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
199 .@"unreachable" => return self.fail(old_inst.src_offset, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
200 .@"fn" => return self.fail(old_inst.src_offset, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
201 .@"export" => return self.fail(old_inst.src_offset, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
202 .primitive => return self.fail(old_inst.src_offset, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
203 .fntype => return self.fail(old_inst.src_offset, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
204 }
205 }
206
207 fn coerce(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst {
208 return self.fail(inst.src_offset, "TODO implement type coercion", .{});
209 }
210
211 fn fail(self: *Analyze, src_offset: usize, comptime format: []const u8, args: var) InnerError {
212 @setCold(true);
213 const msg = try std.fmt.allocPrint(&self.arena.allocator, format, args);
214 (try self.errors.addOne()).* = .{
215 .byte_offset = src_offset,
216 .msg = msg,
217 };
218 return error.AnalysisFail;
219 }
220};
106221
107222pub fn main() anyerror!void {
108223 var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
109224 defer arena.deinit();
110 const allocator = &arena.allocator;
225 const allocator = if (std.builtin.link_libc) std.heap.c_allocator else &arena.allocator;
111226
112227 const args = try std.process.argsAlloc(allocator);
113228
......@@ -116,11 +231,11 @@ pub fn main() anyerror!void {
116231
117232 const source = try std.fs.cwd().readFileAllocOptions(allocator, src_path, std.math.maxInt(u32), 1, 0);
118233
119 var tree = try text.parse(allocator, source);
120 defer tree.deinit();
234 var zir_module = try text.parse(allocator, source);
235 defer zir_module.deinit(allocator);
121236
122 if (tree.errors.len != 0) {
123 for (tree.errors) |err_msg| {
237 if (zir_module.errors.len != 0) {
238 for (zir_module.errors) |err_msg| {
124239 const loc = findLineColumn(source, err_msg.byte_offset);
125240 std.debug.warn("{}:{}:{}: error: {}\n", .{ src_path, loc.line + 1, loc.column + 1, err_msg.msg });
126241 }
......@@ -128,21 +243,22 @@ pub fn main() anyerror!void {
128243 std.process.exit(1);
129244 }
130245
131 tree.dump();
246 var analyzed_module = try analyze(allocator, zir_module);
247 defer analyzed_module.deinit(allocator);
132248
133 //const new_tree = try analyze(allocator, tree);
134 //defer new_tree.deinit();
249 if (analyzed_module.errors.len != 0) {
250 for (analyzed_module.errors) |err_msg| {
251 const loc = findLineColumn(source, err_msg.byte_offset);
252 std.debug.warn("{}:{}:{}: error: {}\n", .{ src_path, loc.line + 1, loc.column + 1, err_msg.msg });
253 }
254 if (debug_error_trace) return error.ParseFailure;
255 std.process.exit(1);
256 }
135257
136 //if (new_tree.errors.len != 0) {
137 // for (new_tree.errors) |err_msg| {
138 // const loc = findLineColumn(source, err_msg.byte_offset);
139 // std.debug.warn("{}:{}:{}: error: {}\n", .{ src_path, loc.line + 1, loc.column + 1, err_msg.msg });
140 // }
141 // if (debug_error_trace) return error.ParseFailure;
142 // std.process.exit(1);
143 //}
258 var new_zir_module = try analyzed_module.emit_zir(allocator);
259 defer new_zir_module.deinit(allocator);
144260
145 //new_tree.dump();
261 new_zir_module.dump();
146262}
147263
148264fn findLineColumn(source: []const u8, byte_offset: usize) struct { line: usize, column: usize } {
src-self-hosted/ir/text.zig+46-23
......@@ -1,4 +1,5 @@
11//! This file has to do with parsing and rendering the ZIR text format.
2
23const std = @import("std");
34const mem = std.mem;
45const Allocator = std.mem.Allocator;
......@@ -11,6 +12,7 @@ const BigInt = std.math.big.Int;
1112/// in-memory, analyzed instructions with types and values.
1213pub const Inst = struct {
1314 tag: Tag,
15 src_offset: usize,
1416
1517 /// These names are used directly as the instruction names in the text format.
1618 pub const Tag = enum {
......@@ -46,15 +48,15 @@ pub const Inst = struct {
4648 }
4749
4850 pub fn cast(base: *Inst, comptime T: type) ?*T {
49 const expected_tag = std.meta.fieldInfo(T, "base").default_value.?.tag;
50 if (base.tag != expected_tag)
51 if (base.tag != T.base_tag)
5152 return null;
5253
5354 return @fieldParentPtr(T, "base", base);
5455 }
5556
5657 pub const Str = struct {
57 base: Inst = Inst{ .tag = .str },
58 pub const base_tag = Tag.str;
59 base: Inst,
5860
5961 positionals: struct {
6062 bytes: []u8,
......@@ -63,7 +65,8 @@ pub const Inst = struct {
6365 };
6466
6567 pub const Int = struct {
66 base: Inst = Inst{ .tag = .int },
68 pub const base_tag = Tag.int;
69 base: Inst,
6770
6871 positionals: struct {
6972 int: BigInt,
......@@ -72,7 +75,8 @@ pub const Inst = struct {
7275 };
7376
7477 pub const PtrToInt = struct {
75 base: Inst = Inst{ .tag = .ptrtoint },
78 pub const base_tag = Tag.ptrtoint;
79 base: Inst,
7680
7781 positionals: struct {
7882 ptr: *Inst,
......@@ -81,7 +85,8 @@ pub const Inst = struct {
8185 };
8286
8387 pub const FieldPtr = struct {
84 base: Inst = Inst{ .tag = .fieldptr },
88 pub const base_tag = Tag.fieldptr;
89 base: Inst,
8590
8691 positionals: struct {
8792 object_ptr: *Inst,
......@@ -91,7 +96,8 @@ pub const Inst = struct {
9196 };
9297
9398 pub const Deref = struct {
94 base: Inst = Inst{ .tag = .deref },
99 pub const base_tag = Tag.deref;
100 base: Inst,
95101
96102 positionals: struct {
97103 ptr: *Inst,
......@@ -100,7 +106,8 @@ pub const Inst = struct {
100106 };
101107
102108 pub const As = struct {
103 base: Inst = Inst{ .tag = .as },
109 pub const base_tag = Tag.as;
110 base: Inst,
104111
105112 positionals: struct {
106113 dest_type: *Inst,
......@@ -110,7 +117,8 @@ pub const Inst = struct {
110117 };
111118
112119 pub const Assembly = struct {
113 base: Inst = Inst{ .tag = .@"asm" },
120 pub const base_tag = Tag.@"asm";
121 base: Inst,
114122
115123 positionals: struct {
116124 asm_source: *Inst,
......@@ -126,14 +134,16 @@ pub const Inst = struct {
126134 };
127135
128136 pub const Unreachable = struct {
129 base: Inst = Inst{ .tag = .@"unreachable" },
137 pub const base_tag = Tag.@"unreachable";
138 base: Inst,
130139
131140 positionals: struct {},
132141 kw_args: struct {},
133142 };
134143
135144 pub const Fn = struct {
136 base: Inst = Inst{ .tag = .@"fn" },
145 pub const base_tag = Tag.@"fn";
146 base: Inst,
137147
138148 positionals: struct {
139149 fn_type: *Inst,
......@@ -147,7 +157,8 @@ pub const Inst = struct {
147157 };
148158
149159 pub const Export = struct {
150 base: Inst = Inst{ .tag = .@"export" },
160 pub const base_tag = Tag.@"export";
161 base: Inst,
151162
152163 positionals: struct {
153164 symbol_name: *Inst,
......@@ -157,7 +168,8 @@ pub const Inst = struct {
157168 };
158169
159170 pub const Primitive = struct {
160 base: Inst = Inst{ .tag = .primitive },
171 pub const base_tag = Tag.primitive;
172 base: Inst,
161173
162174 positionals: struct {
163175 tag: BuiltinType,
......@@ -192,7 +204,8 @@ pub const Inst = struct {
192204 };
193205
194206 pub const FnType = struct {
195 base: Inst = Inst{ .tag = .fntype },
207 pub const base_tag = Tag.fntype;
208 base: Inst,
196209
197210 positionals: struct {
198211 param_types: []*Inst,
......@@ -212,9 +225,12 @@ pub const ErrorMsg = struct {
212225pub const Module = struct {
213226 decls: []*Inst,
214227 errors: []ErrorMsg,
228 arena: std.heap.ArenaAllocator,
215229
216 pub fn deinit(self: *Module) void {
217 // TODO resource deallocation
230 pub fn deinit(self: *Module, allocator: *Allocator) void {
231 allocator.free(self.decls);
232 allocator.free(self.errors);
233 self.arena.deinit();
218234 self.* = undefined;
219235 }
220236
......@@ -225,6 +241,8 @@ pub const Module = struct {
225241
226242 const InstPtrTable = std.AutoHashMap(*Inst, struct { index: usize, fn_body: ?*Inst.Fn.Body });
227243
244 /// The allocator is used for temporary storage, but this function always returns
245 /// with no resources allocated.
228246 pub fn writeToStream(self: Module, allocator: *Allocator, stream: var) !void {
229247 // First, build a map of *Inst to @ or % indexes
230248 var inst_table = InstPtrTable.init(allocator);
......@@ -359,6 +377,7 @@ pub fn parse(allocator: *Allocator, source: [:0]const u8) Allocator.Error!Module
359377
360378 var parser: Parser = .{
361379 .allocator = allocator,
380 .arena = std.heap.ArenaAllocator.init(allocator),
362381 .i = 0,
363382 .source = source,
364383 .decls = std.ArrayList(*Inst).init(allocator),
......@@ -374,11 +393,13 @@ pub fn parse(allocator: *Allocator, source: [:0]const u8) Allocator.Error!Module
374393 return Module{
375394 .decls = parser.decls.toOwnedSlice(),
376395 .errors = parser.errors.toOwnedSlice(),
396 .arena = parser.arena,
377397 };
378398}
379399
380400const Parser = struct {
381401 allocator: *Allocator,
402 arena: std.heap.ArenaAllocator,
382403 i: usize,
383404 source: [:0]const u8,
384405 errors: std.ArrayList(ErrorMsg),
......@@ -439,7 +460,7 @@ const Parser = struct {
439460 self.i += 1;
440461 const span = self.source[start..self.i];
441462 var bad_index: usize = undefined;
442 const parsed = std.zig.parseStringLiteral(self.allocator, span, &bad_index) catch |err| switch (err) {
463 const parsed = std.zig.parseStringLiteral(&self.arena.allocator, span, &bad_index) catch |err| switch (err) {
443464 error.InvalidCharacter => {
444465 self.i = start + bad_index;
445466 const bad_byte = self.source[self.i];
......@@ -466,7 +487,7 @@ const Parser = struct {
466487 else => break,
467488 };
468489 const number_text = self.source[start..self.i];
469 var result = try BigInt.init(self.allocator);
490 var result = try BigInt.init(&self.arena.allocator);
470491 result.setString(10, number_text) catch |err| {
471492 self.i = start;
472493 switch (err) {
......@@ -551,7 +572,7 @@ const Parser = struct {
551572
552573 fn fail(self: *Parser, comptime format: []const u8, args: var) InnerError {
553574 @setCold(true);
554 const msg = try std.fmt.allocPrint(self.allocator, format, args);
575 const msg = try std.fmt.allocPrint(&self.arena.allocator, format, args);
555576 (try self.errors.addOne()).* = .{
556577 .byte_offset = self.i,
557578 .msg = msg,
......@@ -576,8 +597,11 @@ const Parser = struct {
576597 comptime InstType: type,
577598 body_ctx: ?*Body,
578599 ) !*Inst {
579 const inst_specific = try self.allocator.create(InstType);
580 inst_specific.base = std.meta.fieldInfo(InstType, "base").default_value.?;
600 const inst_specific = try self.arena.allocator.create(InstType);
601 inst_specific.base = .{
602 .src_offset = self.i,
603 .tag = InstType.base_tag,
604 };
581605
582606 if (@hasField(InstType, "ty")) {
583607 inst_specific.ty = opt_type orelse {
......@@ -657,8 +681,7 @@ const Parser = struct {
657681 skipSpace(self);
658682 if (eatByte(self, ']')) return &[0]*Inst{};
659683
660 var instructions = std.ArrayList(*Inst).init(self.allocator);
661 defer instructions.deinit();
684 var instructions = std.ArrayList(*Inst).init(&self.arena.allocator);
662685 while (true) {
663686 skipSpace(self);
664687 try instructions.append(try parseParameterInst(self, body_ctx));
src-self-hosted/type.zig+63-31
......@@ -18,9 +18,39 @@ pub const Type = extern union {
1818
1919 pub fn zigTypeTag(self: Type) std.builtin.TypeId {
2020 switch (self.tag()) {
21 .@"u8", .@"usize" => return .Int,
22 .array_u8, .array_u8_sentinel_0 => return .Array,
21 .@"u8",
22 .@"i8",
23 .@"isize",
24 .@"usize",
25 .@"c_short",
26 .@"c_ushort",
27 .@"c_int",
28 .@"c_uint",
29 .@"c_long",
30 .@"c_ulong",
31 .@"c_longlong",
32 .@"c_ulonglong",
33 .@"c_longdouble",
34 => return .Int,
35
36 .@"f16",
37 .@"f32",
38 .@"f64",
39 .@"f128",
40 => return .Float,
41
42 .@"c_void" => return .Opaque,
43 .@"bool" => return .Bool,
44 .@"void" => return .Void,
45 .@"type" => return .Type,
46 .@"anyerror" => return .ErrorSet,
47 .@"comptime_int" => return .ComptimeInt,
48 .@"comptime_float" => return .ComptimeFloat,
49 .@"noreturn" => return .NoReturn,
50
51 .array, .array_u8_sentinel_0 => return .Array,
2352 .single_const_pointer => return .Pointer,
53 .const_slice_u8 => return .Pointer,
2454 }
2555 }
2656
......@@ -51,35 +81,36 @@ pub const Type = extern union {
5181 comptime assert(fmt.len == 0);
5282 var ty = self;
5383 while (true) {
54 switch (ty.tag()) {
55 @"u8",
56 @"i8",
57 @"isize",
58 @"usize",
59 @"noreturn",
60 @"void",
61 @"c_short",
62 @"c_ushort",
63 @"c_int",
64 @"c_uint",
65 @"c_long",
66 @"c_ulong",
67 @"c_longlong",
68 @"c_ulonglong",
69 @"c_longdouble",
70 @"c_void",
71 @"f16",
72 @"f32",
73 @"f64",
74 @"f128",
75 @"bool",
76 @"void",
77 @"type",
78 @"anyerror",
79 @"comptime_int",
80 @"comptime_float",
81 @"noreturn",
82 => |t| return out_stream.writeAll(@tagName(t)),
84 const t = ty.tag();
85 switch (t) {
86 .@"u8",
87 .@"i8",
88 .@"isize",
89 .@"usize",
90 .@"c_short",
91 .@"c_ushort",
92 .@"c_int",
93 .@"c_uint",
94 .@"c_long",
95 .@"c_ulong",
96 .@"c_longlong",
97 .@"c_ulonglong",
98 .@"c_longdouble",
99 .@"c_void",
100 .@"f16",
101 .@"f32",
102 .@"f64",
103 .@"f128",
104 .@"bool",
105 .@"void",
106 .@"type",
107 .@"anyerror",
108 .@"comptime_int",
109 .@"comptime_float",
110 .@"noreturn",
111 => return out_stream.writeAll(@tagName(t)),
112
113 .const_slice_u8 => return out_stream.writeAll("[]const u8"),
83114
84115 .array_u8_sentinel_0 => {
85116 const payload = @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", ty.ptr_otherwise);
......@@ -110,6 +141,7 @@ pub const Type = extern union {
110141 /// See `zigTypeTag` for the function that corresponds to `std.builtin.TypeId`.
111142 pub const Tag = enum {
112143 // The first section of this enum are tags that require no payload.
144 const_slice_u8,
113145 @"u8",
114146 @"i8",
115147 @"isize",
src-self-hosted/value.zig+9
......@@ -91,6 +91,15 @@ pub const Value = extern union {
9191 }
9292 }
9393
94 /// Asserts that the value is representable as an array of bytes.
95 /// Copies the value into a freshly allocated slice of memory, which is owned by the caller.
96 pub fn toAllocatedBytes(self: Value, allocator: *std.mem.Allocator) error{OutOfMemory}![]u8 {
97 if (self.cast(Payload.Bytes)) |bytes| {
98 return std.mem.dupe(allocator, u8, bytes.data);
99 }
100 unreachable;
101 }
102
94103 /// This type is not copyable since it may contain pointers to its inner data.
95104 pub const Payload = struct {
96105 tag: Tag,