| ... | ... | @@ -33,7 +33,7 @@ pub fn run( |
| 33 | 33 | sema: *Sema, |
| 34 | 34 | file: *File, |
| 35 | 35 | file_index: Zcu.File.Index, |
| 36 | | res_ty: Type, |
| 36 | res_ty_interned: InternPool.Index, |
| 37 | 37 | import_loc: LazySrcLoc, |
| 38 | 38 | block: *Sema.Block, |
| 39 | 39 | ) CompileError!InternPool.Index { |
| ... | ... | @@ -53,13 +53,167 @@ pub fn run( |
| 53 | 53 | .base_node_inst = tracked_inst, |
| 54 | 54 | }; |
| 55 | 55 | |
| 56 | | try lower_zon.checkType(res_ty); |
| 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 | } |
| 57 | 64 | |
| 58 | | return lower_zon.lowerExpr(.root, res_ty); |
| 65 | fn 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 pt.intern(.{ .aggregate = .{ |
| 124 | .ty = ty, |
| 125 | .storage = .{ .elems = values }, |
| 126 | } }); |
| 127 | }, |
| 128 | .struct_literal => |init| { |
| 129 | const elems = try self.sema.arena.alloc(InternPool.Index, init.names.len); |
| 130 | for (0..init.names.len) |i| { |
| 131 | elems[i] = try self.lowerExprAnonResTy(init.vals.at(@intCast(i))); |
| 132 | } |
| 133 | const struct_ty = switch (try ip.getStructType( |
| 134 | gpa, |
| 135 | pt.tid, |
| 136 | .{ |
| 137 | .layout = .auto, |
| 138 | .fields_len = @intCast(init.names.len), |
| 139 | .known_non_opv = false, |
| 140 | .requires_comptime = .no, |
| 141 | .any_comptime_fields = true, |
| 142 | .any_default_inits = true, |
| 143 | .inits_resolved = true, |
| 144 | .any_aligned_fields = false, |
| 145 | .key = .{ .reified = .{ |
| 146 | .zir_index = self.base_node_inst, |
| 147 | .type_hash = hash: { |
| 148 | var hasher: std.hash.Wyhash = .init(0); |
| 149 | hasher.update(std.mem.asBytes(&node)); |
| 150 | hasher.update(std.mem.sliceAsBytes(elems)); |
| 151 | hasher.update(std.mem.sliceAsBytes(init.names)); |
| 152 | break :hash hasher.final(); |
| 153 | }, |
| 154 | } }, |
| 155 | }, |
| 156 | false, |
| 157 | )) { |
| 158 | .wip => |wip| ty: { |
| 159 | errdefer wip.cancel(ip, pt.tid); |
| 160 | wip.setName(ip, try self.sema.createTypeName( |
| 161 | self.block, |
| 162 | .anon, |
| 163 | "struct", |
| 164 | self.base_node_inst.resolve(ip), |
| 165 | wip.index, |
| 166 | )); |
| 167 | |
| 168 | const struct_type = ip.loadStructType(wip.index); |
| 169 | |
| 170 | for (init.names, 0..) |name, field_idx| { |
| 171 | const name_interned = try ip.getOrPutString( |
| 172 | gpa, |
| 173 | pt.tid, |
| 174 | name.get(self.file.zoir.?), |
| 175 | .no_embedded_nulls, |
| 176 | ); |
| 177 | assert(struct_type.addFieldName(ip, name_interned) == null); |
| 178 | struct_type.setFieldComptime(ip, field_idx); |
| 179 | } |
| 180 | |
| 181 | @memcpy(struct_type.field_inits.get(ip), elems); |
| 182 | const types = struct_type.field_types.get(ip); |
| 183 | for (0..init.names.len) |i| { |
| 184 | types[i] = Value.fromInterned(elems[i]).typeOf(pt.zcu).toIntern(); |
| 185 | } |
| 186 | |
| 187 | const new_namespace_index = try pt.createNamespace(.{ |
| 188 | .parent = self.block.namespace.toOptional(), |
| 189 | .owner_type = wip.index, |
| 190 | .file_scope = self.block.getFileScopeIndex(pt.zcu), |
| 191 | .generation = pt.zcu.generation, |
| 192 | }); |
| 193 | try pt.zcu.comp.queueJob(.{ .resolve_type_fully = wip.index }); |
| 194 | codegen_type: { |
| 195 | if (pt.zcu.comp.config.use_llvm) break :codegen_type; |
| 196 | if (self.block.ownerModule().strip) break :codegen_type; |
| 197 | try pt.zcu.comp.queueJob(.{ .codegen_type = wip.index }); |
| 198 | } |
| 199 | break :ty wip.finish(ip, new_namespace_index); |
| 200 | }, |
| 201 | .existing => |ty| ty, |
| 202 | }; |
| 203 | try self.sema.declareDependency(.{ .interned = struct_ty }); |
| 204 | try self.sema.addTypeReferenceEntry(self.nodeSrc(node), struct_ty); |
| 205 | |
| 206 | return try pt.intern(.{ .aggregate = .{ |
| 207 | .ty = struct_ty, |
| 208 | .storage = .{ .elems = elems }, |
| 209 | } }); |
| 210 | }, |
| 211 | } |
| 59 | 212 | } |
| 60 | 213 | |
| 61 | | /// Validate that `ty` is a valid ZON type. If not, emit a compile error. |
| 62 | | /// i.e. no nested optionals, no error sets, etc. |
| 214 | /// Validate that `ty` is a valid ZON type, or emit a compile error. |
| 215 | /// |
| 216 | /// Rules out nested optionals, error sets, etc. |
| 63 | 217 | fn checkType(self: *LowerZon, ty: Type) !void { |
| 64 | 218 | var visited: std.AutoHashMapUnmanaged(InternPool.Index, void) = .empty; |
| 65 | 219 | try self.checkTypeInner(ty, null, &visited); |
| ... | ... | @@ -201,9 +355,9 @@ fn fail( |
| 201 | 355 | return self.sema.failWithOwnedErrorMsg(self.block, err_msg); |
| 202 | 356 | } |
| 203 | 357 | |
| 204 | | fn lowerExpr(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) CompileError!InternPool.Index { |
| 358 | fn lowerExprKnownResTy(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) CompileError!InternPool.Index { |
| 205 | 359 | const pt = self.sema.pt; |
| 206 | | return self.lowerExprInner(node, res_ty) catch |err| switch (err) { |
| 360 | return self.lowerExprKnownResTyInner(node, res_ty) catch |err| switch (err) { |
| 207 | 361 | error.WrongType => return self.fail( |
| 208 | 362 | node, |
| 209 | 363 | "expected type '{}'", |
| ... | ... | @@ -213,7 +367,7 @@ fn lowerExpr(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) CompileError! |
| 213 | 367 | }; |
| 214 | 368 | } |
| 215 | 369 | |
| 216 | | fn lowerExprInner( |
| 370 | fn lowerExprKnownResTyInner( |
| 217 | 371 | self: *LowerZon, |
| 218 | 372 | node: Zoir.Node.Index, |
| 219 | 373 | res_ty: Type, |
| ... | ... | @@ -227,7 +381,7 @@ fn lowerExprInner( |
| 227 | 381 | break :b .none; |
| 228 | 382 | } else b: { |
| 229 | 383 | const child_type = res_ty.optionalChild(pt.zcu); |
| 230 | | break :b try self.lowerExprInner(node, child_type); |
| 384 | break :b try self.lowerExprKnownResTyInner(node, child_type); |
| 231 | 385 | }, |
| 232 | 386 | }, |
| 233 | 387 | }), |
| ... | ... | @@ -239,7 +393,7 @@ fn lowerExprInner( |
| 239 | 393 | .base_addr = .{ |
| 240 | 394 | .uav = .{ |
| 241 | 395 | .orig_ty = res_ty.toIntern(), |
| 242 | | .val = try self.lowerExprInner(node, .fromInterned(ptr_info.child)), |
| 396 | .val = try self.lowerExprKnownResTyInner(node, .fromInterned(ptr_info.child)), |
| 243 | 397 | }, |
| 244 | 398 | }, |
| 245 | 399 | .byte_offset = 0, |
| ... | ... | @@ -486,7 +640,7 @@ fn lowerArray(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool. |
| 486 | 640 | ); |
| 487 | 641 | |
| 488 | 642 | for (0..nodes.len) |i| { |
| 489 | | elems[i] = try self.lowerExpr(nodes.at(@intCast(i)), array_info.elem_type); |
| 643 | elems[i] = try self.lowerExprKnownResTy(nodes.at(@intCast(i)), array_info.elem_type); |
| 490 | 644 | } |
| 491 | 645 | |
| 492 | 646 | if (array_info.sentinel) |sentinel| { |
| ... | ... | @@ -587,7 +741,7 @@ fn lowerTuple(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool. |
| 587 | 741 | ); |
| 588 | 742 | } |
| 589 | 743 | |
| 590 | | const val = try self.lowerExpr(elem_nodes.at(@intCast(i)), .fromInterned(field_types[i])); |
| 744 | const val = try self.lowerExprKnownResTy(elem_nodes.at(@intCast(i)), .fromInterned(field_types[i])); |
| 591 | 745 | |
| 592 | 746 | if (elems[i] != .none and val != elems[i]) { |
| 593 | 747 | const elem_node = elem_nodes.at(@intCast(i)); |
| ... | ... | @@ -650,7 +804,7 @@ fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool |
| 650 | 804 | }; |
| 651 | 805 | |
| 652 | 806 | const field_type: Type = .fromInterned(struct_info.field_types.get(ip)[name_index]); |
| 653 | | field_values[name_index] = try self.lowerExpr(field_node, field_type); |
| 807 | field_values[name_index] = try self.lowerExprKnownResTy(field_node, field_type); |
| 654 | 808 | |
| 655 | 809 | if (struct_info.comptime_bits.getBit(ip, name_index)) { |
| 656 | 810 | const val = ip.indexToKey(field_values[name_index]); |
| ... | ... | @@ -715,7 +869,7 @@ fn lowerSlice(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool. |
| 715 | 869 | const elems = try self.sema.arena.alloc(InternPool.Index, elem_nodes.len + @intFromBool(ptr_info.sentinel != .none)); |
| 716 | 870 | |
| 717 | 871 | for (elems, 0..) |*elem, i| { |
| 718 | | elem.* = try self.lowerExpr(elem_nodes.at(@intCast(i)), .fromInterned(ptr_info.child)); |
| 872 | elem.* = try self.lowerExprKnownResTy(elem_nodes.at(@intCast(i)), .fromInterned(ptr_info.child)); |
| 719 | 873 | } |
| 720 | 874 | |
| 721 | 875 | if (ptr_info.sentinel != .none) { |
| ... | ... | @@ -810,7 +964,7 @@ fn lowerUnion(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool. |
| 810 | 964 | if (field_type.toIntern() == .void_type) { |
| 811 | 965 | return self.fail(field_node, "expected type 'void'", .{}); |
| 812 | 966 | } |
| 813 | | break :b try self.lowerExpr(field_node, field_type); |
| 967 | break :b try self.lowerExprKnownResTy(field_node, field_type); |
| 814 | 968 | } else b: { |
| 815 | 969 | if (field_type.toIntern() != .void_type) { |
| 816 | 970 | return error.WrongType; |
| ... | ... | @@ -846,7 +1000,7 @@ fn lowerVector(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool |
| 846 | 1000 | } |
| 847 | 1001 | |
| 848 | 1002 | for (elems, 0..) |*elem, i| { |
| 849 | | elem.* = try self.lowerExpr(elem_nodes.at(@intCast(i)), .fromInterned(vector_info.child)); |
| 1003 | elem.* = try self.lowerExprKnownResTy(elem_nodes.at(@intCast(i)), .fromInterned(vector_info.child)); |
| 850 | 1004 | } |
| 851 | 1005 | |
| 852 | 1006 | return self.sema.pt.intern(.{ .aggregate = .{ |