master
1const std = @import("std");
2const Zcu = @import("../Zcu.zig");
3const Sema = @import("../Sema.zig");
4const Air = @import("../Air.zig");
5const InternPool = @import("../InternPool.zig");
6const Type = @import("../Type.zig");
7const Value = @import("../Value.zig");
8const Zir = std.zig.Zir;
9const AstGen = std.zig.AstGen;
10const CompileError = Zcu.CompileError;
11const Ast = std.zig.Ast;
12const Allocator = std.mem.Allocator;
13const assert = std.debug.assert;
14const File = Zcu.File;
15const LazySrcLoc = Zcu.LazySrcLoc;
16const Ref = std.zig.Zir.Inst.Ref;
17const NullTerminatedString = InternPool.NullTerminatedString;
18const NumberLiteralError = std.zig.number_literal.Error;
19const NodeIndex = std.zig.Ast.Node.Index;
20const Zoir = std.zig.Zoir;
21
22const LowerZon = @This();
23
24sema: *Sema,
25file: *File,
26file_index: Zcu.File.Index,
27import_loc: LazySrcLoc,
28block: *Sema.Block,
29base_node_inst: InternPool.TrackedInst.Index,
30
31/// Lowers the given file as ZON.
32pub fn run(
33 sema: *Sema,
34 file: *File,
35 file_index: Zcu.File.Index,
36 res_ty_interned: InternPool.Index,
37 import_loc: LazySrcLoc,
38 block: *Sema.Block,
39) CompileError!InternPool.Index {
40 const pt = sema.pt;
41
42 const tracked_inst = try pt.zcu.intern_pool.trackZir(pt.zcu.gpa, pt.tid, .{
43 .file = file_index,
44 .inst = .main_struct_inst, // this is the only trackable instruction in a ZON file
45 });
46
47 var lower_zon: LowerZon = .{
48 .sema = sema,
49 .file = file,
50 .file_index = file_index,
51 .import_loc = import_loc,
52 .block = block,
53 .base_node_inst = tracked_inst,
54 };
55
56 if (res_ty_interned == .none) {
57 return lower_zon.lowerExprAnonResTy(.root);
58 } else {
59 const res_ty: Type = .fromInterned(res_ty_interned);
60 try lower_zon.checkType(res_ty);
61 return lower_zon.lowerExprKnownResTy(.root, res_ty);
62 }
63}
64
65fn lowerExprAnonResTy(self: *LowerZon, node: Zoir.Node.Index) CompileError!InternPool.Index {
66 const gpa = self.sema.gpa;
67 const pt = self.sema.pt;
68 const ip = &pt.zcu.intern_pool;
69 switch (node.get(self.file.zoir.?)) {
70 .true => return .bool_true,
71 .false => return .bool_false,
72 .null => return .null_value,
73 .pos_inf => return self.fail(node, "infinity requires a known result type", .{}),
74 .neg_inf => return self.fail(node, "negative infinity requires a known result type", .{}),
75 .nan => return self.fail(node, "NaN requires a known result type", .{}),
76 .int_literal => |int| switch (int) {
77 .small => |val| return pt.intern(.{ .int = .{
78 .ty = .comptime_int_type,
79 .storage = .{ .i64 = val },
80 } }),
81 .big => |val| return pt.intern(.{ .int = .{
82 .ty = .comptime_int_type,
83 .storage = .{ .big_int = val },
84 } }),
85 },
86 .float_literal => |val| {
87 const result = try pt.floatValue(.comptime_float, val);
88 return result.toIntern();
89 },
90 .char_literal => |val| return pt.intern(.{ .int = .{
91 .ty = .comptime_int_type,
92 .storage = .{ .i64 = val },
93 } }),
94 .enum_literal => |val| return pt.intern(.{
95 .enum_literal = try ip.getOrPutString(
96 gpa,
97 pt.tid,
98 val.get(self.file.zoir.?),
99 .no_embedded_nulls,
100 ),
101 }),
102 .string_literal => |val| {
103 const ip_str = try ip.getOrPutString(gpa, pt.tid, val, .maybe_embedded_nulls);
104 const result = try self.sema.addStrLit(ip_str, val.len);
105 return result.toInterned().?;
106 },
107 .empty_literal => return .empty_tuple,
108 .array_literal => |nodes| {
109 const types = try self.sema.arena.alloc(InternPool.Index, nodes.len);
110 const values = try self.sema.arena.alloc(InternPool.Index, nodes.len);
111 for (0..nodes.len) |i| {
112 values[i] = try self.lowerExprAnonResTy(nodes.at(@intCast(i)));
113 types[i] = Value.fromInterned(values[i]).typeOf(pt.zcu).toIntern();
114 }
115 const ty = try ip.getTupleType(
116 gpa,
117 pt.tid,
118 .{
119 .types = types,
120 .values = values,
121 },
122 );
123 return (try pt.aggregateValue(.fromInterned(ty), values)).toIntern();
124 },
125 .struct_literal => |init| {
126 const elems = try self.sema.arena.alloc(InternPool.Index, init.names.len);
127 for (0..init.names.len) |i| {
128 elems[i] = try self.lowerExprAnonResTy(init.vals.at(@intCast(i)));
129 }
130 const struct_ty = switch (try ip.getStructType(
131 gpa,
132 pt.tid,
133 .{
134 .layout = .auto,
135 .fields_len = @intCast(init.names.len),
136 .known_non_opv = false,
137 .requires_comptime = .no,
138 .any_comptime_fields = true,
139 .any_default_inits = true,
140 .inits_resolved = true,
141 .any_aligned_fields = false,
142 .key = .{ .reified = .{
143 .zir_index = self.base_node_inst,
144 .type_hash = hash: {
145 var hasher: std.hash.Wyhash = .init(0);
146 hasher.update(std.mem.asBytes(&node));
147 hasher.update(std.mem.sliceAsBytes(elems));
148 hasher.update(std.mem.sliceAsBytes(init.names));
149 break :hash hasher.final();
150 },
151 } },
152 },
153 false,
154 )) {
155 .wip => |wip| ty: {
156 errdefer wip.cancel(ip, pt.tid);
157 const type_name = try self.sema.createTypeName(
158 self.block,
159 .anon,
160 "struct",
161 self.base_node_inst.resolve(ip),
162 wip.index,
163 );
164 wip.setName(ip, type_name.name, type_name.nav);
165
166 const struct_type = ip.loadStructType(wip.index);
167
168 for (init.names, 0..) |name, field_idx| {
169 const name_interned = try ip.getOrPutString(
170 gpa,
171 pt.tid,
172 name.get(self.file.zoir.?),
173 .no_embedded_nulls,
174 );
175 assert(struct_type.addFieldName(ip, name_interned) == null);
176 struct_type.setFieldComptime(ip, field_idx);
177 }
178
179 @memcpy(struct_type.field_inits.get(ip), elems);
180 const types = struct_type.field_types.get(ip);
181 for (0..init.names.len) |i| {
182 types[i] = Value.fromInterned(elems[i]).typeOf(pt.zcu).toIntern();
183 }
184
185 const new_namespace_index = try pt.createNamespace(.{
186 .parent = self.block.namespace.toOptional(),
187 .owner_type = wip.index,
188 .file_scope = self.block.getFileScopeIndex(pt.zcu),
189 .generation = pt.zcu.generation,
190 });
191 try pt.zcu.comp.queueJob(.{ .resolve_type_fully = wip.index });
192 codegen_type: {
193 if (pt.zcu.comp.config.use_llvm) break :codegen_type;
194 if (self.block.ownerModule().strip) break :codegen_type;
195 pt.zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
196 try pt.zcu.comp.queueJob(.{ .link_type = wip.index });
197 }
198 break :ty wip.finish(ip, new_namespace_index);
199 },
200 .existing => |ty| ty,
201 };
202 try self.sema.declareDependency(.{ .interned = struct_ty });
203 try self.sema.addTypeReferenceEntry(self.nodeSrc(node), struct_ty);
204
205 return (try pt.aggregateValue(.fromInterned(struct_ty), elems)).toIntern();
206 },
207 }
208}
209
210/// Validate that `ty` is a valid ZON type, or emit a compile error.
211///
212/// Rules out nested optionals, error sets, etc.
213fn checkType(self: *LowerZon, ty: Type) !void {
214 var visited: std.AutoHashMapUnmanaged(InternPool.Index, void) = .empty;
215 try self.checkTypeInner(ty, null, &visited);
216}
217
218fn checkTypeInner(
219 self: *LowerZon,
220 ty: Type,
221 parent_opt_ty: ?Type,
222 /// Visited structs and unions (not tuples). These are tracked because they are the only way in
223 /// which a type can be self-referential, so must be tracked to avoid loops. Tracking more types
224 /// consumes memory unnecessarily, and would be complicated by optionals.
225 /// Allocated into `self.sema.arena`.
226 visited: *std.AutoHashMapUnmanaged(InternPool.Index, void),
227) !void {
228 const sema = self.sema;
229 const pt = sema.pt;
230 const zcu = pt.zcu;
231 const ip = &zcu.intern_pool;
232
233 switch (ty.zigTypeTag(zcu)) {
234 .bool,
235 .int,
236 .float,
237 .null,
238 .@"enum",
239 .comptime_float,
240 .comptime_int,
241 .enum_literal,
242 => {},
243
244 .noreturn,
245 .void,
246 .type,
247 .undefined,
248 .error_union,
249 .error_set,
250 .@"fn",
251 .frame,
252 .@"anyframe",
253 .@"opaque",
254 => return self.failUnsupportedResultType(ty, null),
255
256 .pointer => {
257 const ptr_info = ty.ptrInfo(zcu);
258 if (!ptr_info.flags.is_const) {
259 return self.failUnsupportedResultType(
260 ty,
261 "ZON does not allow mutable pointers",
262 );
263 }
264 switch (ptr_info.flags.size) {
265 .one => try self.checkTypeInner(
266 .fromInterned(ptr_info.child),
267 parent_opt_ty, // preserved
268 visited,
269 ),
270 .slice => try self.checkTypeInner(
271 .fromInterned(ptr_info.child),
272 null,
273 visited,
274 ),
275 .many => return self.failUnsupportedResultType(ty, "ZON does not allow many-pointers"),
276 .c => return self.failUnsupportedResultType(ty, "ZON does not allow C pointers"),
277 }
278 },
279 .optional => if (parent_opt_ty) |p| {
280 return self.failUnsupportedResultType(p, "ZON does not allow nested optionals");
281 } else try self.checkTypeInner(
282 ty.optionalChild(zcu),
283 ty,
284 visited,
285 ),
286 .array, .vector => {
287 try self.checkTypeInner(ty.childType(zcu), null, visited);
288 },
289 .@"struct" => if (ty.isTuple(zcu)) {
290 const tuple_info = ip.indexToKey(ty.toIntern()).tuple_type;
291 const field_types = tuple_info.types.get(ip);
292 for (field_types) |field_type| {
293 try self.checkTypeInner(.fromInterned(field_type), null, visited);
294 }
295 } else {
296 const gop = try visited.getOrPut(sema.arena, ty.toIntern());
297 if (gop.found_existing) return;
298 try ty.resolveFields(pt);
299 const struct_info = zcu.typeToStruct(ty).?;
300 for (struct_info.field_types.get(ip)) |field_type| {
301 try self.checkTypeInner(.fromInterned(field_type), null, visited);
302 }
303 },
304 .@"union" => {
305 const gop = try visited.getOrPut(sema.arena, ty.toIntern());
306 if (gop.found_existing) return;
307 try ty.resolveFields(pt);
308 const union_info = zcu.typeToUnion(ty).?;
309 for (union_info.field_types.get(ip)) |field_type| {
310 if (field_type != .void_type) {
311 try self.checkTypeInner(.fromInterned(field_type), null, visited);
312 }
313 }
314 },
315 }
316}
317
318fn nodeSrc(self: *LowerZon, node: Zoir.Node.Index) LazySrcLoc {
319 return .{
320 .base_node_inst = self.base_node_inst,
321 .offset = .{ .node_abs = node.getAstNode(self.file.zoir.?) },
322 };
323}
324
325fn failUnsupportedResultType(
326 self: *LowerZon,
327 ty: Type,
328 opt_note: ?[]const u8,
329) error{ AnalysisFail, OutOfMemory } {
330 @branchHint(.cold);
331 const sema = self.sema;
332 const gpa = sema.gpa;
333 const pt = sema.pt;
334 return sema.failWithOwnedErrorMsg(self.block, msg: {
335 const msg = try sema.errMsg(self.import_loc, "type '{f}' is not available in ZON", .{ty.fmt(pt)});
336 errdefer msg.destroy(gpa);
337 if (opt_note) |n| try sema.errNote(self.import_loc, msg, "{s}", .{n});
338 break :msg msg;
339 });
340}
341
342fn fail(
343 self: *LowerZon,
344 node: Zoir.Node.Index,
345 comptime format: []const u8,
346 args: anytype,
347) error{ AnalysisFail, OutOfMemory } {
348 @branchHint(.cold);
349 const err_msg = try Zcu.ErrorMsg.create(self.sema.pt.zcu.gpa, self.nodeSrc(node), format, args);
350 try self.sema.pt.zcu.errNote(self.import_loc, err_msg, "imported here", .{});
351 return self.sema.failWithOwnedErrorMsg(self.block, err_msg);
352}
353
354fn lowerExprKnownResTy(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) CompileError!InternPool.Index {
355 const pt = self.sema.pt;
356 return self.lowerExprKnownResTyInner(node, res_ty) catch |err| switch (err) {
357 error.WrongType => return self.fail(node, "expected type '{f}'", .{res_ty.fmt(pt)}),
358 else => |e| return e,
359 };
360}
361
362fn lowerExprKnownResTyInner(
363 self: *LowerZon,
364 node: Zoir.Node.Index,
365 res_ty: Type,
366) (CompileError || error{WrongType})!InternPool.Index {
367 const pt = self.sema.pt;
368 switch (res_ty.zigTypeTag(pt.zcu)) {
369 .optional => return pt.intern(.{
370 .opt = .{
371 .ty = res_ty.toIntern(),
372 .val = if (node.get(self.file.zoir.?) == .null) b: {
373 break :b .none;
374 } else b: {
375 const child_type = res_ty.optionalChild(pt.zcu);
376 break :b try self.lowerExprKnownResTyInner(node, child_type);
377 },
378 },
379 }),
380 .pointer => {
381 const ptr_info = res_ty.ptrInfo(pt.zcu);
382 switch (ptr_info.flags.size) {
383 .one => return pt.intern(.{ .ptr = .{
384 .ty = res_ty.toIntern(),
385 .base_addr = .{
386 .uav = .{
387 .orig_ty = res_ty.toIntern(),
388 .val = try self.lowerExprKnownResTyInner(node, .fromInterned(ptr_info.child)),
389 },
390 },
391 .byte_offset = 0,
392 } }),
393 .slice => return self.lowerSlice(node, res_ty),
394 else => {
395 // Unsupported pointer type, checked in `lower`
396 unreachable;
397 },
398 }
399 },
400 .bool => return self.lowerBool(node),
401 .int, .comptime_int => return self.lowerInt(node, res_ty),
402 .float, .comptime_float => return self.lowerFloat(node, res_ty),
403 .null => return self.lowerNull(node),
404 .@"enum" => return self.lowerEnum(node, res_ty),
405 .enum_literal => return self.lowerEnumLiteral(node),
406 .array => return self.lowerArray(node, res_ty),
407 .@"struct" => return self.lowerStructOrTuple(node, res_ty),
408 .@"union" => return self.lowerUnion(node, res_ty),
409 .vector => return self.lowerVector(node, res_ty),
410
411 .type,
412 .noreturn,
413 .undefined,
414 .error_union,
415 .error_set,
416 .@"fn",
417 .@"opaque",
418 .frame,
419 .@"anyframe",
420 .void,
421 => return self.fail(node, "type '{f}' not available in ZON", .{res_ty.fmt(pt)}),
422 }
423}
424
425fn lowerBool(self: *LowerZon, node: Zoir.Node.Index) !InternPool.Index {
426 return switch (node.get(self.file.zoir.?)) {
427 .true => .bool_true,
428 .false => .bool_false,
429 else => return error.WrongType,
430 };
431}
432
433fn lowerInt(
434 self: *LowerZon,
435 node: Zoir.Node.Index,
436 res_ty: Type,
437) !InternPool.Index {
438 @setFloatMode(.strict);
439 return switch (node.get(self.file.zoir.?)) {
440 .int_literal => |int| switch (int) {
441 .small => |val| {
442 const rhs: i32 = val;
443
444 // If our result is a fixed size integer, check that our value is not out of bounds
445 if (res_ty.zigTypeTag(self.sema.pt.zcu) == .int) {
446 const lhs_info = res_ty.intInfo(self.sema.pt.zcu);
447
448 // If lhs is unsigned and rhs is less than 0, we're out of bounds
449 if (lhs_info.signedness == .unsigned and rhs < 0) return self.fail(
450 node,
451 "type '{f}' cannot represent integer value '{d}'",
452 .{ res_ty.fmt(self.sema.pt), rhs },
453 );
454
455 // If lhs has less than the 32 bits rhs can hold, we need to check the max and
456 // min values
457 if (std.math.cast(u5, lhs_info.bits)) |bits| {
458 const min_int: i32 = if (lhs_info.signedness == .unsigned or bits == 0) b: {
459 break :b 0;
460 } else b: {
461 break :b -(@as(i32, 1) << (bits - 1));
462 };
463 const max_int: i32 = if (bits == 0) b: {
464 break :b 0;
465 } else b: {
466 break :b (@as(i32, 1) << (bits - @intFromBool(lhs_info.signedness == .signed))) - 1;
467 };
468 if (rhs < min_int or rhs > max_int) {
469 return self.fail(
470 node,
471 "type '{f}' cannot represent integer value '{d}'",
472 .{ res_ty.fmt(self.sema.pt), rhs },
473 );
474 }
475 }
476 }
477
478 return self.sema.pt.intern(.{ .int = .{
479 .ty = res_ty.toIntern(),
480 .storage = .{ .i64 = rhs },
481 } });
482 },
483 .big => |val| {
484 if (res_ty.zigTypeTag(self.sema.pt.zcu) == .int) {
485 const int_info = res_ty.intInfo(self.sema.pt.zcu);
486 if (!val.fitsInTwosComp(int_info.signedness, int_info.bits)) {
487 return self.fail(
488 node,
489 "type '{f}' cannot represent integer value '{d}'",
490 .{ res_ty.fmt(self.sema.pt), val },
491 );
492 }
493 }
494
495 return self.sema.pt.intern(.{ .int = .{
496 .ty = res_ty.toIntern(),
497 .storage = .{ .big_int = val },
498 } });
499 },
500 },
501 .float_literal => |val| {
502 var big_int: std.math.big.int.Mutable = .{
503 .limbs = try self.sema.arena.alloc(std.math.big.Limb, std.math.big.int.calcLimbLen(val)),
504 .len = undefined,
505 .positive = undefined,
506 };
507 switch (big_int.setFloat(val, .trunc)) {
508 .inexact => return self.fail(
509 node,
510 "fractional component prevents float value '{d}' from coercion to type '{f}'",
511 .{ val, res_ty.fmt(self.sema.pt) },
512 ),
513 .exact => {},
514 }
515
516 // Check that the result is in range of the result type
517 const int_info = res_ty.intInfo(self.sema.pt.zcu);
518 if (!big_int.toConst().fitsInTwosComp(int_info.signedness, int_info.bits)) {
519 return self.fail(
520 node,
521 "type '{f}' cannot represent integer value '{d}'",
522 .{ res_ty.fmt(self.sema.pt), val },
523 );
524 }
525
526 return self.sema.pt.intern(.{
527 .int = .{
528 .ty = res_ty.toIntern(),
529 .storage = .{ .big_int = big_int.toConst() },
530 },
531 });
532 },
533 .char_literal => |val| {
534 // If our result is a fixed size integer, check that our value is not out of bounds
535 if (res_ty.zigTypeTag(self.sema.pt.zcu) == .int) {
536 const dest_info = res_ty.intInfo(self.sema.pt.zcu);
537 const unsigned_bits = dest_info.bits - @intFromBool(dest_info.signedness == .signed);
538 if (unsigned_bits < 21) {
539 const out_of_range: u21 = @as(u21, 1) << @intCast(unsigned_bits);
540 if (val >= out_of_range) {
541 return self.fail(
542 node,
543 "type '{f}' cannot represent integer value '{d}'",
544 .{ res_ty.fmt(self.sema.pt), val },
545 );
546 }
547 }
548 }
549 return self.sema.pt.intern(.{
550 .int = .{
551 .ty = res_ty.toIntern(),
552 .storage = .{ .i64 = val },
553 },
554 });
555 },
556
557 else => return error.WrongType,
558 };
559}
560
561fn lowerFloat(
562 self: *LowerZon,
563 node: Zoir.Node.Index,
564 res_ty: Type,
565) !InternPool.Index {
566 @setFloatMode(.strict);
567 const value = switch (node.get(self.file.zoir.?)) {
568 .int_literal => |int| switch (int) {
569 .small => |val| try self.sema.pt.floatValue(res_ty, @as(f128, @floatFromInt(val))),
570 .big => |val| try self.sema.pt.floatValue(res_ty, val.toFloat(f128, .nearest_even)[0]),
571 },
572 .float_literal => |val| try self.sema.pt.floatValue(res_ty, val),
573 .char_literal => |val| try self.sema.pt.floatValue(res_ty, @as(f128, @floatFromInt(val))),
574 .pos_inf => b: {
575 if (res_ty.toIntern() == .comptime_float_type) return self.fail(
576 node,
577 "expected type '{f}'",
578 .{res_ty.fmt(self.sema.pt)},
579 );
580 break :b try self.sema.pt.floatValue(res_ty, std.math.inf(f128));
581 },
582 .neg_inf => b: {
583 if (res_ty.toIntern() == .comptime_float_type) return self.fail(
584 node,
585 "expected type '{f}'",
586 .{res_ty.fmt(self.sema.pt)},
587 );
588 break :b try self.sema.pt.floatValue(res_ty, -std.math.inf(f128));
589 },
590 .nan => b: {
591 if (res_ty.toIntern() == .comptime_float_type) return self.fail(
592 node,
593 "expected type '{f}'",
594 .{res_ty.fmt(self.sema.pt)},
595 );
596 break :b try self.sema.pt.floatValue(res_ty, std.math.nan(f128));
597 },
598 else => return error.WrongType,
599 };
600 return value.toIntern();
601}
602
603fn lowerNull(self: *LowerZon, node: Zoir.Node.Index) !InternPool.Index {
604 switch (node.get(self.file.zoir.?)) {
605 .null => return .null_value,
606 else => return error.WrongType,
607 }
608}
609
610fn lowerArray(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.Index {
611 const array_info = res_ty.arrayInfo(self.sema.pt.zcu);
612 const nodes: Zoir.Node.Index.Range = switch (node.get(self.file.zoir.?)) {
613 .array_literal => |nodes| nodes,
614 .empty_literal => .{ .start = node, .len = 0 },
615 else => return error.WrongType,
616 };
617
618 if (nodes.len != array_info.len) {
619 return error.WrongType;
620 }
621
622 const elems = try self.sema.arena.alloc(
623 InternPool.Index,
624 nodes.len + @intFromBool(array_info.sentinel != null),
625 );
626
627 for (0..nodes.len) |i| {
628 elems[i] = try self.lowerExprKnownResTy(nodes.at(@intCast(i)), array_info.elem_type);
629 }
630
631 if (array_info.sentinel) |sentinel| {
632 elems[elems.len - 1] = sentinel.toIntern();
633 }
634
635 return (try self.sema.pt.aggregateValue(res_ty, elems)).toIntern();
636}
637
638fn lowerEnum(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.Index {
639 const ip = &self.sema.pt.zcu.intern_pool;
640 switch (node.get(self.file.zoir.?)) {
641 .enum_literal => |field_name| {
642 const field_name_interned = try ip.getOrPutString(
643 self.sema.gpa,
644 self.sema.pt.tid,
645 field_name.get(self.file.zoir.?),
646 .no_embedded_nulls,
647 );
648 const field_index = res_ty.enumFieldIndex(field_name_interned, self.sema.pt.zcu) orelse {
649 return self.fail(
650 node,
651 "enum {f} has no member named '{f}'",
652 .{
653 res_ty.fmt(self.sema.pt),
654 std.zig.fmtId(field_name.get(self.file.zoir.?)),
655 },
656 );
657 };
658
659 const value = try self.sema.pt.enumValueFieldIndex(res_ty, field_index);
660
661 return value.toIntern();
662 },
663 else => return error.WrongType,
664 }
665}
666
667fn lowerEnumLiteral(self: *LowerZon, node: Zoir.Node.Index) !InternPool.Index {
668 const ip = &self.sema.pt.zcu.intern_pool;
669 switch (node.get(self.file.zoir.?)) {
670 .enum_literal => |field_name| {
671 const field_name_interned = try ip.getOrPutString(
672 self.sema.gpa,
673 self.sema.pt.tid,
674 field_name.get(self.file.zoir.?),
675 .no_embedded_nulls,
676 );
677 return self.sema.pt.intern(.{ .enum_literal = field_name_interned });
678 },
679 else => return error.WrongType,
680 }
681}
682
683fn lowerStructOrTuple(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.Index {
684 const ip = &self.sema.pt.zcu.intern_pool;
685 return switch (ip.indexToKey(res_ty.toIntern())) {
686 .tuple_type => self.lowerTuple(node, res_ty),
687 .struct_type => self.lowerStruct(node, res_ty),
688 else => unreachable,
689 };
690}
691
692fn lowerTuple(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.Index {
693 const ip = &self.sema.pt.zcu.intern_pool;
694
695 const tuple_info = ip.indexToKey(res_ty.toIntern()).tuple_type;
696
697 const elem_nodes: Zoir.Node.Index.Range = switch (node.get(self.file.zoir.?)) {
698 .array_literal => |nodes| nodes,
699 .empty_literal => .{ .start = node, .len = 0 },
700 else => return error.WrongType,
701 };
702
703 const field_types = tuple_info.types.get(ip);
704 const elems = try self.sema.arena.alloc(InternPool.Index, field_types.len);
705
706 const field_comptime_vals = tuple_info.values.get(ip);
707 if (field_comptime_vals.len > 0) {
708 @memcpy(elems, field_comptime_vals);
709 } else {
710 @memset(elems, .none);
711 }
712
713 for (0..elem_nodes.len) |i| {
714 if (i >= elems.len) {
715 const elem_node = elem_nodes.at(@intCast(i));
716 return self.fail(
717 elem_node,
718 "index {} outside tuple of length {}",
719 .{
720 elems.len,
721 elem_nodes.at(@intCast(i)).getAstNode(self.file.zoir.?),
722 },
723 );
724 }
725
726 const val = try self.lowerExprKnownResTy(elem_nodes.at(@intCast(i)), .fromInterned(field_types[i]));
727
728 if (elems[i] != .none and val != elems[i]) {
729 const elem_node = elem_nodes.at(@intCast(i));
730 return self.fail(
731 elem_node,
732 "value stored in comptime field does not match the default value of the field",
733 .{},
734 );
735 }
736
737 elems[i] = val;
738 }
739
740 for (elems, 0..) |val, i| {
741 if (val == .none) {
742 return self.fail(node, "missing tuple field with index {}", .{i});
743 }
744 }
745
746 return (try self.sema.pt.aggregateValue(res_ty, elems)).toIntern();
747}
748
749fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.Index {
750 const ip = &self.sema.pt.zcu.intern_pool;
751 const gpa = self.sema.gpa;
752
753 try res_ty.resolveFields(self.sema.pt);
754 try res_ty.resolveStructFieldInits(self.sema.pt);
755 const struct_info = self.sema.pt.zcu.typeToStruct(res_ty).?;
756
757 const fields: @FieldType(Zoir.Node, "struct_literal") = switch (node.get(self.file.zoir.?)) {
758 .struct_literal => |fields| fields,
759 .empty_literal => .{ .names = &.{}, .vals = .{ .start = node, .len = 0 } },
760 else => return error.WrongType,
761 };
762
763 const field_values = try self.sema.arena.alloc(InternPool.Index, struct_info.field_names.len);
764
765 const field_defaults = struct_info.field_inits.get(ip);
766 if (field_defaults.len > 0) {
767 @memcpy(field_values, field_defaults);
768 } else {
769 @memset(field_values, .none);
770 }
771
772 for (0..fields.names.len) |i| {
773 const field_name = try ip.getOrPutString(
774 gpa,
775 self.sema.pt.tid,
776 fields.names[i].get(self.file.zoir.?),
777 .no_embedded_nulls,
778 );
779 const field_node = fields.vals.at(@intCast(i));
780
781 const name_index = struct_info.nameIndex(ip, field_name) orelse {
782 return self.fail(field_node, "unexpected field '{f}'", .{field_name.fmt(ip)});
783 };
784
785 const field_type: Type = .fromInterned(struct_info.field_types.get(ip)[name_index]);
786 field_values[name_index] = try self.lowerExprKnownResTy(field_node, field_type);
787
788 if (struct_info.comptime_bits.getBit(ip, name_index)) {
789 const val = ip.indexToKey(field_values[name_index]);
790 const default = ip.indexToKey(field_defaults[name_index]);
791 if (!val.eql(default, ip)) {
792 return self.fail(
793 field_node,
794 "value stored in comptime field does not match the default value of the field",
795 .{},
796 );
797 }
798 }
799 }
800
801 const field_names = struct_info.field_names.get(ip);
802 for (field_values, field_names) |*value, name| {
803 if (value.* == .none) return self.fail(node, "missing field '{f}'", .{name.fmt(ip)});
804 }
805
806 return (try self.sema.pt.aggregateValue(res_ty, field_values)).toIntern();
807}
808
809fn lowerSlice(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.Index {
810 const ip = &self.sema.pt.zcu.intern_pool;
811 const gpa = self.sema.gpa;
812
813 const ptr_info = res_ty.ptrInfo(self.sema.pt.zcu);
814
815 assert(ptr_info.flags.size == .slice);
816
817 // String literals
818 const string_alignment = ptr_info.flags.alignment == .none or ptr_info.flags.alignment == .@"1";
819 const string_sentinel = ptr_info.sentinel == .none or ptr_info.sentinel == .zero_u8;
820 if (string_alignment and ptr_info.child == .u8_type and string_sentinel) {
821 switch (node.get(self.file.zoir.?)) {
822 .string_literal => |val| {
823 const ip_str = try ip.getOrPutString(gpa, self.sema.pt.tid, val, .maybe_embedded_nulls);
824 const str_ref = try self.sema.addStrLit(ip_str, val.len);
825 return (try self.sema.coerce(
826 self.block,
827 res_ty,
828 str_ref,
829 self.nodeSrc(node),
830 )).toInterned().?;
831 },
832 else => {},
833 }
834 }
835
836 // Slice literals
837 const elem_nodes: Zoir.Node.Index.Range = switch (node.get(self.file.zoir.?)) {
838 .array_literal => |nodes| nodes,
839 .empty_literal => .{ .start = node, .len = 0 },
840 else => return error.WrongType,
841 };
842
843 const elems = try self.sema.arena.alloc(InternPool.Index, elem_nodes.len + @intFromBool(ptr_info.sentinel != .none));
844
845 for (elems, 0..) |*elem, i| {
846 elem.* = try self.lowerExprKnownResTy(elem_nodes.at(@intCast(i)), .fromInterned(ptr_info.child));
847 }
848
849 if (ptr_info.sentinel != .none) {
850 elems[elems.len - 1] = ptr_info.sentinel;
851 }
852
853 const array_ty = try self.sema.pt.arrayType(.{
854 .len = elems.len,
855 .sentinel = ptr_info.sentinel,
856 .child = ptr_info.child,
857 });
858
859 const array_val = try self.sema.pt.aggregateValue(array_ty, elems);
860
861 const many_item_ptr_type = try self.sema.pt.intern(.{ .ptr_type = .{
862 .child = ptr_info.child,
863 .sentinel = ptr_info.sentinel,
864 .flags = b: {
865 var flags = ptr_info.flags;
866 flags.size = .many;
867 break :b flags;
868 },
869 .packed_offset = ptr_info.packed_offset,
870 } });
871
872 const many_item_ptr = try self.sema.pt.intern(.{
873 .ptr = .{
874 .ty = many_item_ptr_type,
875 .base_addr = .{
876 .uav = .{
877 .orig_ty = (try self.sema.pt.singleConstPtrType(array_ty)).toIntern(),
878 .val = array_val.toIntern(),
879 },
880 },
881 .byte_offset = 0,
882 },
883 });
884
885 const len = (try self.sema.pt.intValue(.usize, elems.len)).toIntern();
886
887 return self.sema.pt.intern(.{ .slice = .{
888 .ty = res_ty.toIntern(),
889 .ptr = many_item_ptr,
890 .len = len,
891 } });
892}
893
894fn lowerUnion(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.Index {
895 const ip = &self.sema.pt.zcu.intern_pool;
896 try res_ty.resolveFields(self.sema.pt);
897 const union_info = self.sema.pt.zcu.typeToUnion(res_ty).?;
898 const enum_tag_info = union_info.loadTagType(ip);
899
900 const field_name, const maybe_field_node = switch (node.get(self.file.zoir.?)) {
901 .enum_literal => |name| b: {
902 const field_name = try ip.getOrPutString(
903 self.sema.gpa,
904 self.sema.pt.tid,
905 name.get(self.file.zoir.?),
906 .no_embedded_nulls,
907 );
908 break :b .{ field_name, null };
909 },
910 .struct_literal => b: {
911 const fields: @FieldType(Zoir.Node, "struct_literal") = switch (node.get(self.file.zoir.?)) {
912 .struct_literal => |fields| fields,
913 else => return self.fail(node, "expected type '{f}'", .{res_ty.fmt(self.sema.pt)}),
914 };
915 if (fields.names.len != 1) {
916 return error.WrongType;
917 }
918 const field_name = try ip.getOrPutString(
919 self.sema.gpa,
920 self.sema.pt.tid,
921 fields.names[0].get(self.file.zoir.?),
922 .no_embedded_nulls,
923 );
924 break :b .{ field_name, fields.vals.at(0) };
925 },
926 else => return error.WrongType,
927 };
928
929 const name_index = enum_tag_info.nameIndex(ip, field_name) orelse {
930 return error.WrongType;
931 };
932 const tag = try self.sema.pt.enumValueFieldIndex(.fromInterned(union_info.enum_tag_ty), name_index);
933 const field_type: Type = .fromInterned(union_info.field_types.get(ip)[name_index]);
934 const val = if (maybe_field_node) |field_node| b: {
935 if (field_type.toIntern() == .void_type) {
936 return self.fail(field_node, "expected type 'void'", .{});
937 }
938 break :b try self.lowerExprKnownResTy(field_node, field_type);
939 } else b: {
940 if (field_type.toIntern() != .void_type) {
941 return error.WrongType;
942 }
943 break :b .void_value;
944 };
945 return ip.getUnion(self.sema.pt.zcu.gpa, self.sema.pt.tid, .{
946 .ty = res_ty.toIntern(),
947 .tag = tag.toIntern(),
948 .val = val,
949 });
950}
951
952fn lowerVector(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.Index {
953 const ip = &self.sema.pt.zcu.intern_pool;
954
955 const vector_info = ip.indexToKey(res_ty.toIntern()).vector_type;
956
957 const elem_nodes: Zoir.Node.Index.Range = switch (node.get(self.file.zoir.?)) {
958 .array_literal => |nodes| nodes,
959 .empty_literal => .{ .start = node, .len = 0 },
960 else => return error.WrongType,
961 };
962
963 const elems = try self.sema.arena.alloc(InternPool.Index, vector_info.len);
964
965 if (elem_nodes.len != vector_info.len) {
966 return self.fail(
967 node,
968 "expected {} vector elements; found {}",
969 .{ vector_info.len, elem_nodes.len },
970 );
971 }
972
973 for (elems, 0..) |*elem, i| {
974 elem.* = try self.lowerExprKnownResTy(elem_nodes.at(@intCast(i)), .fromInterned(vector_info.child));
975 }
976
977 return (try self.sema.pt.aggregateValue(res_ty, elems)).toIntern();
978}