| author | |
| committer | |
| log | 152a2ceaf738301cd59165a4f17d915391321bdc |
| tree | f2239a36d9d2ce92bfaf34742620ce74ec7defb5 |
| parent | 884d957b6c291961536c10401f60264da26cba30 |
| signature |
This commit also performs some refactors to `TypedValue.print` in
preparation for improved comptime pointer access logic. Once that logic
exists, `TypedValue.print` can use Sema to access pointers for more
helpful printing.
This commit also implements proposal #19435, because the existing logic
there relied on some blatantly incorrect code in `Value.sliceLen`.
Resolves: #194354 files changed, 406 insertions(+), 467 deletions(-)
src/Sema.zig+112-80| ... | @@ -1881,10 +1881,10 @@ pub fn toConstString( | ... | @@ -1881,10 +1881,10 @@ pub fn toConstString( |
| 1881 | air_inst: Air.Inst.Ref, | 1881 | air_inst: Air.Inst.Ref, |
| 1882 | reason: NeededComptimeReason, | 1882 | reason: NeededComptimeReason, |
| 1883 | ) ![]u8 { | 1883 | ) ![]u8 { |
| 1884 | const wanted_type = Type.slice_const_u8; | 1884 | const coerced_inst = try sema.coerce(block, Type.slice_const_u8, air_inst, src); |
| 1885 | const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src); | 1885 | const slice_val = try sema.resolveConstDefinedValue(block, src, coerced_inst, reason); |
| 1886 | const val = try sema.resolveConstDefinedValue(block, src, coerced_inst, reason); | 1886 | const arr_val = try sema.derefSliceAsArray(block, src, slice_val, reason); |
| 1887 | return val.toAllocatedBytes(wanted_type, sema.arena, sema.mod); | 1887 | return arr_val.toAllocatedBytes(arr_val.typeOf(sema.mod), sema.arena, sema.mod); |
| 1888 | } | 1888 | } |
| 1889 | 1889 | ||
| 1890 | pub fn resolveConstStringIntern( | 1890 | pub fn resolveConstStringIntern( |
| ... | @@ -14498,12 +14498,16 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -14498,12 +14498,16 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 14498 | else => unreachable, | 14498 | else => unreachable, |
| 14499 | }) |rhs_val| { | 14499 | }) |rhs_val| { |
| 14500 | const lhs_sub_val = if (lhs_ty.isSinglePointer(mod)) | 14500 | const lhs_sub_val = if (lhs_ty.isSinglePointer(mod)) |
| 14501 | (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).? | 14501 | try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty) orelse break :rs lhs_src |
| 14502 | else if (lhs_ty.isSlice(mod)) | ||
| 14503 | try sema.maybeDerefSliceAsArray(block, lhs_src, lhs_val) orelse break :rs lhs_src | ||
| 14502 | else | 14504 | else |
| 14503 | lhs_val; | 14505 | lhs_val; |
| 14504 | 14506 | ||
| 14505 | const rhs_sub_val = if (rhs_ty.isSinglePointer(mod)) | 14507 | const rhs_sub_val = if (rhs_ty.isSinglePointer(mod)) |
| 14506 | (try sema.pointerDeref(block, rhs_src, rhs_val, rhs_ty)).? | 14508 | try sema.pointerDeref(block, rhs_src, rhs_val, rhs_ty) orelse break :rs rhs_src |
| 14509 | else if (rhs_ty.isSlice(mod)) | ||
| 14510 | try sema.maybeDerefSliceAsArray(block, rhs_src, rhs_val) orelse break :rs rhs_src | ||
| 14507 | else | 14511 | else |
| 14508 | rhs_val; | 14512 | rhs_val; |
| 14509 | 14513 | ||
| ... | @@ -14623,10 +14627,7 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Ins | ... | @@ -14623,10 +14627,7 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Ins |
| 14623 | .Pointer => { | 14627 | .Pointer => { |
| 14624 | const ptr_info = operand_ty.ptrInfo(mod); | 14628 | const ptr_info = operand_ty.ptrInfo(mod); |
| 14625 | switch (ptr_info.flags.size) { | 14629 | switch (ptr_info.flags.size) { |
| 14626 | // TODO: in the Many case here this should only work if the type | 14630 | .Slice => { |
| 14627 | // has a sentinel, and this code should compute the length based | ||
| 14628 | // on the sentinel value. | ||
| 14629 | .Slice, .Many => { | ||
| 14630 | const val = try sema.resolveConstDefinedValue(block, src, operand, .{ | 14631 | const val = try sema.resolveConstDefinedValue(block, src, operand, .{ |
| 14631 | .needed_comptime_reason = "slice value being concatenated must be comptime-known", | 14632 | .needed_comptime_reason = "slice value being concatenated must be comptime-known", |
| 14632 | }); | 14633 | }); |
| ... | @@ -14636,7 +14637,7 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Ins | ... | @@ -14636,7 +14637,7 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Ins |
| 14636 | .none => null, | 14637 | .none => null, |
| 14637 | else => Value.fromInterned(ptr_info.sentinel), | 14638 | else => Value.fromInterned(ptr_info.sentinel), |
| 14638 | }, | 14639 | }, |
| 14639 | .len = val.sliceLen(mod), | 14640 | .len = try val.sliceLen(sema), |
| 14640 | }; | 14641 | }; |
| 14641 | }, | 14642 | }, |
| 14642 | .One => { | 14643 | .One => { |
| ... | @@ -14644,7 +14645,7 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Ins | ... | @@ -14644,7 +14645,7 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Ins |
| 14644 | return Type.fromInterned(ptr_info.child).arrayInfo(mod); | 14645 | return Type.fromInterned(ptr_info.child).arrayInfo(mod); |
| 14645 | } | 14646 | } |
| 14646 | }, | 14647 | }, |
| 14647 | .C => {}, | 14648 | .C, .Many => {}, |
| 14648 | } | 14649 | } |
| 14649 | }, | 14650 | }, |
| 14650 | .Struct => { | 14651 | .Struct => { |
| ... | @@ -14830,9 +14831,11 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -14830,9 +14831,11 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 14830 | const ptr_addrspace = if (lhs_ty.zigTypeTag(mod) == .Pointer) lhs_ty.ptrAddressSpace(mod) else null; | 14831 | const ptr_addrspace = if (lhs_ty.zigTypeTag(mod) == .Pointer) lhs_ty.ptrAddressSpace(mod) else null; |
| 14831 | const lhs_len = try sema.usizeCast(block, lhs_src, lhs_info.len); | 14832 | const lhs_len = try sema.usizeCast(block, lhs_src, lhs_info.len); |
| 14832 | 14833 | ||
| 14833 | if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| { | 14834 | if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| ct: { |
| 14834 | const lhs_sub_val = if (lhs_ty.isSinglePointer(mod)) | 14835 | const lhs_sub_val = if (lhs_ty.isSinglePointer(mod)) |
| 14835 | (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).? | 14836 | try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty) orelse break :ct |
| 14837 | else if (lhs_ty.isSlice(mod)) | ||
| 14838 | try sema.maybeDerefSliceAsArray(block, lhs_src, lhs_val) orelse break :ct | ||
| 14836 | else | 14839 | else |
| 14837 | lhs_val; | 14840 | lhs_val; |
| 14838 | 14841 | ||
| ... | @@ -14840,7 +14843,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -14840,7 +14843,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 14840 | // Optimization for the common pattern of a single element repeated N times, such | 14843 | // Optimization for the common pattern of a single element repeated N times, such |
| 14841 | // as zero-filling a byte array. | 14844 | // as zero-filling a byte array. |
| 14842 | if (lhs_len == 1 and lhs_info.sentinel == null) { | 14845 | if (lhs_len == 1 and lhs_info.sentinel == null) { |
| 14843 | const elem_val = (try lhs_sub_val.maybeElemValueFull(sema, mod, 0)).?; | 14846 | const elem_val = try lhs_sub_val.elemValue(mod, 0); |
| 14844 | break :v try mod.intern(.{ .aggregate = .{ | 14847 | break :v try mod.intern(.{ .aggregate = .{ |
| 14845 | .ty = result_ty.toIntern(), | 14848 | .ty = result_ty.toIntern(), |
| 14846 | .storage = .{ .repeated_elem = elem_val.toIntern() }, | 14849 | .storage = .{ .repeated_elem = elem_val.toIntern() }, |
| ... | @@ -14852,7 +14855,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -14852,7 +14855,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 14852 | while (elem_i < result_len) { | 14855 | while (elem_i < result_len) { |
| 14853 | var lhs_i: usize = 0; | 14856 | var lhs_i: usize = 0; |
| 14854 | while (lhs_i < lhs_len) : (lhs_i += 1) { | 14857 | while (lhs_i < lhs_len) : (lhs_i += 1) { |
| 14855 | const elem_val = (try lhs_sub_val.maybeElemValueFull(sema, mod, lhs_i)).?; | 14858 | const elem_val = try lhs_sub_val.elemValue(mod, lhs_i); |
| 14856 | element_vals[elem_i] = elem_val.toIntern(); | 14859 | element_vals[elem_i] = elem_val.toIntern(); |
| 14857 | elem_i += 1; | 14860 | elem_i += 1; |
| 14858 | } | 14861 | } |
| ... | @@ -21124,7 +21127,9 @@ fn zirReify( | ... | @@ -21124,7 +21127,9 @@ fn zirReify( |
| 21124 | .needed_comptime_reason = "operand to @Type must be comptime-known", | 21127 | .needed_comptime_reason = "operand to @Type must be comptime-known", |
| 21125 | }); | 21128 | }); |
| 21126 | const union_val = ip.indexToKey(val.toIntern()).un; | 21129 | const union_val = ip.indexToKey(val.toIntern()).un; |
| 21127 | if (try sema.anyUndef(Value.fromInterned(union_val.val))) return sema.failWithUseOfUndef(block, src); | 21130 | if (try sema.anyUndef(block, operand_src, Value.fromInterned(union_val.val))) { |
| 21131 | return sema.failWithUseOfUndef(block, operand_src); | ||
| 21132 | } | ||
| 21128 | const tag_index = type_info_ty.unionTagFieldIndex(Value.fromInterned(union_val.tag), mod).?; | 21133 | const tag_index = type_info_ty.unionTagFieldIndex(Value.fromInterned(union_val.tag), mod).?; |
| 21129 | switch (@as(std.builtin.TypeId, @enumFromInt(tag_index))) { | 21134 | switch (@as(std.builtin.TypeId, @enumFromInt(tag_index))) { |
| 21130 | .Type => return .type_type, | 21135 | .Type => return .type_type, |
| ... | @@ -21365,11 +21370,15 @@ fn zirReify( | ... | @@ -21365,11 +21370,15 @@ fn zirReify( |
| 21365 | const payload_val = Value.fromInterned(union_val.val).optionalValue(mod) orelse | 21370 | const payload_val = Value.fromInterned(union_val.val).optionalValue(mod) orelse |
| 21366 | return Air.internedToRef(Type.anyerror.toIntern()); | 21371 | return Air.internedToRef(Type.anyerror.toIntern()); |
| 21367 | 21372 | ||
| 21368 | const len = try sema.usizeCast(block, src, payload_val.sliceLen(mod)); | 21373 | const names_val = try sema.derefSliceAsArray(block, src, payload_val, .{ |
| 21374 | .needed_comptime_reason = "error set contents must be comptime-known", | ||
| 21375 | }); | ||
| 21376 | |||
| 21377 | const len = try sema.usizeCast(block, src, names_val.typeOf(mod).arrayLen(mod)); | ||
| 21369 | var names: InferredErrorSet.NameMap = .{}; | 21378 | var names: InferredErrorSet.NameMap = .{}; |
| 21370 | try names.ensureUnusedCapacity(sema.arena, len); | 21379 | try names.ensureUnusedCapacity(sema.arena, len); |
| 21371 | for (0..len) |i| { | 21380 | for (0..len) |i| { |
| 21372 | const elem_val = (try payload_val.maybeElemValueFull(sema, mod, i)).?; | 21381 | const elem_val = try names_val.elemValue(mod, i); |
| 21373 | const elem_struct_type = ip.loadStructType(ip.typeOf(elem_val.toIntern())); | 21382 | const elem_struct_type = ip.loadStructType(ip.typeOf(elem_val.toIntern())); |
| 21374 | const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex( | 21383 | const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex( |
| 21375 | ip, | 21384 | ip, |
| ... | @@ -21417,7 +21426,7 @@ fn zirReify( | ... | @@ -21417,7 +21426,7 @@ fn zirReify( |
| 21417 | const layout = mod.toEnum(std.builtin.Type.ContainerLayout, layout_val); | 21426 | const layout = mod.toEnum(std.builtin.Type.ContainerLayout, layout_val); |
| 21418 | 21427 | ||
| 21419 | // Decls | 21428 | // Decls |
| 21420 | if (decls_val.sliceLen(mod) > 0) { | 21429 | if (try decls_val.sliceLen(sema) > 0) { |
| 21421 | return sema.fail(block, src, "reified structs must have no decls", .{}); | 21430 | return sema.fail(block, src, "reified structs must have no decls", .{}); |
| 21422 | } | 21431 | } |
| 21423 | 21432 | ||
| ... | @@ -21425,7 +21434,11 @@ fn zirReify( | ... | @@ -21425,7 +21434,11 @@ fn zirReify( |
| 21425 | return sema.fail(block, src, "non-packed struct does not support backing integer type", .{}); | 21434 | return sema.fail(block, src, "non-packed struct does not support backing integer type", .{}); |
| 21426 | } | 21435 | } |
| 21427 | 21436 | ||
| 21428 | return try sema.reifyStruct(block, inst, src, layout, backing_integer_val, fields_val, name_strategy, is_tuple_val.toBool()); | 21437 | const fields_arr = try sema.derefSliceAsArray(block, operand_src, fields_val, .{ |
| 21438 | .needed_comptime_reason = "struct fields must be comptime-known", | ||
| 21439 | }); | ||
| 21440 | |||
| 21441 | return try sema.reifyStruct(block, inst, src, layout, backing_integer_val, fields_arr, name_strategy, is_tuple_val.toBool()); | ||
| 21429 | }, | 21442 | }, |
| 21430 | .Enum => { | 21443 | .Enum => { |
| 21431 | const struct_type = ip.loadStructType(ip.typeOf(union_val.val)); | 21444 | const struct_type = ip.loadStructType(ip.typeOf(union_val.val)); |
| ... | @@ -21446,11 +21459,15 @@ fn zirReify( | ... | @@ -21446,11 +21459,15 @@ fn zirReify( |
| 21446 | try ip.getOrPutString(gpa, "is_exhaustive"), | 21459 | try ip.getOrPutString(gpa, "is_exhaustive"), |
| 21447 | ).?); | 21460 | ).?); |
| 21448 | 21461 | ||
| 21449 | if (decls_val.sliceLen(mod) > 0) { | 21462 | if (try decls_val.sliceLen(sema) > 0) { |
| 21450 | return sema.fail(block, src, "reified enums must have no decls", .{}); | 21463 | return sema.fail(block, src, "reified enums must have no decls", .{}); |
| 21451 | } | 21464 | } |
| 21452 | 21465 | ||
| 21453 | return sema.reifyEnum(block, inst, src, tag_type_val.toType(), is_exhaustive_val.toBool(), fields_val, name_strategy); | 21466 | const fields_arr = try sema.derefSliceAsArray(block, operand_src, fields_val, .{ |
| 21467 | .needed_comptime_reason = "enum fields must be comptime-known", | ||
| 21468 | }); | ||
| 21469 | |||
| 21470 | return sema.reifyEnum(block, inst, src, tag_type_val.toType(), is_exhaustive_val.toBool(), fields_arr, name_strategy); | ||
| 21454 | }, | 21471 | }, |
| 21455 | .Opaque => { | 21472 | .Opaque => { |
| 21456 | const struct_type = ip.loadStructType(ip.typeOf(union_val.val)); | 21473 | const struct_type = ip.loadStructType(ip.typeOf(union_val.val)); |
| ... | @@ -21460,7 +21477,7 @@ fn zirReify( | ... | @@ -21460,7 +21477,7 @@ fn zirReify( |
| 21460 | ).?); | 21477 | ).?); |
| 21461 | 21478 | ||
| 21462 | // Decls | 21479 | // Decls |
| 21463 | if (decls_val.sliceLen(mod) > 0) { | 21480 | if (try decls_val.sliceLen(sema) > 0) { |
| 21464 | return sema.fail(block, src, "reified opaque must have no decls", .{}); | 21481 | return sema.fail(block, src, "reified opaque must have no decls", .{}); |
| 21465 | } | 21482 | } |
| 21466 | 21483 | ||
| ... | @@ -21505,12 +21522,16 @@ fn zirReify( | ... | @@ -21505,12 +21522,16 @@ fn zirReify( |
| 21505 | try ip.getOrPutString(gpa, "decls"), | 21522 | try ip.getOrPutString(gpa, "decls"), |
| 21506 | ).?); | 21523 | ).?); |
| 21507 | 21524 | ||
| 21508 | if (decls_val.sliceLen(mod) > 0) { | 21525 | if (try decls_val.sliceLen(sema) > 0) { |
| 21509 | return sema.fail(block, src, "reified unions must have no decls", .{}); | 21526 | return sema.fail(block, src, "reified unions must have no decls", .{}); |
| 21510 | } | 21527 | } |
| 21511 | const layout = mod.toEnum(std.builtin.Type.ContainerLayout, layout_val); | 21528 | const layout = mod.toEnum(std.builtin.Type.ContainerLayout, layout_val); |
| 21512 | 21529 | ||
| 21513 | return sema.reifyUnion(block, inst, src, layout, tag_type_val, fields_val, name_strategy); | 21530 | const fields_arr = try sema.derefSliceAsArray(block, operand_src, fields_val, .{ |
| 21531 | .needed_comptime_reason = "union fields must be comptime-known", | ||
| 21532 | }); | ||
| 21533 | |||
| 21534 | return sema.reifyUnion(block, inst, src, layout, tag_type_val, fields_arr, name_strategy); | ||
| 21514 | }, | 21535 | }, |
| 21515 | .Fn => { | 21536 | .Fn => { |
| 21516 | const struct_type = ip.loadStructType(ip.typeOf(union_val.val)); | 21537 | const struct_type = ip.loadStructType(ip.typeOf(union_val.val)); |
| ... | @@ -21530,7 +21551,7 @@ fn zirReify( | ... | @@ -21530,7 +21551,7 @@ fn zirReify( |
| 21530 | ip, | 21551 | ip, |
| 21531 | try ip.getOrPutString(gpa, "return_type"), | 21552 | try ip.getOrPutString(gpa, "return_type"), |
| 21532 | ).?); | 21553 | ).?); |
| 21533 | const params_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex( | 21554 | const params_slice_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex( |
| 21534 | ip, | 21555 | ip, |
| 21535 | try ip.getOrPutString(gpa, "params"), | 21556 | try ip.getOrPutString(gpa, "params"), |
| 21536 | ).?); | 21557 | ).?); |
| ... | @@ -21549,12 +21570,16 @@ fn zirReify( | ... | @@ -21549,12 +21570,16 @@ fn zirReify( |
| 21549 | const return_type = return_type_val.optionalValue(mod) orelse | 21570 | const return_type = return_type_val.optionalValue(mod) orelse |
| 21550 | return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{}); | 21571 | return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{}); |
| 21551 | 21572 | ||
| 21552 | const args_len = try sema.usizeCast(block, src, params_val.sliceLen(mod)); | 21573 | const params_val = try sema.derefSliceAsArray(block, operand_src, params_slice_val, .{ |
| 21574 | .needed_comptime_reason = "function parameters must be comptime-known", | ||
| 21575 | }); | ||
| 21576 | |||
| 21577 | const args_len = try sema.usizeCast(block, src, params_val.typeOf(mod).arrayLen(mod)); | ||
| 21553 | const param_types = try sema.arena.alloc(InternPool.Index, args_len); | 21578 | const param_types = try sema.arena.alloc(InternPool.Index, args_len); |
| 21554 | 21579 | ||
| 21555 | var noalias_bits: u32 = 0; | 21580 | var noalias_bits: u32 = 0; |
| 21556 | for (param_types, 0..) |*param_type, i| { | 21581 | for (param_types, 0..) |*param_type, i| { |
| 21557 | const elem_val = (try params_val.maybeElemValueFull(sema, mod, i)).?; | 21582 | const elem_val = try params_val.elemValue(mod, i); |
| 21558 | const elem_struct_type = ip.loadStructType(ip.typeOf(elem_val.toIntern())); | 21583 | const elem_struct_type = ip.loadStructType(ip.typeOf(elem_val.toIntern())); |
| 21559 | const param_is_generic_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex( | 21584 | const param_is_generic_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex( |
| 21560 | ip, | 21585 | ip, |
| ... | @@ -21615,7 +21640,7 @@ fn reifyEnum( | ... | @@ -21615,7 +21640,7 @@ fn reifyEnum( |
| 21615 | 21640 | ||
| 21616 | // This logic must stay in sync with the structure of `std.builtin.Type.Enum` - search for `fieldValue`. | 21641 | // This logic must stay in sync with the structure of `std.builtin.Type.Enum` - search for `fieldValue`. |
| 21617 | 21642 | ||
| 21618 | const fields_len: u32 = @intCast(fields_val.sliceLen(mod)); | 21643 | const fields_len: u32 = @intCast(fields_val.typeOf(mod).arrayLen(mod)); |
| 21619 | 21644 | ||
| 21620 | // The validation work here is non-trivial, and it's possible the type already exists. | 21645 | // The validation work here is non-trivial, and it's possible the type already exists. |
| 21621 | // So in this first pass, let's just construct a hash to optimize for this case. If the | 21646 | // So in this first pass, let's just construct a hash to optimize for this case. If the |
| ... | @@ -21629,7 +21654,7 @@ fn reifyEnum( | ... | @@ -21629,7 +21654,7 @@ fn reifyEnum( |
| 21629 | std.hash.autoHash(&hasher, fields_len); | 21654 | std.hash.autoHash(&hasher, fields_len); |
| 21630 | 21655 | ||
| 21631 | for (0..fields_len) |field_idx| { | 21656 | for (0..fields_len) |field_idx| { |
| 21632 | const field_info = (try fields_val.maybeElemValueFull(sema, mod, field_idx)).?; | 21657 | const field_info = try fields_val.elemValue(mod, field_idx); |
| 21633 | 21658 | ||
| 21634 | const field_name_val = try field_info.fieldValue(mod, 0); | 21659 | const field_name_val = try field_info.fieldValue(mod, 0); |
| 21635 | const field_value_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 1)); | 21660 | const field_value_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 1)); |
| ... | @@ -21674,7 +21699,7 @@ fn reifyEnum( | ... | @@ -21674,7 +21699,7 @@ fn reifyEnum( |
| 21674 | wip_ty.setTagTy(ip, tag_ty.toIntern()); | 21699 | wip_ty.setTagTy(ip, tag_ty.toIntern()); |
| 21675 | 21700 | ||
| 21676 | for (0..fields_len) |field_idx| { | 21701 | for (0..fields_len) |field_idx| { |
| 21677 | const field_info = (try fields_val.maybeElemValueFull(sema, mod, field_idx)).?; | 21702 | const field_info = try fields_val.elemValue(mod, field_idx); |
| 21678 | 21703 | ||
| 21679 | const field_name_val = try field_info.fieldValue(mod, 0); | 21704 | const field_name_val = try field_info.fieldValue(mod, 0); |
| 21680 | const field_value_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 1)); | 21705 | const field_value_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 1)); |
| ... | @@ -21736,7 +21761,7 @@ fn reifyUnion( | ... | @@ -21736,7 +21761,7 @@ fn reifyUnion( |
| 21736 | 21761 | ||
| 21737 | // This logic must stay in sync with the structure of `std.builtin.Type.Union` - search for `fieldValue`. | 21762 | // This logic must stay in sync with the structure of `std.builtin.Type.Union` - search for `fieldValue`. |
| 21738 | 21763 | ||
| 21739 | const fields_len: u32 = @intCast(fields_val.sliceLen(mod)); | 21764 | const fields_len: u32 = @intCast(fields_val.typeOf(mod).arrayLen(mod)); |
| 21740 | 21765 | ||
| 21741 | // The validation work here is non-trivial, and it's possible the type already exists. | 21766 | // The validation work here is non-trivial, and it's possible the type already exists. |
| 21742 | // So in this first pass, let's just construct a hash to optimize for this case. If the | 21767 | // So in this first pass, let's just construct a hash to optimize for this case. If the |
| ... | @@ -21752,7 +21777,7 @@ fn reifyUnion( | ... | @@ -21752,7 +21777,7 @@ fn reifyUnion( |
| 21752 | var any_aligns = false; | 21777 | var any_aligns = false; |
| 21753 | 21778 | ||
| 21754 | for (0..fields_len) |field_idx| { | 21779 | for (0..fields_len) |field_idx| { |
| 21755 | const field_info = (try fields_val.maybeElemValueFull(sema, mod, field_idx)).?; | 21780 | const field_info = try fields_val.elemValue(mod, field_idx); |
| 21756 | 21781 | ||
| 21757 | const field_name_val = try field_info.fieldValue(mod, 0); | 21782 | const field_name_val = try field_info.fieldValue(mod, 0); |
| 21758 | const field_type_val = try field_info.fieldValue(mod, 1); | 21783 | const field_type_val = try field_info.fieldValue(mod, 1); |
| ... | @@ -21828,7 +21853,7 @@ fn reifyUnion( | ... | @@ -21828,7 +21853,7 @@ fn reifyUnion( |
| 21828 | var seen_tags = try std.DynamicBitSetUnmanaged.initEmpty(sema.arena, tag_ty_fields_len); | 21853 | var seen_tags = try std.DynamicBitSetUnmanaged.initEmpty(sema.arena, tag_ty_fields_len); |
| 21829 | 21854 | ||
| 21830 | for (field_types, 0..) |*field_ty, field_idx| { | 21855 | for (field_types, 0..) |*field_ty, field_idx| { |
| 21831 | const field_info = (try fields_val.maybeElemValueFull(sema, mod, field_idx)).?; | 21856 | const field_info = try fields_val.elemValue(mod, field_idx); |
| 21832 | 21857 | ||
| 21833 | const field_name_val = try field_info.fieldValue(mod, 0); | 21858 | const field_name_val = try field_info.fieldValue(mod, 0); |
| 21834 | const field_type_val = try field_info.fieldValue(mod, 1); | 21859 | const field_type_val = try field_info.fieldValue(mod, 1); |
| ... | @@ -21880,7 +21905,7 @@ fn reifyUnion( | ... | @@ -21880,7 +21905,7 @@ fn reifyUnion( |
| 21880 | try field_names.ensureTotalCapacity(sema.arena, fields_len); | 21905 | try field_names.ensureTotalCapacity(sema.arena, fields_len); |
| 21881 | 21906 | ||
| 21882 | for (field_types, 0..) |*field_ty, field_idx| { | 21907 | for (field_types, 0..) |*field_ty, field_idx| { |
| 21883 | const field_info = (try fields_val.maybeElemValueFull(sema, mod, field_idx)).?; | 21908 | const field_info = try fields_val.elemValue(mod, field_idx); |
| 21884 | 21909 | ||
| 21885 | const field_name_val = try field_info.fieldValue(mod, 0); | 21910 | const field_name_val = try field_info.fieldValue(mod, 0); |
| 21886 | const field_type_val = try field_info.fieldValue(mod, 1); | 21911 | const field_type_val = try field_info.fieldValue(mod, 1); |
| ... | @@ -21974,7 +21999,7 @@ fn reifyStruct( | ... | @@ -21974,7 +21999,7 @@ fn reifyStruct( |
| 21974 | 21999 | ||
| 21975 | // This logic must stay in sync with the structure of `std.builtin.Type.Struct` - search for `fieldValue`. | 22000 | // This logic must stay in sync with the structure of `std.builtin.Type.Struct` - search for `fieldValue`. |
| 21976 | 22001 | ||
| 21977 | const fields_len: u32 = @intCast(fields_val.sliceLen(mod)); | 22002 | const fields_len: u32 = @intCast(fields_val.typeOf(mod).arrayLen(mod)); |
| 21978 | 22003 | ||
| 21979 | // The validation work here is non-trivial, and it's possible the type already exists. | 22004 | // The validation work here is non-trivial, and it's possible the type already exists. |
| 21980 | // So in this first pass, let's just construct a hash to optimize for this case. If the | 22005 | // So in this first pass, let's just construct a hash to optimize for this case. If the |
| ... | @@ -21993,7 +22018,7 @@ fn reifyStruct( | ... | @@ -21993,7 +22018,7 @@ fn reifyStruct( |
| 21993 | var any_aligned_fields = false; | 22018 | var any_aligned_fields = false; |
| 21994 | 22019 | ||
| 21995 | for (0..fields_len) |field_idx| { | 22020 | for (0..fields_len) |field_idx| { |
| 21996 | const field_info = (try fields_val.maybeElemValueFull(sema, mod, field_idx)).?; | 22021 | const field_info = try fields_val.elemValue(mod, field_idx); |
| 21997 | 22022 | ||
| 21998 | const field_name_val = try field_info.fieldValue(mod, 0); | 22023 | const field_name_val = try field_info.fieldValue(mod, 0); |
| 21999 | const field_type_val = try field_info.fieldValue(mod, 1); | 22024 | const field_type_val = try field_info.fieldValue(mod, 1); |
| ... | @@ -22071,7 +22096,7 @@ fn reifyStruct( | ... | @@ -22071,7 +22096,7 @@ fn reifyStruct( |
| 22071 | const struct_type = ip.loadStructType(wip_ty.index); | 22096 | const struct_type = ip.loadStructType(wip_ty.index); |
| 22072 | 22097 | ||
| 22073 | for (0..fields_len) |field_idx| { | 22098 | for (0..fields_len) |field_idx| { |
| 22074 | const field_info = (try fields_val.maybeElemValueFull(sema, mod, field_idx)).?; | 22099 | const field_info = try fields_val.elemValue(mod, field_idx); |
| 22075 | 22100 | ||
| 22076 | const field_name_val = try field_info.fieldValue(mod, 0); | 22101 | const field_name_val = try field_info.fieldValue(mod, 0); |
| 22077 | const field_type_val = try field_info.fieldValue(mod, 1); | 22102 | const field_type_val = try field_info.fieldValue(mod, 1); |
| ... | @@ -23892,11 +23917,9 @@ fn resolveExportOptions( | ... | @@ -23892,11 +23917,9 @@ fn resolveExportOptions( |
| 23892 | const visibility_src = sema.maybeOptionsSrc(block, src, "visibility"); | 23917 | const visibility_src = sema.maybeOptionsSrc(block, src, "visibility"); |
| 23893 | 23918 | ||
| 23894 | const name_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "name"), name_src); | 23919 | const name_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "name"), name_src); |
| 23895 | const name_val = try sema.resolveConstDefinedValue(block, name_src, name_operand, .{ | 23920 | const name = try sema.toConstString(block, name_src, name_operand, .{ |
| 23896 | .needed_comptime_reason = "name of exported value must be comptime-known", | 23921 | .needed_comptime_reason = "name of exported value must be comptime-known", |
| 23897 | }); | 23922 | }); |
| 23898 | const name_ty = Type.slice_const_u8; | ||
| 23899 | const name = try name_val.toAllocatedBytes(name_ty, sema.arena, mod); | ||
| 23900 | 23923 | ||
| 23901 | const linkage_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "linkage"), linkage_src); | 23924 | const linkage_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "linkage"), linkage_src); |
| 23902 | const linkage_val = try sema.resolveConstDefinedValue(block, linkage_src, linkage_operand, .{ | 23925 | const linkage_val = try sema.resolveConstDefinedValue(block, linkage_src, linkage_operand, .{ |
| ... | @@ -23908,9 +23931,10 @@ fn resolveExportOptions( | ... | @@ -23908,9 +23931,10 @@ fn resolveExportOptions( |
| 23908 | const section_opt_val = try sema.resolveConstDefinedValue(block, section_src, section_operand, .{ | 23931 | const section_opt_val = try sema.resolveConstDefinedValue(block, section_src, section_operand, .{ |
| 23909 | .needed_comptime_reason = "linksection of exported value must be comptime-known", | 23932 | .needed_comptime_reason = "linksection of exported value must be comptime-known", |
| 23910 | }); | 23933 | }); |
| 23911 | const section_ty = Type.slice_const_u8; | ||
| 23912 | const section = if (section_opt_val.optionalValue(mod)) |section_val| | 23934 | const section = if (section_opt_val.optionalValue(mod)) |section_val| |
| 23913 | try section_val.toAllocatedBytes(section_ty, sema.arena, mod) | 23935 | try sema.toConstString(block, section_src, Air.internedToRef(section_val.toIntern()), .{ |
| 23936 | .needed_comptime_reason = "linksection of exported value must be comptime-known", | ||
| 23937 | }) | ||
| 23914 | else | 23938 | else |
| 23915 | null; | 23939 | null; |
| 23916 | 23940 | ||
| ... | @@ -26028,10 +26052,9 @@ fn resolveExternOptions( | ... | @@ -26028,10 +26052,9 @@ fn resolveExternOptions( |
| 26028 | const thread_local_src = sema.maybeOptionsSrc(block, src, "thread_local"); | 26052 | const thread_local_src = sema.maybeOptionsSrc(block, src, "thread_local"); |
| 26029 | 26053 | ||
| 26030 | const name_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "name"), name_src); | 26054 | const name_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "name"), name_src); |
| 26031 | const name_val = try sema.resolveConstDefinedValue(block, name_src, name_ref, .{ | 26055 | const name = try sema.toConstString(block, name_src, name_ref, .{ |
| 26032 | .needed_comptime_reason = "name of the extern symbol must be comptime-known", | 26056 | .needed_comptime_reason = "name of the extern symbol must be comptime-known", |
| 26033 | }); | 26057 | }); |
| 26034 | const name = try name_val.toAllocatedBytes(Type.slice_const_u8, sema.arena, mod); | ||
| 26035 | 26058 | ||
| 26036 | const library_name_inst = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "library_name"), library_src); | 26059 | const library_name_inst = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "library_name"), library_src); |
| 26037 | const library_name_val = try sema.resolveConstDefinedValue(block, library_src, library_name_inst, .{ | 26060 | const library_name_val = try sema.resolveConstDefinedValue(block, library_src, library_name_inst, .{ |
| ... | @@ -26050,7 +26073,9 @@ fn resolveExternOptions( | ... | @@ -26050,7 +26073,9 @@ fn resolveExternOptions( |
| 26050 | }); | 26073 | }); |
| 26051 | 26074 | ||
| 26052 | const library_name = if (library_name_val.optionalValue(mod)) |library_name_payload| library_name: { | 26075 | const library_name = if (library_name_val.optionalValue(mod)) |library_name_payload| library_name: { |
| 26053 | const library_name = try library_name_payload.toAllocatedBytes(Type.slice_const_u8, sema.arena, mod); | 26076 | const library_name = try sema.toConstString(block, library_src, Air.internedToRef(library_name_payload.toIntern()), .{ |
| 26077 | .needed_comptime_reason = "library in which extern symbol is must be comptime-known", | ||
| 26078 | }); | ||
| 26054 | if (library_name.len == 0) { | 26079 | if (library_name.len == 0) { |
| 26055 | return sema.fail(block, library_src, "library name cannot be empty", .{}); | 26080 | return sema.fail(block, library_src, "library name cannot be empty", .{}); |
| 26056 | } | 26081 | } |
| ... | @@ -28564,7 +28589,7 @@ fn elemValSlice( | ... | @@ -28564,7 +28589,7 @@ fn elemValSlice( |
| 28564 | 28589 | ||
| 28565 | if (maybe_slice_val) |slice_val| { | 28590 | if (maybe_slice_val) |slice_val| { |
| 28566 | runtime_src = elem_index_src; | 28591 | runtime_src = elem_index_src; |
| 28567 | const slice_len = slice_val.sliceLen(mod); | 28592 | const slice_len = try slice_val.sliceLen(sema); |
| 28568 | const slice_len_s = slice_len + @intFromBool(slice_sent); | 28593 | const slice_len_s = slice_len + @intFromBool(slice_sent); |
| 28569 | if (slice_len_s == 0) { | 28594 | if (slice_len_s == 0) { |
| 28570 | return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{}); | 28595 | return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{}); |
| ... | @@ -28589,7 +28614,7 @@ fn elemValSlice( | ... | @@ -28589,7 +28614,7 @@ fn elemValSlice( |
| 28589 | try sema.requireRuntimeBlock(block, src, runtime_src); | 28614 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| 28590 | if (oob_safety and block.wantSafety()) { | 28615 | if (oob_safety and block.wantSafety()) { |
| 28591 | const len_inst = if (maybe_slice_val) |slice_val| | 28616 | const len_inst = if (maybe_slice_val) |slice_val| |
| 28592 | try mod.intRef(Type.usize, slice_val.sliceLen(mod)) | 28617 | try mod.intRef(Type.usize, try slice_val.sliceLen(sema)) |
| 28593 | else | 28618 | else |
| 28594 | try block.addTyOp(.slice_len, Type.usize, slice); | 28619 | try block.addTyOp(.slice_len, Type.usize, slice); |
| 28595 | const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt; | 28620 | const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt; |
| ... | @@ -28626,7 +28651,7 @@ fn elemPtrSlice( | ... | @@ -28626,7 +28651,7 @@ fn elemPtrSlice( |
| 28626 | if (slice_val.isUndef(mod)) { | 28651 | if (slice_val.isUndef(mod)) { |
| 28627 | return mod.undefRef(elem_ptr_ty); | 28652 | return mod.undefRef(elem_ptr_ty); |
| 28628 | } | 28653 | } |
| 28629 | const slice_len = slice_val.sliceLen(mod); | 28654 | const slice_len = try slice_val.sliceLen(sema); |
| 28630 | const slice_len_s = slice_len + @intFromBool(slice_sent); | 28655 | const slice_len_s = slice_len + @intFromBool(slice_sent); |
| 28631 | if (slice_len_s == 0) { | 28656 | if (slice_len_s == 0) { |
| 28632 | return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{}); | 28657 | return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{}); |
| ... | @@ -28649,7 +28674,7 @@ fn elemPtrSlice( | ... | @@ -28649,7 +28674,7 @@ fn elemPtrSlice( |
| 28649 | const len_inst = len: { | 28674 | const len_inst = len: { |
| 28650 | if (maybe_undef_slice_val) |slice_val| | 28675 | if (maybe_undef_slice_val) |slice_val| |
| 28651 | if (!slice_val.isUndef(mod)) | 28676 | if (!slice_val.isUndef(mod)) |
| 28652 | break :len try mod.intRef(Type.usize, slice_val.sliceLen(mod)); | 28677 | break :len try mod.intRef(Type.usize, try slice_val.sliceLen(sema)); |
| 28653 | break :len try block.addTyOp(.slice_len, Type.usize, slice); | 28678 | break :len try block.addTyOp(.slice_len, Type.usize, slice); |
| 28654 | }; | 28679 | }; |
| 28655 | const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt; | 28680 | const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt; |
| ... | @@ -31523,16 +31548,11 @@ fn coerceArrayPtrToSlice( | ... | @@ -31523,16 +31548,11 @@ fn coerceArrayPtrToSlice( |
| 31523 | if (try sema.resolveValue(inst)) |val| { | 31548 | if (try sema.resolveValue(inst)) |val| { |
| 31524 | const ptr_array_ty = sema.typeOf(inst); | 31549 | const ptr_array_ty = sema.typeOf(inst); |
| 31525 | const array_ty = ptr_array_ty.childType(mod); | 31550 | const array_ty = ptr_array_ty.childType(mod); |
| 31551 | const slice_ptr_ty = dest_ty.slicePtrFieldType(mod); | ||
| 31552 | const slice_ptr = try mod.getCoerced(val, slice_ptr_ty); | ||
| 31526 | const slice_val = try mod.intern(.{ .slice = .{ | 31553 | const slice_val = try mod.intern(.{ .slice = .{ |
| 31527 | .ty = dest_ty.toIntern(), | 31554 | .ty = dest_ty.toIntern(), |
| 31528 | .ptr = try mod.intern(.{ .ptr = .{ | 31555 | .ptr = slice_ptr.toIntern(), |
| 31529 | .ty = dest_ty.slicePtrFieldType(mod).toIntern(), | ||
| 31530 | .addr = switch (mod.intern_pool.indexToKey(val.toIntern())) { | ||
| 31531 | .undef => .{ .int = try mod.intern(.{ .undef = .usize_type }) }, | ||
| 31532 | .ptr => |ptr| ptr.addr, | ||
| 31533 | else => unreachable, | ||
| 31534 | }, | ||
| 31535 | } }), | ||
| 31536 | .len = (try mod.intValue(Type.usize, array_ty.arrayLen(mod))).toIntern(), | 31556 | .len = (try mod.intValue(Type.usize, array_ty.arrayLen(mod))).toIntern(), |
| 31537 | } }); | 31557 | } }); |
| 31538 | return Air.internedToRef(slice_val); | 31558 | return Air.internedToRef(slice_val); |
| ... | @@ -32602,7 +32622,7 @@ fn analyzeSliceLen( | ... | @@ -32602,7 +32622,7 @@ fn analyzeSliceLen( |
| 32602 | if (slice_val.isUndef(mod)) { | 32622 | if (slice_val.isUndef(mod)) { |
| 32603 | return mod.undefRef(Type.usize); | 32623 | return mod.undefRef(Type.usize); |
| 32604 | } | 32624 | } |
| 32605 | return mod.intRef(Type.usize, slice_val.sliceLen(sema.mod)); | 32625 | return mod.intRef(Type.usize, try slice_val.sliceLen(sema)); |
| 32606 | } | 32626 | } |
| 32607 | try sema.requireRuntimeBlock(block, src, null); | 32627 | try sema.requireRuntimeBlock(block, src, null); |
| 32608 | return block.addTyOp(.slice_len, Type.usize, slice_inst); | 32628 | return block.addTyOp(.slice_len, Type.usize, slice_inst); |
| ... | @@ -33041,7 +33061,7 @@ fn analyzeSlice( | ... | @@ -33041,7 +33061,7 @@ fn analyzeSlice( |
| 33041 | return sema.fail(block, src, "slice of undefined", .{}); | 33061 | return sema.fail(block, src, "slice of undefined", .{}); |
| 33042 | } | 33062 | } |
| 33043 | const has_sentinel = slice_ty.sentinel(mod) != null; | 33063 | const has_sentinel = slice_ty.sentinel(mod) != null; |
| 33044 | const slice_len = slice_val.sliceLen(mod); | 33064 | const slice_len = try slice_val.sliceLen(sema); |
| 33045 | const len_plus_sent = slice_len + @intFromBool(has_sentinel); | 33065 | const len_plus_sent = slice_len + @intFromBool(has_sentinel); |
| 33046 | const slice_len_val_with_sentinel = try mod.intValue(Type.usize, len_plus_sent); | 33066 | const slice_len_val_with_sentinel = try mod.intValue(Type.usize, len_plus_sent); |
| 33047 | if (!(try sema.compareAll(end_val, .lte, slice_len_val_with_sentinel, Type.usize))) { | 33067 | if (!(try sema.compareAll(end_val, .lte, slice_len_val_with_sentinel, Type.usize))) { |
| ... | @@ -33056,7 +33076,7 @@ fn analyzeSlice( | ... | @@ -33056,7 +33076,7 @@ fn analyzeSlice( |
| 33056 | "end index {} out of bounds for slice of length {d}{s}", | 33076 | "end index {} out of bounds for slice of length {d}{s}", |
| 33057 | .{ | 33077 | .{ |
| 33058 | end_val.fmtValue(Type.usize, mod), | 33078 | end_val.fmtValue(Type.usize, mod), |
| 33059 | slice_val.sliceLen(mod), | 33079 | try slice_val.sliceLen(sema), |
| 33060 | sentinel_label, | 33080 | sentinel_label, |
| 33061 | }, | 33081 | }, |
| 33062 | ); | 33082 | ); |
| ... | @@ -33285,7 +33305,7 @@ fn analyzeSlice( | ... | @@ -33285,7 +33305,7 @@ fn analyzeSlice( |
| 33285 | if (try sema.resolveDefinedValue(block, src, ptr_or_slice)) |slice_val| { | 33305 | if (try sema.resolveDefinedValue(block, src, ptr_or_slice)) |slice_val| { |
| 33286 | // we don't need to add one for sentinels because the | 33306 | // we don't need to add one for sentinels because the |
| 33287 | // underlying value data includes the sentinel | 33307 | // underlying value data includes the sentinel |
| 33288 | break :blk try mod.intRef(Type.usize, slice_val.sliceLen(mod)); | 33308 | break :blk try mod.intRef(Type.usize, try slice_val.sliceLen(sema)); |
| 33289 | } | 33309 | } |
| 33290 | 33310 | ||
| 33291 | const slice_len_inst = try block.addTyOp(.slice_len, Type.usize, ptr_or_slice); | 33311 | const slice_len_inst = try block.addTyOp(.slice_len, Type.usize, ptr_or_slice); |
| ... | @@ -39003,22 +39023,22 @@ fn validateRuntimeValue(sema: *Sema, block: *Block, val_src: LazySrcLoc, val: Ai | ... | @@ -39003,22 +39023,22 @@ fn validateRuntimeValue(sema: *Sema, block: *Block, val_src: LazySrcLoc, val: Ai |
| 39003 | } | 39023 | } |
| 39004 | 39024 | ||
| 39005 | /// Returns true if any value contained in `val` is undefined. | 39025 | /// Returns true if any value contained in `val` is undefined. |
| 39006 | fn anyUndef(sema: *Sema, val: Value) !bool { | 39026 | fn anyUndef(sema: *Sema, block: *Block, src: LazySrcLoc, val: Value) !bool { |
| 39007 | const mod = sema.mod; | 39027 | const mod = sema.mod; |
| 39008 | return switch (val.toIntern()) { | 39028 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 39009 | .undef => true, | 39029 | .undef => true, |
| 39010 | else => switch (mod.intern_pool.indexToKey(val.toIntern())) { | 39030 | .simple_value => |v| v == .undefined, |
| 39011 | .undef => true, | 39031 | .slice => { |
| 39012 | .simple_value => |v| v == .undefined, | 39032 | // If the slice contents are runtime-known, reification will fail later on with a |
| 39013 | .slice => |slice| for (0..@intCast(Value.fromInterned(slice.len).toUnsignedInt(mod))) |idx| { | 39033 | // specific error message. |
| 39014 | if (try sema.anyUndef((try val.maybeElemValueFull(sema, mod, idx)).?)) break true; | 39034 | const arr = try sema.maybeDerefSliceAsArray(block, src, val) orelse return false; |
| 39015 | } else false, | 39035 | return sema.anyUndef(block, src, arr); |
| 39016 | .aggregate => |aggregate| for (0..aggregate.storage.values().len) |i| { | 39036 | }, |
| 39017 | const elem = mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.values()[i]; | 39037 | .aggregate => |aggregate| for (0..aggregate.storage.values().len) |i| { |
| 39018 | if (try sema.anyUndef(Value.fromInterned(elem))) break true; | 39038 | const elem = mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.values()[i]; |
| 39019 | } else false, | 39039 | if (try sema.anyUndef(block, src, Value.fromInterned(elem))) break true; |
| 39020 | else => false, | 39040 | } else false, |
| 39021 | }, | 39041 | else => false, |
| 39022 | }; | 39042 | }; |
| 39023 | } | 39043 | } |
| 39024 | 39044 | ||
| ... | @@ -39050,6 +39070,20 @@ fn derefSliceAsArray( | ... | @@ -39050,6 +39070,20 @@ fn derefSliceAsArray( |
| 39050 | slice_val: Value, | 39070 | slice_val: Value, |
| 39051 | reason: NeededComptimeReason, | 39071 | reason: NeededComptimeReason, |
| 39052 | ) CompileError!Value { | 39072 | ) CompileError!Value { |
| 39073 | return try sema.maybeDerefSliceAsArray(block, src, slice_val) orelse { | ||
| 39074 | return sema.failWithNeededComptime(block, src, reason); | ||
| 39075 | }; | ||
| 39076 | } | ||
| 39077 | |||
| 39078 | /// Given a slice value, attempts to dereference it into a comptime-known array. | ||
| 39079 | /// Returns `null` if the contents of the slice are not comptime-known. | ||
| 39080 | /// Asserts that `slice_val` is a slice. | ||
| 39081 | fn maybeDerefSliceAsArray( | ||
| 39082 | sema: *Sema, | ||
| 39083 | block: *Block, | ||
| 39084 | src: LazySrcLoc, | ||
| 39085 | slice_val: Value, | ||
| 39086 | ) CompileError!?Value { | ||
| 39053 | const zcu = sema.mod; | 39087 | const zcu = sema.mod; |
| 39054 | const ip = &zcu.intern_pool; | 39088 | const ip = &zcu.intern_pool; |
| 39055 | assert(Type.fromInterned(ip.typeOf(slice_val.toIntern())).isSlice(zcu)); | 39089 | assert(Type.fromInterned(ip.typeOf(slice_val.toIntern())).isSlice(zcu)); |
| ... | @@ -39072,7 +39106,5 @@ fn derefSliceAsArray( | ... | @@ -39072,7 +39106,5 @@ fn derefSliceAsArray( |
| 39072 | break :p p; | 39106 | break :p p; |
| 39073 | }); | 39107 | }); |
| 39074 | const casted_ptr = try zcu.getCoerced(Value.fromInterned(slice.ptr), ptr_ty); | 39108 | const casted_ptr = try zcu.getCoerced(Value.fromInterned(slice.ptr), ptr_ty); |
| 39075 | return try sema.pointerDeref(block, src, casted_ptr, ptr_ty) orelse { | 39109 | return sema.pointerDeref(block, src, casted_ptr, ptr_ty); |
| 39076 | return sema.failWithNeededComptime(block, src, reason); | ||
| 39077 | }; | ||
| 39078 | } | 39110 | } |
src/TypedValue.zig+250-270| ... | @@ -1,7 +1,10 @@ | ... | @@ -1,7 +1,10 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const Type = @import("type.zig").Type; | 2 | const Type = @import("type.zig").Type; |
| 3 | const Value = @import("Value.zig"); | 3 | const Value = @import("Value.zig"); |
| 4 | const Module = @import("Module.zig"); | 4 | const Zcu = @import("Module.zig"); |
| 5 | const Module = Zcu; | ||
| 6 | const Sema = @import("Sema.zig"); | ||
| 7 | const InternPool = @import("InternPool.zig"); | ||
| 5 | const Allocator = std.mem.Allocator; | 8 | const Allocator = std.mem.Allocator; |
| 6 | const TypedValue = @This(); | 9 | const TypedValue = @This(); |
| 7 | const Target = std.Target; | 10 | const Target = std.Target; |
| ... | @@ -61,8 +64,10 @@ pub fn format( | ... | @@ -61,8 +64,10 @@ pub fn format( |
| 61 | ) !void { | 64 | ) !void { |
| 62 | _ = options; | 65 | _ = options; |
| 63 | comptime std.debug.assert(fmt.len == 0); | 66 | comptime std.debug.assert(fmt.len == 0); |
| 64 | return ctx.tv.print(writer, 3, ctx.mod) catch |err| switch (err) { | 67 | return ctx.tv.print(writer, 3, ctx.mod, null) catch |err| switch (err) { |
| 65 | error.OutOfMemory => @panic("OOM"), // We're not allowed to return this from a format function | 68 | error.OutOfMemory => @panic("OOM"), // We're not allowed to return this from a format function |
| 69 | error.ComptimeBreak, error.ComptimeReturn => unreachable, | ||
| 70 | error.AnalysisFail, error.NeededSourceLocation => unreachable, // TODO: re-evaluate when we actually pass `opt_sema` | ||
| 66 | else => |e| return e, | 71 | else => |e| return e, |
| 67 | }; | 72 | }; |
| 68 | } | 73 | } |
| ... | @@ -73,11 +78,12 @@ pub fn print( | ... | @@ -73,11 +78,12 @@ pub fn print( |
| 73 | writer: anytype, | 78 | writer: anytype, |
| 74 | level: u8, | 79 | level: u8, |
| 75 | mod: *Module, | 80 | mod: *Module, |
| 76 | ) (@TypeOf(writer).Error || Allocator.Error)!void { | 81 | /// If this `Sema` is provided, we will recurse through pointers where possible to provide friendly output. |
| 77 | var val = tv.val; | 82 | opt_sema: ?*Sema, |
| 78 | var ty = tv.ty; | 83 | ) (@TypeOf(writer).Error || Module.CompileError)!void { |
| 79 | const ip = &mod.intern_pool; | 84 | const ip = &mod.intern_pool; |
| 80 | while (true) switch (ip.indexToKey(val.toIntern())) { | 85 | const val = tv.val; |
| 86 | switch (ip.indexToKey(val.toIntern())) { | ||
| 81 | .int_type, | 87 | .int_type, |
| 82 | .ptr_type, | 88 | .ptr_type, |
| 83 | .array_type, | 89 | .array_type, |
| ... | @@ -94,324 +100,298 @@ pub fn print( | ... | @@ -94,324 +100,298 @@ pub fn print( |
| 94 | .func_type, | 100 | .func_type, |
| 95 | .error_set_type, | 101 | .error_set_type, |
| 96 | .inferred_error_set_type, | 102 | .inferred_error_set_type, |
| 97 | => return Type.print(val.toType(), writer, mod), | 103 | => try Type.print(val.toType(), writer, mod), |
| 98 | .undef => return writer.writeAll("undefined"), | 104 | .undef => try writer.writeAll("undefined"), |
| 99 | .simple_value => |simple_value| switch (simple_value) { | 105 | .simple_value => |simple_value| switch (simple_value) { |
| 100 | .void => return writer.writeAll("{}"), | 106 | .void => try writer.writeAll("{}"), |
| 101 | .empty_struct => return printAggregate(ty, val, writer, level, mod), | 107 | .empty_struct => try writer.writeAll(".{}"), |
| 102 | .generic_poison => return writer.writeAll("(generic poison)"), | 108 | .generic_poison => try writer.writeAll("(generic poison)"), |
| 103 | else => return writer.writeAll(@tagName(simple_value)), | 109 | else => try writer.writeAll(@tagName(simple_value)), |
| 104 | }, | 110 | }, |
| 105 | .variable => return writer.writeAll("(variable)"), | 111 | .variable => try writer.writeAll("(variable)"), |
| 106 | .extern_func => |extern_func| return writer.print("(extern function '{}')", .{ | 112 | .extern_func => |extern_func| try writer.print("(extern function '{}')", .{ |
| 107 | mod.declPtr(extern_func.decl).name.fmt(ip), | 113 | mod.declPtr(extern_func.decl).name.fmt(ip), |
| 108 | }), | 114 | }), |
| 109 | .func => |func| return writer.print("(function '{}')", .{ | 115 | .func => |func| try writer.print("(function '{}')", .{ |
| 110 | mod.declPtr(func.owner_decl).name.fmt(ip), | 116 | mod.declPtr(func.owner_decl).name.fmt(ip), |
| 111 | }), | 117 | }), |
| 112 | .int => |int| switch (int.storage) { | 118 | .int => |int| switch (int.storage) { |
| 113 | inline .u64, .i64, .big_int => |x| return writer.print("{}", .{x}), | 119 | inline .u64, .i64, .big_int => |x| try writer.print("{}", .{x}), |
| 114 | .lazy_align => |lazy_ty| return writer.print("{d}", .{ | 120 | .lazy_align => |ty| if (opt_sema) |sema| { |
| 115 | Type.fromInterned(lazy_ty).abiAlignment(mod), | 121 | const a = (try Type.fromInterned(ty).abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar; |
| 116 | }), | 122 | try writer.print("{}", .{a.toByteUnits(0)}); |
| 117 | .lazy_size => |lazy_ty| return writer.print("{d}", .{ | 123 | } else try writer.print("@alignOf({})", .{Type.fromInterned(ty).fmt(mod)}), |
| 118 | Type.fromInterned(lazy_ty).abiSize(mod), | 124 | .lazy_size => |ty| if (opt_sema) |sema| { |
| 119 | }), | 125 | const s = (try Type.fromInterned(ty).abiSizeAdvanced(mod, .{ .sema = sema })).scalar; |
| 126 | try writer.print("{}", .{s}); | ||
| 127 | } else try writer.print("@sizeOf({})", .{Type.fromInterned(ty).fmt(mod)}), | ||
| 120 | }, | 128 | }, |
| 121 | .err => |err| return writer.print("error.{}", .{ | 129 | .err => |err| try writer.print("error.{}", .{ |
| 122 | err.name.fmt(ip), | 130 | err.name.fmt(ip), |
| 123 | }), | 131 | }), |
| 124 | .error_union => |error_union| switch (error_union.val) { | 132 | .error_union => |error_union| switch (error_union.val) { |
| 125 | .err_name => |err_name| return writer.print("error.{}", .{ | 133 | .err_name => |err_name| try writer.print("error.{}", .{ |
| 126 | err_name.fmt(ip), | 134 | err_name.fmt(ip), |
| 127 | }), | 135 | }), |
| 128 | .payload => |payload| { | 136 | .payload => |payload| try print(.{ |
| 129 | val = Value.fromInterned(payload); | 137 | .ty = tv.ty.errorUnionPayload(mod), |
| 130 | ty = ty.errorUnionPayload(mod); | 138 | .val = Value.fromInterned(payload), |
| 131 | }, | 139 | }, writer, level, mod, opt_sema), |
| 132 | }, | 140 | }, |
| 133 | .enum_literal => |enum_literal| return writer.print(".{}", .{ | 141 | .enum_literal => |enum_literal| try writer.print(".{}", .{ |
| 134 | enum_literal.fmt(ip), | 142 | enum_literal.fmt(ip), |
| 135 | }), | 143 | }), |
| 136 | .enum_tag => |enum_tag| { | 144 | .enum_tag => |enum_tag| { |
| 137 | if (level == 0) { | 145 | const enum_type = ip.loadEnumType(val.typeOf(mod).toIntern()); |
| 138 | return writer.writeAll("(enum)"); | ||
| 139 | } | ||
| 140 | const enum_type = ip.loadEnumType(ty.toIntern()); | ||
| 141 | if (enum_type.tagValueIndex(ip, val.toIntern())) |tag_index| { | 146 | if (enum_type.tagValueIndex(ip, val.toIntern())) |tag_index| { |
| 142 | try writer.print(".{i}", .{enum_type.names.get(ip)[tag_index].fmt(ip)}); | 147 | try writer.print(".{i}", .{enum_type.names.get(ip)[tag_index].fmt(ip)}); |
| 143 | return; | 148 | return; |
| 144 | } | 149 | } |
| 150 | if (level == 0) { | ||
| 151 | try writer.writeAll("@enumFromInt(...)"); | ||
| 152 | } | ||
| 145 | try writer.writeAll("@enumFromInt("); | 153 | try writer.writeAll("@enumFromInt("); |
| 146 | try print(.{ | 154 | try print(.{ |
| 147 | .ty = Type.fromInterned(ip.typeOf(enum_tag.int)), | 155 | .ty = Type.fromInterned(ip.typeOf(enum_tag.int)), |
| 148 | .val = Value.fromInterned(enum_tag.int), | 156 | .val = Value.fromInterned(enum_tag.int), |
| 149 | }, writer, level - 1, mod); | 157 | }, writer, level - 1, mod, opt_sema); |
| 150 | try writer.writeAll(")"); | 158 | try writer.writeAll(")"); |
| 151 | return; | ||
| 152 | }, | 159 | }, |
| 153 | .empty_enum_value => return writer.writeAll("(empty enum value)"), | 160 | .empty_enum_value => try writer.writeAll("(empty enum value)"), |
| 154 | .float => |float| switch (float.storage) { | 161 | .float => |float| switch (float.storage) { |
| 155 | inline else => |x| return writer.print("{d}", .{@as(f64, @floatCast(x))}), | 162 | inline else => |x| try writer.print("{d}", .{@as(f64, @floatCast(x))}), |
| 156 | }, | 163 | }, |
| 157 | .slice => |slice| { | 164 | .slice => |slice| { |
| 158 | const ptr_ty = switch (ip.indexToKey(slice.ptr)) { | 165 | const print_contents = switch (ip.getBackingAddrTag(slice.ptr).?) { |
| 159 | .ptr => |ptr| ty: { | 166 | .field, .elem, .eu_payload, .opt_payload => unreachable, |
| 160 | if (ptr.addr == .int) return print(.{ | 167 | .anon_decl, .comptime_alloc, .comptime_field => true, |
| 161 | .ty = Type.fromInterned(ptr.ty), | 168 | .decl, .int => false, |
| 162 | .val = Value.fromInterned(slice.ptr), | ||
| 163 | }, writer, level - 1, mod); | ||
| 164 | break :ty ip.indexToKey(ptr.ty).ptr_type; | ||
| 165 | }, | ||
| 166 | .undef => |ptr_ty| ip.indexToKey(ptr_ty).ptr_type, | ||
| 167 | else => unreachable, | ||
| 168 | }; | 169 | }; |
| 169 | if (level == 0) { | 170 | if (print_contents) { |
| 170 | return writer.writeAll(".{ ... }"); | 171 | // TODO: eventually we want to load the slice as an array with `opt_sema`, but that's |
| 171 | } | 172 | // currently not possible without e.g. triggering compile errors. |
| 172 | const elem_ty = Type.fromInterned(ptr_ty.child); | ||
| 173 | const len = Value.fromInterned(slice.len).toUnsignedInt(mod); | ||
| 174 | if (elem_ty.eql(Type.u8, mod)) str: { | ||
| 175 | const max_len = @min(len, max_string_len); | ||
| 176 | var buf: [max_string_len]u8 = undefined; | ||
| 177 | for (buf[0..max_len], 0..) |*c, i| { | ||
| 178 | const maybe_elem = try val.maybeElemValue(mod, i); | ||
| 179 | const elem = maybe_elem orelse return writer.writeAll(".{ (reinterpreted data) }"); | ||
| 180 | if (elem.isUndef(mod)) break :str; | ||
| 181 | c.* = @as(u8, @intCast(elem.toUnsignedInt(mod))); | ||
| 182 | } | ||
| 183 | const truncated = if (len > max_string_len) " (truncated)" else ""; | ||
| 184 | return writer.print("\"{}{s}\"", .{ std.zig.fmtEscapes(buf[0..max_len]), truncated }); | ||
| 185 | } | 173 | } |
| 186 | try writer.writeAll(".{ "); | 174 | try printPtr(slice.ptr, writer, false, false, 0, level, mod, opt_sema); |
| 187 | const max_len = @min(len, max_aggregate_items); | 175 | try writer.writeAll("[0.."); |
| 188 | for (0..max_len) |i| { | 176 | try print(.{ |
| 189 | if (i != 0) try writer.writeAll(", "); | 177 | .ty = Type.usize, |
| 190 | const maybe_elem = try val.maybeElemValue(mod, i); | 178 | .val = Value.fromInterned(slice.len), |
| 191 | const elem = maybe_elem orelse return writer.writeAll("(reinterpreted data) }"); | 179 | }, writer, level - 1, mod, opt_sema); |
| 192 | try print(.{ | 180 | try writer.writeAll("]"); |
| 193 | .ty = elem_ty, | ||
| 194 | .val = elem, | ||
| 195 | }, writer, level - 1, mod); | ||
| 196 | } | ||
| 197 | if (len > max_aggregate_items) { | ||
| 198 | try writer.writeAll(", ..."); | ||
| 199 | } | ||
| 200 | return writer.writeAll(" }"); | ||
| 201 | }, | 181 | }, |
| 202 | .ptr => |ptr| { | 182 | .ptr => { |
| 203 | switch (ptr.addr) { | 183 | const print_contents = switch (ip.getBackingAddrTag(val.toIntern()).?) { |
| 204 | .decl => |decl_index| { | 184 | .field, .elem, .eu_payload, .opt_payload => unreachable, |
| 205 | const decl = mod.declPtr(decl_index); | 185 | .anon_decl, .comptime_alloc, .comptime_field => true, |
| 206 | if (level == 0) return writer.print("(decl '{}')", .{decl.name.fmt(ip)}); | 186 | .decl, .int => false, |
| 207 | return print(.{ | 187 | }; |
| 208 | .ty = decl.typeOf(mod), | 188 | if (print_contents) { |
| 209 | .val = decl.val, | 189 | // TODO: eventually we want to load the pointer with `opt_sema`, but that's |
| 210 | }, writer, level - 1, mod); | 190 | // currently not possible without e.g. triggering compile errors. |
| 211 | }, | ||
| 212 | .anon_decl => |anon_decl| { | ||
| 213 | const decl_val = anon_decl.val; | ||
| 214 | if (level == 0) return writer.print("(anon decl '{d}')", .{ | ||
| 215 | @intFromEnum(decl_val), | ||
| 216 | }); | ||
| 217 | return print(.{ | ||
| 218 | .ty = Type.fromInterned(ip.typeOf(decl_val)), | ||
| 219 | .val = Value.fromInterned(decl_val), | ||
| 220 | }, writer, level - 1, mod); | ||
| 221 | }, | ||
| 222 | .comptime_alloc => { | ||
| 223 | // TODO: we need a Sema to print this! | ||
| 224 | return writer.writeAll("(comptime alloc)"); | ||
| 225 | }, | ||
| 226 | .comptime_field => |field_val_ip| { | ||
| 227 | return print(.{ | ||
| 228 | .ty = Type.fromInterned(ip.typeOf(field_val_ip)), | ||
| 229 | .val = Value.fromInterned(field_val_ip), | ||
| 230 | }, writer, level - 1, mod); | ||
| 231 | }, | ||
| 232 | .int => |int_ip| { | ||
| 233 | try writer.writeAll("@ptrFromInt("); | ||
| 234 | try print(.{ | ||
| 235 | .ty = Type.usize, | ||
| 236 | .val = Value.fromInterned(int_ip), | ||
| 237 | }, writer, level - 1, mod); | ||
| 238 | try writer.writeByte(')'); | ||
| 239 | }, | ||
| 240 | .eu_payload => |eu_ip| { | ||
| 241 | try writer.writeAll("(payload of "); | ||
| 242 | try print(.{ | ||
| 243 | .ty = Type.fromInterned(ip.typeOf(eu_ip)), | ||
| 244 | .val = Value.fromInterned(eu_ip), | ||
| 245 | }, writer, level - 1, mod); | ||
| 246 | try writer.writeAll(")"); | ||
| 247 | }, | ||
| 248 | .opt_payload => |opt_ip| { | ||
| 249 | try print(.{ | ||
| 250 | .ty = Type.fromInterned(ip.typeOf(opt_ip)), | ||
| 251 | .val = Value.fromInterned(opt_ip), | ||
| 252 | }, writer, level - 1, mod); | ||
| 253 | try writer.writeAll(".?"); | ||
| 254 | }, | ||
| 255 | .elem => |elem| { | ||
| 256 | if (level == 0) { | ||
| 257 | try writer.writeAll("(...)"); | ||
| 258 | } else { | ||
| 259 | try print(.{ | ||
| 260 | .ty = Type.fromInterned(ip.typeOf(elem.base)), | ||
| 261 | .val = Value.fromInterned(elem.base), | ||
| 262 | }, writer, level - 1, mod); | ||
| 263 | } | ||
| 264 | try writer.print("[{}]", .{elem.index}); | ||
| 265 | }, | ||
| 266 | .field => |field| { | ||
| 267 | const ptr_container_ty = Type.fromInterned(ip.typeOf(field.base)); | ||
| 268 | if (level == 0) { | ||
| 269 | try writer.writeAll("(...)"); | ||
| 270 | } else { | ||
| 271 | try print(.{ | ||
| 272 | .ty = ptr_container_ty, | ||
| 273 | .val = Value.fromInterned(field.base), | ||
| 274 | }, writer, level - 1, mod); | ||
| 275 | } | ||
| 276 | |||
| 277 | const container_ty = ptr_container_ty.childType(mod); | ||
| 278 | switch (container_ty.zigTypeTag(mod)) { | ||
| 279 | .Struct => { | ||
| 280 | if (container_ty.structFieldName(@intCast(field.index), mod).unwrap()) |field_name| { | ||
| 281 | try writer.print(".{i}", .{field_name.fmt(ip)}); | ||
| 282 | } else { | ||
| 283 | try writer.print("[{d}]", .{field.index}); | ||
| 284 | } | ||
| 285 | }, | ||
| 286 | .Union => { | ||
| 287 | const field_name = mod.typeToUnion(container_ty).?.loadTagType(ip).names.get(ip)[@intCast(field.index)]; | ||
| 288 | try writer.print(".{i}", .{field_name.fmt(ip)}); | ||
| 289 | }, | ||
| 290 | .Pointer => { | ||
| 291 | std.debug.assert(container_ty.isSlice(mod)); | ||
| 292 | try writer.writeAll(switch (field.index) { | ||
| 293 | Value.slice_ptr_index => ".ptr", | ||
| 294 | Value.slice_len_index => ".len", | ||
| 295 | else => unreachable, | ||
| 296 | }); | ||
| 297 | }, | ||
| 298 | else => unreachable, | ||
| 299 | } | ||
| 300 | }, | ||
| 301 | } | 191 | } |
| 302 | return; | 192 | try printPtr(val.toIntern(), writer, false, false, 0, level, mod, opt_sema); |
| 303 | }, | 193 | }, |
| 304 | .opt => |opt| switch (opt.val) { | 194 | .opt => |opt| switch (opt.val) { |
| 305 | .none => return writer.writeAll("null"), | 195 | .none => try writer.writeAll("null"), |
| 306 | else => |payload| { | 196 | else => |payload| try print(.{ |
| 307 | val = Value.fromInterned(payload); | 197 | .ty = tv.ty.childType(mod), |
| 308 | ty = ty.optionalChild(mod); | 198 | .val = Value.fromInterned(payload), |
| 309 | }, | 199 | }, writer, level, mod, opt_sema), |
| 310 | }, | ||
| 311 | .aggregate => |aggregate| switch (aggregate.storage) { | ||
| 312 | .bytes => |bytes| { | ||
| 313 | // Strip the 0 sentinel off of strings before printing | ||
| 314 | const zero_sent = blk: { | ||
| 315 | const sent = ty.sentinel(mod) orelse break :blk false; | ||
| 316 | break :blk sent.eql(Value.zero_u8, Type.u8, mod); | ||
| 317 | }; | ||
| 318 | const str = if (zero_sent) bytes[0 .. bytes.len - 1] else bytes; | ||
| 319 | return writer.print("\"{}\"", .{std.zig.fmtEscapes(str)}); | ||
| 320 | }, | ||
| 321 | .elems, .repeated_elem => return printAggregate(ty, val, writer, level, mod), | ||
| 322 | }, | 200 | }, |
| 201 | .aggregate => |aggregate| try printAggregate(val, aggregate, writer, level, mod, opt_sema), | ||
| 323 | .un => |un| { | 202 | .un => |un| { |
| 324 | try writer.writeAll(".{ "); | 203 | if (level == 0) { |
| 325 | if (level > 0) { | 204 | try writer.writeAll(".{ ... }"); |
| 326 | if (un.tag != .none) { | 205 | return; |
| 327 | try print(.{ | 206 | } |
| 328 | .ty = ty.unionTagTypeHypothetical(mod), | 207 | if (un.tag == .none) { |
| 329 | .val = Value.fromInterned(un.tag), | 208 | const backing_ty = try tv.ty.unionBackingType(mod); |
| 330 | }, writer, level - 1, mod); | 209 | try writer.print("@bitCast(@as({}, ", .{backing_ty.fmt(mod)}); |
| 331 | try writer.writeAll(" = "); | 210 | try print(.{ |
| 332 | const field_ty = ty.unionFieldType(Value.fromInterned(un.tag), mod).?; | 211 | .ty = backing_ty, |
| 333 | try print(.{ | 212 | .val = Value.fromInterned(un.val), |
| 334 | .ty = field_ty, | 213 | }, writer, level - 1, mod, opt_sema); |
| 335 | .val = Value.fromInterned(un.val), | 214 | try writer.writeAll("))"); |
| 336 | }, writer, level - 1, mod); | 215 | } else { |
| 337 | } else { | 216 | try writer.writeAll(".{ "); |
| 338 | try writer.writeAll("(unknown tag) = "); | 217 | try print(.{ |
| 339 | const backing_ty = try ty.unionBackingType(mod); | 218 | .ty = tv.ty.unionTagTypeHypothetical(mod), |
| 340 | try print(.{ | 219 | .val = Value.fromInterned(un.tag), |
| 341 | .ty = backing_ty, | 220 | }, writer, level - 1, mod, opt_sema); |
| 342 | .val = Value.fromInterned(un.val), | 221 | try writer.writeAll(" = "); |
| 343 | }, writer, level - 1, mod); | 222 | const field_ty = tv.ty.unionFieldType(Value.fromInterned(un.tag), mod).?; |
| 344 | } | 223 | try print(.{ |
| 345 | } else try writer.writeAll("..."); | 224 | .ty = field_ty, |
| 346 | return writer.writeAll(" }"); | 225 | .val = Value.fromInterned(un.val), |
| 226 | }, writer, level - 1, mod, opt_sema); | ||
| 227 | try writer.writeAll(" }"); | ||
| 228 | } | ||
| 347 | }, | 229 | }, |
| 348 | .memoized_call => unreachable, | 230 | .memoized_call => unreachable, |
| 349 | }; | 231 | } |
| 350 | } | 232 | } |
| 351 | 233 | ||
| 352 | fn printAggregate( | 234 | fn printAggregate( |
| 353 | ty: Type, | ||
| 354 | val: Value, | 235 | val: Value, |
| 236 | aggregate: InternPool.Key.Aggregate, | ||
| 355 | writer: anytype, | 237 | writer: anytype, |
| 356 | level: u8, | 238 | level: u8, |
| 357 | mod: *Module, | 239 | zcu: *Zcu, |
| 358 | ) (@TypeOf(writer).Error || Allocator.Error)!void { | 240 | opt_sema: ?*Sema, |
| 241 | ) (@TypeOf(writer).Error || Module.CompileError)!void { | ||
| 359 | if (level == 0) { | 242 | if (level == 0) { |
| 360 | return writer.writeAll(".{ ... }"); | 243 | return writer.writeAll(".{ ... }"); |
| 361 | } | 244 | } |
| 362 | const ip = &mod.intern_pool; | 245 | const ip = &zcu.intern_pool; |
| 363 | if (ty.zigTypeTag(mod) == .Struct) { | 246 | const ty = Type.fromInterned(aggregate.ty); |
| 364 | try writer.writeAll(".{"); | 247 | switch (ty.zigTypeTag(zcu)) { |
| 365 | const max_len = @min(ty.structFieldCount(mod), max_aggregate_items); | 248 | .Struct => if (!ty.isTuple(zcu)) { |
| 366 | 249 | if (ty.structFieldCount(zcu) == 0) { | |
| 367 | for (0..max_len) |i| { | 250 | return writer.writeAll(".{}"); |
| 368 | if (i != 0) try writer.writeAll(", "); | 251 | } |
| 252 | try writer.writeAll(".{ "); | ||
| 253 | const max_len = @min(ty.structFieldCount(zcu), max_aggregate_items); | ||
| 254 | for (0..max_len) |i| { | ||
| 255 | if (i != 0) try writer.writeAll(", "); | ||
| 256 | const field_name = ty.structFieldName(@intCast(i), zcu).unwrap().?; | ||
| 257 | try writer.print(".{i} = ", .{field_name.fmt(ip)}); | ||
| 258 | try print(.{ | ||
| 259 | .ty = ty.structFieldType(i, zcu), | ||
| 260 | .val = try val.fieldValue(zcu, i), | ||
| 261 | }, writer, level - 1, zcu, opt_sema); | ||
| 262 | } | ||
| 263 | try writer.writeAll(" }"); | ||
| 264 | return; | ||
| 265 | }, | ||
| 266 | .Array => if (aggregate.storage == .bytes) { | ||
| 267 | return writer.print("\"{}\".*", .{std.zig.fmtEscapes(aggregate.storage.bytes)}); | ||
| 268 | } else if (ty.arrayLen(zcu) == 0) { | ||
| 269 | return writer.writeAll(".{}"); | ||
| 270 | }, | ||
| 271 | .Vector => if (ty.arrayLen(zcu) == 0) { | ||
| 272 | return writer.writeAll(".{}"); | ||
| 273 | }, | ||
| 274 | else => unreachable, | ||
| 275 | } | ||
| 369 | 276 | ||
| 370 | const field_name = ty.structFieldName(@intCast(i), mod); | 277 | const elem_ty = ty.childType(zcu); |
| 278 | const len = ty.arrayLen(zcu); | ||
| 371 | 279 | ||
| 372 | if (field_name.unwrap()) |name| try writer.print(".{} = ", .{name.fmt(ip)}); | 280 | try writer.writeAll(".{ "); |
| 373 | try print(.{ | ||
| 374 | .ty = ty.structFieldType(i, mod), | ||
| 375 | .val = try val.fieldValue(mod, i), | ||
| 376 | }, writer, level - 1, mod); | ||
| 377 | } | ||
| 378 | if (ty.structFieldCount(mod) > max_aggregate_items) { | ||
| 379 | try writer.writeAll(", ..."); | ||
| 380 | } | ||
| 381 | return writer.writeAll("}"); | ||
| 382 | } else { | ||
| 383 | const elem_ty = ty.elemType2(mod); | ||
| 384 | const len = ty.arrayLen(mod); | ||
| 385 | 281 | ||
| 386 | if (elem_ty.eql(Type.u8, mod)) str: { | 282 | const max_len = @min(len, max_aggregate_items); |
| 387 | const max_len: usize = @min(len, max_string_len); | 283 | for (0..max_len) |i| { |
| 388 | var buf: [max_string_len]u8 = undefined; | 284 | if (i != 0) try writer.writeAll(", "); |
| 285 | try print(.{ | ||
| 286 | .ty = elem_ty, | ||
| 287 | .val = try val.fieldValue(zcu, i), | ||
| 288 | }, writer, level - 1, zcu, opt_sema); | ||
| 289 | } | ||
| 290 | if (len > max_aggregate_items) { | ||
| 291 | try writer.writeAll(", ..."); | ||
| 292 | } | ||
| 293 | return writer.writeAll(" }"); | ||
| 294 | } | ||
| 389 | 295 | ||
| 390 | var i: u32 = 0; | 296 | fn printPtr( |
| 391 | while (i < max_len) : (i += 1) { | 297 | ptr_val: InternPool.Index, |
| 392 | const elem = try val.fieldValue(mod, i); | 298 | writer: anytype, |
| 393 | if (elem.isUndef(mod)) break :str; | 299 | force_type: bool, |
| 394 | buf[i] = std.math.cast(u8, elem.toUnsignedInt(mod)) orelse break :str; | 300 | force_addrof: bool, |
| 301 | leading_parens: u32, | ||
| 302 | level: u8, | ||
| 303 | zcu: *Zcu, | ||
| 304 | opt_sema: ?*Sema, | ||
| 305 | ) (@TypeOf(writer).Error || Module.CompileError)!void { | ||
| 306 | const ip = &zcu.intern_pool; | ||
| 307 | const ptr = switch (ip.indexToKey(ptr_val)) { | ||
| 308 | .undef => |ptr_ty| { | ||
| 309 | if (force_addrof) try writer.writeAll("&"); | ||
| 310 | try writer.writeByteNTimes('(', leading_parens); | ||
| 311 | try writer.print("@as({}, undefined)", .{Type.fromInterned(ptr_ty).fmt(zcu)}); | ||
| 312 | return; | ||
| 313 | }, | ||
| 314 | .ptr => |ptr| ptr, | ||
| 315 | else => unreachable, | ||
| 316 | }; | ||
| 317 | switch (ptr.addr) { | ||
| 318 | .int => |int| { | ||
| 319 | if (force_addrof) try writer.writeAll("&"); | ||
| 320 | try writer.writeByteNTimes('(', leading_parens); | ||
| 321 | if (force_type) { | ||
| 322 | try writer.print("@as({}, @ptrFromInt(", .{Type.fromInterned(ptr.ty).fmt(zcu)}); | ||
| 323 | try print(.{ | ||
| 324 | .ty = Type.usize, | ||
| 325 | .val = Value.fromInterned(int), | ||
| 326 | }, writer, level - 1, zcu, opt_sema); | ||
| 327 | try writer.writeAll("))"); | ||
| 328 | } else { | ||
| 329 | try writer.writeAll("@ptrFromInt("); | ||
| 330 | try print(.{ | ||
| 331 | .ty = Type.usize, | ||
| 332 | .val = Value.fromInterned(int), | ||
| 333 | }, writer, level - 1, zcu, opt_sema); | ||
| 334 | try writer.writeAll(")"); | ||
| 395 | } | 335 | } |
| 396 | 336 | }, | |
| 397 | const truncated = if (len > max_string_len) " (truncated)" else ""; | 337 | .decl => |index| { |
| 398 | return writer.print("\"{}{s}\"", .{ std.zig.fmtEscapes(buf[0..max_len]), truncated }); | 338 | try writer.writeAll("&"); |
| 399 | } | 339 | try zcu.declPtr(index).renderFullyQualifiedName(zcu, writer); |
| 400 | 340 | }, | |
| 401 | try writer.writeAll(".{ "); | 341 | .comptime_alloc => try writer.writeAll("&(comptime alloc)"), |
| 402 | 342 | .anon_decl => |anon| { | |
| 403 | const max_len = @min(len, max_aggregate_items); | 343 | const ty = Type.fromInterned(ip.typeOf(anon.val)); |
| 404 | var i: u32 = 0; | 344 | try writer.print("&@as({}, ", .{ty.fmt(zcu)}); |
| 405 | while (i < max_len) : (i += 1) { | ||
| 406 | if (i != 0) try writer.writeAll(", "); | ||
| 407 | try print(.{ | 345 | try print(.{ |
| 408 | .ty = elem_ty, | 346 | .ty = ty, |
| 409 | .val = try val.fieldValue(mod, i), | 347 | .val = Value.fromInterned(anon.val), |
| 410 | }, writer, level - 1, mod); | 348 | }, writer, level - 1, zcu, opt_sema); |
| 411 | } | 349 | try writer.writeAll(")"); |
| 412 | if (len > max_aggregate_items) { | 350 | }, |
| 413 | try writer.writeAll(", ..."); | 351 | .comptime_field => |val| { |
| 414 | } | 352 | const ty = Type.fromInterned(ip.typeOf(val)); |
| 415 | return writer.writeAll(" }"); | 353 | try writer.print("&@as({}, ", .{ty.fmt(zcu)}); |
| 354 | try print(.{ | ||
| 355 | .ty = ty, | ||
| 356 | .val = Value.fromInterned(val), | ||
| 357 | }, writer, level - 1, zcu, opt_sema); | ||
| 358 | try writer.writeAll(")"); | ||
| 359 | }, | ||
| 360 | .eu_payload => |base| { | ||
| 361 | try printPtr(base, writer, true, true, leading_parens, level, zcu, opt_sema); | ||
| 362 | try writer.writeAll(".?"); | ||
| 363 | }, | ||
| 364 | .opt_payload => |base| { | ||
| 365 | try writer.writeAll("("); | ||
| 366 | try printPtr(base, writer, true, true, leading_parens + 1, level, zcu, opt_sema); | ||
| 367 | try writer.writeAll(" catch unreachable"); | ||
| 368 | }, | ||
| 369 | .elem => |elem| { | ||
| 370 | try printPtr(elem.base, writer, true, true, leading_parens, level, zcu, opt_sema); | ||
| 371 | try writer.print("[{d}]", .{elem.index}); | ||
| 372 | }, | ||
| 373 | .field => |field| { | ||
| 374 | try printPtr(field.base, writer, true, true, leading_parens, level, zcu, opt_sema); | ||
| 375 | const base_ty = Type.fromInterned(ip.typeOf(field.base)).childType(zcu); | ||
| 376 | switch (base_ty.zigTypeTag(zcu)) { | ||
| 377 | .Struct => if (base_ty.isTuple(zcu)) { | ||
| 378 | try writer.print("[{d}]", .{field.index}); | ||
| 379 | } else { | ||
| 380 | const field_name = base_ty.structFieldName(@intCast(field.index), zcu).unwrap().?; | ||
| 381 | try writer.print(".{i}", .{field_name.fmt(ip)}); | ||
| 382 | }, | ||
| 383 | .Union => { | ||
| 384 | const tag_ty = base_ty.unionTagTypeHypothetical(zcu); | ||
| 385 | const field_name = tag_ty.enumFieldName(@intCast(field.index), zcu); | ||
| 386 | try writer.print(".{i}", .{field_name.fmt(ip)}); | ||
| 387 | }, | ||
| 388 | .Pointer => switch (field.index) { | ||
| 389 | Value.slice_ptr_index => try writer.writeAll(".ptr"), | ||
| 390 | Value.slice_len_index => try writer.writeAll(".len"), | ||
| 391 | else => unreachable, | ||
| 392 | }, | ||
| 393 | else => unreachable, | ||
| 394 | } | ||
| 395 | }, | ||
| 416 | } | 396 | } |
| 417 | } | 397 | } |
src/Value.zig+44-92| ... | @@ -305,16 +305,16 @@ pub fn toBool(val: Value) bool { | ... | @@ -305,16 +305,16 @@ pub fn toBool(val: Value) bool { |
| 305 | }; | 305 | }; |
| 306 | } | 306 | } |
| 307 | 307 | ||
| 308 | fn isDeclRef(val: Value, mod: *Module) bool { | 308 | fn ptrHasIntAddr(val: Value, mod: *Module) bool { |
| 309 | var check = val; | 309 | var check = val; |
| 310 | while (true) switch (mod.intern_pool.indexToKey(check.toIntern())) { | 310 | while (true) switch (mod.intern_pool.indexToKey(check.toIntern())) { |
| 311 | .ptr => |ptr| switch (ptr.addr) { | 311 | .ptr => |ptr| switch (ptr.addr) { |
| 312 | .decl, .comptime_alloc, .comptime_field, .anon_decl => return true, | 312 | .decl, .comptime_alloc, .comptime_field, .anon_decl => return false, |
| 313 | .int => return true, | ||
| 313 | .eu_payload, .opt_payload => |base| check = Value.fromInterned(base), | 314 | .eu_payload, .opt_payload => |base| check = Value.fromInterned(base), |
| 314 | .elem, .field => |base_index| check = Value.fromInterned(base_index.base), | 315 | .elem, .field => |base_index| check = Value.fromInterned(base_index.base), |
| 315 | .int => return false, | ||
| 316 | }, | 316 | }, |
| 317 | else => return false, | 317 | else => unreachable, |
| 318 | }; | 318 | }; |
| 319 | } | 319 | } |
| 320 | 320 | ||
| ... | @@ -439,7 +439,7 @@ pub fn writeToMemory(val: Value, ty: Type, mod: *Module, buffer: []u8) error{ | ... | @@ -439,7 +439,7 @@ pub fn writeToMemory(val: Value, ty: Type, mod: *Module, buffer: []u8) error{ |
| 439 | }, | 439 | }, |
| 440 | .Pointer => { | 440 | .Pointer => { |
| 441 | if (ty.isSlice(mod)) return error.IllDefinedMemoryLayout; | 441 | if (ty.isSlice(mod)) return error.IllDefinedMemoryLayout; |
| 442 | if (val.isDeclRef(mod)) return error.ReinterpretDeclRef; | 442 | if (!val.ptrHasIntAddr(mod)) return error.ReinterpretDeclRef; |
| 443 | return val.writeToMemory(Type.usize, mod, buffer); | 443 | return val.writeToMemory(Type.usize, mod, buffer); |
| 444 | }, | 444 | }, |
| 445 | .Optional => { | 445 | .Optional => { |
| ... | @@ -566,7 +566,7 @@ pub fn writeToPackedMemory( | ... | @@ -566,7 +566,7 @@ pub fn writeToPackedMemory( |
| 566 | }, | 566 | }, |
| 567 | .Pointer => { | 567 | .Pointer => { |
| 568 | assert(!ty.isSlice(mod)); // No well defined layout. | 568 | assert(!ty.isSlice(mod)); // No well defined layout. |
| 569 | if (val.isDeclRef(mod)) return error.ReinterpretDeclRef; | 569 | if (!val.ptrHasIntAddr(mod)) return error.ReinterpretDeclRef; |
| 570 | return val.writeToPackedMemory(Type.usize, mod, buffer, bit_offset); | 570 | return val.writeToPackedMemory(Type.usize, mod, buffer, bit_offset); |
| 571 | }, | 571 | }, |
| 572 | .Optional => { | 572 | .Optional => { |
| ... | @@ -1261,62 +1261,23 @@ pub fn slicePtr(val: Value, mod: *Module) Value { | ... | @@ -1261,62 +1261,23 @@ pub fn slicePtr(val: Value, mod: *Module) Value { |
| 1261 | return Value.fromInterned(mod.intern_pool.slicePtr(val.toIntern())); | 1261 | return Value.fromInterned(mod.intern_pool.slicePtr(val.toIntern())); |
| 1262 | } | 1262 | } |
| 1263 | 1263 | ||
| 1264 | pub fn sliceLen(val: Value, mod: *Module) u64 { | 1264 | /// Gets the `len` field of a slice value as a `u64`. |
| 1265 | const ip = &mod.intern_pool; | 1265 | /// Resolves the length using the provided `Sema` if necessary. |
| 1266 | return switch (ip.indexToKey(val.toIntern())) { | 1266 | pub fn sliceLen(val: Value, sema: *Sema) !u64 { |
| 1267 | .ptr => |ptr| switch (ip.indexToKey(switch (ptr.addr) { | 1267 | return Value.fromInterned(sema.mod.intern_pool.sliceLen(val.toIntern())).toUnsignedIntAdvanced(sema); |
| 1268 | .decl => |decl| mod.declPtr(decl).typeOf(mod).toIntern(), | ||
| 1269 | .comptime_alloc => @panic("TODO"), | ||
| 1270 | .anon_decl => |anon_decl| ip.typeOf(anon_decl.val), | ||
| 1271 | .comptime_field => |comptime_field| ip.typeOf(comptime_field), | ||
| 1272 | else => unreachable, | ||
| 1273 | })) { | ||
| 1274 | .array_type => |array_type| array_type.len, | ||
| 1275 | else => 1, | ||
| 1276 | }, | ||
| 1277 | .slice => |slice| Value.fromInterned(slice.len).toUnsignedInt(mod), | ||
| 1278 | else => unreachable, | ||
| 1279 | }; | ||
| 1280 | } | ||
| 1281 | |||
| 1282 | /// Asserts the value is a single-item pointer to an array, or an array, | ||
| 1283 | /// or an unknown-length pointer, and returns the element value at the index. | ||
| 1284 | pub fn elemValue(val: Value, mod: *Module, index: usize) Allocator.Error!Value { | ||
| 1285 | return (try val.maybeElemValue(mod, index)).?; | ||
| 1286 | } | ||
| 1287 | |||
| 1288 | /// Like `elemValue`, but returns `null` instead of asserting on failure. | ||
| 1289 | pub fn maybeElemValue(val: Value, mod: *Module, index: usize) Allocator.Error!?Value { | ||
| 1290 | return val.maybeElemValueFull(null, mod, index); | ||
| 1291 | } | 1268 | } |
| 1292 | 1269 | ||
| 1293 | pub fn maybeElemValueFull(val: Value, sema: ?*Sema, mod: *Module, index: usize) Allocator.Error!?Value { | 1270 | /// Asserts the value is an aggregate, and returns the element value at the given index. |
| 1294 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { | 1271 | pub fn elemValue(val: Value, zcu: *Zcu, index: usize) Allocator.Error!Value { |
| 1295 | .undef => |ty| Value.fromInterned((try mod.intern(.{ | 1272 | const ip = &zcu.intern_pool; |
| 1296 | .undef = Type.fromInterned(ty).elemType2(mod).toIntern(), | 1273 | switch (zcu.intern_pool.indexToKey(val.toIntern())) { |
| 1297 | }))), | 1274 | .undef => |ty| { |
| 1298 | .slice => |slice| return Value.fromInterned(slice.ptr).maybeElemValueFull(sema, mod, index), | 1275 | return Value.fromInterned(try zcu.intern(.{ .undef = Type.fromInterned(ty).childType(zcu).toIntern() })); |
| 1299 | .ptr => |ptr| switch (ptr.addr) { | 1276 | }, |
| 1300 | .decl => |decl| mod.declPtr(decl).val.maybeElemValueFull(sema, mod, index), | ||
| 1301 | .anon_decl => |anon_decl| Value.fromInterned(anon_decl.val).maybeElemValueFull(sema, mod, index), | ||
| 1302 | .comptime_alloc => |idx| if (sema) |s| Value.fromInterned( | ||
| 1303 | try s.getComptimeAlloc(idx).val.intern(mod, s.arena), | ||
| 1304 | ).maybeElemValueFull(sema, mod, index) else null, | ||
| 1305 | .int, .eu_payload => null, | ||
| 1306 | .opt_payload => |base| Value.fromInterned(base).maybeElemValueFull(sema, mod, index), | ||
| 1307 | .comptime_field => |field_val| Value.fromInterned(field_val).maybeElemValueFull(sema, mod, index), | ||
| 1308 | .elem => |elem| Value.fromInterned(elem.base).maybeElemValueFull(sema, mod, index + @as(usize, @intCast(elem.index))), | ||
| 1309 | .field => |field| if (Value.fromInterned(field.base).pointerDecl(mod)) |decl_index| { | ||
| 1310 | const base_decl = mod.declPtr(decl_index); | ||
| 1311 | const field_val = try base_decl.val.fieldValue(mod, @as(usize, @intCast(field.index))); | ||
| 1312 | return field_val.maybeElemValueFull(sema, mod, index); | ||
| 1313 | } else null, | ||
| 1314 | }, | ||
| 1315 | .opt => |opt| Value.fromInterned(opt.val).maybeElemValueFull(sema, mod, index), | ||
| 1316 | .aggregate => |aggregate| { | 1277 | .aggregate => |aggregate| { |
| 1317 | const len = mod.intern_pool.aggregateTypeLen(aggregate.ty); | 1278 | const len = ip.aggregateTypeLen(aggregate.ty); |
| 1318 | if (index < len) return Value.fromInterned(switch (aggregate.storage) { | 1279 | if (index < len) return Value.fromInterned(switch (aggregate.storage) { |
| 1319 | .bytes => |bytes| try mod.intern(.{ .int = .{ | 1280 | .bytes => |bytes| try zcu.intern(.{ .int = .{ |
| 1320 | .ty = .u8_type, | 1281 | .ty = .u8_type, |
| 1321 | .storage = .{ .u64 = bytes[index] }, | 1282 | .storage = .{ .u64 = bytes[index] }, |
| 1322 | } }), | 1283 | } }), |
| ... | @@ -1324,10 +1285,10 @@ pub fn maybeElemValueFull(val: Value, sema: ?*Sema, mod: *Module, index: usize) | ... | @@ -1324,10 +1285,10 @@ pub fn maybeElemValueFull(val: Value, sema: ?*Sema, mod: *Module, index: usize) |
| 1324 | .repeated_elem => |elem| elem, | 1285 | .repeated_elem => |elem| elem, |
| 1325 | }); | 1286 | }); |
| 1326 | assert(index == len); | 1287 | assert(index == len); |
| 1327 | return Value.fromInterned(mod.intern_pool.indexToKey(aggregate.ty).array_type.sentinel); | 1288 | return Type.fromInterned(aggregate.ty).sentinel(zcu).?; |
| 1328 | }, | 1289 | }, |
| 1329 | else => null, | 1290 | else => unreachable, |
| 1330 | }; | 1291 | } |
| 1331 | } | 1292 | } |
| 1332 | 1293 | ||
| 1333 | pub fn isLazyAlign(val: Value, mod: *Module) bool { | 1294 | pub fn isLazyAlign(val: Value, mod: *Module) bool { |
| ... | @@ -1359,39 +1320,26 @@ pub fn sliceArray( | ... | @@ -1359,39 +1320,26 @@ pub fn sliceArray( |
| 1359 | ) error{OutOfMemory}!Value { | 1320 | ) error{OutOfMemory}!Value { |
| 1360 | // TODO: write something like getCoercedInts to avoid needing to dupe | 1321 | // TODO: write something like getCoercedInts to avoid needing to dupe |
| 1361 | const mod = sema.mod; | 1322 | const mod = sema.mod; |
| 1362 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { | 1323 | const aggregate = mod.intern_pool.indexToKey(val.toIntern()).aggregate; |
| 1363 | .ptr => |ptr| switch (ptr.addr) { | 1324 | return Value.fromInterned(try mod.intern(.{ .aggregate = .{ |
| 1364 | .decl => |decl| try mod.declPtr(decl).val.sliceArray(sema, start, end), | 1325 | .ty = switch (mod.intern_pool.indexToKey(mod.intern_pool.typeOf(val.toIntern()))) { |
| 1365 | .comptime_alloc => |idx| try Value.fromInterned( | 1326 | .array_type => |array_type| try mod.arrayType(.{ |
| 1366 | try sema.getComptimeAlloc(idx).val.intern(mod, sema.arena), | 1327 | .len = @as(u32, @intCast(end - start)), |
| 1367 | ).sliceArray(sema, start, end), | 1328 | .child = array_type.child, |
| 1368 | .comptime_field => |comptime_field| Value.fromInterned(comptime_field) | 1329 | .sentinel = if (end == array_type.len) array_type.sentinel else .none, |
| 1369 | .sliceArray(sema, start, end), | 1330 | }), |
| 1370 | .elem => |elem| Value.fromInterned(elem.base) | 1331 | .vector_type => |vector_type| try mod.vectorType(.{ |
| 1371 | .sliceArray(sema, start + @as(usize, @intCast(elem.index)), end + @as(usize, @intCast(elem.index))), | 1332 | .len = @as(u32, @intCast(end - start)), |
| 1333 | .child = vector_type.child, | ||
| 1334 | }), | ||
| 1372 | else => unreachable, | 1335 | else => unreachable, |
| 1336 | }.toIntern(), | ||
| 1337 | .storage = switch (aggregate.storage) { | ||
| 1338 | .bytes => .{ .bytes = try sema.arena.dupe(u8, mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.bytes[start..end]) }, | ||
| 1339 | .elems => .{ .elems = try sema.arena.dupe(InternPool.Index, mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.elems[start..end]) }, | ||
| 1340 | .repeated_elem => |elem| .{ .repeated_elem = elem }, | ||
| 1373 | }, | 1341 | }, |
| 1374 | .aggregate => |aggregate| Value.fromInterned((try mod.intern(.{ .aggregate = .{ | 1342 | } })); |
| 1375 | .ty = switch (mod.intern_pool.indexToKey(mod.intern_pool.typeOf(val.toIntern()))) { | ||
| 1376 | .array_type => |array_type| try mod.arrayType(.{ | ||
| 1377 | .len = @as(u32, @intCast(end - start)), | ||
| 1378 | .child = array_type.child, | ||
| 1379 | .sentinel = if (end == array_type.len) array_type.sentinel else .none, | ||
| 1380 | }), | ||
| 1381 | .vector_type => |vector_type| try mod.vectorType(.{ | ||
| 1382 | .len = @as(u32, @intCast(end - start)), | ||
| 1383 | .child = vector_type.child, | ||
| 1384 | }), | ||
| 1385 | else => unreachable, | ||
| 1386 | }.toIntern(), | ||
| 1387 | .storage = switch (aggregate.storage) { | ||
| 1388 | .bytes => .{ .bytes = try sema.arena.dupe(u8, mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.bytes[start..end]) }, | ||
| 1389 | .elems => .{ .elems = try sema.arena.dupe(InternPool.Index, mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.elems[start..end]) }, | ||
| 1390 | .repeated_elem => |elem| .{ .repeated_elem = elem }, | ||
| 1391 | }, | ||
| 1392 | } }))), | ||
| 1393 | else => unreachable, | ||
| 1394 | }; | ||
| 1395 | } | 1343 | } |
| 1396 | 1344 | ||
| 1397 | pub fn fieldValue(val: Value, mod: *Module, index: usize) !Value { | 1345 | pub fn fieldValue(val: Value, mod: *Module, index: usize) !Value { |
| ... | @@ -3586,6 +3534,10 @@ pub fn isGenericPoison(val: Value) bool { | ... | @@ -3586,6 +3534,10 @@ pub fn isGenericPoison(val: Value) bool { |
| 3586 | return val.toIntern() == .generic_poison; | 3534 | return val.toIntern() == .generic_poison; |
| 3587 | } | 3535 | } |
| 3588 | 3536 | ||
| 3537 | pub fn typeOf(val: Value, zcu: *const Zcu) Type { | ||
| 3538 | return Type.fromInterned(zcu.intern_pool.typeOf(val.toIntern())); | ||
| 3539 | } | ||
| 3540 | |||
| 3589 | /// For an integer (comptime or fixed-width) `val`, returns the comptime-known bounds of the value. | 3541 | /// For an integer (comptime or fixed-width) `val`, returns the comptime-known bounds of the value. |
| 3590 | /// If `val` is not undef, the bounds are both `val`. | 3542 | /// If `val` is not undef, the bounds are both `val`. |
| 3591 | /// If `val` is undef and has a fixed-width type, the bounds are the bounds of the type. | 3543 | /// If `val` is undef and has a fixed-width type, the bounds are the bounds of the type. |
test/behavior/basic.zig-25| ... | @@ -693,31 +693,6 @@ test "string concatenation" { | ... | @@ -693,31 +693,6 @@ test "string concatenation" { |
| 693 | try expect(b[len] == 0); | 693 | try expect(b[len] == 0); |
| 694 | } | 694 | } |
| 695 | 695 | ||
| 696 | fn manyptrConcat(comptime s: [*:0]const u8) [*:0]const u8 { | ||
| 697 | return "very " ++ s; | ||
| 698 | } | ||
| 699 | |||
| 700 | test "comptime manyptr concatenation" { | ||
| 701 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | ||
| 702 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 703 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | ||
| 704 | |||
| 705 | const s = "epic"; | ||
| 706 | const actual = manyptrConcat(s); | ||
| 707 | const expected = "very epic"; | ||
| 708 | |||
| 709 | const len = mem.len(actual); | ||
| 710 | const len_with_null = len + 1; | ||
| 711 | { | ||
| 712 | var i: u32 = 0; | ||
| 713 | while (i < len_with_null) : (i += 1) { | ||
| 714 | try expect(actual[i] == expected[i]); | ||
| 715 | } | ||
| 716 | } | ||
| 717 | try expect(actual[len] == 0); | ||
| 718 | try expect(expected[len] == 0); | ||
| 719 | } | ||
| 720 | |||
| 721 | test "result location is optional inside error union" { | 696 | test "result location is optional inside error union" { |
| 722 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 697 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 723 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 698 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |