| author | |
| committer | |
| log | 6ab8b6f8b273356ce248a075b6a0657bfea33c79 |
| tree | cf0ea8802bc77376a38a4cfa25c6e9413d5b3fc0 |
| parent | 773fabf3610629c8974b59ed6fbd27050b7e505b |
10 files changed, 1440 insertions(+), 1333 deletions(-)
src/Module.zig+4-4| ... | ... | @@ -932,7 +932,7 @@ pub const Decl = struct { |
| 932 | 932 | assert(decl.has_tv); |
| 933 | 933 | return switch (decl.val.tag()) { |
| 934 | 934 | .extern_fn => true, |
| 935 | .variable => decl.val.castTag(.variable).?.data.init.tag() == .unreachable_value, | |
| 935 | .variable => decl.val.castTag(.variable).?.data.init.ip_index == .unreachable_value, | |
| 936 | 936 | else => false, |
| 937 | 937 | }; |
| 938 | 938 | } |
| ... | ... | @@ -4849,6 +4849,8 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 4849 | 4849 | var is_extern = false; |
| 4850 | 4850 | switch (decl_tv.val.ip_index) { |
| 4851 | 4851 | .generic_poison => unreachable, |
| 4852 | .unreachable_value => unreachable, | |
| 4853 | ||
| 4852 | 4854 | .none => switch (decl_tv.val.tag()) { |
| 4853 | 4855 | .variable => { |
| 4854 | 4856 | const variable = decl_tv.val.castTag(.variable).?.data; |
| ... | ... | @@ -4869,8 +4871,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 4869 | 4871 | } |
| 4870 | 4872 | }, |
| 4871 | 4873 | |
| 4872 | .unreachable_value => unreachable, | |
| 4873 | ||
| 4874 | 4874 | .function => {}, |
| 4875 | 4875 | |
| 4876 | 4876 | else => { |
| ... | ... | @@ -6592,7 +6592,7 @@ pub fn populateTestFunctions( |
| 6592 | 6592 | .len = try Value.Tag.int_u64.create(arena, test_name_slice.len), |
| 6593 | 6593 | }), // name |
| 6594 | 6594 | try Value.Tag.decl_ref.create(arena, test_decl_index), // func |
| 6595 | Value.initTag(.null_value), // async_frame_size | |
| 6595 | Value.null, // async_frame_size | |
| 6596 | 6596 | }; |
| 6597 | 6597 | test_fn_vals[i] = try Value.Tag.aggregate.create(arena, field_vals); |
| 6598 | 6598 | } |
src/Sema.zig+572-530| ... | ... | @@ -1877,8 +1877,8 @@ fn resolveConstValue( |
| 1877 | 1877 | if (try sema.resolveMaybeUndefValAllowVariables(air_ref)) |val| { |
| 1878 | 1878 | switch (val.ip_index) { |
| 1879 | 1879 | .generic_poison => return error.GenericPoison, |
| 1880 | .undef => return sema.failWithUseOfUndef(block, src), | |
| 1880 | 1881 | .none => switch (val.tag()) { |
| 1881 | .undef => return sema.failWithUseOfUndef(block, src), | |
| 1882 | 1882 | .variable => return sema.failWithNeededComptime(block, src, reason), |
| 1883 | 1883 | else => return val, |
| 1884 | 1884 | }, |
| ... | ... | @@ -4409,7 +4409,7 @@ fn validateStructInit( |
| 4409 | 4409 | if (field_ptr != 0) continue; |
| 4410 | 4410 | |
| 4411 | 4411 | const default_val = struct_ty.structFieldDefaultValue(i); |
| 4412 | if (default_val.tag() == .unreachable_value) { | |
| 4412 | if (default_val.ip_index == .unreachable_value) { | |
| 4413 | 4413 | if (struct_ty.isTuple()) { |
| 4414 | 4414 | const template = "missing tuple field with index {d}"; |
| 4415 | 4415 | if (root_msg) |msg| { |
| ... | ... | @@ -4554,7 +4554,7 @@ fn validateStructInit( |
| 4554 | 4554 | } |
| 4555 | 4555 | |
| 4556 | 4556 | const default_val = struct_ty.structFieldDefaultValue(i); |
| 4557 | if (default_val.tag() == .unreachable_value) { | |
| 4557 | if (default_val.ip_index == .unreachable_value) { | |
| 4558 | 4558 | if (struct_ty.isTuple()) { |
| 4559 | 4559 | const template = "missing tuple field with index {d}"; |
| 4560 | 4560 | if (root_msg) |msg| { |
| ... | ... | @@ -4644,7 +4644,7 @@ fn zirValidateArrayInit( |
| 4644 | 4644 | var i = instrs.len; |
| 4645 | 4645 | while (i < array_len) : (i += 1) { |
| 4646 | 4646 | const default_val = array_ty.structFieldDefaultValue(i); |
| 4647 | if (default_val.tag() == .unreachable_value) { | |
| 4647 | if (default_val.ip_index == .unreachable_value) { | |
| 4648 | 4648 | const template = "missing tuple field with index {d}"; |
| 4649 | 4649 | if (root_msg) |msg| { |
| 4650 | 4650 | try sema.errNote(block, init_src, msg, template, .{i}); |
| ... | ... | @@ -7885,7 +7885,7 @@ fn resolveTupleLazyValues(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) |
| 7885 | 7885 | const tuple = ty.tupleFields(); |
| 7886 | 7886 | for (tuple.values, 0..) |field_val, i| { |
| 7887 | 7887 | try sema.resolveTupleLazyValues(block, src, tuple.types[i]); |
| 7888 | if (field_val.tag() == .unreachable_value) continue; | |
| 7888 | if (field_val.ip_index == .unreachable_value) continue; | |
| 7889 | 7889 | try sema.resolveLazyValue(field_val); |
| 7890 | 7890 | } |
| 7891 | 7891 | } |
| ... | ... | @@ -12641,7 +12641,7 @@ fn analyzeTupleCat( |
| 12641 | 12641 | const default_val = lhs_ty.structFieldDefaultValue(i); |
| 12642 | 12642 | values[i] = default_val; |
| 12643 | 12643 | const operand_src = lhs_src; // TODO better source location |
| 12644 | if (default_val.tag() == .unreachable_value) { | |
| 12644 | if (default_val.ip_index == .unreachable_value) { | |
| 12645 | 12645 | runtime_src = operand_src; |
| 12646 | 12646 | } |
| 12647 | 12647 | } |
| ... | ... | @@ -12651,7 +12651,7 @@ fn analyzeTupleCat( |
| 12651 | 12651 | const default_val = rhs_ty.structFieldDefaultValue(i); |
| 12652 | 12652 | values[i + lhs_len] = default_val; |
| 12653 | 12653 | const operand_src = rhs_src; // TODO better source location |
| 12654 | if (default_val.tag() == .unreachable_value) { | |
| 12654 | if (default_val.ip_index == .unreachable_value) { | |
| 12655 | 12655 | runtime_src = operand_src; |
| 12656 | 12656 | } |
| 12657 | 12657 | } |
| ... | ... | @@ -12809,8 +12809,8 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 12809 | 12809 | while (elem_i < lhs_len) : (elem_i += 1) { |
| 12810 | 12810 | const lhs_elem_i = elem_i; |
| 12811 | 12811 | const elem_ty = if (lhs_is_tuple) lhs_ty.structFieldType(lhs_elem_i) else lhs_info.elem_type; |
| 12812 | const elem_default_val = if (lhs_is_tuple) lhs_ty.structFieldDefaultValue(lhs_elem_i) else Value.initTag(.unreachable_value); | |
| 12813 | const elem_val = if (elem_default_val.tag() == .unreachable_value) try lhs_sub_val.elemValue(sema.mod, sema.arena, lhs_elem_i) else elem_default_val; | |
| 12812 | const elem_default_val = if (lhs_is_tuple) lhs_ty.structFieldDefaultValue(lhs_elem_i) else Value.@"unreachable"; | |
| 12813 | const elem_val = if (elem_default_val.ip_index == .unreachable_value) try lhs_sub_val.elemValue(sema.mod, sema.arena, lhs_elem_i) else elem_default_val; | |
| 12814 | 12814 | const elem_val_inst = try sema.addConstant(elem_ty, elem_val); |
| 12815 | 12815 | const coerced_elem_val_inst = try sema.coerce(block, resolved_elem_ty, elem_val_inst, .unneeded); |
| 12816 | 12816 | const coerced_elem_val = try sema.resolveConstMaybeUndefVal(block, .unneeded, coerced_elem_val_inst, ""); |
| ... | ... | @@ -12819,8 +12819,8 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 12819 | 12819 | while (elem_i < result_len) : (elem_i += 1) { |
| 12820 | 12820 | const rhs_elem_i = elem_i - lhs_len; |
| 12821 | 12821 | const elem_ty = if (rhs_is_tuple) rhs_ty.structFieldType(rhs_elem_i) else rhs_info.elem_type; |
| 12822 | const elem_default_val = if (rhs_is_tuple) rhs_ty.structFieldDefaultValue(rhs_elem_i) else Value.initTag(.unreachable_value); | |
| 12823 | const elem_val = if (elem_default_val.tag() == .unreachable_value) try rhs_sub_val.elemValue(sema.mod, sema.arena, rhs_elem_i) else elem_default_val; | |
| 12822 | const elem_default_val = if (rhs_is_tuple) rhs_ty.structFieldDefaultValue(rhs_elem_i) else Value.@"unreachable"; | |
| 12823 | const elem_val = if (elem_default_val.ip_index == .unreachable_value) try rhs_sub_val.elemValue(sema.mod, sema.arena, rhs_elem_i) else elem_default_val; | |
| 12824 | 12824 | const elem_val_inst = try sema.addConstant(elem_ty, elem_val); |
| 12825 | 12825 | const coerced_elem_val_inst = try sema.coerce(block, resolved_elem_ty, elem_val_inst, .unneeded); |
| 12826 | 12826 | const coerced_elem_val = try sema.resolveConstMaybeUndefVal(block, .unneeded, coerced_elem_val_inst, ""); |
| ... | ... | @@ -12962,7 +12962,7 @@ fn analyzeTupleMul( |
| 12962 | 12962 | types[i] = operand_ty.structFieldType(i); |
| 12963 | 12963 | values[i] = operand_ty.structFieldDefaultValue(i); |
| 12964 | 12964 | const operand_src = lhs_src; // TODO better source location |
| 12965 | if (values[i].tag() == .unreachable_value) { | |
| 12965 | if (values[i].ip_index == .unreachable_value) { | |
| 12966 | 12966 | runtime_src = operand_src; |
| 12967 | 12967 | } |
| 12968 | 12968 | } |
| ... | ... | @@ -14332,7 +14332,7 @@ fn zirOverflowArithmetic( |
| 14332 | 14332 | |
| 14333 | 14333 | var result: struct { |
| 14334 | 14334 | inst: Air.Inst.Ref = .none, |
| 14335 | wrapped: Value = Value.initTag(.unreachable_value), | |
| 14335 | wrapped: Value = Value.@"unreachable", | |
| 14336 | 14336 | overflow_bit: Value, |
| 14337 | 14337 | } = result: { |
| 14338 | 14338 | switch (zir_tag) { |
| ... | ... | @@ -14508,8 +14508,8 @@ fn overflowArithmeticTupleType(sema: *Sema, ty: Type) !Type { |
| 14508 | 14508 | |
| 14509 | 14509 | types[0] = ty; |
| 14510 | 14510 | types[1] = ov_ty; |
| 14511 | values[0] = Value.initTag(.unreachable_value); | |
| 14512 | values[1] = Value.initTag(.unreachable_value); | |
| 14511 | values[0] = Value.@"unreachable"; | |
| 14512 | values[1] = Value.@"unreachable"; | |
| 14513 | 14513 | |
| 14514 | 14514 | return tuple_ty; |
| 14515 | 14515 | } |
| ... | ... | @@ -15647,7 +15647,7 @@ fn zirClosureCapture( |
| 15647 | 15647 | // value only. In such case we preserve the type and use a dummy runtime value. |
| 15648 | 15648 | const operand = try sema.resolveInst(inst_data.operand); |
| 15649 | 15649 | const val = (try sema.resolveMaybeUndefValAllowVariables(operand)) orelse |
| 15650 | Value.initTag(.unreachable_value); | |
| 15650 | Value.@"unreachable"; | |
| 15651 | 15651 | |
| 15652 | 15652 | try block.wip_capture_scope.captures.putNoClobber(sema.gpa, inst, .{ |
| 15653 | 15653 | .ty = try sema.typeOf(operand).copy(sema.perm_arena), |
| ... | ... | @@ -15684,7 +15684,7 @@ fn zirClosureGet( |
| 15684 | 15684 | scope = scope.parent.?; |
| 15685 | 15685 | }; |
| 15686 | 15686 | |
| 15687 | if (tv.val.tag() == .unreachable_value and !block.is_typeof and sema.func == null) { | |
| 15687 | if (tv.val.ip_index == .unreachable_value and !block.is_typeof and sema.func == null) { | |
| 15688 | 15688 | const msg = msg: { |
| 15689 | 15689 | const name = name: { |
| 15690 | 15690 | const file = sema.owner_decl.getFileScope(); |
| ... | ... | @@ -15712,7 +15712,7 @@ fn zirClosureGet( |
| 15712 | 15712 | return sema.failWithOwnedErrorMsg(msg); |
| 15713 | 15713 | } |
| 15714 | 15714 | |
| 15715 | if (tv.val.tag() == .unreachable_value and !block.is_typeof and !block.is_comptime and sema.func != null) { | |
| 15715 | if (tv.val.ip_index == .unreachable_value and !block.is_typeof and !block.is_comptime and sema.func != null) { | |
| 15716 | 15716 | const msg = msg: { |
| 15717 | 15717 | const name = name: { |
| 15718 | 15718 | const file = sema.owner_decl.getFileScope(); |
| ... | ... | @@ -15742,7 +15742,7 @@ fn zirClosureGet( |
| 15742 | 15742 | return sema.failWithOwnedErrorMsg(msg); |
| 15743 | 15743 | } |
| 15744 | 15744 | |
| 15745 | if (tv.val.tag() == .unreachable_value) { | |
| 15745 | if (tv.val.ip_index == .unreachable_value) { | |
| 15746 | 15746 | assert(block.is_typeof); |
| 15747 | 15747 | // We need a dummy runtime instruction with the correct type. |
| 15748 | 15748 | return block.addTy(.alloc, tv.ty); |
| ... | ... | @@ -16477,7 +16477,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16477 | 16477 | |
| 16478 | 16478 | const struct_field_fields = try fields_anon_decl.arena().create([5]Value); |
| 16479 | 16479 | const field_val = tuple.values[i]; |
| 16480 | const is_comptime = field_val.tag() != .unreachable_value; | |
| 16480 | const is_comptime = field_val.ip_index != .unreachable_value; | |
| 16481 | 16481 | const opt_default_val = if (is_comptime) field_val else null; |
| 16482 | 16482 | const default_val_ptr = try sema.optRefValue(block, field_ty, opt_default_val); |
| 16483 | 16483 | struct_field_fields.* = .{ |
| ... | ... | @@ -16518,7 +16518,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16518 | 16518 | }; |
| 16519 | 16519 | |
| 16520 | 16520 | const struct_field_fields = try fields_anon_decl.arena().create([5]Value); |
| 16521 | const opt_default_val = if (field.default_val.tag() == .unreachable_value) | |
| 16521 | const opt_default_val = if (field.default_val.ip_index == .unreachable_value) | |
| 16522 | 16522 | null |
| 16523 | 16523 | else |
| 16524 | 16524 | field.default_val; |
| ... | ... | @@ -16570,7 +16570,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16570 | 16570 | const backing_int_ty_val = try Value.Tag.ty.create(sema.arena, struct_obj.backing_int_ty); |
| 16571 | 16571 | break :blk try Value.Tag.opt_payload.create(sema.arena, backing_int_ty_val); |
| 16572 | 16572 | } else { |
| 16573 | break :blk Value.initTag(.null_value); | |
| 16573 | break :blk Value.null; | |
| 16574 | 16574 | } |
| 16575 | 16575 | }; |
| 16576 | 16576 | |
| ... | ... | @@ -17974,7 +17974,7 @@ fn finishStructInit( |
| 17974 | 17974 | for (struct_obj.values, 0..) |default_val, i| { |
| 17975 | 17975 | if (field_inits[i] != .none) continue; |
| 17976 | 17976 | |
| 17977 | if (default_val.tag() == .unreachable_value) { | |
| 17977 | if (default_val.ip_index == .unreachable_value) { | |
| 17978 | 17978 | const field_name = struct_obj.names[i]; |
| 17979 | 17979 | const template = "missing struct field: {s}"; |
| 17980 | 17980 | const args = .{field_name}; |
| ... | ... | @@ -17994,7 +17994,7 @@ fn finishStructInit( |
| 17994 | 17994 | if (field_inits[i] != .none) continue; |
| 17995 | 17995 | |
| 17996 | 17996 | const default_val = struct_ty.structFieldDefaultValue(i); |
| 17997 | if (default_val.tag() == .unreachable_value) { | |
| 17997 | if (default_val.ip_index == .unreachable_value) { | |
| 17998 | 17998 | const template = "missing tuple field with index {d}"; |
| 17999 | 17999 | if (root_msg) |msg| { |
| 18000 | 18000 | try sema.errNote(block, init_src, msg, template, .{i}); |
| ... | ... | @@ -18010,7 +18010,7 @@ fn finishStructInit( |
| 18010 | 18010 | for (struct_obj.fields.values(), 0..) |field, i| { |
| 18011 | 18011 | if (field_inits[i] != .none) continue; |
| 18012 | 18012 | |
| 18013 | if (field.default_val.tag() == .unreachable_value) { | |
| 18013 | if (field.default_val.ip_index == .unreachable_value) { | |
| 18014 | 18014 | const field_name = struct_obj.fields.keys()[i]; |
| 18015 | 18015 | const template = "missing struct field: {s}"; |
| 18016 | 18016 | const args = .{field_name}; |
| ... | ... | @@ -18145,7 +18145,7 @@ fn zirStructInitAnon( |
| 18145 | 18145 | if (try sema.resolveMaybeUndefVal(init)) |init_val| { |
| 18146 | 18146 | values[i] = init_val; |
| 18147 | 18147 | } else { |
| 18148 | values[i] = Value.initTag(.unreachable_value); | |
| 18148 | values[i] = Value.@"unreachable"; | |
| 18149 | 18149 | runtime_index = i; |
| 18150 | 18150 | } |
| 18151 | 18151 | } |
| ... | ... | @@ -18191,7 +18191,7 @@ fn zirStructInitAnon( |
| 18191 | 18191 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), |
| 18192 | 18192 | .pointee_type = field_ty, |
| 18193 | 18193 | }); |
| 18194 | if (values[i].tag() == .unreachable_value) { | |
| 18194 | if (values[i].ip_index == .unreachable_value) { | |
| 18195 | 18195 | const init = try sema.resolveInst(item.data.init); |
| 18196 | 18196 | const field_ptr = try block.addStructFieldPtr(alloc, i, field_ptr_ty); |
| 18197 | 18197 | _ = try block.addBinOp(.store, field_ptr, init); |
| ... | ... | @@ -18357,7 +18357,7 @@ fn zirArrayInitAnon( |
| 18357 | 18357 | if (try sema.resolveMaybeUndefVal(elem)) |val| { |
| 18358 | 18358 | values[i] = val; |
| 18359 | 18359 | } else { |
| 18360 | values[i] = Value.initTag(.unreachable_value); | |
| 18360 | values[i] = Value.@"unreachable"; | |
| 18361 | 18361 | runtime_src = operand_src; |
| 18362 | 18362 | } |
| 18363 | 18363 | } |
| ... | ... | @@ -18390,7 +18390,7 @@ fn zirArrayInitAnon( |
| 18390 | 18390 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), |
| 18391 | 18391 | .pointee_type = types[i], |
| 18392 | 18392 | }); |
| 18393 | if (values[i].tag() == .unreachable_value) { | |
| 18393 | if (values[i].ip_index == .unreachable_value) { | |
| 18394 | 18394 | const field_ptr = try block.addStructFieldPtr(alloc, i, field_ptr_ty); |
| 18395 | 18395 | _ = try block.addBinOp(.store, field_ptr, try sema.resolveInst(operand)); |
| 18396 | 18396 | } |
| ... | ... | @@ -19545,8 +19545,8 @@ fn reifyStruct( |
| 19545 | 19545 | else |
| 19546 | 19546 | opt_val; |
| 19547 | 19547 | break :blk try payload_val.copy(new_decl_arena_allocator); |
| 19548 | } else Value.initTag(.unreachable_value); | |
| 19549 | if (is_comptime_val.toBool(mod) and default_val.tag() == .unreachable_value) { | |
| 19548 | } else Value.@"unreachable"; | |
| 19549 | if (is_comptime_val.toBool(mod) and default_val.ip_index == .unreachable_value) { | |
| 19550 | 19550 | return sema.fail(block, src, "comptime field without default initialization value", .{}); |
| 19551 | 19551 | } |
| 19552 | 19552 | |
| ... | ... | @@ -22579,7 +22579,7 @@ fn zirVarExtended( |
| 22579 | 22579 | |
| 22580 | 22580 | break :blk (try sema.resolveMaybeUndefVal(init)) orelse |
| 22581 | 22581 | return sema.failWithNeededComptime(block, init_src, "container level variable initializers must be comptime-known"); |
| 22582 | } else Value.initTag(.unreachable_value); | |
| 22582 | } else Value.@"unreachable"; | |
| 22583 | 22583 | |
| 22584 | 22584 | try sema.validateVarType(block, ty_src, var_ty, small.is_extern); |
| 22585 | 22585 | |
| ... | ... | @@ -23080,7 +23080,7 @@ fn zirBuiltinExtern( |
| 23080 | 23080 | const new_var = try new_decl_arena_allocator.create(Module.Var); |
| 23081 | 23081 | new_var.* = .{ |
| 23082 | 23082 | .owner_decl = sema.owner_decl_index, |
| 23083 | .init = Value.initTag(.unreachable_value), | |
| 23083 | .init = Value.@"unreachable", | |
| 23084 | 23084 | .is_extern = true, |
| 23085 | 23085 | .is_mutable = false, |
| 23086 | 23086 | .is_threadlocal = options.is_thread_local, |
| ... | ... | @@ -25736,7 +25736,7 @@ fn coerceExtra( |
| 25736 | 25736 | } |
| 25737 | 25737 | } else { |
| 25738 | 25738 | in_memory_result = .{ .ptr_sentinel = .{ |
| 25739 | .actual = Value.initTag(.unreachable_value), | |
| 25739 | .actual = Value.@"unreachable", | |
| 25740 | 25740 | .wanted = dest_sent, |
| 25741 | 25741 | .ty = dst_elem_type, |
| 25742 | 25742 | } }; |
| ... | ... | @@ -26116,26 +26116,28 @@ fn coerceExtra( |
| 26116 | 26116 | .ErrorUnion => switch (inst_ty.zigTypeTag(mod)) { |
| 26117 | 26117 | .ErrorUnion => eu: { |
| 26118 | 26118 | if (maybe_inst_val) |inst_val| { |
| 26119 | switch (inst_val.tag()) { | |
| 26119 | switch (inst_val.ip_index) { | |
| 26120 | 26120 | .undef => return sema.addConstUndef(dest_ty), |
| 26121 | .eu_payload => { | |
| 26122 | const payload = try sema.addConstant( | |
| 26123 | inst_ty.errorUnionPayload(), | |
| 26124 | inst_val.castTag(.eu_payload).?.data, | |
| 26125 | ); | |
| 26126 | return sema.wrapErrorUnionPayload(block, dest_ty, payload, inst_src) catch |err| switch (err) { | |
| 26127 | error.NotCoercible => break :eu, | |
| 26128 | else => |e| return e, | |
| 26129 | }; | |
| 26130 | }, | |
| 26131 | else => { | |
| 26132 | const error_set = try sema.addConstant( | |
| 26133 | inst_ty.errorUnionSet(), | |
| 26134 | inst_val, | |
| 26135 | ); | |
| 26136 | return sema.wrapErrorUnionSet(block, dest_ty, error_set, inst_src); | |
| 26121 | .none => switch (inst_val.tag()) { | |
| 26122 | .eu_payload => { | |
| 26123 | const payload = try sema.addConstant( | |
| 26124 | inst_ty.errorUnionPayload(), | |
| 26125 | inst_val.castTag(.eu_payload).?.data, | |
| 26126 | ); | |
| 26127 | return sema.wrapErrorUnionPayload(block, dest_ty, payload, inst_src) catch |err| switch (err) { | |
| 26128 | error.NotCoercible => break :eu, | |
| 26129 | else => |e| return e, | |
| 26130 | }; | |
| 26131 | }, | |
| 26132 | else => {}, | |
| 26137 | 26133 | }, |
| 26134 | else => {}, | |
| 26138 | 26135 | } |
| 26136 | const error_set = try sema.addConstant( | |
| 26137 | inst_ty.errorUnionSet(), | |
| 26138 | inst_val, | |
| 26139 | ); | |
| 26140 | return sema.wrapErrorUnionSet(block, dest_ty, error_set, inst_src); | |
| 26139 | 26141 | } |
| 26140 | 26142 | }, |
| 26141 | 26143 | .ErrorSet => { |
| ... | ... | @@ -26413,7 +26415,7 @@ const InMemoryCoercionResult = union(enum) { |
| 26413 | 26415 | break; |
| 26414 | 26416 | }, |
| 26415 | 26417 | .array_sentinel => |sentinel| { |
| 26416 | if (sentinel.actual.tag() != .unreachable_value) { | |
| 26418 | if (sentinel.actual.ip_index != .unreachable_value) { | |
| 26417 | 26419 | try sema.errNote(block, src, msg, "array sentinel '{}' cannot cast into array sentinel '{}'", .{ |
| 26418 | 26420 | sentinel.actual.fmtValue(sentinel.ty, sema.mod), sentinel.wanted.fmtValue(sentinel.ty, sema.mod), |
| 26419 | 26421 | }); |
| ... | ... | @@ -26539,7 +26541,7 @@ const InMemoryCoercionResult = union(enum) { |
| 26539 | 26541 | break; |
| 26540 | 26542 | }, |
| 26541 | 26543 | .ptr_sentinel => |sentinel| { |
| 26542 | if (sentinel.actual.tag() != .unreachable_value) { | |
| 26544 | if (sentinel.actual.ip_index != .unreachable_value) { | |
| 26543 | 26545 | try sema.errNote(block, src, msg, "pointer sentinel '{}' cannot cast into pointer sentinel '{}'", .{ |
| 26544 | 26546 | sentinel.actual.fmtValue(sentinel.ty, sema.mod), sentinel.wanted.fmtValue(sentinel.ty, sema.mod), |
| 26545 | 26547 | }); |
| ... | ... | @@ -26747,8 +26749,8 @@ fn coerceInMemoryAllowed( |
| 26747 | 26749 | dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.elem_type, mod)); |
| 26748 | 26750 | if (!ok_sent) { |
| 26749 | 26751 | return InMemoryCoercionResult{ .array_sentinel = .{ |
| 26750 | .actual = src_info.sentinel orelse Value.initTag(.unreachable_value), | |
| 26751 | .wanted = dest_info.sentinel orelse Value.initTag(.unreachable_value), | |
| 26752 | .actual = src_info.sentinel orelse Value.@"unreachable", | |
| 26753 | .wanted = dest_info.sentinel orelse Value.@"unreachable", | |
| 26752 | 26754 | .ty = dest_info.elem_type, |
| 26753 | 26755 | } }; |
| 26754 | 26756 | } |
| ... | ... | @@ -27129,8 +27131,8 @@ fn coerceInMemoryAllowedPtrs( |
| 27129 | 27131 | dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.pointee_type, sema.mod)); |
| 27130 | 27132 | if (!ok_sent) { |
| 27131 | 27133 | return InMemoryCoercionResult{ .ptr_sentinel = .{ |
| 27132 | .actual = src_info.sentinel orelse Value.initTag(.unreachable_value), | |
| 27133 | .wanted = dest_info.sentinel orelse Value.initTag(.unreachable_value), | |
| 27134 | .actual = src_info.sentinel orelse Value.@"unreachable", | |
| 27135 | .wanted = dest_info.sentinel orelse Value.@"unreachable", | |
| 27134 | 27136 | .ty = dest_info.pointee_type, |
| 27135 | 27137 | } }; |
| 27136 | 27138 | } |
| ... | ... | @@ -27540,7 +27542,7 @@ fn beginComptimePtrMutation( |
| 27540 | 27542 | }; |
| 27541 | 27543 | } |
| 27542 | 27544 | |
| 27543 | switch (val_ptr.tag()) { | |
| 27545 | switch (val_ptr.ip_index) { | |
| 27544 | 27546 | .undef => { |
| 27545 | 27547 | // An array has been initialized to undefined at comptime and now we |
| 27546 | 27548 | // are for the first time setting an element. We must change the representation |
| ... | ... | @@ -27565,127 +27567,130 @@ fn beginComptimePtrMutation( |
| 27565 | 27567 | parent.decl_ref_mut, |
| 27566 | 27568 | ); |
| 27567 | 27569 | }, |
| 27568 | .bytes => { | |
| 27569 | // An array is memory-optimized to store a slice of bytes, but we are about | |
| 27570 | // to modify an individual field and the representation has to change. | |
| 27571 | // If we wanted to avoid this, there would need to be special detection | |
| 27572 | // elsewhere to identify when writing a value to an array element that is stored | |
| 27573 | // using the `bytes` tag, and handle it without making a call to this function. | |
| 27574 | const arena = parent.beginArena(sema.mod); | |
| 27575 | defer parent.finishArena(sema.mod); | |
| 27576 | ||
| 27577 | const bytes = val_ptr.castTag(.bytes).?.data; | |
| 27578 | const dest_len = parent.ty.arrayLenIncludingSentinel(mod); | |
| 27579 | // bytes.len may be one greater than dest_len because of the case when | |
| 27580 | // assigning `[N:S]T` to `[N]T`. This is allowed; the sentinel is omitted. | |
| 27581 | assert(bytes.len >= dest_len); | |
| 27582 | const elems = try arena.alloc(Value, @intCast(usize, dest_len)); | |
| 27583 | for (elems, 0..) |*elem, i| { | |
| 27584 | elem.* = try Value.Tag.int_u64.create(arena, bytes[i]); | |
| 27585 | } | |
| 27586 | ||
| 27587 | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); | |
| 27570 | .none => switch (val_ptr.tag()) { | |
| 27571 | .bytes => { | |
| 27572 | // An array is memory-optimized to store a slice of bytes, but we are about | |
| 27573 | // to modify an individual field and the representation has to change. | |
| 27574 | // If we wanted to avoid this, there would need to be special detection | |
| 27575 | // elsewhere to identify when writing a value to an array element that is stored | |
| 27576 | // using the `bytes` tag, and handle it without making a call to this function. | |
| 27577 | const arena = parent.beginArena(sema.mod); | |
| 27578 | defer parent.finishArena(sema.mod); | |
| 27579 | ||
| 27580 | const bytes = val_ptr.castTag(.bytes).?.data; | |
| 27581 | const dest_len = parent.ty.arrayLenIncludingSentinel(mod); | |
| 27582 | // bytes.len may be one greater than dest_len because of the case when | |
| 27583 | // assigning `[N:S]T` to `[N]T`. This is allowed; the sentinel is omitted. | |
| 27584 | assert(bytes.len >= dest_len); | |
| 27585 | const elems = try arena.alloc(Value, @intCast(usize, dest_len)); | |
| 27586 | for (elems, 0..) |*elem, i| { | |
| 27587 | elem.* = try Value.Tag.int_u64.create(arena, bytes[i]); | |
| 27588 | } | |
| 27588 | 27589 | |
| 27589 | return beginComptimePtrMutationInner( | |
| 27590 | sema, | |
| 27591 | block, | |
| 27592 | src, | |
| 27593 | elem_ty, | |
| 27594 | &elems[elem_ptr.index], | |
| 27595 | ptr_elem_ty, | |
| 27596 | parent.decl_ref_mut, | |
| 27597 | ); | |
| 27598 | }, | |
| 27599 | .str_lit => { | |
| 27600 | // An array is memory-optimized to store a slice of bytes, but we are about | |
| 27601 | // to modify an individual field and the representation has to change. | |
| 27602 | // If we wanted to avoid this, there would need to be special detection | |
| 27603 | // elsewhere to identify when writing a value to an array element that is stored | |
| 27604 | // using the `str_lit` tag, and handle it without making a call to this function. | |
| 27605 | const arena = parent.beginArena(sema.mod); | |
| 27606 | defer parent.finishArena(sema.mod); | |
| 27590 | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); | |
| 27607 | 27591 | |
| 27608 | const str_lit = val_ptr.castTag(.str_lit).?.data; | |
| 27609 | const dest_len = parent.ty.arrayLenIncludingSentinel(mod); | |
| 27610 | const bytes = sema.mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | |
| 27611 | const elems = try arena.alloc(Value, @intCast(usize, dest_len)); | |
| 27612 | for (bytes, 0..) |byte, i| { | |
| 27613 | elems[i] = try Value.Tag.int_u64.create(arena, byte); | |
| 27614 | } | |
| 27615 | if (parent.ty.sentinel(mod)) |sent_val| { | |
| 27616 | assert(elems.len == bytes.len + 1); | |
| 27617 | elems[bytes.len] = sent_val; | |
| 27618 | } | |
| 27592 | return beginComptimePtrMutationInner( | |
| 27593 | sema, | |
| 27594 | block, | |
| 27595 | src, | |
| 27596 | elem_ty, | |
| 27597 | &elems[elem_ptr.index], | |
| 27598 | ptr_elem_ty, | |
| 27599 | parent.decl_ref_mut, | |
| 27600 | ); | |
| 27601 | }, | |
| 27602 | .str_lit => { | |
| 27603 | // An array is memory-optimized to store a slice of bytes, but we are about | |
| 27604 | // to modify an individual field and the representation has to change. | |
| 27605 | // If we wanted to avoid this, there would need to be special detection | |
| 27606 | // elsewhere to identify when writing a value to an array element that is stored | |
| 27607 | // using the `str_lit` tag, and handle it without making a call to this function. | |
| 27608 | const arena = parent.beginArena(sema.mod); | |
| 27609 | defer parent.finishArena(sema.mod); | |
| 27610 | ||
| 27611 | const str_lit = val_ptr.castTag(.str_lit).?.data; | |
| 27612 | const dest_len = parent.ty.arrayLenIncludingSentinel(mod); | |
| 27613 | const bytes = sema.mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | |
| 27614 | const elems = try arena.alloc(Value, @intCast(usize, dest_len)); | |
| 27615 | for (bytes, 0..) |byte, i| { | |
| 27616 | elems[i] = try Value.Tag.int_u64.create(arena, byte); | |
| 27617 | } | |
| 27618 | if (parent.ty.sentinel(mod)) |sent_val| { | |
| 27619 | assert(elems.len == bytes.len + 1); | |
| 27620 | elems[bytes.len] = sent_val; | |
| 27621 | } | |
| 27619 | 27622 | |
| 27620 | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); | |
| 27623 | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); | |
| 27621 | 27624 | |
| 27622 | return beginComptimePtrMutationInner( | |
| 27623 | sema, | |
| 27624 | block, | |
| 27625 | src, | |
| 27626 | elem_ty, | |
| 27627 | &elems[elem_ptr.index], | |
| 27628 | ptr_elem_ty, | |
| 27629 | parent.decl_ref_mut, | |
| 27630 | ); | |
| 27631 | }, | |
| 27632 | .repeated => { | |
| 27633 | // An array is memory-optimized to store only a single element value, and | |
| 27634 | // that value is understood to be the same for the entire length of the array. | |
| 27635 | // However, now we want to modify an individual field and so the | |
| 27636 | // representation has to change. If we wanted to avoid this, there would | |
| 27637 | // need to be special detection elsewhere to identify when writing a value to an | |
| 27638 | // array element that is stored using the `repeated` tag, and handle it | |
| 27639 | // without making a call to this function. | |
| 27640 | const arena = parent.beginArena(sema.mod); | |
| 27641 | defer parent.finishArena(sema.mod); | |
| 27625 | return beginComptimePtrMutationInner( | |
| 27626 | sema, | |
| 27627 | block, | |
| 27628 | src, | |
| 27629 | elem_ty, | |
| 27630 | &elems[elem_ptr.index], | |
| 27631 | ptr_elem_ty, | |
| 27632 | parent.decl_ref_mut, | |
| 27633 | ); | |
| 27634 | }, | |
| 27635 | .repeated => { | |
| 27636 | // An array is memory-optimized to store only a single element value, and | |
| 27637 | // that value is understood to be the same for the entire length of the array. | |
| 27638 | // However, now we want to modify an individual field and so the | |
| 27639 | // representation has to change. If we wanted to avoid this, there would | |
| 27640 | // need to be special detection elsewhere to identify when writing a value to an | |
| 27641 | // array element that is stored using the `repeated` tag, and handle it | |
| 27642 | // without making a call to this function. | |
| 27643 | const arena = parent.beginArena(sema.mod); | |
| 27644 | defer parent.finishArena(sema.mod); | |
| 27645 | ||
| 27646 | const repeated_val = try val_ptr.castTag(.repeated).?.data.copy(arena); | |
| 27647 | const array_len_including_sentinel = | |
| 27648 | try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel(mod)); | |
| 27649 | const elems = try arena.alloc(Value, array_len_including_sentinel); | |
| 27650 | if (elems.len > 0) elems[0] = repeated_val; | |
| 27651 | for (elems[1..]) |*elem| { | |
| 27652 | elem.* = try repeated_val.copy(arena); | |
| 27653 | } | |
| 27642 | 27654 | |
| 27643 | const repeated_val = try val_ptr.castTag(.repeated).?.data.copy(arena); | |
| 27644 | const array_len_including_sentinel = | |
| 27645 | try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel(mod)); | |
| 27646 | const elems = try arena.alloc(Value, array_len_including_sentinel); | |
| 27647 | if (elems.len > 0) elems[0] = repeated_val; | |
| 27648 | for (elems[1..]) |*elem| { | |
| 27649 | elem.* = try repeated_val.copy(arena); | |
| 27650 | } | |
| 27655 | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); | |
| 27651 | 27656 | |
| 27652 | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); | |
| 27657 | return beginComptimePtrMutationInner( | |
| 27658 | sema, | |
| 27659 | block, | |
| 27660 | src, | |
| 27661 | elem_ty, | |
| 27662 | &elems[elem_ptr.index], | |
| 27663 | ptr_elem_ty, | |
| 27664 | parent.decl_ref_mut, | |
| 27665 | ); | |
| 27666 | }, | |
| 27653 | 27667 | |
| 27654 | return beginComptimePtrMutationInner( | |
| 27668 | .aggregate => return beginComptimePtrMutationInner( | |
| 27655 | 27669 | sema, |
| 27656 | 27670 | block, |
| 27657 | 27671 | src, |
| 27658 | 27672 | elem_ty, |
| 27659 | &elems[elem_ptr.index], | |
| 27673 | &val_ptr.castTag(.aggregate).?.data[elem_ptr.index], | |
| 27660 | 27674 | ptr_elem_ty, |
| 27661 | 27675 | parent.decl_ref_mut, |
| 27662 | ); | |
| 27663 | }, | |
| 27676 | ), | |
| 27664 | 27677 | |
| 27665 | .aggregate => return beginComptimePtrMutationInner( | |
| 27666 | sema, | |
| 27667 | block, | |
| 27668 | src, | |
| 27669 | elem_ty, | |
| 27670 | &val_ptr.castTag(.aggregate).?.data[elem_ptr.index], | |
| 27671 | ptr_elem_ty, | |
| 27672 | parent.decl_ref_mut, | |
| 27673 | ), | |
| 27678 | .the_only_possible_value => { | |
| 27679 | const duped = try sema.arena.create(Value); | |
| 27680 | duped.* = Value.initTag(.the_only_possible_value); | |
| 27681 | return beginComptimePtrMutationInner( | |
| 27682 | sema, | |
| 27683 | block, | |
| 27684 | src, | |
| 27685 | elem_ty, | |
| 27686 | duped, | |
| 27687 | ptr_elem_ty, | |
| 27688 | parent.decl_ref_mut, | |
| 27689 | ); | |
| 27690 | }, | |
| 27674 | 27691 | |
| 27675 | .the_only_possible_value => { | |
| 27676 | const duped = try sema.arena.create(Value); | |
| 27677 | duped.* = Value.initTag(.the_only_possible_value); | |
| 27678 | return beginComptimePtrMutationInner( | |
| 27679 | sema, | |
| 27680 | block, | |
| 27681 | src, | |
| 27682 | elem_ty, | |
| 27683 | duped, | |
| 27684 | ptr_elem_ty, | |
| 27685 | parent.decl_ref_mut, | |
| 27686 | ); | |
| 27692 | else => unreachable, | |
| 27687 | 27693 | }, |
| 27688 | ||
| 27689 | 27694 | else => unreachable, |
| 27690 | 27695 | } |
| 27691 | 27696 | }, |
| ... | ... | @@ -27738,7 +27743,7 @@ fn beginComptimePtrMutation( |
| 27738 | 27743 | |
| 27739 | 27744 | var parent = try sema.beginComptimePtrMutation(block, src, field_ptr.container_ptr, field_ptr.container_ty); |
| 27740 | 27745 | switch (parent.pointee) { |
| 27741 | .direct => |val_ptr| switch (val_ptr.tag()) { | |
| 27746 | .direct => |val_ptr| switch (val_ptr.ip_index) { | |
| 27742 | 27747 | .undef => { |
| 27743 | 27748 | // A struct or union has been initialized to undefined at comptime and now we |
| 27744 | 27749 | // are for the first time setting a field. We must change the representation |
| ... | ... | @@ -27815,72 +27820,75 @@ fn beginComptimePtrMutation( |
| 27815 | 27820 | else => unreachable, |
| 27816 | 27821 | } |
| 27817 | 27822 | }, |
| 27818 | .aggregate => return beginComptimePtrMutationInner( | |
| 27819 | sema, | |
| 27820 | block, | |
| 27821 | src, | |
| 27822 | parent.ty.structFieldType(field_index), | |
| 27823 | &val_ptr.castTag(.aggregate).?.data[field_index], | |
| 27824 | ptr_elem_ty, | |
| 27825 | parent.decl_ref_mut, | |
| 27826 | ), | |
| 27827 | ||
| 27828 | .@"union" => { | |
| 27829 | // We need to set the active field of the union. | |
| 27830 | const arena = parent.beginArena(sema.mod); | |
| 27831 | defer parent.finishArena(sema.mod); | |
| 27832 | ||
| 27833 | const payload = &val_ptr.castTag(.@"union").?.data; | |
| 27834 | payload.tag = try Value.Tag.enum_field_index.create(arena, field_index); | |
| 27835 | ||
| 27836 | return beginComptimePtrMutationInner( | |
| 27823 | .none => switch (val_ptr.tag()) { | |
| 27824 | .aggregate => return beginComptimePtrMutationInner( | |
| 27837 | 27825 | sema, |
| 27838 | 27826 | block, |
| 27839 | 27827 | src, |
| 27840 | 27828 | parent.ty.structFieldType(field_index), |
| 27841 | &payload.val, | |
| 27842 | ptr_elem_ty, | |
| 27843 | parent.decl_ref_mut, | |
| 27844 | ); | |
| 27845 | }, | |
| 27846 | .slice => switch (field_index) { | |
| 27847 | Value.Payload.Slice.ptr_index => return beginComptimePtrMutationInner( | |
| 27848 | sema, | |
| 27849 | block, | |
| 27850 | src, | |
| 27851 | parent.ty.slicePtrFieldType(try sema.arena.create(Type.SlicePtrFieldTypeBuffer)), | |
| 27852 | &val_ptr.castTag(.slice).?.data.ptr, | |
| 27829 | &val_ptr.castTag(.aggregate).?.data[field_index], | |
| 27853 | 27830 | ptr_elem_ty, |
| 27854 | 27831 | parent.decl_ref_mut, |
| 27855 | 27832 | ), |
| 27856 | 27833 | |
| 27857 | Value.Payload.Slice.len_index => return beginComptimePtrMutationInner( | |
| 27858 | sema, | |
| 27859 | block, | |
| 27860 | src, | |
| 27861 | Type.usize, | |
| 27862 | &val_ptr.castTag(.slice).?.data.len, | |
| 27863 | ptr_elem_ty, | |
| 27864 | parent.decl_ref_mut, | |
| 27865 | ), | |
| 27834 | .@"union" => { | |
| 27835 | // We need to set the active field of the union. | |
| 27836 | const arena = parent.beginArena(sema.mod); | |
| 27837 | defer parent.finishArena(sema.mod); | |
| 27866 | 27838 | |
| 27867 | else => unreachable, | |
| 27868 | }, | |
| 27839 | const payload = &val_ptr.castTag(.@"union").?.data; | |
| 27840 | payload.tag = try Value.Tag.enum_field_index.create(arena, field_index); | |
| 27869 | 27841 | |
| 27870 | .empty_struct_value => { | |
| 27871 | const duped = try sema.arena.create(Value); | |
| 27872 | duped.* = Value.initTag(.the_only_possible_value); | |
| 27873 | return beginComptimePtrMutationInner( | |
| 27874 | sema, | |
| 27875 | block, | |
| 27876 | src, | |
| 27877 | parent.ty.structFieldType(field_index), | |
| 27878 | duped, | |
| 27879 | ptr_elem_ty, | |
| 27880 | parent.decl_ref_mut, | |
| 27881 | ); | |
| 27882 | }, | |
| 27842 | return beginComptimePtrMutationInner( | |
| 27843 | sema, | |
| 27844 | block, | |
| 27845 | src, | |
| 27846 | parent.ty.structFieldType(field_index), | |
| 27847 | &payload.val, | |
| 27848 | ptr_elem_ty, | |
| 27849 | parent.decl_ref_mut, | |
| 27850 | ); | |
| 27851 | }, | |
| 27852 | .slice => switch (field_index) { | |
| 27853 | Value.Payload.Slice.ptr_index => return beginComptimePtrMutationInner( | |
| 27854 | sema, | |
| 27855 | block, | |
| 27856 | src, | |
| 27857 | parent.ty.slicePtrFieldType(try sema.arena.create(Type.SlicePtrFieldTypeBuffer)), | |
| 27858 | &val_ptr.castTag(.slice).?.data.ptr, | |
| 27859 | ptr_elem_ty, | |
| 27860 | parent.decl_ref_mut, | |
| 27861 | ), | |
| 27862 | ||
| 27863 | Value.Payload.Slice.len_index => return beginComptimePtrMutationInner( | |
| 27864 | sema, | |
| 27865 | block, | |
| 27866 | src, | |
| 27867 | Type.usize, | |
| 27868 | &val_ptr.castTag(.slice).?.data.len, | |
| 27869 | ptr_elem_ty, | |
| 27870 | parent.decl_ref_mut, | |
| 27871 | ), | |
| 27872 | ||
| 27873 | else => unreachable, | |
| 27874 | }, | |
| 27875 | ||
| 27876 | .empty_struct_value => { | |
| 27877 | const duped = try sema.arena.create(Value); | |
| 27878 | duped.* = Value.initTag(.the_only_possible_value); | |
| 27879 | return beginComptimePtrMutationInner( | |
| 27880 | sema, | |
| 27881 | block, | |
| 27882 | src, | |
| 27883 | parent.ty.structFieldType(field_index), | |
| 27884 | duped, | |
| 27885 | ptr_elem_ty, | |
| 27886 | parent.decl_ref_mut, | |
| 27887 | ); | |
| 27888 | }, | |
| 27883 | 27889 | |
| 27890 | else => unreachable, | |
| 27891 | }, | |
| 27884 | 27892 | else => unreachable, |
| 27885 | 27893 | }, |
| 27886 | 27894 | .reinterpret => |reinterpret| { |
| ... | ... | @@ -27951,7 +27959,7 @@ fn beginComptimePtrMutation( |
| 27951 | 27959 | switch (parent.pointee) { |
| 27952 | 27960 | .direct => |val_ptr| { |
| 27953 | 27961 | const payload_ty = parent.ty.optionalChild(mod); |
| 27954 | switch (val_ptr.tag()) { | |
| 27962 | switch (val_ptr.ip_index) { | |
| 27955 | 27963 | .undef, .null_value => { |
| 27956 | 27964 | // An optional has been initialized to undefined at comptime and now we |
| 27957 | 27965 | // are for the first time setting the payload. We must change the |
| ... | ... | @@ -27973,12 +27981,19 @@ fn beginComptimePtrMutation( |
| 27973 | 27981 | .ty = payload_ty, |
| 27974 | 27982 | }; |
| 27975 | 27983 | }, |
| 27976 | .opt_payload => return ComptimePtrMutationKit{ | |
| 27977 | .decl_ref_mut = parent.decl_ref_mut, | |
| 27978 | .pointee = .{ .direct = &val_ptr.castTag(.opt_payload).?.data }, | |
| 27979 | .ty = payload_ty, | |
| 27980 | }, | |
| 27984 | .none => switch (val_ptr.tag()) { | |
| 27985 | .opt_payload => return ComptimePtrMutationKit{ | |
| 27986 | .decl_ref_mut = parent.decl_ref_mut, | |
| 27987 | .pointee = .{ .direct = &val_ptr.castTag(.opt_payload).?.data }, | |
| 27988 | .ty = payload_ty, | |
| 27989 | }, | |
| 27981 | 27990 | |
| 27991 | else => return ComptimePtrMutationKit{ | |
| 27992 | .decl_ref_mut = parent.decl_ref_mut, | |
| 27993 | .pointee = .{ .direct = val_ptr }, | |
| 27994 | .ty = payload_ty, | |
| 27995 | }, | |
| 27996 | }, | |
| 27982 | 27997 | else => return ComptimePtrMutationKit{ |
| 27983 | 27998 | .decl_ref_mut = parent.decl_ref_mut, |
| 27984 | 27999 | .pointee = .{ .direct = val_ptr }, |
| ... | ... | @@ -28092,231 +28107,236 @@ fn beginComptimePtrLoad( |
| 28092 | 28107 | ) ComptimePtrLoadError!ComptimePtrLoadKit { |
| 28093 | 28108 | const mod = sema.mod; |
| 28094 | 28109 | const target = sema.mod.getTarget(); |
| 28095 | var deref: ComptimePtrLoadKit = switch (ptr_val.tag()) { | |
| 28096 | .decl_ref, | |
| 28097 | .decl_ref_mut, | |
| 28098 | => blk: { | |
| 28099 | const decl_index = switch (ptr_val.tag()) { | |
| 28100 | .decl_ref => ptr_val.castTag(.decl_ref).?.data, | |
| 28101 | .decl_ref_mut => ptr_val.castTag(.decl_ref_mut).?.data.decl_index, | |
| 28102 | else => unreachable, | |
| 28103 | }; | |
| 28104 | const is_mutable = ptr_val.tag() == .decl_ref_mut; | |
| 28105 | const decl = sema.mod.declPtr(decl_index); | |
| 28106 | const decl_tv = try decl.typedValue(); | |
| 28107 | if (decl_tv.val.tag() == .variable) return error.RuntimeLoad; | |
| 28108 | ||
| 28109 | const layout_defined = decl.ty.hasWellDefinedLayout(mod); | |
| 28110 | break :blk ComptimePtrLoadKit{ | |
| 28111 | .parent = if (layout_defined) .{ .tv = decl_tv, .byte_offset = 0 } else null, | |
| 28112 | .pointee = decl_tv, | |
| 28113 | .is_mutable = is_mutable, | |
| 28114 | .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null, | |
| 28115 | }; | |
| 28110 | ||
| 28111 | var deref: ComptimePtrLoadKit = switch (ptr_val.ip_index) { | |
| 28112 | .null_value => { | |
| 28113 | return sema.fail(block, src, "attempt to use null value", .{}); | |
| 28116 | 28114 | }, |
| 28117 | 28115 | |
| 28118 | .elem_ptr => blk: { | |
| 28119 | const elem_ptr = ptr_val.castTag(.elem_ptr).?.data; | |
| 28120 | const elem_ty = elem_ptr.elem_ty; | |
| 28121 | var deref = try sema.beginComptimePtrLoad(block, src, elem_ptr.array_ptr, null); | |
| 28116 | .none => switch (ptr_val.tag()) { | |
| 28117 | .decl_ref, | |
| 28118 | .decl_ref_mut, | |
| 28119 | => blk: { | |
| 28120 | const decl_index = switch (ptr_val.tag()) { | |
| 28121 | .decl_ref => ptr_val.castTag(.decl_ref).?.data, | |
| 28122 | .decl_ref_mut => ptr_val.castTag(.decl_ref_mut).?.data.decl_index, | |
| 28123 | else => unreachable, | |
| 28124 | }; | |
| 28125 | const is_mutable = ptr_val.tag() == .decl_ref_mut; | |
| 28126 | const decl = sema.mod.declPtr(decl_index); | |
| 28127 | const decl_tv = try decl.typedValue(); | |
| 28128 | if (decl_tv.val.tag() == .variable) return error.RuntimeLoad; | |
| 28129 | ||
| 28130 | const layout_defined = decl.ty.hasWellDefinedLayout(mod); | |
| 28131 | break :blk ComptimePtrLoadKit{ | |
| 28132 | .parent = if (layout_defined) .{ .tv = decl_tv, .byte_offset = 0 } else null, | |
| 28133 | .pointee = decl_tv, | |
| 28134 | .is_mutable = is_mutable, | |
| 28135 | .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null, | |
| 28136 | }; | |
| 28137 | }, | |
| 28122 | 28138 | |
| 28123 | // This code assumes that elem_ptrs have been "flattened" in order for direct dereference | |
| 28124 | // to succeed, meaning that elem ptrs of the same elem_ty are coalesced. Here we check that | |
| 28125 | // our parent is not an elem_ptr with the same elem_ty, since that would be "unflattened" | |
| 28126 | if (elem_ptr.array_ptr.castTag(.elem_ptr)) |parent_elem_ptr| { | |
| 28127 | assert(!(parent_elem_ptr.data.elem_ty.eql(elem_ty, sema.mod))); | |
| 28128 | } | |
| 28139 | .elem_ptr => blk: { | |
| 28140 | const elem_ptr = ptr_val.castTag(.elem_ptr).?.data; | |
| 28141 | const elem_ty = elem_ptr.elem_ty; | |
| 28142 | var deref = try sema.beginComptimePtrLoad(block, src, elem_ptr.array_ptr, null); | |
| 28143 | ||
| 28144 | // This code assumes that elem_ptrs have been "flattened" in order for direct dereference | |
| 28145 | // to succeed, meaning that elem ptrs of the same elem_ty are coalesced. Here we check that | |
| 28146 | // our parent is not an elem_ptr with the same elem_ty, since that would be "unflattened" | |
| 28147 | if (elem_ptr.array_ptr.castTag(.elem_ptr)) |parent_elem_ptr| { | |
| 28148 | assert(!(parent_elem_ptr.data.elem_ty.eql(elem_ty, sema.mod))); | |
| 28149 | } | |
| 28150 | ||
| 28151 | if (elem_ptr.index != 0) { | |
| 28152 | if (elem_ty.hasWellDefinedLayout(mod)) { | |
| 28153 | if (deref.parent) |*parent| { | |
| 28154 | // Update the byte offset (in-place) | |
| 28155 | const elem_size = try sema.typeAbiSize(elem_ty); | |
| 28156 | const offset = parent.byte_offset + elem_size * elem_ptr.index; | |
| 28157 | parent.byte_offset = try sema.usizeCast(block, src, offset); | |
| 28158 | } | |
| 28159 | } else { | |
| 28160 | deref.parent = null; | |
| 28161 | deref.ty_without_well_defined_layout = elem_ty; | |
| 28162 | } | |
| 28163 | } | |
| 28164 | ||
| 28165 | // If we're loading an elem_ptr that was derived from a different type | |
| 28166 | // than the true type of the underlying decl, we cannot deref directly | |
| 28167 | const ty_matches = if (deref.pointee != null and deref.pointee.?.ty.isArrayOrVector(mod)) x: { | |
| 28168 | const deref_elem_ty = deref.pointee.?.ty.childType(mod); | |
| 28169 | break :x (try sema.coerceInMemoryAllowed(block, deref_elem_ty, elem_ty, false, target, src, src)) == .ok or | |
| 28170 | (try sema.coerceInMemoryAllowed(block, elem_ty, deref_elem_ty, false, target, src, src)) == .ok; | |
| 28171 | } else false; | |
| 28172 | if (!ty_matches) { | |
| 28173 | deref.pointee = null; | |
| 28174 | break :blk deref; | |
| 28175 | } | |
| 28176 | ||
| 28177 | var array_tv = deref.pointee.?; | |
| 28178 | const check_len = array_tv.ty.arrayLenIncludingSentinel(mod); | |
| 28179 | if (maybe_array_ty) |load_ty| { | |
| 28180 | // It's possible that we're loading a [N]T, in which case we'd like to slice | |
| 28181 | // the pointee array directly from our parent array. | |
| 28182 | if (load_ty.isArrayOrVector(mod) and load_ty.childType(mod).eql(elem_ty, sema.mod)) { | |
| 28183 | const N = try sema.usizeCast(block, src, load_ty.arrayLenIncludingSentinel(mod)); | |
| 28184 | deref.pointee = if (elem_ptr.index + N <= check_len) TypedValue{ | |
| 28185 | .ty = try Type.array(sema.arena, N, null, elem_ty, sema.mod), | |
| 28186 | .val = try array_tv.val.sliceArray(sema.mod, sema.arena, elem_ptr.index, elem_ptr.index + N), | |
| 28187 | } else null; | |
| 28188 | break :blk deref; | |
| 28189 | } | |
| 28190 | } | |
| 28191 | ||
| 28192 | if (elem_ptr.index >= check_len) { | |
| 28193 | deref.pointee = null; | |
| 28194 | break :blk deref; | |
| 28195 | } | |
| 28196 | if (elem_ptr.index == check_len - 1) { | |
| 28197 | if (array_tv.ty.sentinel(mod)) |sent| { | |
| 28198 | deref.pointee = TypedValue{ | |
| 28199 | .ty = elem_ty, | |
| 28200 | .val = sent, | |
| 28201 | }; | |
| 28202 | break :blk deref; | |
| 28203 | } | |
| 28204 | } | |
| 28205 | deref.pointee = TypedValue{ | |
| 28206 | .ty = elem_ty, | |
| 28207 | .val = try array_tv.val.elemValue(sema.mod, sema.arena, elem_ptr.index), | |
| 28208 | }; | |
| 28209 | break :blk deref; | |
| 28210 | }, | |
| 28129 | 28211 | |
| 28130 | if (elem_ptr.index != 0) { | |
| 28131 | if (elem_ty.hasWellDefinedLayout(mod)) { | |
| 28132 | if (deref.parent) |*parent| { | |
| 28212 | .slice => blk: { | |
| 28213 | const slice = ptr_val.castTag(.slice).?.data; | |
| 28214 | break :blk try sema.beginComptimePtrLoad(block, src, slice.ptr, null); | |
| 28215 | }, | |
| 28216 | ||
| 28217 | .field_ptr => blk: { | |
| 28218 | const field_ptr = ptr_val.castTag(.field_ptr).?.data; | |
| 28219 | const field_index = @intCast(u32, field_ptr.field_index); | |
| 28220 | var deref = try sema.beginComptimePtrLoad(block, src, field_ptr.container_ptr, field_ptr.container_ty); | |
| 28221 | ||
| 28222 | if (field_ptr.container_ty.hasWellDefinedLayout(mod)) { | |
| 28223 | const struct_ty = field_ptr.container_ty.castTag(.@"struct"); | |
| 28224 | if (struct_ty != null and struct_ty.?.data.layout == .Packed) { | |
| 28225 | // packed structs are not byte addressable | |
| 28226 | deref.parent = null; | |
| 28227 | } else if (deref.parent) |*parent| { | |
| 28133 | 28228 | // Update the byte offset (in-place) |
| 28134 | const elem_size = try sema.typeAbiSize(elem_ty); | |
| 28135 | const offset = parent.byte_offset + elem_size * elem_ptr.index; | |
| 28136 | parent.byte_offset = try sema.usizeCast(block, src, offset); | |
| 28229 | try sema.resolveTypeLayout(field_ptr.container_ty); | |
| 28230 | const field_offset = field_ptr.container_ty.structFieldOffset(field_index, mod); | |
| 28231 | parent.byte_offset = try sema.usizeCast(block, src, parent.byte_offset + field_offset); | |
| 28137 | 28232 | } |
| 28138 | 28233 | } else { |
| 28139 | 28234 | deref.parent = null; |
| 28140 | deref.ty_without_well_defined_layout = elem_ty; | |
| 28235 | deref.ty_without_well_defined_layout = field_ptr.container_ty; | |
| 28141 | 28236 | } |
| 28142 | } | |
| 28143 | 28237 | |
| 28144 | // If we're loading an elem_ptr that was derived from a different type | |
| 28145 | // than the true type of the underlying decl, we cannot deref directly | |
| 28146 | const ty_matches = if (deref.pointee != null and deref.pointee.?.ty.isArrayOrVector(mod)) x: { | |
| 28147 | const deref_elem_ty = deref.pointee.?.ty.childType(mod); | |
| 28148 | break :x (try sema.coerceInMemoryAllowed(block, deref_elem_ty, elem_ty, false, target, src, src)) == .ok or | |
| 28149 | (try sema.coerceInMemoryAllowed(block, elem_ty, deref_elem_ty, false, target, src, src)) == .ok; | |
| 28150 | } else false; | |
| 28151 | if (!ty_matches) { | |
| 28152 | deref.pointee = null; | |
| 28153 | break :blk deref; | |
| 28154 | } | |
| 28155 | ||
| 28156 | var array_tv = deref.pointee.?; | |
| 28157 | const check_len = array_tv.ty.arrayLenIncludingSentinel(mod); | |
| 28158 | if (maybe_array_ty) |load_ty| { | |
| 28159 | // It's possible that we're loading a [N]T, in which case we'd like to slice | |
| 28160 | // the pointee array directly from our parent array. | |
| 28161 | if (load_ty.isArrayOrVector(mod) and load_ty.childType(mod).eql(elem_ty, sema.mod)) { | |
| 28162 | const N = try sema.usizeCast(block, src, load_ty.arrayLenIncludingSentinel(mod)); | |
| 28163 | deref.pointee = if (elem_ptr.index + N <= check_len) TypedValue{ | |
| 28164 | .ty = try Type.array(sema.arena, N, null, elem_ty, sema.mod), | |
| 28165 | .val = try array_tv.val.sliceArray(sema.mod, sema.arena, elem_ptr.index, elem_ptr.index + N), | |
| 28166 | } else null; | |
| 28238 | const tv = deref.pointee orelse { | |
| 28239 | deref.pointee = null; | |
| 28240 | break :blk deref; | |
| 28241 | }; | |
| 28242 | const coerce_in_mem_ok = | |
| 28243 | (try sema.coerceInMemoryAllowed(block, field_ptr.container_ty, tv.ty, false, target, src, src)) == .ok or | |
| 28244 | (try sema.coerceInMemoryAllowed(block, tv.ty, field_ptr.container_ty, false, target, src, src)) == .ok; | |
| 28245 | if (!coerce_in_mem_ok) { | |
| 28246 | deref.pointee = null; | |
| 28167 | 28247 | break :blk deref; |
| 28168 | 28248 | } |
| 28169 | } | |
| 28170 | 28249 | |
| 28171 | if (elem_ptr.index >= check_len) { | |
| 28172 | deref.pointee = null; | |
| 28173 | break :blk deref; | |
| 28174 | } | |
| 28175 | if (elem_ptr.index == check_len - 1) { | |
| 28176 | if (array_tv.ty.sentinel(mod)) |sent| { | |
| 28250 | if (field_ptr.container_ty.isSlice(mod)) { | |
| 28251 | const slice_val = tv.val.castTag(.slice).?.data; | |
| 28252 | deref.pointee = switch (field_index) { | |
| 28253 | Value.Payload.Slice.ptr_index => TypedValue{ | |
| 28254 | .ty = field_ptr.container_ty.slicePtrFieldType(try sema.arena.create(Type.SlicePtrFieldTypeBuffer)), | |
| 28255 | .val = slice_val.ptr, | |
| 28256 | }, | |
| 28257 | Value.Payload.Slice.len_index => TypedValue{ | |
| 28258 | .ty = Type.usize, | |
| 28259 | .val = slice_val.len, | |
| 28260 | }, | |
| 28261 | else => unreachable, | |
| 28262 | }; | |
| 28263 | } else { | |
| 28264 | const field_ty = field_ptr.container_ty.structFieldType(field_index); | |
| 28177 | 28265 | deref.pointee = TypedValue{ |
| 28178 | .ty = elem_ty, | |
| 28179 | .val = sent, | |
| 28266 | .ty = field_ty, | |
| 28267 | .val = tv.val.fieldValue(tv.ty, mod, field_index), | |
| 28180 | 28268 | }; |
| 28181 | break :blk deref; | |
| 28182 | 28269 | } |
| 28183 | } | |
| 28184 | deref.pointee = TypedValue{ | |
| 28185 | .ty = elem_ty, | |
| 28186 | .val = try array_tv.val.elemValue(sema.mod, sema.arena, elem_ptr.index), | |
| 28187 | }; | |
| 28188 | break :blk deref; | |
| 28189 | }, | |
| 28270 | break :blk deref; | |
| 28271 | }, | |
| 28190 | 28272 | |
| 28191 | .slice => blk: { | |
| 28192 | const slice = ptr_val.castTag(.slice).?.data; | |
| 28193 | break :blk try sema.beginComptimePtrLoad(block, src, slice.ptr, null); | |
| 28194 | }, | |
| 28273 | .comptime_field_ptr => blk: { | |
| 28274 | const comptime_field_ptr = ptr_val.castTag(.comptime_field_ptr).?.data; | |
| 28275 | break :blk ComptimePtrLoadKit{ | |
| 28276 | .parent = null, | |
| 28277 | .pointee = .{ .ty = comptime_field_ptr.field_ty, .val = comptime_field_ptr.field_val }, | |
| 28278 | .is_mutable = false, | |
| 28279 | .ty_without_well_defined_layout = comptime_field_ptr.field_ty, | |
| 28280 | }; | |
| 28281 | }, | |
| 28195 | 28282 | |
| 28196 | .field_ptr => blk: { | |
| 28197 | const field_ptr = ptr_val.castTag(.field_ptr).?.data; | |
| 28198 | const field_index = @intCast(u32, field_ptr.field_index); | |
| 28199 | var deref = try sema.beginComptimePtrLoad(block, src, field_ptr.container_ptr, field_ptr.container_ty); | |
| 28283 | .opt_payload_ptr, | |
| 28284 | .eu_payload_ptr, | |
| 28285 | => blk: { | |
| 28286 | const payload_ptr = ptr_val.cast(Value.Payload.PayloadPtr).?.data; | |
| 28287 | const payload_ty = switch (ptr_val.tag()) { | |
| 28288 | .eu_payload_ptr => payload_ptr.container_ty.errorUnionPayload(), | |
| 28289 | .opt_payload_ptr => payload_ptr.container_ty.optionalChild(mod), | |
| 28290 | else => unreachable, | |
| 28291 | }; | |
| 28292 | var deref = try sema.beginComptimePtrLoad(block, src, payload_ptr.container_ptr, payload_ptr.container_ty); | |
| 28200 | 28293 | |
| 28201 | if (field_ptr.container_ty.hasWellDefinedLayout(mod)) { | |
| 28202 | const struct_ty = field_ptr.container_ty.castTag(.@"struct"); | |
| 28203 | if (struct_ty != null and struct_ty.?.data.layout == .Packed) { | |
| 28204 | // packed structs are not byte addressable | |
| 28294 | // eu_payload_ptr and opt_payload_ptr never have a well-defined layout | |
| 28295 | if (deref.parent != null) { | |
| 28205 | 28296 | deref.parent = null; |
| 28206 | } else if (deref.parent) |*parent| { | |
| 28207 | // Update the byte offset (in-place) | |
| 28208 | try sema.resolveTypeLayout(field_ptr.container_ty); | |
| 28209 | const field_offset = field_ptr.container_ty.structFieldOffset(field_index, mod); | |
| 28210 | parent.byte_offset = try sema.usizeCast(block, src, parent.byte_offset + field_offset); | |
| 28297 | deref.ty_without_well_defined_layout = payload_ptr.container_ty; | |
| 28211 | 28298 | } |
| 28212 | } else { | |
| 28213 | deref.parent = null; | |
| 28214 | deref.ty_without_well_defined_layout = field_ptr.container_ty; | |
| 28215 | } | |
| 28216 | 28299 | |
| 28217 | const tv = deref.pointee orelse { | |
| 28218 | deref.pointee = null; | |
| 28219 | break :blk deref; | |
| 28220 | }; | |
| 28221 | const coerce_in_mem_ok = | |
| 28222 | (try sema.coerceInMemoryAllowed(block, field_ptr.container_ty, tv.ty, false, target, src, src)) == .ok or | |
| 28223 | (try sema.coerceInMemoryAllowed(block, tv.ty, field_ptr.container_ty, false, target, src, src)) == .ok; | |
| 28224 | if (!coerce_in_mem_ok) { | |
| 28300 | if (deref.pointee) |*tv| { | |
| 28301 | const coerce_in_mem_ok = | |
| 28302 | (try sema.coerceInMemoryAllowed(block, payload_ptr.container_ty, tv.ty, false, target, src, src)) == .ok or | |
| 28303 | (try sema.coerceInMemoryAllowed(block, tv.ty, payload_ptr.container_ty, false, target, src, src)) == .ok; | |
| 28304 | if (coerce_in_mem_ok) { | |
| 28305 | const payload_val = switch (ptr_val.tag()) { | |
| 28306 | .eu_payload_ptr => if (tv.val.castTag(.eu_payload)) |some| some.data else { | |
| 28307 | return sema.fail(block, src, "attempt to unwrap error: {s}", .{tv.val.castTag(.@"error").?.data.name}); | |
| 28308 | }, | |
| 28309 | .opt_payload_ptr => if (tv.val.castTag(.opt_payload)) |some| some.data else opt: { | |
| 28310 | if (tv.val.isNull(mod)) return sema.fail(block, src, "attempt to use null value", .{}); | |
| 28311 | break :opt tv.val; | |
| 28312 | }, | |
| 28313 | else => unreachable, | |
| 28314 | }; | |
| 28315 | tv.* = TypedValue{ .ty = payload_ty, .val = payload_val }; | |
| 28316 | break :blk deref; | |
| 28317 | } | |
| 28318 | } | |
| 28225 | 28319 | deref.pointee = null; |
| 28226 | 28320 | break :blk deref; |
| 28227 | } | |
| 28228 | ||
| 28229 | if (field_ptr.container_ty.isSlice(mod)) { | |
| 28230 | const slice_val = tv.val.castTag(.slice).?.data; | |
| 28231 | deref.pointee = switch (field_index) { | |
| 28232 | Value.Payload.Slice.ptr_index => TypedValue{ | |
| 28233 | .ty = field_ptr.container_ty.slicePtrFieldType(try sema.arena.create(Type.SlicePtrFieldTypeBuffer)), | |
| 28234 | .val = slice_val.ptr, | |
| 28235 | }, | |
| 28236 | Value.Payload.Slice.len_index => TypedValue{ | |
| 28237 | .ty = Type.usize, | |
| 28238 | .val = slice_val.len, | |
| 28239 | }, | |
| 28240 | else => unreachable, | |
| 28241 | }; | |
| 28242 | } else { | |
| 28243 | const field_ty = field_ptr.container_ty.structFieldType(field_index); | |
| 28244 | deref.pointee = TypedValue{ | |
| 28245 | .ty = field_ty, | |
| 28246 | .val = tv.val.fieldValue(tv.ty, mod, field_index), | |
| 28247 | }; | |
| 28248 | } | |
| 28249 | break :blk deref; | |
| 28250 | }, | |
| 28251 | ||
| 28252 | .comptime_field_ptr => blk: { | |
| 28253 | const comptime_field_ptr = ptr_val.castTag(.comptime_field_ptr).?.data; | |
| 28254 | break :blk ComptimePtrLoadKit{ | |
| 28255 | .parent = null, | |
| 28256 | .pointee = .{ .ty = comptime_field_ptr.field_ty, .val = comptime_field_ptr.field_val }, | |
| 28257 | .is_mutable = false, | |
| 28258 | .ty_without_well_defined_layout = comptime_field_ptr.field_ty, | |
| 28259 | }; | |
| 28260 | }, | |
| 28261 | ||
| 28262 | .opt_payload_ptr, | |
| 28263 | .eu_payload_ptr, | |
| 28264 | => blk: { | |
| 28265 | const payload_ptr = ptr_val.cast(Value.Payload.PayloadPtr).?.data; | |
| 28266 | const payload_ty = switch (ptr_val.tag()) { | |
| 28267 | .eu_payload_ptr => payload_ptr.container_ty.errorUnionPayload(), | |
| 28268 | .opt_payload_ptr => payload_ptr.container_ty.optionalChild(mod), | |
| 28269 | else => unreachable, | |
| 28270 | }; | |
| 28271 | var deref = try sema.beginComptimePtrLoad(block, src, payload_ptr.container_ptr, payload_ptr.container_ty); | |
| 28321 | }, | |
| 28322 | .opt_payload => blk: { | |
| 28323 | const opt_payload = ptr_val.castTag(.opt_payload).?.data; | |
| 28324 | break :blk try sema.beginComptimePtrLoad(block, src, opt_payload, null); | |
| 28325 | }, | |
| 28272 | 28326 | |
| 28273 | // eu_payload_ptr and opt_payload_ptr never have a well-defined layout | |
| 28274 | if (deref.parent != null) { | |
| 28275 | deref.parent = null; | |
| 28276 | deref.ty_without_well_defined_layout = payload_ptr.container_ty; | |
| 28277 | } | |
| 28327 | .zero, | |
| 28328 | .one, | |
| 28329 | .int_u64, | |
| 28330 | .int_i64, | |
| 28331 | .int_big_positive, | |
| 28332 | .int_big_negative, | |
| 28333 | .variable, | |
| 28334 | .extern_fn, | |
| 28335 | .function, | |
| 28336 | => return error.RuntimeLoad, | |
| 28278 | 28337 | |
| 28279 | if (deref.pointee) |*tv| { | |
| 28280 | const coerce_in_mem_ok = | |
| 28281 | (try sema.coerceInMemoryAllowed(block, payload_ptr.container_ty, tv.ty, false, target, src, src)) == .ok or | |
| 28282 | (try sema.coerceInMemoryAllowed(block, tv.ty, payload_ptr.container_ty, false, target, src, src)) == .ok; | |
| 28283 | if (coerce_in_mem_ok) { | |
| 28284 | const payload_val = switch (ptr_val.tag()) { | |
| 28285 | .eu_payload_ptr => if (tv.val.castTag(.eu_payload)) |some| some.data else { | |
| 28286 | return sema.fail(block, src, "attempt to unwrap error: {s}", .{tv.val.castTag(.@"error").?.data.name}); | |
| 28287 | }, | |
| 28288 | .opt_payload_ptr => if (tv.val.castTag(.opt_payload)) |some| some.data else opt: { | |
| 28289 | if (tv.val.isNull(mod)) return sema.fail(block, src, "attempt to use null value", .{}); | |
| 28290 | break :opt tv.val; | |
| 28291 | }, | |
| 28292 | else => unreachable, | |
| 28293 | }; | |
| 28294 | tv.* = TypedValue{ .ty = payload_ty, .val = payload_val }; | |
| 28295 | break :blk deref; | |
| 28296 | } | |
| 28297 | } | |
| 28298 | deref.pointee = null; | |
| 28299 | break :blk deref; | |
| 28300 | }, | |
| 28301 | .null_value => { | |
| 28302 | return sema.fail(block, src, "attempt to use null value", .{}); | |
| 28303 | }, | |
| 28304 | .opt_payload => blk: { | |
| 28305 | const opt_payload = ptr_val.castTag(.opt_payload).?.data; | |
| 28306 | break :blk try sema.beginComptimePtrLoad(block, src, opt_payload, null); | |
| 28338 | else => unreachable, | |
| 28307 | 28339 | }, |
| 28308 | ||
| 28309 | .zero, | |
| 28310 | .one, | |
| 28311 | .int_u64, | |
| 28312 | .int_i64, | |
| 28313 | .int_big_positive, | |
| 28314 | .int_big_negative, | |
| 28315 | .variable, | |
| 28316 | .extern_fn, | |
| 28317 | .function, | |
| 28318 | => return error.RuntimeLoad, | |
| 28319 | ||
| 28320 | 28340 | else => unreachable, |
| 28321 | 28341 | }; |
| 28322 | 28342 | |
| ... | ... | @@ -28953,7 +28973,7 @@ fn coerceTupleToStruct( |
| 28953 | 28973 | const field_name = fields.keys()[i]; |
| 28954 | 28974 | const field = fields.values()[i]; |
| 28955 | 28975 | const field_src = inst_src; // TODO better source location |
| 28956 | if (field.default_val.tag() == .unreachable_value) { | |
| 28976 | if (field.default_val.ip_index == .unreachable_value) { | |
| 28957 | 28977 | const template = "missing struct field: {s}"; |
| 28958 | 28978 | const args = .{field_name}; |
| 28959 | 28979 | if (root_msg) |msg| { |
| ... | ... | @@ -29023,7 +29043,7 @@ fn coerceTupleToTuple( |
| 29023 | 29043 | const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, field_i); |
| 29024 | 29044 | const coerced = try sema.coerce(block, field_ty, elem_ref, field_src); |
| 29025 | 29045 | field_refs[field_index] = coerced; |
| 29026 | if (default_val.tag() != .unreachable_value) { | |
| 29046 | if (default_val.ip_index != .unreachable_value) { | |
| 29027 | 29047 | const init_val = (try sema.resolveMaybeUndefVal(coerced)) orelse { |
| 29028 | 29048 | return sema.failWithNeededComptime(block, field_src, "value stored in comptime field must be comptime-known"); |
| 29029 | 29049 | }; |
| ... | ... | @@ -29052,7 +29072,7 @@ fn coerceTupleToTuple( |
| 29052 | 29072 | const field_ty = tuple_ty.structFieldType(i); |
| 29053 | 29073 | |
| 29054 | 29074 | const field_src = inst_src; // TODO better source location |
| 29055 | if (default_val.tag() == .unreachable_value) { | |
| 29075 | if (default_val.ip_index == .unreachable_value) { | |
| 29056 | 29076 | if (tuple_ty.isTuple()) { |
| 29057 | 29077 | const template = "missing tuple field: {d}"; |
| 29058 | 29078 | if (root_msg) |msg| { |
| ... | ... | @@ -31557,7 +31577,7 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { |
| 31557 | 31577 | .tuple, .anon_struct => { |
| 31558 | 31578 | const tuple = ty.tupleFields(); |
| 31559 | 31579 | for (tuple.types, 0..) |field_ty, i| { |
| 31560 | const have_comptime_val = tuple.values[i].tag() != .unreachable_value; | |
| 31580 | const have_comptime_val = tuple.values[i].ip_index != .unreachable_value; | |
| 31561 | 31581 | if (!have_comptime_val and try sema.resolveTypeRequiresComptime(field_ty)) { |
| 31562 | 31582 | return true; |
| 31563 | 31583 | } |
| ... | ... | @@ -32141,7 +32161,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 32141 | 32161 | gop.value_ptr.* = .{ |
| 32142 | 32162 | .ty = Type.noreturn, |
| 32143 | 32163 | .abi_align = 0, |
| 32144 | .default_val = Value.initTag(.unreachable_value), | |
| 32164 | .default_val = Value.@"unreachable", | |
| 32145 | 32165 | .is_comptime = is_comptime, |
| 32146 | 32166 | .offset = undefined, |
| 32147 | 32167 | }; |
| ... | ... | @@ -32965,7 +32985,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { |
| 32965 | 32985 | => return null, |
| 32966 | 32986 | |
| 32967 | 32987 | .void => return Value.void, |
| 32968 | .noreturn => return Value.initTag(.unreachable_value), | |
| 32988 | .noreturn => return Value.@"unreachable", | |
| 32969 | 32989 | .null => return Value.null, |
| 32970 | 32990 | .undefined => return Value.undef, |
| 32971 | 32991 | |
| ... | ... | @@ -33027,7 +33047,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { |
| 33027 | 33047 | .tuple, .anon_struct => { |
| 33028 | 33048 | const tuple = ty.tupleFields(); |
| 33029 | 33049 | for (tuple.values, 0..) |val, i| { |
| 33030 | const is_comptime = val.tag() != .unreachable_value; | |
| 33050 | const is_comptime = val.ip_index != .unreachable_value; | |
| 33031 | 33051 | if (is_comptime) continue; |
| 33032 | 33052 | if ((try sema.typeHasOnePossibleValue(tuple.types[i])) != null) continue; |
| 33033 | 33053 | return null; |
| ... | ... | @@ -33059,7 +33079,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { |
| 33059 | 33079 | return null; |
| 33060 | 33080 | } |
| 33061 | 33081 | switch (enum_obj.fields.count()) { |
| 33062 | 0 => return Value.initTag(.unreachable_value), | |
| 33082 | 0 => return Value.@"unreachable", | |
| 33063 | 33083 | 1 => if (enum_obj.values.count() == 0) { |
| 33064 | 33084 | return Value.zero; // auto-numbered |
| 33065 | 33085 | } else { |
| ... | ... | @@ -33072,7 +33092,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { |
| 33072 | 33092 | const resolved_ty = try sema.resolveTypeFields(ty); |
| 33073 | 33093 | const enum_simple = resolved_ty.castTag(.enum_simple).?.data; |
| 33074 | 33094 | switch (enum_simple.fields.count()) { |
| 33075 | 0 => return Value.initTag(.unreachable_value), | |
| 33095 | 0 => return Value.@"unreachable", | |
| 33076 | 33096 | 1 => return Value.zero, |
| 33077 | 33097 | else => return null, |
| 33078 | 33098 | } |
| ... | ... | @@ -33091,7 +33111,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { |
| 33091 | 33111 | const tag_val = (try sema.typeHasOnePossibleValue(union_obj.tag_ty)) orelse |
| 33092 | 33112 | return null; |
| 33093 | 33113 | const fields = union_obj.fields.values(); |
| 33094 | if (fields.len == 0) return Value.initTag(.unreachable_value); | |
| 33114 | if (fields.len == 0) return Value.@"unreachable"; | |
| 33095 | 33115 | const only_field = fields[0]; |
| 33096 | 33116 | if (only_field.ty.eql(resolved_ty, sema.mod)) { |
| 33097 | 33117 | const msg = try Module.ErrorMsg.create( |
| ... | ... | @@ -33600,7 +33620,7 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { |
| 33600 | 33620 | .tuple, .anon_struct => { |
| 33601 | 33621 | const tuple = ty.tupleFields(); |
| 33602 | 33622 | for (tuple.types, 0..) |field_ty, i| { |
| 33603 | const have_comptime_val = tuple.values[i].tag() != .unreachable_value; | |
| 33623 | const have_comptime_val = tuple.values[i].ip_index != .unreachable_value; | |
| 33604 | 33624 | if (!have_comptime_val and try sema.typeRequiresComptime(field_ty)) { |
| 33605 | 33625 | return true; |
| 33606 | 33626 | } |
| ... | ... | @@ -33814,7 +33834,7 @@ fn numberAddWrapScalar( |
| 33814 | 33834 | rhs: Value, |
| 33815 | 33835 | ty: Type, |
| 33816 | 33836 | ) !Value { |
| 33817 | if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef); | |
| 33837 | if (lhs.isUndef() or rhs.isUndef()) return Value.undef; | |
| 33818 | 33838 | |
| 33819 | 33839 | const mod = sema.mod; |
| 33820 | 33840 | if (ty.zigTypeTag(mod) == .ComptimeInt) { |
| ... | ... | @@ -33874,7 +33894,7 @@ fn numberSubWrapScalar( |
| 33874 | 33894 | rhs: Value, |
| 33875 | 33895 | ty: Type, |
| 33876 | 33896 | ) !Value { |
| 33877 | if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef); | |
| 33897 | if (lhs.isUndef() or rhs.isUndef()) return Value.undef; | |
| 33878 | 33898 | |
| 33879 | 33899 | const mod = sema.mod; |
| 33880 | 33900 | if (ty.zigTypeTag(mod) == .ComptimeInt) { |
| ... | ... | @@ -34156,12 +34176,16 @@ fn intFitsInType( |
| 34156 | 34176 | ) CompileError!bool { |
| 34157 | 34177 | const mod = sema.mod; |
| 34158 | 34178 | const target = mod.getTarget(); |
| 34159 | switch (val.tag()) { | |
| 34160 | .zero, | |
| 34179 | switch (val.ip_index) { | |
| 34161 | 34180 | .undef, |
| 34181 | .zero, | |
| 34182 | .zero_usize, | |
| 34183 | .zero_u8, | |
| 34162 | 34184 | => return true, |
| 34163 | 34185 | |
| 34164 | .one => switch (ty.zigTypeTag(mod)) { | |
| 34186 | .one, | |
| 34187 | .one_usize, | |
| 34188 | => switch (ty.zigTypeTag(mod)) { | |
| 34165 | 34189 | .Int => { |
| 34166 | 34190 | const info = ty.intInfo(mod); |
| 34167 | 34191 | return switch (info.signedness) { |
| ... | ... | @@ -34173,111 +34197,129 @@ fn intFitsInType( |
| 34173 | 34197 | else => unreachable, |
| 34174 | 34198 | }, |
| 34175 | 34199 | |
| 34176 | .lazy_align => switch (ty.zigTypeTag(mod)) { | |
| 34177 | .Int => { | |
| 34178 | const info = ty.intInfo(mod); | |
| 34179 | const max_needed_bits = @as(u16, 16) + @boolToInt(info.signedness == .signed); | |
| 34180 | // If it is u16 or bigger we know the alignment fits without resolving it. | |
| 34181 | if (info.bits >= max_needed_bits) return true; | |
| 34182 | const x = try sema.typeAbiAlignment(val.castTag(.lazy_align).?.data); | |
| 34183 | if (x == 0) return true; | |
| 34184 | const actual_needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed); | |
| 34185 | return info.bits >= actual_needed_bits; | |
| 34200 | .none => switch (val.tag()) { | |
| 34201 | .zero => return true, | |
| 34202 | ||
| 34203 | .one => switch (ty.zigTypeTag(mod)) { | |
| 34204 | .Int => { | |
| 34205 | const info = ty.intInfo(mod); | |
| 34206 | return switch (info.signedness) { | |
| 34207 | .signed => info.bits >= 2, | |
| 34208 | .unsigned => info.bits >= 1, | |
| 34209 | }; | |
| 34210 | }, | |
| 34211 | .ComptimeInt => return true, | |
| 34212 | else => unreachable, | |
| 34186 | 34213 | }, |
| 34187 | .ComptimeInt => return true, | |
| 34188 | else => unreachable, | |
| 34189 | }, | |
| 34190 | .lazy_size => switch (ty.zigTypeTag(mod)) { | |
| 34191 | .Int => { | |
| 34192 | const info = ty.intInfo(mod); | |
| 34193 | const max_needed_bits = @as(u16, 64) + @boolToInt(info.signedness == .signed); | |
| 34194 | // If it is u64 or bigger we know the size fits without resolving it. | |
| 34195 | if (info.bits >= max_needed_bits) return true; | |
| 34196 | const x = try sema.typeAbiSize(val.castTag(.lazy_size).?.data); | |
| 34197 | if (x == 0) return true; | |
| 34198 | const actual_needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed); | |
| 34199 | return info.bits >= actual_needed_bits; | |
| 34214 | ||
| 34215 | .lazy_align => switch (ty.zigTypeTag(mod)) { | |
| 34216 | .Int => { | |
| 34217 | const info = ty.intInfo(mod); | |
| 34218 | const max_needed_bits = @as(u16, 16) + @boolToInt(info.signedness == .signed); | |
| 34219 | // If it is u16 or bigger we know the alignment fits without resolving it. | |
| 34220 | if (info.bits >= max_needed_bits) return true; | |
| 34221 | const x = try sema.typeAbiAlignment(val.castTag(.lazy_align).?.data); | |
| 34222 | if (x == 0) return true; | |
| 34223 | const actual_needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed); | |
| 34224 | return info.bits >= actual_needed_bits; | |
| 34225 | }, | |
| 34226 | .ComptimeInt => return true, | |
| 34227 | else => unreachable, | |
| 34228 | }, | |
| 34229 | .lazy_size => switch (ty.zigTypeTag(mod)) { | |
| 34230 | .Int => { | |
| 34231 | const info = ty.intInfo(mod); | |
| 34232 | const max_needed_bits = @as(u16, 64) + @boolToInt(info.signedness == .signed); | |
| 34233 | // If it is u64 or bigger we know the size fits without resolving it. | |
| 34234 | if (info.bits >= max_needed_bits) return true; | |
| 34235 | const x = try sema.typeAbiSize(val.castTag(.lazy_size).?.data); | |
| 34236 | if (x == 0) return true; | |
| 34237 | const actual_needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed); | |
| 34238 | return info.bits >= actual_needed_bits; | |
| 34239 | }, | |
| 34240 | .ComptimeInt => return true, | |
| 34241 | else => unreachable, | |
| 34200 | 34242 | }, |
| 34201 | .ComptimeInt => return true, | |
| 34202 | else => unreachable, | |
| 34203 | }, | |
| 34204 | 34243 | |
| 34205 | .int_u64 => switch (ty.zigTypeTag(mod)) { | |
| 34206 | .Int => { | |
| 34207 | const x = val.castTag(.int_u64).?.data; | |
| 34208 | if (x == 0) return true; | |
| 34209 | const info = ty.intInfo(mod); | |
| 34210 | const needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed); | |
| 34211 | return info.bits >= needed_bits; | |
| 34244 | .int_u64 => switch (ty.zigTypeTag(mod)) { | |
| 34245 | .Int => { | |
| 34246 | const x = val.castTag(.int_u64).?.data; | |
| 34247 | if (x == 0) return true; | |
| 34248 | const info = ty.intInfo(mod); | |
| 34249 | const needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed); | |
| 34250 | return info.bits >= needed_bits; | |
| 34251 | }, | |
| 34252 | .ComptimeInt => return true, | |
| 34253 | else => unreachable, | |
| 34212 | 34254 | }, |
| 34213 | .ComptimeInt => return true, | |
| 34214 | else => unreachable, | |
| 34215 | }, | |
| 34216 | .int_i64 => switch (ty.zigTypeTag(mod)) { | |
| 34217 | .Int => { | |
| 34218 | const x = val.castTag(.int_i64).?.data; | |
| 34219 | if (x == 0) return true; | |
| 34220 | const info = ty.intInfo(mod); | |
| 34221 | if (info.signedness == .unsigned and x < 0) | |
| 34222 | return false; | |
| 34223 | var buffer: Value.BigIntSpace = undefined; | |
| 34224 | return (try val.toBigIntAdvanced(&buffer, mod, sema)).fitsInTwosComp(info.signedness, info.bits); | |
| 34255 | .int_i64 => switch (ty.zigTypeTag(mod)) { | |
| 34256 | .Int => { | |
| 34257 | const x = val.castTag(.int_i64).?.data; | |
| 34258 | if (x == 0) return true; | |
| 34259 | const info = ty.intInfo(mod); | |
| 34260 | if (info.signedness == .unsigned and x < 0) | |
| 34261 | return false; | |
| 34262 | var buffer: Value.BigIntSpace = undefined; | |
| 34263 | return (try val.toBigIntAdvanced(&buffer, mod, sema)).fitsInTwosComp(info.signedness, info.bits); | |
| 34264 | }, | |
| 34265 | .ComptimeInt => return true, | |
| 34266 | else => unreachable, | |
| 34225 | 34267 | }, |
| 34226 | .ComptimeInt => return true, | |
| 34227 | else => unreachable, | |
| 34228 | }, | |
| 34229 | .int_big_positive => switch (ty.zigTypeTag(mod)) { | |
| 34230 | .Int => { | |
| 34231 | const info = ty.intInfo(mod); | |
| 34232 | return val.castTag(.int_big_positive).?.asBigInt().fitsInTwosComp(info.signedness, info.bits); | |
| 34268 | .int_big_positive => switch (ty.zigTypeTag(mod)) { | |
| 34269 | .Int => { | |
| 34270 | const info = ty.intInfo(mod); | |
| 34271 | return val.castTag(.int_big_positive).?.asBigInt().fitsInTwosComp(info.signedness, info.bits); | |
| 34272 | }, | |
| 34273 | .ComptimeInt => return true, | |
| 34274 | else => unreachable, | |
| 34233 | 34275 | }, |
| 34234 | .ComptimeInt => return true, | |
| 34235 | else => unreachable, | |
| 34236 | }, | |
| 34237 | .int_big_negative => switch (ty.zigTypeTag(mod)) { | |
| 34238 | .Int => { | |
| 34239 | const info = ty.intInfo(mod); | |
| 34240 | return val.castTag(.int_big_negative).?.asBigInt().fitsInTwosComp(info.signedness, info.bits); | |
| 34276 | .int_big_negative => switch (ty.zigTypeTag(mod)) { | |
| 34277 | .Int => { | |
| 34278 | const info = ty.intInfo(mod); | |
| 34279 | return val.castTag(.int_big_negative).?.asBigInt().fitsInTwosComp(info.signedness, info.bits); | |
| 34280 | }, | |
| 34281 | .ComptimeInt => return true, | |
| 34282 | else => unreachable, | |
| 34241 | 34283 | }, |
| 34242 | .ComptimeInt => return true, | |
| 34243 | else => unreachable, | |
| 34244 | }, | |
| 34245 | 34284 | |
| 34246 | .the_only_possible_value => { | |
| 34247 | assert(ty.intInfo(mod).bits == 0); | |
| 34248 | return true; | |
| 34249 | }, | |
| 34285 | .the_only_possible_value => { | |
| 34286 | assert(ty.intInfo(mod).bits == 0); | |
| 34287 | return true; | |
| 34288 | }, | |
| 34250 | 34289 | |
| 34251 | .decl_ref_mut, | |
| 34252 | .extern_fn, | |
| 34253 | .decl_ref, | |
| 34254 | .function, | |
| 34255 | .variable, | |
| 34256 | => switch (ty.zigTypeTag(mod)) { | |
| 34257 | .Int => { | |
| 34258 | const info = ty.intInfo(mod); | |
| 34259 | const ptr_bits = target.ptrBitWidth(); | |
| 34260 | return switch (info.signedness) { | |
| 34261 | .signed => info.bits > ptr_bits, | |
| 34262 | .unsigned => info.bits >= ptr_bits, | |
| 34263 | }; | |
| 34290 | .decl_ref_mut, | |
| 34291 | .extern_fn, | |
| 34292 | .decl_ref, | |
| 34293 | .function, | |
| 34294 | .variable, | |
| 34295 | => switch (ty.zigTypeTag(mod)) { | |
| 34296 | .Int => { | |
| 34297 | const info = ty.intInfo(mod); | |
| 34298 | const ptr_bits = target.ptrBitWidth(); | |
| 34299 | return switch (info.signedness) { | |
| 34300 | .signed => info.bits > ptr_bits, | |
| 34301 | .unsigned => info.bits >= ptr_bits, | |
| 34302 | }; | |
| 34303 | }, | |
| 34304 | .ComptimeInt => return true, | |
| 34305 | else => unreachable, | |
| 34264 | 34306 | }, |
| 34265 | .ComptimeInt => return true, | |
| 34266 | else => unreachable, | |
| 34267 | }, | |
| 34268 | 34307 | |
| 34269 | .aggregate => { | |
| 34270 | assert(ty.zigTypeTag(mod) == .Vector); | |
| 34271 | for (val.castTag(.aggregate).?.data, 0..) |elem, i| { | |
| 34272 | if (!(try sema.intFitsInType(elem, ty.scalarType(mod), null))) { | |
| 34273 | if (vector_index) |some| some.* = i; | |
| 34274 | return false; | |
| 34308 | .aggregate => { | |
| 34309 | assert(ty.zigTypeTag(mod) == .Vector); | |
| 34310 | for (val.castTag(.aggregate).?.data, 0..) |elem, i| { | |
| 34311 | if (!(try sema.intFitsInType(elem, ty.scalarType(mod), null))) { | |
| 34312 | if (vector_index) |some| some.* = i; | |
| 34313 | return false; | |
| 34314 | } | |
| 34275 | 34315 | } |
| 34276 | } | |
| 34277 | return true; | |
| 34316 | return true; | |
| 34317 | }, | |
| 34318 | ||
| 34319 | else => unreachable, | |
| 34278 | 34320 | }, |
| 34279 | 34321 | |
| 34280 | else => unreachable, | |
| 34322 | else => @panic("TODO"), | |
| 34281 | 34323 | } |
| 34282 | 34324 | } |
| 34283 | 34325 |
src/TypedValue.zig+289-286| ... | ... | @@ -76,34 +76,236 @@ pub fn print( |
| 76 | 76 | if (val.isVariable(mod)) |
| 77 | 77 | return writer.writeAll("(variable)"); |
| 78 | 78 | |
| 79 | while (true) switch (val.tag()) { | |
| 80 | .empty_struct_value, .aggregate => { | |
| 81 | if (level == 0) { | |
| 82 | return writer.writeAll(".{ ... }"); | |
| 83 | } | |
| 84 | if (ty.zigTypeTag(mod) == .Struct) { | |
| 85 | try writer.writeAll(".{"); | |
| 86 | const max_len = std.math.min(ty.structFieldCount(), max_aggregate_items); | |
| 79 | while (true) switch (val.ip_index) { | |
| 80 | .none => switch (val.tag()) { | |
| 81 | .empty_struct_value, .aggregate => { | |
| 82 | if (level == 0) { | |
| 83 | return writer.writeAll(".{ ... }"); | |
| 84 | } | |
| 85 | if (ty.zigTypeTag(mod) == .Struct) { | |
| 86 | try writer.writeAll(".{"); | |
| 87 | const max_len = std.math.min(ty.structFieldCount(), max_aggregate_items); | |
| 87 | 88 | |
| 88 | var i: u32 = 0; | |
| 89 | while (i < max_len) : (i += 1) { | |
| 90 | if (i != 0) try writer.writeAll(", "); | |
| 91 | switch (ty.tag()) { | |
| 92 | .anon_struct, .@"struct" => try writer.print(".{s} = ", .{ty.structFieldName(i)}), | |
| 93 | else => {}, | |
| 89 | var i: u32 = 0; | |
| 90 | while (i < max_len) : (i += 1) { | |
| 91 | if (i != 0) try writer.writeAll(", "); | |
| 92 | switch (ty.tag()) { | |
| 93 | .anon_struct, .@"struct" => try writer.print(".{s} = ", .{ty.structFieldName(i)}), | |
| 94 | else => {}, | |
| 95 | } | |
| 96 | try print(.{ | |
| 97 | .ty = ty.structFieldType(i), | |
| 98 | .val = val.fieldValue(ty, mod, i), | |
| 99 | }, writer, level - 1, mod); | |
| 94 | 100 | } |
| 101 | if (ty.structFieldCount() > max_aggregate_items) { | |
| 102 | try writer.writeAll(", ..."); | |
| 103 | } | |
| 104 | return writer.writeAll("}"); | |
| 105 | } else { | |
| 106 | const elem_ty = ty.elemType2(mod); | |
| 107 | const len = ty.arrayLen(mod); | |
| 108 | ||
| 109 | if (elem_ty.eql(Type.u8, mod)) str: { | |
| 110 | const max_len = @intCast(usize, std.math.min(len, max_string_len)); | |
| 111 | var buf: [max_string_len]u8 = undefined; | |
| 112 | ||
| 113 | var i: u32 = 0; | |
| 114 | while (i < max_len) : (i += 1) { | |
| 115 | const elem = val.fieldValue(ty, mod, i); | |
| 116 | if (elem.isUndef()) break :str; | |
| 117 | buf[i] = std.math.cast(u8, elem.toUnsignedInt(mod)) orelse break :str; | |
| 118 | } | |
| 119 | ||
| 120 | const truncated = if (len > max_string_len) " (truncated)" else ""; | |
| 121 | return writer.print("\"{}{s}\"", .{ std.zig.fmtEscapes(buf[0..max_len]), truncated }); | |
| 122 | } | |
| 123 | ||
| 124 | try writer.writeAll(".{ "); | |
| 125 | ||
| 126 | const max_len = std.math.min(len, max_aggregate_items); | |
| 127 | var i: u32 = 0; | |
| 128 | while (i < max_len) : (i += 1) { | |
| 129 | if (i != 0) try writer.writeAll(", "); | |
| 130 | try print(.{ | |
| 131 | .ty = elem_ty, | |
| 132 | .val = val.fieldValue(ty, mod, i), | |
| 133 | }, writer, level - 1, mod); | |
| 134 | } | |
| 135 | if (len > max_aggregate_items) { | |
| 136 | try writer.writeAll(", ..."); | |
| 137 | } | |
| 138 | return writer.writeAll(" }"); | |
| 139 | } | |
| 140 | }, | |
| 141 | .@"union" => { | |
| 142 | if (level == 0) { | |
| 143 | return writer.writeAll(".{ ... }"); | |
| 144 | } | |
| 145 | const union_val = val.castTag(.@"union").?.data; | |
| 146 | try writer.writeAll(".{ "); | |
| 147 | ||
| 148 | try print(.{ | |
| 149 | .ty = ty.cast(Type.Payload.Union).?.data.tag_ty, | |
| 150 | .val = union_val.tag, | |
| 151 | }, writer, level - 1, mod); | |
| 152 | try writer.writeAll(" = "); | |
| 153 | try print(.{ | |
| 154 | .ty = ty.unionFieldType(union_val.tag, mod), | |
| 155 | .val = union_val.val, | |
| 156 | }, writer, level - 1, mod); | |
| 157 | ||
| 158 | return writer.writeAll(" }"); | |
| 159 | }, | |
| 160 | .zero => return writer.writeAll("0"), | |
| 161 | .one => return writer.writeAll("1"), | |
| 162 | .the_only_possible_value => return writer.writeAll("0"), | |
| 163 | .ty => return val.castTag(.ty).?.data.print(writer, mod), | |
| 164 | .int_u64 => return std.fmt.formatIntValue(val.castTag(.int_u64).?.data, "", .{}, writer), | |
| 165 | .int_i64 => return std.fmt.formatIntValue(val.castTag(.int_i64).?.data, "", .{}, writer), | |
| 166 | .int_big_positive => return writer.print("{}", .{val.castTag(.int_big_positive).?.asBigInt()}), | |
| 167 | .int_big_negative => return writer.print("{}", .{val.castTag(.int_big_negative).?.asBigInt()}), | |
| 168 | .lazy_align => { | |
| 169 | const sub_ty = val.castTag(.lazy_align).?.data; | |
| 170 | const x = sub_ty.abiAlignment(mod); | |
| 171 | return writer.print("{d}", .{x}); | |
| 172 | }, | |
| 173 | .lazy_size => { | |
| 174 | const sub_ty = val.castTag(.lazy_size).?.data; | |
| 175 | const x = sub_ty.abiSize(mod); | |
| 176 | return writer.print("{d}", .{x}); | |
| 177 | }, | |
| 178 | .function => return writer.print("(function '{s}')", .{ | |
| 179 | mod.declPtr(val.castTag(.function).?.data.owner_decl).name, | |
| 180 | }), | |
| 181 | .extern_fn => return writer.writeAll("(extern function)"), | |
| 182 | .variable => unreachable, | |
| 183 | .decl_ref_mut => { | |
| 184 | const decl_index = val.castTag(.decl_ref_mut).?.data.decl_index; | |
| 185 | const decl = mod.declPtr(decl_index); | |
| 186 | if (level == 0) { | |
| 187 | return writer.print("(decl ref mut '{s}')", .{decl.name}); | |
| 188 | } | |
| 189 | return print(.{ | |
| 190 | .ty = decl.ty, | |
| 191 | .val = decl.val, | |
| 192 | }, writer, level - 1, mod); | |
| 193 | }, | |
| 194 | .decl_ref => { | |
| 195 | const decl_index = val.castTag(.decl_ref).?.data; | |
| 196 | const decl = mod.declPtr(decl_index); | |
| 197 | if (level == 0) { | |
| 198 | return writer.print("(decl ref '{s}')", .{decl.name}); | |
| 199 | } | |
| 200 | return print(.{ | |
| 201 | .ty = decl.ty, | |
| 202 | .val = decl.val, | |
| 203 | }, writer, level - 1, mod); | |
| 204 | }, | |
| 205 | .comptime_field_ptr => { | |
| 206 | const payload = val.castTag(.comptime_field_ptr).?.data; | |
| 207 | if (level == 0) { | |
| 208 | return writer.writeAll("(comptime field ptr)"); | |
| 209 | } | |
| 210 | return print(.{ | |
| 211 | .ty = payload.field_ty, | |
| 212 | .val = payload.field_val, | |
| 213 | }, writer, level - 1, mod); | |
| 214 | }, | |
| 215 | .elem_ptr => { | |
| 216 | const elem_ptr = val.castTag(.elem_ptr).?.data; | |
| 217 | try writer.writeAll("&"); | |
| 218 | if (level == 0) { | |
| 219 | try writer.writeAll("(ptr)"); | |
| 220 | } else { | |
| 95 | 221 | try print(.{ |
| 96 | .ty = ty.structFieldType(i), | |
| 97 | .val = val.fieldValue(ty, mod, i), | |
| 222 | .ty = elem_ptr.elem_ty, | |
| 223 | .val = elem_ptr.array_ptr, | |
| 98 | 224 | }, writer, level - 1, mod); |
| 99 | 225 | } |
| 100 | if (ty.structFieldCount() > max_aggregate_items) { | |
| 226 | return writer.print("[{}]", .{elem_ptr.index}); | |
| 227 | }, | |
| 228 | .field_ptr => { | |
| 229 | const field_ptr = val.castTag(.field_ptr).?.data; | |
| 230 | try writer.writeAll("&"); | |
| 231 | if (level == 0) { | |
| 232 | try writer.writeAll("(ptr)"); | |
| 233 | } else { | |
| 234 | try print(.{ | |
| 235 | .ty = field_ptr.container_ty, | |
| 236 | .val = field_ptr.container_ptr, | |
| 237 | }, writer, level - 1, mod); | |
| 238 | } | |
| 239 | ||
| 240 | if (field_ptr.container_ty.zigTypeTag(mod) == .Struct) { | |
| 241 | switch (field_ptr.container_ty.tag()) { | |
| 242 | .tuple => return writer.print(".@\"{d}\"", .{field_ptr.field_index}), | |
| 243 | else => { | |
| 244 | const field_name = field_ptr.container_ty.structFieldName(field_ptr.field_index); | |
| 245 | return writer.print(".{s}", .{field_name}); | |
| 246 | }, | |
| 247 | } | |
| 248 | } else if (field_ptr.container_ty.zigTypeTag(mod) == .Union) { | |
| 249 | const field_name = field_ptr.container_ty.unionFields().keys()[field_ptr.field_index]; | |
| 250 | return writer.print(".{s}", .{field_name}); | |
| 251 | } else if (field_ptr.container_ty.isSlice(mod)) { | |
| 252 | switch (field_ptr.field_index) { | |
| 253 | Value.Payload.Slice.ptr_index => return writer.writeAll(".ptr"), | |
| 254 | Value.Payload.Slice.len_index => return writer.writeAll(".len"), | |
| 255 | else => unreachable, | |
| 256 | } | |
| 257 | } | |
| 258 | }, | |
| 259 | .empty_array => return writer.writeAll(".{}"), | |
| 260 | .enum_literal => return writer.print(".{}", .{std.zig.fmtId(val.castTag(.enum_literal).?.data)}), | |
| 261 | .enum_field_index => { | |
| 262 | return writer.print(".{s}", .{ty.enumFieldName(val.castTag(.enum_field_index).?.data)}); | |
| 263 | }, | |
| 264 | .bytes => return writer.print("\"{}\"", .{std.zig.fmtEscapes(val.castTag(.bytes).?.data)}), | |
| 265 | .str_lit => { | |
| 266 | const str_lit = val.castTag(.str_lit).?.data; | |
| 267 | const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | |
| 268 | return writer.print("\"{}\"", .{std.zig.fmtEscapes(bytes)}); | |
| 269 | }, | |
| 270 | .repeated => { | |
| 271 | if (level == 0) { | |
| 272 | return writer.writeAll(".{ ... }"); | |
| 273 | } | |
| 274 | var i: u32 = 0; | |
| 275 | try writer.writeAll(".{ "); | |
| 276 | const elem_tv = TypedValue{ | |
| 277 | .ty = ty.elemType2(mod), | |
| 278 | .val = val.castTag(.repeated).?.data, | |
| 279 | }; | |
| 280 | const len = ty.arrayLen(mod); | |
| 281 | const max_len = std.math.min(len, max_aggregate_items); | |
| 282 | while (i < max_len) : (i += 1) { | |
| 283 | if (i != 0) try writer.writeAll(", "); | |
| 284 | try print(elem_tv, writer, level - 1, mod); | |
| 285 | } | |
| 286 | if (len > max_aggregate_items) { | |
| 101 | 287 | try writer.writeAll(", ..."); |
| 102 | 288 | } |
| 103 | return writer.writeAll("}"); | |
| 104 | } else { | |
| 289 | return writer.writeAll(" }"); | |
| 290 | }, | |
| 291 | .empty_array_sentinel => { | |
| 292 | if (level == 0) { | |
| 293 | return writer.writeAll(".{ (sentinel) }"); | |
| 294 | } | |
| 295 | try writer.writeAll(".{ "); | |
| 296 | try print(.{ | |
| 297 | .ty = ty.elemType2(mod), | |
| 298 | .val = ty.sentinel(mod).?, | |
| 299 | }, writer, level - 1, mod); | |
| 300 | return writer.writeAll(" }"); | |
| 301 | }, | |
| 302 | .slice => { | |
| 303 | if (level == 0) { | |
| 304 | return writer.writeAll(".{ ... }"); | |
| 305 | } | |
| 306 | const payload = val.castTag(.slice).?.data; | |
| 105 | 307 | const elem_ty = ty.elemType2(mod); |
| 106 | const len = ty.arrayLen(mod); | |
| 308 | const len = payload.len.toUnsignedInt(mod); | |
| 107 | 309 | |
| 108 | 310 | if (elem_ty.eql(Type.u8, mod)) str: { |
| 109 | 311 | const max_len = @intCast(usize, std.math.min(len, max_string_len)); |
| ... | ... | @@ -111,11 +313,13 @@ pub fn print( |
| 111 | 313 | |
| 112 | 314 | var i: u32 = 0; |
| 113 | 315 | while (i < max_len) : (i += 1) { |
| 114 | const elem = val.fieldValue(ty, mod, i); | |
| 115 | if (elem.isUndef()) break :str; | |
| 116 | buf[i] = std.math.cast(u8, elem.toUnsignedInt(mod)) orelse break :str; | |
| 316 | var elem_buf: Value.ElemValueBuffer = undefined; | |
| 317 | const elem_val = payload.ptr.elemValueBuffer(mod, i, &elem_buf); | |
| 318 | if (elem_val.isUndef()) break :str; | |
| 319 | buf[i] = std.math.cast(u8, elem_val.toUnsignedInt(mod)) orelse break :str; | |
| 117 | 320 | } |
| 118 | 321 | |
| 322 | // TODO would be nice if this had a bit of unicode awareness. | |
| 119 | 323 | const truncated = if (len > max_string_len) " (truncated)" else ""; |
| 120 | 324 | return writer.print("\"{}{s}\"", .{ std.zig.fmtEscapes(buf[0..max_len]), truncated }); |
| 121 | 325 | } |
| ... | ... | @@ -126,292 +330,91 @@ pub fn print( |
| 126 | 330 | var i: u32 = 0; |
| 127 | 331 | while (i < max_len) : (i += 1) { |
| 128 | 332 | if (i != 0) try writer.writeAll(", "); |
| 333 | var buf: Value.ElemValueBuffer = undefined; | |
| 129 | 334 | try print(.{ |
| 130 | 335 | .ty = elem_ty, |
| 131 | .val = val.fieldValue(ty, mod, i), | |
| 336 | .val = payload.ptr.elemValueBuffer(mod, i, &buf), | |
| 132 | 337 | }, writer, level - 1, mod); |
| 133 | 338 | } |
| 134 | 339 | if (len > max_aggregate_items) { |
| 135 | 340 | try writer.writeAll(", ..."); |
| 136 | 341 | } |
| 137 | 342 | return writer.writeAll(" }"); |
| 138 | } | |
| 139 | }, | |
| 140 | .@"union" => { | |
| 141 | if (level == 0) { | |
| 142 | return writer.writeAll(".{ ... }"); | |
| 143 | } | |
| 144 | const union_val = val.castTag(.@"union").?.data; | |
| 145 | try writer.writeAll(".{ "); | |
| 146 | ||
| 147 | try print(.{ | |
| 148 | .ty = ty.cast(Type.Payload.Union).?.data.tag_ty, | |
| 149 | .val = union_val.tag, | |
| 150 | }, writer, level - 1, mod); | |
| 151 | try writer.writeAll(" = "); | |
| 152 | try print(.{ | |
| 153 | .ty = ty.unionFieldType(union_val.tag, mod), | |
| 154 | .val = union_val.val, | |
| 155 | }, writer, level - 1, mod); | |
| 156 | ||
| 157 | return writer.writeAll(" }"); | |
| 158 | }, | |
| 159 | .null_value => return writer.writeAll("null"), | |
| 160 | .undef => return writer.writeAll("undefined"), | |
| 161 | .zero => return writer.writeAll("0"), | |
| 162 | .one => return writer.writeAll("1"), | |
| 163 | .unreachable_value => return writer.writeAll("unreachable"), | |
| 164 | .the_only_possible_value => return writer.writeAll("0"), | |
| 165 | .ty => return val.castTag(.ty).?.data.print(writer, mod), | |
| 166 | .int_u64 => return std.fmt.formatIntValue(val.castTag(.int_u64).?.data, "", .{}, writer), | |
| 167 | .int_i64 => return std.fmt.formatIntValue(val.castTag(.int_i64).?.data, "", .{}, writer), | |
| 168 | .int_big_positive => return writer.print("{}", .{val.castTag(.int_big_positive).?.asBigInt()}), | |
| 169 | .int_big_negative => return writer.print("{}", .{val.castTag(.int_big_negative).?.asBigInt()}), | |
| 170 | .lazy_align => { | |
| 171 | const sub_ty = val.castTag(.lazy_align).?.data; | |
| 172 | const x = sub_ty.abiAlignment(mod); | |
| 173 | return writer.print("{d}", .{x}); | |
| 174 | }, | |
| 175 | .lazy_size => { | |
| 176 | const sub_ty = val.castTag(.lazy_size).?.data; | |
| 177 | const x = sub_ty.abiSize(mod); | |
| 178 | return writer.print("{d}", .{x}); | |
| 179 | }, | |
| 180 | .function => return writer.print("(function '{s}')", .{ | |
| 181 | mod.declPtr(val.castTag(.function).?.data.owner_decl).name, | |
| 182 | }), | |
| 183 | .extern_fn => return writer.writeAll("(extern function)"), | |
| 184 | .variable => unreachable, | |
| 185 | .decl_ref_mut => { | |
| 186 | const decl_index = val.castTag(.decl_ref_mut).?.data.decl_index; | |
| 187 | const decl = mod.declPtr(decl_index); | |
| 188 | if (level == 0) { | |
| 189 | return writer.print("(decl ref mut '{s}')", .{decl.name}); | |
| 190 | } | |
| 191 | return print(.{ | |
| 192 | .ty = decl.ty, | |
| 193 | .val = decl.val, | |
| 194 | }, writer, level - 1, mod); | |
| 195 | }, | |
| 196 | .decl_ref => { | |
| 197 | const decl_index = val.castTag(.decl_ref).?.data; | |
| 198 | const decl = mod.declPtr(decl_index); | |
| 199 | if (level == 0) { | |
| 200 | return writer.print("(decl ref '{s}')", .{decl.name}); | |
| 201 | } | |
| 202 | return print(.{ | |
| 203 | .ty = decl.ty, | |
| 204 | .val = decl.val, | |
| 205 | }, writer, level - 1, mod); | |
| 206 | }, | |
| 207 | .comptime_field_ptr => { | |
| 208 | const payload = val.castTag(.comptime_field_ptr).?.data; | |
| 209 | if (level == 0) { | |
| 210 | return writer.writeAll("(comptime field ptr)"); | |
| 211 | } | |
| 212 | return print(.{ | |
| 213 | .ty = payload.field_ty, | |
| 214 | .val = payload.field_val, | |
| 215 | }, writer, level - 1, mod); | |
| 216 | }, | |
| 217 | .elem_ptr => { | |
| 218 | const elem_ptr = val.castTag(.elem_ptr).?.data; | |
| 219 | try writer.writeAll("&"); | |
| 220 | if (level == 0) { | |
| 221 | try writer.writeAll("(ptr)"); | |
| 222 | } else { | |
| 343 | }, | |
| 344 | .float_16 => return writer.print("{d}", .{val.castTag(.float_16).?.data}), | |
| 345 | .float_32 => return writer.print("{d}", .{val.castTag(.float_32).?.data}), | |
| 346 | .float_64 => return writer.print("{d}", .{val.castTag(.float_64).?.data}), | |
| 347 | .float_80 => return writer.print("{d}", .{@floatCast(f64, val.castTag(.float_80).?.data)}), | |
| 348 | .float_128 => return writer.print("{d}", .{@floatCast(f64, val.castTag(.float_128).?.data)}), | |
| 349 | .@"error" => return writer.print("error.{s}", .{val.castTag(.@"error").?.data.name}), | |
| 350 | .eu_payload => { | |
| 351 | val = val.castTag(.eu_payload).?.data; | |
| 352 | ty = ty.errorUnionPayload(); | |
| 353 | }, | |
| 354 | .opt_payload => { | |
| 355 | val = val.castTag(.opt_payload).?.data; | |
| 356 | ty = ty.optionalChild(mod); | |
| 357 | return print(.{ .ty = ty, .val = val }, writer, level, mod); | |
| 358 | }, | |
| 359 | .eu_payload_ptr => { | |
| 360 | try writer.writeAll("&"); | |
| 361 | ||
| 362 | const data = val.castTag(.eu_payload_ptr).?.data; | |
| 363 | ||
| 364 | var ty_val: Value.Payload.Ty = .{ | |
| 365 | .base = .{ .tag = .ty }, | |
| 366 | .data = ty, | |
| 367 | }; | |
| 368 | ||
| 369 | try writer.writeAll("@as("); | |
| 223 | 370 | try print(.{ |
| 224 | .ty = elem_ptr.elem_ty, | |
| 225 | .val = elem_ptr.array_ptr, | |
| 371 | .ty = Type.type, | |
| 372 | .val = Value.initPayload(&ty_val.base), | |
| 226 | 373 | }, writer, level - 1, mod); |
| 227 | } | |
| 228 | return writer.print("[{}]", .{elem_ptr.index}); | |
| 229 | }, | |
| 230 | .field_ptr => { | |
| 231 | const field_ptr = val.castTag(.field_ptr).?.data; | |
| 232 | try writer.writeAll("&"); | |
| 233 | if (level == 0) { | |
| 234 | try writer.writeAll("(ptr)"); | |
| 235 | } else { | |
| 374 | ||
| 375 | try writer.writeAll(", &(payload of "); | |
| 376 | ||
| 236 | 377 | try print(.{ |
| 237 | .ty = field_ptr.container_ty, | |
| 238 | .val = field_ptr.container_ptr, | |
| 378 | .ty = mod.singleMutPtrType(data.container_ty) catch @panic("OOM"), | |
| 379 | .val = data.container_ptr, | |
| 239 | 380 | }, writer, level - 1, mod); |
| 240 | } | |
| 241 | ||
| 242 | if (field_ptr.container_ty.zigTypeTag(mod) == .Struct) { | |
| 243 | switch (field_ptr.container_ty.tag()) { | |
| 244 | .tuple => return writer.print(".@\"{d}\"", .{field_ptr.field_index}), | |
| 245 | else => { | |
| 246 | const field_name = field_ptr.container_ty.structFieldName(field_ptr.field_index); | |
| 247 | return writer.print(".{s}", .{field_name}); | |
| 248 | }, | |
| 249 | } | |
| 250 | } else if (field_ptr.container_ty.zigTypeTag(mod) == .Union) { | |
| 251 | const field_name = field_ptr.container_ty.unionFields().keys()[field_ptr.field_index]; | |
| 252 | return writer.print(".{s}", .{field_name}); | |
| 253 | } else if (field_ptr.container_ty.isSlice(mod)) { | |
| 254 | switch (field_ptr.field_index) { | |
| 255 | Value.Payload.Slice.ptr_index => return writer.writeAll(".ptr"), | |
| 256 | Value.Payload.Slice.len_index => return writer.writeAll(".len"), | |
| 257 | else => unreachable, | |
| 258 | } | |
| 259 | } | |
| 260 | }, | |
| 261 | .empty_array => return writer.writeAll(".{}"), | |
| 262 | .enum_literal => return writer.print(".{}", .{std.zig.fmtId(val.castTag(.enum_literal).?.data)}), | |
| 263 | .enum_field_index => { | |
| 264 | return writer.print(".{s}", .{ty.enumFieldName(val.castTag(.enum_field_index).?.data)}); | |
| 265 | }, | |
| 266 | .bytes => return writer.print("\"{}\"", .{std.zig.fmtEscapes(val.castTag(.bytes).?.data)}), | |
| 267 | .str_lit => { | |
| 268 | const str_lit = val.castTag(.str_lit).?.data; | |
| 269 | const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | |
| 270 | return writer.print("\"{}\"", .{std.zig.fmtEscapes(bytes)}); | |
| 271 | }, | |
| 272 | .repeated => { | |
| 273 | if (level == 0) { | |
| 274 | return writer.writeAll(".{ ... }"); | |
| 275 | } | |
| 276 | var i: u32 = 0; | |
| 277 | try writer.writeAll(".{ "); | |
| 278 | const elem_tv = TypedValue{ | |
| 279 | .ty = ty.elemType2(mod), | |
| 280 | .val = val.castTag(.repeated).?.data, | |
| 281 | }; | |
| 282 | const len = ty.arrayLen(mod); | |
| 283 | const max_len = std.math.min(len, max_aggregate_items); | |
| 284 | while (i < max_len) : (i += 1) { | |
| 285 | if (i != 0) try writer.writeAll(", "); | |
| 286 | try print(elem_tv, writer, level - 1, mod); | |
| 287 | } | |
| 288 | if (len > max_aggregate_items) { | |
| 289 | try writer.writeAll(", ..."); | |
| 290 | } | |
| 291 | return writer.writeAll(" }"); | |
| 292 | }, | |
| 293 | .empty_array_sentinel => { | |
| 294 | if (level == 0) { | |
| 295 | return writer.writeAll(".{ (sentinel) }"); | |
| 296 | } | |
| 297 | try writer.writeAll(".{ "); | |
| 298 | try print(.{ | |
| 299 | .ty = ty.elemType2(mod), | |
| 300 | .val = ty.sentinel(mod).?, | |
| 301 | }, writer, level - 1, mod); | |
| 302 | return writer.writeAll(" }"); | |
| 303 | }, | |
| 304 | .slice => { | |
| 305 | if (level == 0) { | |
| 306 | return writer.writeAll(".{ ... }"); | |
| 307 | } | |
| 308 | const payload = val.castTag(.slice).?.data; | |
| 309 | const elem_ty = ty.elemType2(mod); | |
| 310 | const len = payload.len.toUnsignedInt(mod); | |
| 311 | ||
| 312 | if (elem_ty.eql(Type.u8, mod)) str: { | |
| 313 | const max_len = @intCast(usize, std.math.min(len, max_string_len)); | |
| 314 | var buf: [max_string_len]u8 = undefined; | |
| 315 | 381 | |
| 316 | var i: u32 = 0; | |
| 317 | while (i < max_len) : (i += 1) { | |
| 318 | var elem_buf: Value.ElemValueBuffer = undefined; | |
| 319 | const elem_val = payload.ptr.elemValueBuffer(mod, i, &elem_buf); | |
| 320 | if (elem_val.isUndef()) break :str; | |
| 321 | buf[i] = std.math.cast(u8, elem_val.toUnsignedInt(mod)) orelse break :str; | |
| 322 | } | |
| 323 | ||
| 324 | // TODO would be nice if this had a bit of unicode awareness. | |
| 325 | const truncated = if (len > max_string_len) " (truncated)" else ""; | |
| 326 | return writer.print("\"{}{s}\"", .{ std.zig.fmtEscapes(buf[0..max_len]), truncated }); | |
| 327 | } | |
| 382 | try writer.writeAll("))"); | |
| 383 | return; | |
| 384 | }, | |
| 385 | .opt_payload_ptr => { | |
| 386 | const data = val.castTag(.opt_payload_ptr).?.data; | |
| 328 | 387 | |
| 329 | try writer.writeAll(".{ "); | |
| 388 | var ty_val: Value.Payload.Ty = .{ | |
| 389 | .base = .{ .tag = .ty }, | |
| 390 | .data = ty, | |
| 391 | }; | |
| 330 | 392 | |
| 331 | const max_len = std.math.min(len, max_aggregate_items); | |
| 332 | var i: u32 = 0; | |
| 333 | while (i < max_len) : (i += 1) { | |
| 334 | if (i != 0) try writer.writeAll(", "); | |
| 335 | var buf: Value.ElemValueBuffer = undefined; | |
| 393 | try writer.writeAll("@as("); | |
| 336 | 394 | try print(.{ |
| 337 | .ty = elem_ty, | |
| 338 | .val = payload.ptr.elemValueBuffer(mod, i, &buf), | |
| 395 | .ty = Type.type, | |
| 396 | .val = Value.initPayload(&ty_val.base), | |
| 339 | 397 | }, writer, level - 1, mod); |
| 340 | } | |
| 341 | if (len > max_aggregate_items) { | |
| 342 | try writer.writeAll(", ..."); | |
| 343 | } | |
| 344 | return writer.writeAll(" }"); | |
| 345 | }, | |
| 346 | .float_16 => return writer.print("{d}", .{val.castTag(.float_16).?.data}), | |
| 347 | .float_32 => return writer.print("{d}", .{val.castTag(.float_32).?.data}), | |
| 348 | .float_64 => return writer.print("{d}", .{val.castTag(.float_64).?.data}), | |
| 349 | .float_80 => return writer.print("{d}", .{@floatCast(f64, val.castTag(.float_80).?.data)}), | |
| 350 | .float_128 => return writer.print("{d}", .{@floatCast(f64, val.castTag(.float_128).?.data)}), | |
| 351 | .@"error" => return writer.print("error.{s}", .{val.castTag(.@"error").?.data.name}), | |
| 352 | .eu_payload => { | |
| 353 | val = val.castTag(.eu_payload).?.data; | |
| 354 | ty = ty.errorUnionPayload(); | |
| 355 | }, | |
| 356 | .opt_payload => { | |
| 357 | val = val.castTag(.opt_payload).?.data; | |
| 358 | ty = ty.optionalChild(mod); | |
| 359 | return print(.{ .ty = ty, .val = val }, writer, level, mod); | |
| 360 | }, | |
| 361 | .eu_payload_ptr => { | |
| 362 | try writer.writeAll("&"); | |
| 363 | 398 | |
| 364 | const data = val.castTag(.eu_payload_ptr).?.data; | |
| 399 | try writer.writeAll(", &(payload of "); | |
| 365 | 400 | |
| 366 | var ty_val: Value.Payload.Ty = .{ | |
| 367 | .base = .{ .tag = .ty }, | |
| 368 | .data = ty, | |
| 369 | }; | |
| 370 | ||
| 371 | try writer.writeAll("@as("); | |
| 372 | try print(.{ | |
| 373 | .ty = Type.type, | |
| 374 | .val = Value.initPayload(&ty_val.base), | |
| 375 | }, writer, level - 1, mod); | |
| 376 | ||
| 377 | try writer.writeAll(", &(payload of "); | |
| 401 | try print(.{ | |
| 402 | .ty = mod.singleMutPtrType(data.container_ty) catch @panic("OOM"), | |
| 403 | .val = data.container_ptr, | |
| 404 | }, writer, level - 1, mod); | |
| 378 | 405 | |
| 379 | try print(.{ | |
| 380 | .ty = mod.singleMutPtrType(data.container_ty) catch @panic("OOM"), | |
| 381 | .val = data.container_ptr, | |
| 382 | }, writer, level - 1, mod); | |
| 406 | try writer.writeAll("))"); | |
| 407 | return; | |
| 408 | }, | |
| 383 | 409 | |
| 384 | try writer.writeAll("))"); | |
| 385 | return; | |
| 410 | // TODO these should not appear in this function | |
| 411 | .inferred_alloc => return writer.writeAll("(inferred allocation value)"), | |
| 412 | .inferred_alloc_comptime => return writer.writeAll("(inferred comptime allocation value)"), | |
| 413 | .runtime_value => return writer.writeAll("[runtime value]"), | |
| 386 | 414 | }, |
| 387 | .opt_payload_ptr => { | |
| 388 | const data = val.castTag(.opt_payload_ptr).?.data; | |
| 389 | ||
| 390 | var ty_val: Value.Payload.Ty = .{ | |
| 391 | .base = .{ .tag = .ty }, | |
| 392 | .data = ty, | |
| 393 | }; | |
| 394 | ||
| 395 | try writer.writeAll("@as("); | |
| 396 | try print(.{ | |
| 397 | .ty = Type.type, | |
| 398 | .val = Value.initPayload(&ty_val.base), | |
| 399 | }, writer, level - 1, mod); | |
| 400 | ||
| 401 | try writer.writeAll(", &(payload of "); | |
| 402 | ||
| 403 | try print(.{ | |
| 404 | .ty = mod.singleMutPtrType(data.container_ty) catch @panic("OOM"), | |
| 405 | .val = data.container_ptr, | |
| 406 | }, writer, level - 1, mod); | |
| 407 | ||
| 408 | try writer.writeAll("))"); | |
| 415 | else => { | |
| 416 | try writer.print("(interned: {})", .{val.ip_index}); | |
| 409 | 417 | return; |
| 410 | 418 | }, |
| 411 | ||
| 412 | // TODO these should not appear in this function | |
| 413 | .inferred_alloc => return writer.writeAll("(inferred allocation value)"), | |
| 414 | .inferred_alloc_comptime => return writer.writeAll("(inferred comptime allocation value)"), | |
| 415 | .runtime_value => return writer.writeAll("[runtime value]"), | |
| 416 | 419 | }; |
| 417 | 420 | } |
src/arch/wasm/CodeGen.zig+9-5| ... | ... | @@ -3088,11 +3088,15 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue { |
| 3088 | 3088 | 64 => return WValue{ .float64 = val.toFloat(f64) }, |
| 3089 | 3089 | else => unreachable, |
| 3090 | 3090 | }, |
| 3091 | .Pointer => switch (val.tag()) { | |
| 3092 | .field_ptr, .elem_ptr, .opt_payload_ptr => return func.lowerParentPtr(val, 0), | |
| 3093 | .int_u64, .one => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt(mod)) }, | |
| 3094 | .zero, .null_value => return WValue{ .imm32 = 0 }, | |
| 3095 | else => return func.fail("Wasm TODO: lowerConstant for other const pointer tag {}", .{val.tag()}), | |
| 3091 | .Pointer => switch (val.ip_index) { | |
| 3092 | .null_value => return WValue{ .imm32 = 0 }, | |
| 3093 | .none => switch (val.tag()) { | |
| 3094 | .field_ptr, .elem_ptr, .opt_payload_ptr => return func.lowerParentPtr(val, 0), | |
| 3095 | .int_u64, .one => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt(mod)) }, | |
| 3096 | .zero => return WValue{ .imm32 = 0 }, | |
| 3097 | else => return func.fail("Wasm TODO: lowerConstant for other const pointer tag {}", .{val.tag()}), | |
| 3098 | }, | |
| 3099 | else => unreachable, | |
| 3096 | 3100 | }, |
| 3097 | 3101 | .Enum => { |
| 3098 | 3102 | if (val.castTag(.enum_field_index)) |field_index| { |
src/codegen.zig+77-73| ... | ... | @@ -312,7 +312,7 @@ pub fn generateSymbol( |
| 312 | 312 | ), |
| 313 | 313 | }, |
| 314 | 314 | }, |
| 315 | .Pointer => switch (typed_value.val.tag()) { | |
| 315 | .Pointer => switch (typed_value.val.ip_index) { | |
| 316 | 316 | .null_value => { |
| 317 | 317 | switch (target.ptrBitWidth()) { |
| 318 | 318 | 32 => { |
| ... | ... | @@ -327,76 +327,79 @@ pub fn generateSymbol( |
| 327 | 327 | } |
| 328 | 328 | return Result.ok; |
| 329 | 329 | }, |
| 330 | .zero, .one, .int_u64, .int_big_positive => { | |
| 331 | switch (target.ptrBitWidth()) { | |
| 332 | 32 => { | |
| 333 | const x = typed_value.val.toUnsignedInt(mod); | |
| 334 | mem.writeInt(u32, try code.addManyAsArray(4), @intCast(u32, x), endian); | |
| 335 | }, | |
| 336 | 64 => { | |
| 337 | const x = typed_value.val.toUnsignedInt(mod); | |
| 338 | mem.writeInt(u64, try code.addManyAsArray(8), x, endian); | |
| 339 | }, | |
| 340 | else => unreachable, | |
| 341 | } | |
| 342 | return Result.ok; | |
| 343 | }, | |
| 344 | .variable, .decl_ref, .decl_ref_mut => |tag| return lowerDeclRef( | |
| 345 | bin_file, | |
| 346 | src_loc, | |
| 347 | typed_value, | |
| 348 | switch (tag) { | |
| 349 | .variable => typed_value.val.castTag(.variable).?.data.owner_decl, | |
| 350 | .decl_ref => typed_value.val.castTag(.decl_ref).?.data, | |
| 351 | .decl_ref_mut => typed_value.val.castTag(.decl_ref_mut).?.data.decl_index, | |
| 352 | else => unreachable, | |
| 330 | .none => switch (typed_value.val.tag()) { | |
| 331 | .zero, .one, .int_u64, .int_big_positive => { | |
| 332 | switch (target.ptrBitWidth()) { | |
| 333 | 32 => { | |
| 334 | const x = typed_value.val.toUnsignedInt(mod); | |
| 335 | mem.writeInt(u32, try code.addManyAsArray(4), @intCast(u32, x), endian); | |
| 336 | }, | |
| 337 | 64 => { | |
| 338 | const x = typed_value.val.toUnsignedInt(mod); | |
| 339 | mem.writeInt(u64, try code.addManyAsArray(8), x, endian); | |
| 340 | }, | |
| 341 | else => unreachable, | |
| 342 | } | |
| 343 | return Result.ok; | |
| 353 | 344 | }, |
| 354 | code, | |
| 355 | debug_output, | |
| 356 | reloc_info, | |
| 357 | ), | |
| 358 | .slice => { | |
| 359 | const slice = typed_value.val.castTag(.slice).?.data; | |
| 345 | .variable, .decl_ref, .decl_ref_mut => |tag| return lowerDeclRef( | |
| 346 | bin_file, | |
| 347 | src_loc, | |
| 348 | typed_value, | |
| 349 | switch (tag) { | |
| 350 | .variable => typed_value.val.castTag(.variable).?.data.owner_decl, | |
| 351 | .decl_ref => typed_value.val.castTag(.decl_ref).?.data, | |
| 352 | .decl_ref_mut => typed_value.val.castTag(.decl_ref_mut).?.data.decl_index, | |
| 353 | else => unreachable, | |
| 354 | }, | |
| 355 | code, | |
| 356 | debug_output, | |
| 357 | reloc_info, | |
| 358 | ), | |
| 359 | .slice => { | |
| 360 | const slice = typed_value.val.castTag(.slice).?.data; | |
| 360 | 361 | |
| 361 | // generate ptr | |
| 362 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | |
| 363 | const slice_ptr_field_type = typed_value.ty.slicePtrFieldType(&buf); | |
| 364 | switch (try generateSymbol(bin_file, src_loc, .{ | |
| 365 | .ty = slice_ptr_field_type, | |
| 366 | .val = slice.ptr, | |
| 367 | }, code, debug_output, reloc_info)) { | |
| 368 | .ok => {}, | |
| 369 | .fail => |em| return Result{ .fail = em }, | |
| 370 | } | |
| 362 | // generate ptr | |
| 363 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | |
| 364 | const slice_ptr_field_type = typed_value.ty.slicePtrFieldType(&buf); | |
| 365 | switch (try generateSymbol(bin_file, src_loc, .{ | |
| 366 | .ty = slice_ptr_field_type, | |
| 367 | .val = slice.ptr, | |
| 368 | }, code, debug_output, reloc_info)) { | |
| 369 | .ok => {}, | |
| 370 | .fail => |em| return Result{ .fail = em }, | |
| 371 | } | |
| 371 | 372 | |
| 372 | // generate length | |
| 373 | switch (try generateSymbol(bin_file, src_loc, .{ | |
| 374 | .ty = Type.usize, | |
| 375 | .val = slice.len, | |
| 376 | }, code, debug_output, reloc_info)) { | |
| 377 | .ok => {}, | |
| 378 | .fail => |em| return Result{ .fail = em }, | |
| 379 | } | |
| 373 | // generate length | |
| 374 | switch (try generateSymbol(bin_file, src_loc, .{ | |
| 375 | .ty = Type.usize, | |
| 376 | .val = slice.len, | |
| 377 | }, code, debug_output, reloc_info)) { | |
| 378 | .ok => {}, | |
| 379 | .fail => |em| return Result{ .fail = em }, | |
| 380 | } | |
| 380 | 381 | |
| 381 | return Result.ok; | |
| 382 | }, | |
| 383 | .field_ptr, .elem_ptr, .opt_payload_ptr => return lowerParentPtr( | |
| 384 | bin_file, | |
| 385 | src_loc, | |
| 386 | typed_value, | |
| 387 | typed_value.val, | |
| 388 | code, | |
| 389 | debug_output, | |
| 390 | reloc_info, | |
| 391 | ), | |
| 392 | else => return Result{ | |
| 393 | .fail = try ErrorMsg.create( | |
| 394 | bin_file.allocator, | |
| 382 | return Result.ok; | |
| 383 | }, | |
| 384 | .field_ptr, .elem_ptr, .opt_payload_ptr => return lowerParentPtr( | |
| 385 | bin_file, | |
| 395 | 386 | src_loc, |
| 396 | "TODO implement generateSymbol for pointer type value: '{s}'", | |
| 397 | .{@tagName(typed_value.val.tag())}, | |
| 387 | typed_value, | |
| 388 | typed_value.val, | |
| 389 | code, | |
| 390 | debug_output, | |
| 391 | reloc_info, | |
| 398 | 392 | ), |
| 393 | else => return Result{ | |
| 394 | .fail = try ErrorMsg.create( | |
| 395 | bin_file.allocator, | |
| 396 | src_loc, | |
| 397 | "TODO implement generateSymbol for pointer type value: '{s}'", | |
| 398 | .{@tagName(typed_value.val.tag())}, | |
| 399 | ), | |
| 400 | }, | |
| 399 | 401 | }, |
| 402 | else => unreachable, | |
| 400 | 403 | }, |
| 401 | 404 | .Int => { |
| 402 | 405 | const info = typed_value.ty.intInfo(mod); |
| ... | ... | @@ -652,7 +655,7 @@ pub fn generateSymbol( |
| 652 | 655 | } |
| 653 | 656 | |
| 654 | 657 | const padding = abi_size - (math.cast(usize, payload_type.abiSize(mod)) orelse return error.Overflow) - 1; |
| 655 | const value = if (typed_value.val.castTag(.opt_payload)) |payload| payload.data else Value.initTag(.undef); | |
| 658 | const value = if (typed_value.val.castTag(.opt_payload)) |payload| payload.data else Value.undef; | |
| 656 | 659 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 657 | 660 | .ty = payload_type, |
| 658 | 661 | .val = value, |
| ... | ... | @@ -696,7 +699,7 @@ pub fn generateSymbol( |
| 696 | 699 | // emit payload part of the error union |
| 697 | 700 | { |
| 698 | 701 | const begin = code.items.len; |
| 699 | const payload_val = if (typed_value.val.castTag(.eu_payload)) |val| val.data else Value.initTag(.undef); | |
| 702 | const payload_val = if (typed_value.val.castTag(.eu_payload)) |val| val.data else Value.undef; | |
| 700 | 703 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 701 | 704 | .ty = payload_ty, |
| 702 | 705 | .val = payload_val, |
| ... | ... | @@ -1189,16 +1192,17 @@ pub fn genTypedValue( |
| 1189 | 1192 | .Void => return GenResult.mcv(.none), |
| 1190 | 1193 | .Pointer => switch (typed_value.ty.ptrSize(mod)) { |
| 1191 | 1194 | .Slice => {}, |
| 1192 | else => { | |
| 1193 | switch (typed_value.val.tag()) { | |
| 1194 | .null_value => { | |
| 1195 | return GenResult.mcv(.{ .immediate = 0 }); | |
| 1196 | }, | |
| 1195 | else => switch (typed_value.val.ip_index) { | |
| 1196 | .null_value => { | |
| 1197 | return GenResult.mcv(.{ .immediate = 0 }); | |
| 1198 | }, | |
| 1199 | .none => switch (typed_value.val.tag()) { | |
| 1197 | 1200 | .int_u64 => { |
| 1198 | 1201 | return GenResult.mcv(.{ .immediate = typed_value.val.toUnsignedInt(mod) }); |
| 1199 | 1202 | }, |
| 1200 | 1203 | else => {}, |
| 1201 | } | |
| 1204 | }, | |
| 1205 | else => {}, | |
| 1202 | 1206 | }, |
| 1203 | 1207 | }, |
| 1204 | 1208 | .Int => { |
| ... | ... | @@ -1216,7 +1220,7 @@ pub fn genTypedValue( |
| 1216 | 1220 | }, |
| 1217 | 1221 | .Optional => { |
| 1218 | 1222 | if (typed_value.ty.isPtrLikeOptional(mod)) { |
| 1219 | if (typed_value.val.tag() == .null_value) return GenResult.mcv(.{ .immediate = 0 }); | |
| 1223 | if (typed_value.val.ip_index == .null_value) return GenResult.mcv(.{ .immediate = 0 }); | |
| 1220 | 1224 | |
| 1221 | 1225 | return genTypedValue(bin_file, src_loc, .{ |
| 1222 | 1226 | .ty = typed_value.ty.optionalChild(mod), |
src/codegen/c.zig+137-105| ... | ... | @@ -1045,8 +1045,8 @@ pub const DeclGen = struct { |
| 1045 | 1045 | if (!empty) try writer.writeByte(')'); |
| 1046 | 1046 | return; |
| 1047 | 1047 | }, |
| 1048 | .Pointer => switch (val.tag()) { | |
| 1049 | .null_value, .zero => if (ty.isSlice(mod)) { | |
| 1048 | .Pointer => switch (val.ip_index) { | |
| 1049 | .null_value => if (ty.isSlice(mod)) { | |
| 1050 | 1050 | var slice_pl = Value.Payload.Slice{ |
| 1051 | 1051 | .base = .{ .tag = .slice }, |
| 1052 | 1052 | .data = .{ .ptr = val, .len = Value.undef }, |
| ... | ... | @@ -1059,46 +1059,63 @@ pub const DeclGen = struct { |
| 1059 | 1059 | try dg.renderType(writer, ty); |
| 1060 | 1060 | try writer.writeAll(")NULL)"); |
| 1061 | 1061 | }, |
| 1062 | .variable => { | |
| 1063 | const decl = val.castTag(.variable).?.data.owner_decl; | |
| 1064 | return dg.renderDeclValue(writer, ty, val, decl, location); | |
| 1065 | }, | |
| 1066 | .slice => { | |
| 1067 | if (!location.isInitializer()) { | |
| 1068 | try writer.writeByte('('); | |
| 1062 | .none => switch (val.tag()) { | |
| 1063 | .zero => if (ty.isSlice(mod)) { | |
| 1064 | var slice_pl = Value.Payload.Slice{ | |
| 1065 | .base = .{ .tag = .slice }, | |
| 1066 | .data = .{ .ptr = val, .len = Value.undef }, | |
| 1067 | }; | |
| 1068 | const slice_val = Value.initPayload(&slice_pl.base); | |
| 1069 | ||
| 1070 | return dg.renderValue(writer, ty, slice_val, location); | |
| 1071 | } else { | |
| 1072 | try writer.writeAll("(("); | |
| 1069 | 1073 | try dg.renderType(writer, ty); |
| 1070 | try writer.writeByte(')'); | |
| 1071 | } | |
| 1074 | try writer.writeAll(")NULL)"); | |
| 1075 | }, | |
| 1076 | .variable => { | |
| 1077 | const decl = val.castTag(.variable).?.data.owner_decl; | |
| 1078 | return dg.renderDeclValue(writer, ty, val, decl, location); | |
| 1079 | }, | |
| 1080 | .slice => { | |
| 1081 | if (!location.isInitializer()) { | |
| 1082 | try writer.writeByte('('); | |
| 1083 | try dg.renderType(writer, ty); | |
| 1084 | try writer.writeByte(')'); | |
| 1085 | } | |
| 1072 | 1086 | |
| 1073 | const slice = val.castTag(.slice).?.data; | |
| 1074 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | |
| 1087 | const slice = val.castTag(.slice).?.data; | |
| 1088 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | |
| 1075 | 1089 | |
| 1076 | try writer.writeByte('{'); | |
| 1077 | try dg.renderValue(writer, ty.slicePtrFieldType(&buf), slice.ptr, initializer_type); | |
| 1078 | try writer.writeAll(", "); | |
| 1079 | try dg.renderValue(writer, Type.usize, slice.len, initializer_type); | |
| 1080 | try writer.writeByte('}'); | |
| 1081 | }, | |
| 1082 | .function => { | |
| 1083 | const func = val.castTag(.function).?.data; | |
| 1084 | try dg.renderDeclName(writer, func.owner_decl, 0); | |
| 1085 | }, | |
| 1086 | .extern_fn => { | |
| 1087 | const extern_fn = val.castTag(.extern_fn).?.data; | |
| 1088 | try dg.renderDeclName(writer, extern_fn.owner_decl, 0); | |
| 1089 | }, | |
| 1090 | .int_u64, .one, .int_big_positive, .lazy_align, .lazy_size => { | |
| 1091 | try writer.writeAll("(("); | |
| 1092 | try dg.renderType(writer, ty); | |
| 1093 | return writer.print("){x})", .{try dg.fmtIntLiteral(Type.usize, val, .Other)}); | |
| 1090 | try writer.writeByte('{'); | |
| 1091 | try dg.renderValue(writer, ty.slicePtrFieldType(&buf), slice.ptr, initializer_type); | |
| 1092 | try writer.writeAll(", "); | |
| 1093 | try dg.renderValue(writer, Type.usize, slice.len, initializer_type); | |
| 1094 | try writer.writeByte('}'); | |
| 1095 | }, | |
| 1096 | .function => { | |
| 1097 | const func = val.castTag(.function).?.data; | |
| 1098 | try dg.renderDeclName(writer, func.owner_decl, 0); | |
| 1099 | }, | |
| 1100 | .extern_fn => { | |
| 1101 | const extern_fn = val.castTag(.extern_fn).?.data; | |
| 1102 | try dg.renderDeclName(writer, extern_fn.owner_decl, 0); | |
| 1103 | }, | |
| 1104 | .int_u64, .one, .int_big_positive, .lazy_align, .lazy_size => { | |
| 1105 | try writer.writeAll("(("); | |
| 1106 | try dg.renderType(writer, ty); | |
| 1107 | return writer.print("){x})", .{try dg.fmtIntLiteral(Type.usize, val, .Other)}); | |
| 1108 | }, | |
| 1109 | .field_ptr, | |
| 1110 | .elem_ptr, | |
| 1111 | .opt_payload_ptr, | |
| 1112 | .eu_payload_ptr, | |
| 1113 | .decl_ref_mut, | |
| 1114 | .decl_ref, | |
| 1115 | => try dg.renderParentPtr(writer, val, ty, location), | |
| 1116 | ||
| 1117 | else => unreachable, | |
| 1094 | 1118 | }, |
| 1095 | .field_ptr, | |
| 1096 | .elem_ptr, | |
| 1097 | .opt_payload_ptr, | |
| 1098 | .eu_payload_ptr, | |
| 1099 | .decl_ref_mut, | |
| 1100 | .decl_ref, | |
| 1101 | => try dg.renderParentPtr(writer, val, ty, location), | |
| 1102 | 1119 | else => unreachable, |
| 1103 | 1120 | }, |
| 1104 | 1121 | .Array, .Vector => { |
| ... | ... | @@ -1109,8 +1126,8 @@ pub const DeclGen = struct { |
| 1109 | 1126 | } |
| 1110 | 1127 | |
| 1111 | 1128 | // First try specific tag representations for more efficiency. |
| 1112 | switch (val.tag()) { | |
| 1113 | .undef, .empty_struct_value, .empty_array => { | |
| 1129 | switch (val.ip_index) { | |
| 1130 | .undef => { | |
| 1114 | 1131 | const ai = ty.arrayInfo(mod); |
| 1115 | 1132 | try writer.writeByte('{'); |
| 1116 | 1133 | if (ai.sentinel) |s| { |
| ... | ... | @@ -1119,76 +1136,91 @@ pub const DeclGen = struct { |
| 1119 | 1136 | try writer.writeByte('0'); |
| 1120 | 1137 | } |
| 1121 | 1138 | try writer.writeByte('}'); |
| 1139 | return; | |
| 1122 | 1140 | }, |
| 1123 | .bytes, .str_lit => |t| { | |
| 1124 | const bytes = switch (t) { | |
| 1125 | .bytes => val.castTag(.bytes).?.data, | |
| 1126 | .str_lit => bytes: { | |
| 1127 | const str_lit = val.castTag(.str_lit).?.data; | |
| 1128 | break :bytes dg.module.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | |
| 1129 | }, | |
| 1130 | else => unreachable, | |
| 1131 | }; | |
| 1132 | const sentinel = if (ty.sentinel(mod)) |sentinel| @intCast(u8, sentinel.toUnsignedInt(mod)) else null; | |
| 1133 | try writer.print("{s}", .{ | |
| 1134 | fmtStringLiteral(bytes[0..@intCast(usize, ty.arrayLen(mod))], sentinel), | |
| 1135 | }); | |
| 1136 | }, | |
| 1137 | else => { | |
| 1138 | // Fall back to generic implementation. | |
| 1139 | var arena = std.heap.ArenaAllocator.init(dg.gpa); | |
| 1140 | defer arena.deinit(); | |
| 1141 | const arena_allocator = arena.allocator(); | |
| 1142 | ||
| 1143 | // MSVC throws C2078 if an array of size 65536 or greater is initialized with a string literal | |
| 1144 | const max_string_initializer_len = 65535; | |
| 1145 | ||
| 1146 | const ai = ty.arrayInfo(mod); | |
| 1147 | if (ai.elem_type.eql(Type.u8, dg.module)) { | |
| 1148 | if (ai.len <= max_string_initializer_len) { | |
| 1149 | var literal = stringLiteral(writer); | |
| 1150 | try literal.start(); | |
| 1151 | var index: usize = 0; | |
| 1152 | while (index < ai.len) : (index += 1) { | |
| 1153 | const elem_val = try val.elemValue(dg.module, arena_allocator, index); | |
| 1154 | const elem_val_u8 = if (elem_val.isUndef()) undefPattern(u8) else @intCast(u8, elem_val.toUnsignedInt(mod)); | |
| 1155 | try literal.writeChar(elem_val_u8); | |
| 1156 | } | |
| 1157 | if (ai.sentinel) |s| { | |
| 1158 | const s_u8 = @intCast(u8, s.toUnsignedInt(mod)); | |
| 1159 | if (s_u8 != 0) try literal.writeChar(s_u8); | |
| 1160 | } | |
| 1161 | try literal.end(); | |
| 1162 | } else { | |
| 1163 | try writer.writeByte('{'); | |
| 1164 | var index: usize = 0; | |
| 1165 | while (index < ai.len) : (index += 1) { | |
| 1166 | if (index != 0) try writer.writeByte(','); | |
| 1167 | const elem_val = try val.elemValue(dg.module, arena_allocator, index); | |
| 1168 | const elem_val_u8 = if (elem_val.isUndef()) undefPattern(u8) else @intCast(u8, elem_val.toUnsignedInt(mod)); | |
| 1169 | try writer.print("'\\x{x}'", .{elem_val_u8}); | |
| 1170 | } | |
| 1171 | if (ai.sentinel) |s| { | |
| 1172 | if (index != 0) try writer.writeByte(','); | |
| 1173 | try dg.renderValue(writer, ai.elem_type, s, initializer_type); | |
| 1174 | } | |
| 1175 | try writer.writeByte('}'); | |
| 1176 | } | |
| 1177 | } else { | |
| 1141 | .none => switch (val.tag()) { | |
| 1142 | .empty_struct_value, .empty_array => { | |
| 1143 | const ai = ty.arrayInfo(mod); | |
| 1178 | 1144 | try writer.writeByte('{'); |
| 1179 | var index: usize = 0; | |
| 1180 | while (index < ai.len) : (index += 1) { | |
| 1181 | if (index != 0) try writer.writeByte(','); | |
| 1182 | const elem_val = try val.elemValue(dg.module, arena_allocator, index); | |
| 1183 | try dg.renderValue(writer, ai.elem_type, elem_val, initializer_type); | |
| 1184 | } | |
| 1185 | 1145 | if (ai.sentinel) |s| { |
| 1186 | if (index != 0) try writer.writeByte(','); | |
| 1187 | 1146 | try dg.renderValue(writer, ai.elem_type, s, initializer_type); |
| 1147 | } else { | |
| 1148 | try writer.writeByte('0'); | |
| 1188 | 1149 | } |
| 1189 | 1150 | try writer.writeByte('}'); |
| 1190 | } | |
| 1151 | return; | |
| 1152 | }, | |
| 1153 | .bytes, .str_lit => |t| { | |
| 1154 | const bytes = switch (t) { | |
| 1155 | .bytes => val.castTag(.bytes).?.data, | |
| 1156 | .str_lit => bytes: { | |
| 1157 | const str_lit = val.castTag(.str_lit).?.data; | |
| 1158 | break :bytes dg.module.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | |
| 1159 | }, | |
| 1160 | else => unreachable, | |
| 1161 | }; | |
| 1162 | const sentinel = if (ty.sentinel(mod)) |sentinel| @intCast(u8, sentinel.toUnsignedInt(mod)) else null; | |
| 1163 | try writer.print("{s}", .{ | |
| 1164 | fmtStringLiteral(bytes[0..@intCast(usize, ty.arrayLen(mod))], sentinel), | |
| 1165 | }); | |
| 1166 | return; | |
| 1167 | }, | |
| 1168 | else => {}, | |
| 1191 | 1169 | }, |
| 1170 | else => {}, | |
| 1171 | } | |
| 1172 | // Fall back to generic implementation. | |
| 1173 | var arena = std.heap.ArenaAllocator.init(dg.gpa); | |
| 1174 | defer arena.deinit(); | |
| 1175 | const arena_allocator = arena.allocator(); | |
| 1176 | ||
| 1177 | // MSVC throws C2078 if an array of size 65536 or greater is initialized with a string literal | |
| 1178 | const max_string_initializer_len = 65535; | |
| 1179 | ||
| 1180 | const ai = ty.arrayInfo(mod); | |
| 1181 | if (ai.elem_type.eql(Type.u8, dg.module)) { | |
| 1182 | if (ai.len <= max_string_initializer_len) { | |
| 1183 | var literal = stringLiteral(writer); | |
| 1184 | try literal.start(); | |
| 1185 | var index: usize = 0; | |
| 1186 | while (index < ai.len) : (index += 1) { | |
| 1187 | const elem_val = try val.elemValue(dg.module, arena_allocator, index); | |
| 1188 | const elem_val_u8 = if (elem_val.isUndef()) undefPattern(u8) else @intCast(u8, elem_val.toUnsignedInt(mod)); | |
| 1189 | try literal.writeChar(elem_val_u8); | |
| 1190 | } | |
| 1191 | if (ai.sentinel) |s| { | |
| 1192 | const s_u8 = @intCast(u8, s.toUnsignedInt(mod)); | |
| 1193 | if (s_u8 != 0) try literal.writeChar(s_u8); | |
| 1194 | } | |
| 1195 | try literal.end(); | |
| 1196 | } else { | |
| 1197 | try writer.writeByte('{'); | |
| 1198 | var index: usize = 0; | |
| 1199 | while (index < ai.len) : (index += 1) { | |
| 1200 | if (index != 0) try writer.writeByte(','); | |
| 1201 | const elem_val = try val.elemValue(dg.module, arena_allocator, index); | |
| 1202 | const elem_val_u8 = if (elem_val.isUndef()) undefPattern(u8) else @intCast(u8, elem_val.toUnsignedInt(mod)); | |
| 1203 | try writer.print("'\\x{x}'", .{elem_val_u8}); | |
| 1204 | } | |
| 1205 | if (ai.sentinel) |s| { | |
| 1206 | if (index != 0) try writer.writeByte(','); | |
| 1207 | try dg.renderValue(writer, ai.elem_type, s, initializer_type); | |
| 1208 | } | |
| 1209 | try writer.writeByte('}'); | |
| 1210 | } | |
| 1211 | } else { | |
| 1212 | try writer.writeByte('{'); | |
| 1213 | var index: usize = 0; | |
| 1214 | while (index < ai.len) : (index += 1) { | |
| 1215 | if (index != 0) try writer.writeByte(','); | |
| 1216 | const elem_val = try val.elemValue(dg.module, arena_allocator, index); | |
| 1217 | try dg.renderValue(writer, ai.elem_type, elem_val, initializer_type); | |
| 1218 | } | |
| 1219 | if (ai.sentinel) |s| { | |
| 1220 | if (index != 0) try writer.writeByte(','); | |
| 1221 | try dg.renderValue(writer, ai.elem_type, s, initializer_type); | |
| 1222 | } | |
| 1223 | try writer.writeByte('}'); | |
| 1192 | 1224 | } |
| 1193 | 1225 | }, |
| 1194 | 1226 | .Bool => { |
| ... | ... | @@ -1201,7 +1233,7 @@ pub const DeclGen = struct { |
| 1201 | 1233 | .Optional => { |
| 1202 | 1234 | const payload_ty = ty.optionalChild(mod); |
| 1203 | 1235 | |
| 1204 | const is_null_val = Value.makeBool(val.tag() == .null_value); | |
| 1236 | const is_null_val = Value.makeBool(val.ip_index == .null_value); | |
| 1205 | 1237 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) |
| 1206 | 1238 | return dg.renderValue(writer, Type.bool, is_null_val, location); |
| 1207 | 1239 | |
| ... | ... | @@ -7765,7 +7797,7 @@ fn lowerFnRetTy(ret_ty: Type, buffer: *LowerFnRetTyBuffer, mod: *const Module) T |
| 7765 | 7797 | if (lowersToArray(ret_ty, mod)) { |
| 7766 | 7798 | buffer.names = [1][]const u8{"array"}; |
| 7767 | 7799 | buffer.types = [1]Type{ret_ty}; |
| 7768 | buffer.values = [1]Value{Value.initTag(.unreachable_value)}; | |
| 7800 | buffer.values = [1]Value{Value.@"unreachable"}; | |
| 7769 | 7801 | buffer.payload = .{ .data = .{ |
| 7770 | 7802 | .names = &buffer.names, |
| 7771 | 7803 | .types = &buffer.types, |
src/codegen/llvm.zig+63-56| ... | ... | @@ -2028,7 +2028,7 @@ pub const Object = struct { |
| 2028 | 2028 | |
| 2029 | 2029 | for (tuple.types, 0..) |field_ty, i| { |
| 2030 | 2030 | const field_val = tuple.values[i]; |
| 2031 | if (field_val.tag() != .unreachable_value or !field_ty.hasRuntimeBits(mod)) continue; | |
| 2031 | if (field_val.ip_index != .unreachable_value or !field_ty.hasRuntimeBits(mod)) continue; | |
| 2032 | 2032 | |
| 2033 | 2033 | const field_size = field_ty.abiSize(mod); |
| 2034 | 2034 | const field_align = field_ty.abiAlignment(mod); |
| ... | ... | @@ -2498,7 +2498,7 @@ pub const DeclGen = struct { |
| 2498 | 2498 | global.setGlobalConstant(.True); |
| 2499 | 2499 | break :init_val decl.val; |
| 2500 | 2500 | }; |
| 2501 | if (init_val.tag() != .unreachable_value) { | |
| 2501 | if (init_val.ip_index != .unreachable_value) { | |
| 2502 | 2502 | const llvm_init = try dg.lowerValue(.{ .ty = decl.ty, .val = init_val }); |
| 2503 | 2503 | if (global.globalGetValueType() == llvm_init.typeOf()) { |
| 2504 | 2504 | global.setInitializer(llvm_init); |
| ... | ... | @@ -2954,7 +2954,7 @@ pub const DeclGen = struct { |
| 2954 | 2954 | |
| 2955 | 2955 | for (tuple.types, 0..) |field_ty, i| { |
| 2956 | 2956 | const field_val = tuple.values[i]; |
| 2957 | if (field_val.tag() != .unreachable_value or !field_ty.hasRuntimeBits(mod)) continue; | |
| 2957 | if (field_val.ip_index != .unreachable_value or !field_ty.hasRuntimeBits(mod)) continue; | |
| 2958 | 2958 | |
| 2959 | 2959 | const field_align = field_ty.abiAlignment(mod); |
| 2960 | 2960 | big_align = @max(big_align, field_align); |
| ... | ... | @@ -3359,58 +3359,65 @@ pub const DeclGen = struct { |
| 3359 | 3359 | else => unreachable, |
| 3360 | 3360 | } |
| 3361 | 3361 | }, |
| 3362 | .Pointer => switch (tv.val.tag()) { | |
| 3363 | .decl_ref_mut => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref_mut).?.data.decl_index), | |
| 3364 | .decl_ref => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref).?.data), | |
| 3365 | .variable => { | |
| 3366 | const decl_index = tv.val.castTag(.variable).?.data.owner_decl; | |
| 3367 | const decl = dg.module.declPtr(decl_index); | |
| 3368 | dg.module.markDeclAlive(decl); | |
| 3369 | ||
| 3370 | const llvm_wanted_addrspace = toLlvmAddressSpace(decl.@"addrspace", target); | |
| 3371 | const llvm_actual_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target); | |
| 3372 | ||
| 3373 | const val = try dg.resolveGlobalDecl(decl_index); | |
| 3374 | const addrspace_casted_ptr = if (llvm_actual_addrspace != llvm_wanted_addrspace) | |
| 3375 | val.constAddrSpaceCast(dg.context.pointerType(llvm_wanted_addrspace)) | |
| 3376 | else | |
| 3377 | val; | |
| 3378 | return addrspace_casted_ptr; | |
| 3379 | }, | |
| 3380 | .slice => { | |
| 3381 | const slice = tv.val.castTag(.slice).?.data; | |
| 3382 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | |
| 3383 | const fields: [2]*llvm.Value = .{ | |
| 3384 | try dg.lowerValue(.{ | |
| 3385 | .ty = tv.ty.slicePtrFieldType(&buf), | |
| 3386 | .val = slice.ptr, | |
| 3387 | }), | |
| 3388 | try dg.lowerValue(.{ | |
| 3389 | .ty = Type.usize, | |
| 3390 | .val = slice.len, | |
| 3391 | }), | |
| 3392 | }; | |
| 3393 | return dg.context.constStruct(&fields, fields.len, .False); | |
| 3394 | }, | |
| 3395 | .int_u64, .one, .int_big_positive, .lazy_align, .lazy_size => { | |
| 3396 | const llvm_usize = try dg.lowerType(Type.usize); | |
| 3397 | const llvm_int = llvm_usize.constInt(tv.val.toUnsignedInt(mod), .False); | |
| 3398 | return llvm_int.constIntToPtr(try dg.lowerType(tv.ty)); | |
| 3399 | }, | |
| 3400 | .field_ptr, .opt_payload_ptr, .eu_payload_ptr, .elem_ptr => { | |
| 3401 | return dg.lowerParentPtr(tv.val, tv.ty.ptrInfo(mod).bit_offset % 8 == 0); | |
| 3402 | }, | |
| 3403 | .null_value, .zero => { | |
| 3362 | .Pointer => switch (tv.val.ip_index) { | |
| 3363 | .null_value => { | |
| 3404 | 3364 | const llvm_type = try dg.lowerType(tv.ty); |
| 3405 | 3365 | return llvm_type.constNull(); |
| 3406 | 3366 | }, |
| 3407 | .opt_payload => { | |
| 3408 | const payload = tv.val.castTag(.opt_payload).?.data; | |
| 3409 | return dg.lowerParentPtr(payload, tv.ty.ptrInfo(mod).bit_offset % 8 == 0); | |
| 3367 | .none => switch (tv.val.tag()) { | |
| 3368 | .decl_ref_mut => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref_mut).?.data.decl_index), | |
| 3369 | .decl_ref => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref).?.data), | |
| 3370 | .variable => { | |
| 3371 | const decl_index = tv.val.castTag(.variable).?.data.owner_decl; | |
| 3372 | const decl = dg.module.declPtr(decl_index); | |
| 3373 | dg.module.markDeclAlive(decl); | |
| 3374 | ||
| 3375 | const llvm_wanted_addrspace = toLlvmAddressSpace(decl.@"addrspace", target); | |
| 3376 | const llvm_actual_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target); | |
| 3377 | ||
| 3378 | const val = try dg.resolveGlobalDecl(decl_index); | |
| 3379 | const addrspace_casted_ptr = if (llvm_actual_addrspace != llvm_wanted_addrspace) | |
| 3380 | val.constAddrSpaceCast(dg.context.pointerType(llvm_wanted_addrspace)) | |
| 3381 | else | |
| 3382 | val; | |
| 3383 | return addrspace_casted_ptr; | |
| 3384 | }, | |
| 3385 | .slice => { | |
| 3386 | const slice = tv.val.castTag(.slice).?.data; | |
| 3387 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | |
| 3388 | const fields: [2]*llvm.Value = .{ | |
| 3389 | try dg.lowerValue(.{ | |
| 3390 | .ty = tv.ty.slicePtrFieldType(&buf), | |
| 3391 | .val = slice.ptr, | |
| 3392 | }), | |
| 3393 | try dg.lowerValue(.{ | |
| 3394 | .ty = Type.usize, | |
| 3395 | .val = slice.len, | |
| 3396 | }), | |
| 3397 | }; | |
| 3398 | return dg.context.constStruct(&fields, fields.len, .False); | |
| 3399 | }, | |
| 3400 | .int_u64, .one, .int_big_positive, .lazy_align, .lazy_size => { | |
| 3401 | const llvm_usize = try dg.lowerType(Type.usize); | |
| 3402 | const llvm_int = llvm_usize.constInt(tv.val.toUnsignedInt(mod), .False); | |
| 3403 | return llvm_int.constIntToPtr(try dg.lowerType(tv.ty)); | |
| 3404 | }, | |
| 3405 | .field_ptr, .opt_payload_ptr, .eu_payload_ptr, .elem_ptr => { | |
| 3406 | return dg.lowerParentPtr(tv.val, tv.ty.ptrInfo(mod).bit_offset % 8 == 0); | |
| 3407 | }, | |
| 3408 | .zero => { | |
| 3409 | const llvm_type = try dg.lowerType(tv.ty); | |
| 3410 | return llvm_type.constNull(); | |
| 3411 | }, | |
| 3412 | .opt_payload => { | |
| 3413 | const payload = tv.val.castTag(.opt_payload).?.data; | |
| 3414 | return dg.lowerParentPtr(payload, tv.ty.ptrInfo(mod).bit_offset % 8 == 0); | |
| 3415 | }, | |
| 3416 | else => |tag| return dg.todo("implement const of pointer type '{}' ({})", .{ | |
| 3417 | tv.ty.fmtDebug(), tag, | |
| 3418 | }), | |
| 3410 | 3419 | }, |
| 3411 | else => |tag| return dg.todo("implement const of pointer type '{}' ({})", .{ | |
| 3412 | tv.ty.fmtDebug(), tag, | |
| 3413 | }), | |
| 3420 | else => unreachable, | |
| 3414 | 3421 | }, |
| 3415 | 3422 | .Array => switch (tv.val.tag()) { |
| 3416 | 3423 | .bytes => { |
| ... | ... | @@ -3555,7 +3562,7 @@ pub const DeclGen = struct { |
| 3555 | 3562 | var fields_buf: [3]*llvm.Value = undefined; |
| 3556 | 3563 | fields_buf[0] = try dg.lowerValue(.{ |
| 3557 | 3564 | .ty = payload_ty, |
| 3558 | .val = if (tv.val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef), | |
| 3565 | .val = if (tv.val.castTag(.opt_payload)) |pl| pl.data else Value.undef, | |
| 3559 | 3566 | }); |
| 3560 | 3567 | fields_buf[1] = non_null_bit; |
| 3561 | 3568 | if (llvm_field_count > 2) { |
| ... | ... | @@ -3606,7 +3613,7 @@ pub const DeclGen = struct { |
| 3606 | 3613 | }); |
| 3607 | 3614 | const llvm_payload_value = try dg.lowerValue(.{ |
| 3608 | 3615 | .ty = payload_type, |
| 3609 | .val = if (tv.val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef), | |
| 3616 | .val = if (tv.val.castTag(.eu_payload)) |pl| pl.data else Value.undef, | |
| 3610 | 3617 | }); |
| 3611 | 3618 | var fields_buf: [3]*llvm.Value = undefined; |
| 3612 | 3619 | |
| ... | ... | @@ -3645,7 +3652,7 @@ pub const DeclGen = struct { |
| 3645 | 3652 | var need_unnamed = false; |
| 3646 | 3653 | |
| 3647 | 3654 | for (tuple.types, 0..) |field_ty, i| { |
| 3648 | if (tuple.values[i].tag() != .unreachable_value) continue; | |
| 3655 | if (tuple.values[i].ip_index != .unreachable_value) continue; | |
| 3649 | 3656 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 3650 | 3657 | |
| 3651 | 3658 | const field_align = field_ty.abiAlignment(mod); |
| ... | ... | @@ -10501,7 +10508,7 @@ fn llvmFieldIndex( |
| 10501 | 10508 | const tuple = ty.tupleFields(); |
| 10502 | 10509 | var llvm_field_index: c_uint = 0; |
| 10503 | 10510 | for (tuple.types, 0..) |field_ty, i| { |
| 10504 | if (tuple.values[i].tag() != .unreachable_value or !field_ty.hasRuntimeBits(mod)) continue; | |
| 10511 | if (tuple.values[i].ip_index != .unreachable_value or !field_ty.hasRuntimeBits(mod)) continue; | |
| 10505 | 10512 | |
| 10506 | 10513 | const field_align = field_ty.abiAlignment(mod); |
| 10507 | 10514 | big_align = @max(big_align, field_align); |
| ... | ... | @@ -11117,7 +11124,7 @@ fn isByRef(ty: Type, mod: *const Module) bool { |
| 11117 | 11124 | const tuple = ty.tupleFields(); |
| 11118 | 11125 | var count: usize = 0; |
| 11119 | 11126 | for (tuple.values, 0..) |field_val, i| { |
| 11120 | if (field_val.tag() != .unreachable_value or !tuple.types[i].hasRuntimeBits(mod)) continue; | |
| 11127 | if (field_val.ip_index != .unreachable_value or !tuple.types[i].hasRuntimeBits(mod)) continue; | |
| 11121 | 11128 | |
| 11122 | 11129 | count += 1; |
| 11123 | 11130 | if (count > max_fields_byval) return true; |
src/codegen/spirv.zig+6-5| ... | ... | @@ -674,7 +674,7 @@ pub const DeclGen = struct { |
| 674 | 674 | try self.lower(ptr_ty, slice.ptr); |
| 675 | 675 | try self.addInt(Type.usize, slice.len); |
| 676 | 676 | }, |
| 677 | .null_value, .zero => try self.addNullPtr(try dg.resolveType(ty, .indirect)), | |
| 677 | .zero => try self.addNullPtr(try dg.resolveType(ty, .indirect)), | |
| 678 | 678 | .int_u64, .one, .int_big_positive, .lazy_align, .lazy_size => { |
| 679 | 679 | try self.addInt(Type.usize, val); |
| 680 | 680 | }, |
| ... | ... | @@ -813,7 +813,8 @@ pub const DeclGen = struct { |
| 813 | 813 | const error_size = Type.anyerror.abiAlignment(mod); |
| 814 | 814 | const ty_size = ty.abiSize(mod); |
| 815 | 815 | const padding = ty_size - payload_size - error_size; |
| 816 | const payload_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef); | |
| 816 | ||
| 817 | const payload_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.undef; | |
| 817 | 818 | |
| 818 | 819 | if (eu_layout.error_first) { |
| 819 | 820 | try self.lower(Type.anyerror, error_val); |
| ... | ... | @@ -1021,7 +1022,7 @@ pub const DeclGen = struct { |
| 1021 | 1022 | return try self.constant(Type.anyerror, error_val, repr); |
| 1022 | 1023 | } |
| 1023 | 1024 | |
| 1024 | const payload_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef); | |
| 1025 | const payload_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.undef; | |
| 1025 | 1026 | |
| 1026 | 1027 | var members: [2]IdRef = undefined; |
| 1027 | 1028 | if (eu_layout.error_first) { |
| ... | ... | @@ -1292,7 +1293,7 @@ pub const DeclGen = struct { |
| 1292 | 1293 | var member_index: usize = 0; |
| 1293 | 1294 | for (tuple.types, 0..) |field_ty, i| { |
| 1294 | 1295 | const field_val = tuple.values[i]; |
| 1295 | if (field_val.tag() != .unreachable_value or !field_ty.hasRuntimeBits(mod)) continue; | |
| 1296 | if (field_val.ip_index != .unreachable_value or !field_ty.hasRuntimeBits(mod)) continue; | |
| 1296 | 1297 | |
| 1297 | 1298 | member_types[member_index] = try self.resolveType(field_ty, .indirect); |
| 1298 | 1299 | member_index += 1; |
| ... | ... | @@ -1596,7 +1597,7 @@ pub const DeclGen = struct { |
| 1596 | 1597 | else |
| 1597 | 1598 | decl.val; |
| 1598 | 1599 | |
| 1599 | if (init_val.tag() == .unreachable_value) { | |
| 1600 | if (init_val.ip_index == .unreachable_value) { | |
| 1600 | 1601 | return self.todo("importing extern variables", .{}); |
| 1601 | 1602 | } |
| 1602 | 1603 |
src/type.zig+29-29| ... | ... | @@ -533,14 +533,14 @@ pub const Type = struct { |
| 533 | 533 | for (a_tuple.values, 0..) |a_val, i| { |
| 534 | 534 | const ty = a_tuple.types[i]; |
| 535 | 535 | const b_val = b_tuple.values[i]; |
| 536 | if (a_val.tag() == .unreachable_value) { | |
| 537 | if (b_val.tag() == .unreachable_value) { | |
| 536 | if (a_val.ip_index == .unreachable_value) { | |
| 537 | if (b_val.ip_index == .unreachable_value) { | |
| 538 | 538 | continue; |
| 539 | 539 | } else { |
| 540 | 540 | return false; |
| 541 | 541 | } |
| 542 | 542 | } else { |
| 543 | if (b_val.tag() == .unreachable_value) { | |
| 543 | if (b_val.ip_index == .unreachable_value) { | |
| 544 | 544 | return false; |
| 545 | 545 | } else { |
| 546 | 546 | if (!Value.eql(a_val, b_val, ty, mod)) return false; |
| ... | ... | @@ -569,14 +569,14 @@ pub const Type = struct { |
| 569 | 569 | for (a_struct_obj.values, 0..) |a_val, i| { |
| 570 | 570 | const ty = a_struct_obj.types[i]; |
| 571 | 571 | const b_val = b_struct_obj.values[i]; |
| 572 | if (a_val.tag() == .unreachable_value) { | |
| 573 | if (b_val.tag() == .unreachable_value) { | |
| 572 | if (a_val.ip_index == .unreachable_value) { | |
| 573 | if (b_val.ip_index == .unreachable_value) { | |
| 574 | 574 | continue; |
| 575 | 575 | } else { |
| 576 | 576 | return false; |
| 577 | 577 | } |
| 578 | 578 | } else { |
| 579 | if (b_val.tag() == .unreachable_value) { | |
| 579 | if (b_val.ip_index == .unreachable_value) { | |
| 580 | 580 | return false; |
| 581 | 581 | } else { |
| 582 | 582 | if (!Value.eql(a_val, b_val, ty, mod)) return false; |
| ... | ... | @@ -750,7 +750,7 @@ pub const Type = struct { |
| 750 | 750 | for (tuple.types, 0..) |field_ty, i| { |
| 751 | 751 | hashWithHasher(field_ty, hasher, mod); |
| 752 | 752 | const field_val = tuple.values[i]; |
| 753 | if (field_val.tag() == .unreachable_value) continue; | |
| 753 | if (field_val.ip_index == .unreachable_value) continue; | |
| 754 | 754 | field_val.hash(field_ty, hasher, mod); |
| 755 | 755 | } |
| 756 | 756 | }, |
| ... | ... | @@ -764,7 +764,7 @@ pub const Type = struct { |
| 764 | 764 | const field_val = struct_obj.values[i]; |
| 765 | 765 | hasher.update(field_name); |
| 766 | 766 | hashWithHasher(field_ty, hasher, mod); |
| 767 | if (field_val.tag() == .unreachable_value) continue; | |
| 767 | if (field_val.ip_index == .unreachable_value) continue; | |
| 768 | 768 | field_val.hash(field_ty, hasher, mod); |
| 769 | 769 | } |
| 770 | 770 | }, |
| ... | ... | @@ -1139,11 +1139,11 @@ pub const Type = struct { |
| 1139 | 1139 | for (tuple.types, 0..) |field_ty, i| { |
| 1140 | 1140 | if (i != 0) try writer.writeAll(", "); |
| 1141 | 1141 | const val = tuple.values[i]; |
| 1142 | if (val.tag() != .unreachable_value) { | |
| 1142 | if (val.ip_index != .unreachable_value) { | |
| 1143 | 1143 | try writer.writeAll("comptime "); |
| 1144 | 1144 | } |
| 1145 | 1145 | try field_ty.dump("", .{}, writer); |
| 1146 | if (val.tag() != .unreachable_value) { | |
| 1146 | if (val.ip_index != .unreachable_value) { | |
| 1147 | 1147 | try writer.print(" = {}", .{val.fmtDebug()}); |
| 1148 | 1148 | } |
| 1149 | 1149 | } |
| ... | ... | @@ -1156,13 +1156,13 @@ pub const Type = struct { |
| 1156 | 1156 | for (anon_struct.types, 0..) |field_ty, i| { |
| 1157 | 1157 | if (i != 0) try writer.writeAll(", "); |
| 1158 | 1158 | const val = anon_struct.values[i]; |
| 1159 | if (val.tag() != .unreachable_value) { | |
| 1159 | if (val.ip_index != .unreachable_value) { | |
| 1160 | 1160 | try writer.writeAll("comptime "); |
| 1161 | 1161 | } |
| 1162 | 1162 | try writer.writeAll(anon_struct.names[i]); |
| 1163 | 1163 | try writer.writeAll(": "); |
| 1164 | 1164 | try field_ty.dump("", .{}, writer); |
| 1165 | if (val.tag() != .unreachable_value) { | |
| 1165 | if (val.ip_index != .unreachable_value) { | |
| 1166 | 1166 | try writer.print(" = {}", .{val.fmtDebug()}); |
| 1167 | 1167 | } |
| 1168 | 1168 | } |
| ... | ... | @@ -1408,11 +1408,11 @@ pub const Type = struct { |
| 1408 | 1408 | for (tuple.types, 0..) |field_ty, i| { |
| 1409 | 1409 | if (i != 0) try writer.writeAll(", "); |
| 1410 | 1410 | const val = tuple.values[i]; |
| 1411 | if (val.tag() != .unreachable_value) { | |
| 1411 | if (val.ip_index != .unreachable_value) { | |
| 1412 | 1412 | try writer.writeAll("comptime "); |
| 1413 | 1413 | } |
| 1414 | 1414 | try print(field_ty, writer, mod); |
| 1415 | if (val.tag() != .unreachable_value) { | |
| 1415 | if (val.ip_index != .unreachable_value) { | |
| 1416 | 1416 | try writer.print(" = {}", .{val.fmtValue(field_ty, mod)}); |
| 1417 | 1417 | } |
| 1418 | 1418 | } |
| ... | ... | @@ -1425,7 +1425,7 @@ pub const Type = struct { |
| 1425 | 1425 | for (anon_struct.types, 0..) |field_ty, i| { |
| 1426 | 1426 | if (i != 0) try writer.writeAll(", "); |
| 1427 | 1427 | const val = anon_struct.values[i]; |
| 1428 | if (val.tag() != .unreachable_value) { | |
| 1428 | if (val.ip_index != .unreachable_value) { | |
| 1429 | 1429 | try writer.writeAll("comptime "); |
| 1430 | 1430 | } |
| 1431 | 1431 | try writer.writeAll(anon_struct.names[i]); |
| ... | ... | @@ -1433,7 +1433,7 @@ pub const Type = struct { |
| 1433 | 1433 | |
| 1434 | 1434 | try print(field_ty, writer, mod); |
| 1435 | 1435 | |
| 1436 | if (val.tag() != .unreachable_value) { | |
| 1436 | if (val.ip_index != .unreachable_value) { | |
| 1437 | 1437 | try writer.print(" = {}", .{val.fmtValue(field_ty, mod)}); |
| 1438 | 1438 | } |
| 1439 | 1439 | } |
| ... | ... | @@ -1770,7 +1770,7 @@ pub const Type = struct { |
| 1770 | 1770 | const tuple = ty.tupleFields(); |
| 1771 | 1771 | for (tuple.types, 0..) |field_ty, i| { |
| 1772 | 1772 | const val = tuple.values[i]; |
| 1773 | if (val.tag() != .unreachable_value) continue; // comptime field | |
| 1773 | if (val.ip_index != .unreachable_value) continue; // comptime field | |
| 1774 | 1774 | if (try field_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat)) return true; |
| 1775 | 1775 | } |
| 1776 | 1776 | return false; |
| ... | ... | @@ -2283,7 +2283,7 @@ pub const Type = struct { |
| 2283 | 2283 | var big_align: u32 = 0; |
| 2284 | 2284 | for (tuple.types, 0..) |field_ty, i| { |
| 2285 | 2285 | const val = tuple.values[i]; |
| 2286 | if (val.tag() != .unreachable_value) continue; // comptime field | |
| 2286 | if (val.ip_index != .unreachable_value) continue; // comptime field | |
| 2287 | 2287 | if (!(field_ty.hasRuntimeBits(mod))) continue; |
| 2288 | 2288 | |
| 2289 | 2289 | switch (try field_ty.abiAlignmentAdvanced(mod, strat)) { |
| ... | ... | @@ -3845,7 +3845,7 @@ pub const Type = struct { |
| 3845 | 3845 | => return null, |
| 3846 | 3846 | |
| 3847 | 3847 | .void => return Value.void, |
| 3848 | .noreturn => return Value.initTag(.unreachable_value), | |
| 3848 | .noreturn => return Value.@"unreachable", | |
| 3849 | 3849 | .null => return Value.null, |
| 3850 | 3850 | .undefined => return Value.undef, |
| 3851 | 3851 | |
| ... | ... | @@ -3896,7 +3896,7 @@ pub const Type = struct { |
| 3896 | 3896 | .tuple, .anon_struct => { |
| 3897 | 3897 | const tuple = ty.tupleFields(); |
| 3898 | 3898 | for (tuple.values, 0..) |val, i| { |
| 3899 | const is_comptime = val.tag() != .unreachable_value; | |
| 3899 | const is_comptime = val.ip_index != .unreachable_value; | |
| 3900 | 3900 | if (is_comptime) continue; |
| 3901 | 3901 | if (tuple.types[i].onePossibleValue(mod) != null) continue; |
| 3902 | 3902 | return null; |
| ... | ... | @@ -3919,7 +3919,7 @@ pub const Type = struct { |
| 3919 | 3919 | return null; |
| 3920 | 3920 | } |
| 3921 | 3921 | switch (enum_full.fields.count()) { |
| 3922 | 0 => return Value.initTag(.unreachable_value), | |
| 3922 | 0 => return Value.@"unreachable", | |
| 3923 | 3923 | 1 => if (enum_full.values.count() == 0) { |
| 3924 | 3924 | return Value.zero; // auto-numbered |
| 3925 | 3925 | } else { |
| ... | ... | @@ -3931,7 +3931,7 @@ pub const Type = struct { |
| 3931 | 3931 | .enum_simple => { |
| 3932 | 3932 | const enum_simple = ty.castTag(.enum_simple).?.data; |
| 3933 | 3933 | switch (enum_simple.fields.count()) { |
| 3934 | 0 => return Value.initTag(.unreachable_value), | |
| 3934 | 0 => return Value.@"unreachable", | |
| 3935 | 3935 | 1 => return Value.zero, |
| 3936 | 3936 | else => return null, |
| 3937 | 3937 | } |
| ... | ... | @@ -3947,7 +3947,7 @@ pub const Type = struct { |
| 3947 | 3947 | .@"union", .union_safety_tagged, .union_tagged => { |
| 3948 | 3948 | const union_obj = ty.cast(Payload.Union).?.data; |
| 3949 | 3949 | const tag_val = union_obj.tag_ty.onePossibleValue(mod) orelse return null; |
| 3950 | if (union_obj.fields.count() == 0) return Value.initTag(.unreachable_value); | |
| 3950 | if (union_obj.fields.count() == 0) return Value.@"unreachable"; | |
| 3951 | 3951 | const only_field = union_obj.fields.values()[0]; |
| 3952 | 3952 | const val_val = only_field.ty.onePossibleValue(mod) orelse return null; |
| 3953 | 3953 | _ = tag_val; |
| ... | ... | @@ -4075,7 +4075,7 @@ pub const Type = struct { |
| 4075 | 4075 | .tuple, .anon_struct => { |
| 4076 | 4076 | const tuple = ty.tupleFields(); |
| 4077 | 4077 | for (tuple.types, 0..) |field_ty, i| { |
| 4078 | const have_comptime_val = tuple.values[i].tag() != .unreachable_value; | |
| 4078 | const have_comptime_val = tuple.values[i].ip_index != .unreachable_value; | |
| 4079 | 4079 | if (!have_comptime_val and field_ty.comptimeOnly(mod)) return true; |
| 4080 | 4080 | } |
| 4081 | 4081 | return false; |
| ... | ... | @@ -4514,7 +4514,7 @@ pub const Type = struct { |
| 4514 | 4514 | .tuple => { |
| 4515 | 4515 | const tuple = ty.castTag(.tuple).?.data; |
| 4516 | 4516 | const val = tuple.values[index]; |
| 4517 | if (val.tag() == .unreachable_value) { | |
| 4517 | if (val.ip_index == .unreachable_value) { | |
| 4518 | 4518 | return tuple.types[index].onePossibleValue(mod); |
| 4519 | 4519 | } else { |
| 4520 | 4520 | return val; |
| ... | ... | @@ -4523,7 +4523,7 @@ pub const Type = struct { |
| 4523 | 4523 | .anon_struct => { |
| 4524 | 4524 | const anon_struct = ty.castTag(.anon_struct).?.data; |
| 4525 | 4525 | const val = anon_struct.values[index]; |
| 4526 | if (val.tag() == .unreachable_value) { | |
| 4526 | if (val.ip_index == .unreachable_value) { | |
| 4527 | 4527 | return anon_struct.types[index].onePossibleValue(mod); |
| 4528 | 4528 | } else { |
| 4529 | 4529 | return val; |
| ... | ... | @@ -4544,12 +4544,12 @@ pub const Type = struct { |
| 4544 | 4544 | .tuple => { |
| 4545 | 4545 | const tuple = ty.castTag(.tuple).?.data; |
| 4546 | 4546 | const val = tuple.values[index]; |
| 4547 | return val.tag() != .unreachable_value; | |
| 4547 | return val.ip_index != .unreachable_value; | |
| 4548 | 4548 | }, |
| 4549 | 4549 | .anon_struct => { |
| 4550 | 4550 | const anon_struct = ty.castTag(.anon_struct).?.data; |
| 4551 | 4551 | const val = anon_struct.values[index]; |
| 4552 | return val.tag() != .unreachable_value; | |
| 4552 | return val.ip_index != .unreachable_value; | |
| 4553 | 4553 | }, |
| 4554 | 4554 | else => unreachable, |
| 4555 | 4555 | } |
| ... | ... | @@ -4647,7 +4647,7 @@ pub const Type = struct { |
| 4647 | 4647 | |
| 4648 | 4648 | for (tuple.types, 0..) |field_ty, i| { |
| 4649 | 4649 | const field_val = tuple.values[i]; |
| 4650 | if (field_val.tag() != .unreachable_value or !field_ty.hasRuntimeBits(mod)) { | |
| 4650 | if (field_val.ip_index != .unreachable_value or !field_ty.hasRuntimeBits(mod)) { | |
| 4651 | 4651 | // comptime field |
| 4652 | 4652 | if (i == index) return offset; |
| 4653 | 4653 | continue; |
src/value.zig+254-240| ... | ... | @@ -33,13 +33,10 @@ pub const Value = struct { |
| 33 | 33 | // Keep in sync with tools/stage2_pretty_printers_common.py |
| 34 | 34 | pub const Tag = enum(usize) { |
| 35 | 35 | // The first section of this enum are tags that require no payload. |
| 36 | undef, | |
| 37 | 36 | zero, |
| 38 | 37 | one, |
| 39 | unreachable_value, | |
| 40 | 38 | /// The only possible value for a particular type, which is stored externally. |
| 41 | 39 | the_only_possible_value, |
| 42 | null_value, | |
| 43 | 40 | |
| 44 | 41 | empty_struct_value, |
| 45 | 42 | empty_array, // See last_no_payload_tag below. |
| ... | ... | @@ -132,14 +129,11 @@ pub const Value = struct { |
| 132 | 129 | |
| 133 | 130 | pub fn Type(comptime t: Tag) type { |
| 134 | 131 | return switch (t) { |
| 135 | .undef, | |
| 136 | 132 | .zero, |
| 137 | 133 | .one, |
| 138 | .unreachable_value, | |
| 139 | 134 | .the_only_possible_value, |
| 140 | 135 | .empty_struct_value, |
| 141 | 136 | .empty_array, |
| 142 | .null_value, | |
| 143 | 137 | => @compileError("Value Tag " ++ @tagName(t) ++ " has no payload"), |
| 144 | 138 | |
| 145 | 139 | .int_big_positive, |
| ... | ... | @@ -287,13 +281,10 @@ pub const Value = struct { |
| 287 | 281 | .legacy = .{ .tag_if_small_enough = self.legacy.tag_if_small_enough }, |
| 288 | 282 | }; |
| 289 | 283 | } else switch (self.legacy.ptr_otherwise.tag) { |
| 290 | .undef, | |
| 291 | 284 | .zero, |
| 292 | 285 | .one, |
| 293 | .unreachable_value, | |
| 294 | 286 | .the_only_possible_value, |
| 295 | 287 | .empty_array, |
| 296 | .null_value, | |
| 297 | 288 | .empty_struct_value, |
| 298 | 289 | => unreachable, |
| 299 | 290 | |
| ... | ... | @@ -522,7 +513,7 @@ pub const Value = struct { |
| 522 | 513 | ) !void { |
| 523 | 514 | comptime assert(fmt.len == 0); |
| 524 | 515 | if (start_val.ip_index != .none) { |
| 525 | try out_stream.print("(interned {d})", .{@enumToInt(start_val.ip_index)}); | |
| 516 | try out_stream.print("(interned: {})", .{start_val.ip_index}); | |
| 526 | 517 | return; |
| 527 | 518 | } |
| 528 | 519 | var val = start_val; |
| ... | ... | @@ -534,11 +525,8 @@ pub const Value = struct { |
| 534 | 525 | .@"union" => { |
| 535 | 526 | return out_stream.writeAll("(union value)"); |
| 536 | 527 | }, |
| 537 | .null_value => return out_stream.writeAll("null"), | |
| 538 | .undef => return out_stream.writeAll("undefined"), | |
| 539 | 528 | .zero => return out_stream.writeAll("0"), |
| 540 | 529 | .one => return out_stream.writeAll("1"), |
| 541 | .unreachable_value => return out_stream.writeAll("unreachable"), | |
| 542 | 530 | .the_only_possible_value => return out_stream.writeAll("(the only possible value)"), |
| 543 | 531 | .ty => return val.castTag(.ty).?.data.dump("", options, out_stream), |
| 544 | 532 | .lazy_align => { |
| ... | ... | @@ -811,8 +799,9 @@ pub const Value = struct { |
| 811 | 799 | switch (val.ip_index) { |
| 812 | 800 | .bool_false => return BigIntMutable.init(&space.limbs, 0).toConst(), |
| 813 | 801 | .bool_true => return BigIntMutable.init(&space.limbs, 1).toConst(), |
| 802 | .undef => unreachable, | |
| 803 | .null_value => return BigIntMutable.init(&space.limbs, 0).toConst(), | |
| 814 | 804 | .none => switch (val.tag()) { |
| 815 | .null_value, | |
| 816 | 805 | .zero, |
| 817 | 806 | .the_only_possible_value, // i0, u0 |
| 818 | 807 | => return BigIntMutable.init(&space.limbs, 0).toConst(), |
| ... | ... | @@ -832,8 +821,6 @@ pub const Value = struct { |
| 832 | 821 | .int_big_positive => return val.castTag(.int_big_positive).?.asBigInt(), |
| 833 | 822 | .int_big_negative => return val.castTag(.int_big_negative).?.asBigInt(), |
| 834 | 823 | |
| 835 | .undef => unreachable, | |
| 836 | ||
| 837 | 824 | .lazy_align => { |
| 838 | 825 | const ty = val.castTag(.lazy_align).?.data; |
| 839 | 826 | if (opt_sema) |sema| { |
| ... | ... | @@ -880,6 +867,7 @@ pub const Value = struct { |
| 880 | 867 | switch (val.ip_index) { |
| 881 | 868 | .bool_false => return 0, |
| 882 | 869 | .bool_true => return 1, |
| 870 | .undef => unreachable, | |
| 883 | 871 | .none => switch (val.tag()) { |
| 884 | 872 | .zero, |
| 885 | 873 | .the_only_possible_value, // i0, u0 |
| ... | ... | @@ -892,8 +880,6 @@ pub const Value = struct { |
| 892 | 880 | .int_big_positive => return val.castTag(.int_big_positive).?.asBigInt().to(u64) catch null, |
| 893 | 881 | .int_big_negative => return val.castTag(.int_big_negative).?.asBigInt().to(u64) catch null, |
| 894 | 882 | |
| 895 | .undef => unreachable, | |
| 896 | ||
| 897 | 883 | .lazy_align => { |
| 898 | 884 | const ty = val.castTag(.lazy_align).?.data; |
| 899 | 885 | if (opt_sema) |sema| { |
| ... | ... | @@ -913,9 +899,9 @@ pub const Value = struct { |
| 913 | 899 | |
| 914 | 900 | else => return null, |
| 915 | 901 | }, |
| 916 | else => switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 917 | .int => |int| return int.big_int.to(u64) catch null, | |
| 918 | else => unreachable, | |
| 902 | else => return switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 903 | .int => |int| int.big_int.to(u64) catch null, | |
| 904 | else => null, | |
| 919 | 905 | }, |
| 920 | 906 | } |
| 921 | 907 | } |
| ... | ... | @@ -930,6 +916,7 @@ pub const Value = struct { |
| 930 | 916 | switch (val.ip_index) { |
| 931 | 917 | .bool_false => return 0, |
| 932 | 918 | .bool_true => return 1, |
| 919 | .undef => unreachable, | |
| 933 | 920 | .none => switch (val.tag()) { |
| 934 | 921 | .zero, |
| 935 | 922 | .the_only_possible_value, // i0, u0 |
| ... | ... | @@ -951,7 +938,6 @@ pub const Value = struct { |
| 951 | 938 | return @intCast(i64, ty.abiSize(mod)); |
| 952 | 939 | }, |
| 953 | 940 | |
| 954 | .undef => unreachable, | |
| 955 | 941 | else => unreachable, |
| 956 | 942 | }, |
| 957 | 943 | else => switch (mod.intern_pool.indexToKey(val.ip_index)) { |
| ... | ... | @@ -2032,8 +2018,7 @@ pub const Value = struct { |
| 2032 | 2018 | const a_tag = a.tag(); |
| 2033 | 2019 | const b_tag = b.tag(); |
| 2034 | 2020 | if (a_tag == b_tag) switch (a_tag) { |
| 2035 | .undef => return true, | |
| 2036 | .null_value, .the_only_possible_value, .empty_struct_value => return true, | |
| 2021 | .the_only_possible_value, .empty_struct_value => return true, | |
| 2037 | 2022 | .enum_literal => { |
| 2038 | 2023 | const a_name = a.castTag(.enum_literal).?.data; |
| 2039 | 2024 | const b_name = b.castTag(.enum_literal).?.data; |
| ... | ... | @@ -2162,9 +2147,7 @@ pub const Value = struct { |
| 2162 | 2147 | return eqlAdvanced(a_union.val, active_field_ty, b_union.val, active_field_ty, mod, opt_sema); |
| 2163 | 2148 | }, |
| 2164 | 2149 | else => {}, |
| 2165 | } else if (b_tag == .null_value or b_tag == .@"error") { | |
| 2166 | return false; | |
| 2167 | } else if (a_tag == .undef or b_tag == .undef) { | |
| 2150 | } else if (b_tag == .@"error") { | |
| 2168 | 2151 | return false; |
| 2169 | 2152 | } |
| 2170 | 2153 | |
| ... | ... | @@ -2283,7 +2266,7 @@ pub const Value = struct { |
| 2283 | 2266 | if (a_nan) return true; |
| 2284 | 2267 | return a_float == b_float; |
| 2285 | 2268 | }, |
| 2286 | .Optional => if (a_tag != .null_value and b_tag == .opt_payload) { | |
| 2269 | .Optional => if (b_tag == .opt_payload) { | |
| 2287 | 2270 | var sub_pl: Payload.SubValue = .{ |
| 2288 | 2271 | .base = .{ .tag = b.tag() }, |
| 2289 | 2272 | .data = a, |
| ... | ... | @@ -2301,7 +2284,7 @@ pub const Value = struct { |
| 2301 | 2284 | }, |
| 2302 | 2285 | else => {}, |
| 2303 | 2286 | } |
| 2304 | if (a_tag == .null_value or a_tag == .@"error") return false; | |
| 2287 | if (a_tag == .@"error") return false; | |
| 2305 | 2288 | return (try orderAdvanced(a, b, mod, opt_sema)).compare(.eq); |
| 2306 | 2289 | } |
| 2307 | 2290 | |
| ... | ... | @@ -2642,7 +2625,6 @@ pub const Value = struct { |
| 2642 | 2625 | |
| 2643 | 2626 | .zero, |
| 2644 | 2627 | .one, |
| 2645 | .null_value, | |
| 2646 | 2628 | .int_u64, |
| 2647 | 2629 | .int_i64, |
| 2648 | 2630 | .int_big_positive, |
| ... | ... | @@ -2717,102 +2699,108 @@ pub const Value = struct { |
| 2717 | 2699 | arena: ?Allocator, |
| 2718 | 2700 | buffer: *ElemValueBuffer, |
| 2719 | 2701 | ) error{OutOfMemory}!Value { |
| 2720 | switch (val.tag()) { | |
| 2721 | // This is the case of accessing an element of an undef array. | |
| 2702 | switch (val.ip_index) { | |
| 2722 | 2703 | .undef => return Value.undef, |
| 2723 | .empty_array => unreachable, // out of bounds array index | |
| 2724 | .empty_struct_value => unreachable, // out of bounds array index | |
| 2704 | .none => switch (val.tag()) { | |
| 2705 | // This is the case of accessing an element of an undef array. | |
| 2706 | .empty_array => unreachable, // out of bounds array index | |
| 2707 | .empty_struct_value => unreachable, // out of bounds array index | |
| 2725 | 2708 | |
| 2726 | .empty_array_sentinel => { | |
| 2727 | assert(index == 0); // The only valid index for an empty array with sentinel. | |
| 2728 | return val.castTag(.empty_array_sentinel).?.data; | |
| 2729 | }, | |
| 2709 | .empty_array_sentinel => { | |
| 2710 | assert(index == 0); // The only valid index for an empty array with sentinel. | |
| 2711 | return val.castTag(.empty_array_sentinel).?.data; | |
| 2712 | }, | |
| 2730 | 2713 | |
| 2731 | .bytes => { | |
| 2732 | const byte = val.castTag(.bytes).?.data[index]; | |
| 2733 | if (arena) |a| { | |
| 2734 | return Tag.int_u64.create(a, byte); | |
| 2735 | } else { | |
| 2736 | buffer.* = .{ | |
| 2737 | .base = .{ .tag = .int_u64 }, | |
| 2738 | .data = byte, | |
| 2739 | }; | |
| 2740 | return initPayload(&buffer.base); | |
| 2741 | } | |
| 2742 | }, | |
| 2743 | .str_lit => { | |
| 2744 | const str_lit = val.castTag(.str_lit).?.data; | |
| 2745 | const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | |
| 2746 | const byte = bytes[index]; | |
| 2747 | if (arena) |a| { | |
| 2748 | return Tag.int_u64.create(a, byte); | |
| 2749 | } else { | |
| 2750 | buffer.* = .{ | |
| 2751 | .base = .{ .tag = .int_u64 }, | |
| 2752 | .data = byte, | |
| 2753 | }; | |
| 2754 | return initPayload(&buffer.base); | |
| 2755 | } | |
| 2756 | }, | |
| 2714 | .bytes => { | |
| 2715 | const byte = val.castTag(.bytes).?.data[index]; | |
| 2716 | if (arena) |a| { | |
| 2717 | return Tag.int_u64.create(a, byte); | |
| 2718 | } else { | |
| 2719 | buffer.* = .{ | |
| 2720 | .base = .{ .tag = .int_u64 }, | |
| 2721 | .data = byte, | |
| 2722 | }; | |
| 2723 | return initPayload(&buffer.base); | |
| 2724 | } | |
| 2725 | }, | |
| 2726 | .str_lit => { | |
| 2727 | const str_lit = val.castTag(.str_lit).?.data; | |
| 2728 | const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | |
| 2729 | const byte = bytes[index]; | |
| 2730 | if (arena) |a| { | |
| 2731 | return Tag.int_u64.create(a, byte); | |
| 2732 | } else { | |
| 2733 | buffer.* = .{ | |
| 2734 | .base = .{ .tag = .int_u64 }, | |
| 2735 | .data = byte, | |
| 2736 | }; | |
| 2737 | return initPayload(&buffer.base); | |
| 2738 | } | |
| 2739 | }, | |
| 2757 | 2740 | |
| 2758 | // No matter the index; all the elements are the same! | |
| 2759 | .repeated => return val.castTag(.repeated).?.data, | |
| 2741 | // No matter the index; all the elements are the same! | |
| 2742 | .repeated => return val.castTag(.repeated).?.data, | |
| 2760 | 2743 | |
| 2761 | .aggregate => return val.castTag(.aggregate).?.data[index], | |
| 2762 | .slice => return val.castTag(.slice).?.data.ptr.elemValueAdvanced(mod, index, arena, buffer), | |
| 2744 | .aggregate => return val.castTag(.aggregate).?.data[index], | |
| 2745 | .slice => return val.castTag(.slice).?.data.ptr.elemValueAdvanced(mod, index, arena, buffer), | |
| 2763 | 2746 | |
| 2764 | .decl_ref => return mod.declPtr(val.castTag(.decl_ref).?.data).val.elemValueAdvanced(mod, index, arena, buffer), | |
| 2765 | .decl_ref_mut => return mod.declPtr(val.castTag(.decl_ref_mut).?.data.decl_index).val.elemValueAdvanced(mod, index, arena, buffer), | |
| 2766 | .comptime_field_ptr => return val.castTag(.comptime_field_ptr).?.data.field_val.elemValueAdvanced(mod, index, arena, buffer), | |
| 2767 | .elem_ptr => { | |
| 2768 | const data = val.castTag(.elem_ptr).?.data; | |
| 2769 | return data.array_ptr.elemValueAdvanced(mod, index + data.index, arena, buffer); | |
| 2770 | }, | |
| 2771 | .field_ptr => { | |
| 2772 | const data = val.castTag(.field_ptr).?.data; | |
| 2773 | if (data.container_ptr.pointerDecl()) |decl_index| { | |
| 2774 | const container_decl = mod.declPtr(decl_index); | |
| 2775 | const field_type = data.container_ty.structFieldType(data.field_index); | |
| 2776 | const field_val = container_decl.val.fieldValue(field_type, mod, data.field_index); | |
| 2777 | return field_val.elemValueAdvanced(mod, index, arena, buffer); | |
| 2778 | } else unreachable; | |
| 2779 | }, | |
| 2747 | .decl_ref => return mod.declPtr(val.castTag(.decl_ref).?.data).val.elemValueAdvanced(mod, index, arena, buffer), | |
| 2748 | .decl_ref_mut => return mod.declPtr(val.castTag(.decl_ref_mut).?.data.decl_index).val.elemValueAdvanced(mod, index, arena, buffer), | |
| 2749 | .comptime_field_ptr => return val.castTag(.comptime_field_ptr).?.data.field_val.elemValueAdvanced(mod, index, arena, buffer), | |
| 2750 | .elem_ptr => { | |
| 2751 | const data = val.castTag(.elem_ptr).?.data; | |
| 2752 | return data.array_ptr.elemValueAdvanced(mod, index + data.index, arena, buffer); | |
| 2753 | }, | |
| 2754 | .field_ptr => { | |
| 2755 | const data = val.castTag(.field_ptr).?.data; | |
| 2756 | if (data.container_ptr.pointerDecl()) |decl_index| { | |
| 2757 | const container_decl = mod.declPtr(decl_index); | |
| 2758 | const field_type = data.container_ty.structFieldType(data.field_index); | |
| 2759 | const field_val = container_decl.val.fieldValue(field_type, mod, data.field_index); | |
| 2760 | return field_val.elemValueAdvanced(mod, index, arena, buffer); | |
| 2761 | } else unreachable; | |
| 2762 | }, | |
| 2780 | 2763 | |
| 2781 | // The child type of arrays which have only one possible value need | |
| 2782 | // to have only one possible value itself. | |
| 2783 | .the_only_possible_value => return val, | |
| 2764 | // The child type of arrays which have only one possible value need | |
| 2765 | // to have only one possible value itself. | |
| 2766 | .the_only_possible_value => return val, | |
| 2784 | 2767 | |
| 2785 | .opt_payload_ptr => return val.castTag(.opt_payload_ptr).?.data.container_ptr.elemValueAdvanced(mod, index, arena, buffer), | |
| 2786 | .eu_payload_ptr => return val.castTag(.eu_payload_ptr).?.data.container_ptr.elemValueAdvanced(mod, index, arena, buffer), | |
| 2768 | .opt_payload_ptr => return val.castTag(.opt_payload_ptr).?.data.container_ptr.elemValueAdvanced(mod, index, arena, buffer), | |
| 2769 | .eu_payload_ptr => return val.castTag(.eu_payload_ptr).?.data.container_ptr.elemValueAdvanced(mod, index, arena, buffer), | |
| 2787 | 2770 | |
| 2788 | .opt_payload => return val.castTag(.opt_payload).?.data.elemValueAdvanced(mod, index, arena, buffer), | |
| 2789 | .eu_payload => return val.castTag(.eu_payload).?.data.elemValueAdvanced(mod, index, arena, buffer), | |
| 2771 | .opt_payload => return val.castTag(.opt_payload).?.data.elemValueAdvanced(mod, index, arena, buffer), | |
| 2772 | .eu_payload => return val.castTag(.eu_payload).?.data.elemValueAdvanced(mod, index, arena, buffer), | |
| 2790 | 2773 | |
| 2774 | else => unreachable, | |
| 2775 | }, | |
| 2791 | 2776 | else => unreachable, |
| 2792 | 2777 | } |
| 2793 | 2778 | } |
| 2794 | 2779 | |
| 2795 | 2780 | /// Returns true if a Value is backed by a variable |
| 2796 | 2781 | pub fn isVariable(val: Value, mod: *Module) bool { |
| 2797 | return switch (val.tag()) { | |
| 2798 | .slice => val.castTag(.slice).?.data.ptr.isVariable(mod), | |
| 2799 | .comptime_field_ptr => val.castTag(.comptime_field_ptr).?.data.field_val.isVariable(mod), | |
| 2800 | .elem_ptr => val.castTag(.elem_ptr).?.data.array_ptr.isVariable(mod), | |
| 2801 | .field_ptr => val.castTag(.field_ptr).?.data.container_ptr.isVariable(mod), | |
| 2802 | .eu_payload_ptr => val.castTag(.eu_payload_ptr).?.data.container_ptr.isVariable(mod), | |
| 2803 | .opt_payload_ptr => val.castTag(.opt_payload_ptr).?.data.container_ptr.isVariable(mod), | |
| 2804 | .decl_ref => { | |
| 2805 | const decl = mod.declPtr(val.castTag(.decl_ref).?.data); | |
| 2806 | assert(decl.has_tv); | |
| 2807 | return decl.val.isVariable(mod); | |
| 2808 | }, | |
| 2809 | .decl_ref_mut => { | |
| 2810 | const decl = mod.declPtr(val.castTag(.decl_ref_mut).?.data.decl_index); | |
| 2811 | assert(decl.has_tv); | |
| 2812 | return decl.val.isVariable(mod); | |
| 2813 | }, | |
| 2782 | return switch (val.ip_index) { | |
| 2783 | .none => switch (val.tag()) { | |
| 2784 | .slice => val.castTag(.slice).?.data.ptr.isVariable(mod), | |
| 2785 | .comptime_field_ptr => val.castTag(.comptime_field_ptr).?.data.field_val.isVariable(mod), | |
| 2786 | .elem_ptr => val.castTag(.elem_ptr).?.data.array_ptr.isVariable(mod), | |
| 2787 | .field_ptr => val.castTag(.field_ptr).?.data.container_ptr.isVariable(mod), | |
| 2788 | .eu_payload_ptr => val.castTag(.eu_payload_ptr).?.data.container_ptr.isVariable(mod), | |
| 2789 | .opt_payload_ptr => val.castTag(.opt_payload_ptr).?.data.container_ptr.isVariable(mod), | |
| 2790 | .decl_ref => { | |
| 2791 | const decl = mod.declPtr(val.castTag(.decl_ref).?.data); | |
| 2792 | assert(decl.has_tv); | |
| 2793 | return decl.val.isVariable(mod); | |
| 2794 | }, | |
| 2795 | .decl_ref_mut => { | |
| 2796 | const decl = mod.declPtr(val.castTag(.decl_ref_mut).?.data.decl_index); | |
| 2797 | assert(decl.has_tv); | |
| 2798 | return decl.val.isVariable(mod); | |
| 2799 | }, | |
| 2814 | 2800 | |
| 2815 | .variable => true, | |
| 2801 | .variable => true, | |
| 2802 | else => false, | |
| 2803 | }, | |
| 2816 | 2804 | else => false, |
| 2817 | 2805 | }; |
| 2818 | 2806 | } |
| ... | ... | @@ -2878,39 +2866,46 @@ pub const Value = struct { |
| 2878 | 2866 | } |
| 2879 | 2867 | |
| 2880 | 2868 | pub fn fieldValue(val: Value, ty: Type, mod: *const Module, index: usize) Value { |
| 2881 | switch (val.tag()) { | |
| 2882 | .aggregate => { | |
| 2883 | const field_values = val.castTag(.aggregate).?.data; | |
| 2884 | return field_values[index]; | |
| 2885 | }, | |
| 2886 | .@"union" => { | |
| 2887 | const payload = val.castTag(.@"union").?.data; | |
| 2888 | // TODO assert the tag is correct | |
| 2889 | return payload.val; | |
| 2890 | }, | |
| 2869 | switch (val.ip_index) { | |
| 2870 | .undef => return Value.undef, | |
| 2871 | .none => switch (val.tag()) { | |
| 2872 | .aggregate => { | |
| 2873 | const field_values = val.castTag(.aggregate).?.data; | |
| 2874 | return field_values[index]; | |
| 2875 | }, | |
| 2876 | .@"union" => { | |
| 2877 | const payload = val.castTag(.@"union").?.data; | |
| 2878 | // TODO assert the tag is correct | |
| 2879 | return payload.val; | |
| 2880 | }, | |
| 2891 | 2881 | |
| 2892 | .the_only_possible_value => return ty.onePossibleValue(mod).?, | |
| 2882 | .the_only_possible_value => return ty.onePossibleValue(mod).?, | |
| 2893 | 2883 | |
| 2894 | .empty_struct_value => { | |
| 2895 | if (ty.isSimpleTupleOrAnonStruct()) { | |
| 2896 | const tuple = ty.tupleFields(); | |
| 2897 | return tuple.values[index]; | |
| 2898 | } | |
| 2899 | if (ty.structFieldValueComptime(mod, index)) |some| { | |
| 2900 | return some; | |
| 2901 | } | |
| 2902 | unreachable; | |
| 2903 | }, | |
| 2904 | .undef => return Value.undef, | |
| 2884 | .empty_struct_value => { | |
| 2885 | if (ty.isSimpleTupleOrAnonStruct()) { | |
| 2886 | const tuple = ty.tupleFields(); | |
| 2887 | return tuple.values[index]; | |
| 2888 | } | |
| 2889 | if (ty.structFieldValueComptime(mod, index)) |some| { | |
| 2890 | return some; | |
| 2891 | } | |
| 2892 | unreachable; | |
| 2893 | }, | |
| 2905 | 2894 | |
| 2895 | else => unreachable, | |
| 2896 | }, | |
| 2906 | 2897 | else => unreachable, |
| 2907 | 2898 | } |
| 2908 | 2899 | } |
| 2909 | 2900 | |
| 2910 | 2901 | pub fn unionTag(val: Value) Value { |
| 2911 | switch (val.tag()) { | |
| 2912 | .undef, .enum_field_index => return val, | |
| 2913 | .@"union" => return val.castTag(.@"union").?.data.tag, | |
| 2902 | switch (val.ip_index) { | |
| 2903 | .undef => return val, | |
| 2904 | .none => switch (val.tag()) { | |
| 2905 | .enum_field_index => return val, | |
| 2906 | .@"union" => return val.castTag(.@"union").?.data.tag, | |
| 2907 | else => unreachable, | |
| 2908 | }, | |
| 2914 | 2909 | else => unreachable, |
| 2915 | 2910 | } |
| 2916 | 2911 | } |
| ... | ... | @@ -2946,15 +2941,15 @@ pub const Value = struct { |
| 2946 | 2941 | }); |
| 2947 | 2942 | } |
| 2948 | 2943 | |
| 2949 | pub fn isUndef(self: Value) bool { | |
| 2950 | return self.tag() == .undef; | |
| 2944 | pub fn isUndef(val: Value) bool { | |
| 2945 | return val.ip_index == .undef; | |
| 2951 | 2946 | } |
| 2952 | 2947 | |
| 2953 | 2948 | /// TODO: check for cases such as array that is not marked undef but all the element |
| 2954 | 2949 | /// values are marked undef, or struct that is not marked undef but all fields are marked |
| 2955 | 2950 | /// undef, etc. |
| 2956 | pub fn isUndefDeep(self: Value) bool { | |
| 2957 | return self.isUndef(); | |
| 2951 | pub fn isUndefDeep(val: Value) bool { | |
| 2952 | return val.isUndef(); | |
| 2958 | 2953 | } |
| 2959 | 2954 | |
| 2960 | 2955 | /// Returns true if any value contained in `self` is undefined. |
| ... | ... | @@ -2962,27 +2957,29 @@ pub const Value = struct { |
| 2962 | 2957 | /// values are marked undef, or struct that is not marked undef but all fields are marked |
| 2963 | 2958 | /// undef, etc. |
| 2964 | 2959 | pub fn anyUndef(self: Value, mod: *Module) bool { |
| 2965 | switch (self.tag()) { | |
| 2966 | .slice => { | |
| 2967 | const payload = self.castTag(.slice).?; | |
| 2968 | const len = payload.data.len.toUnsignedInt(mod); | |
| 2969 | ||
| 2970 | var elem_value_buf: ElemValueBuffer = undefined; | |
| 2971 | var i: usize = 0; | |
| 2972 | while (i < len) : (i += 1) { | |
| 2973 | const elem_val = payload.data.ptr.elemValueBuffer(mod, i, &elem_value_buf); | |
| 2974 | if (elem_val.anyUndef(mod)) return true; | |
| 2975 | } | |
| 2976 | }, | |
| 2960 | switch (self.ip_index) { | |
| 2961 | .undef => return true, | |
| 2962 | .none => switch (self.tag()) { | |
| 2963 | .slice => { | |
| 2964 | const payload = self.castTag(.slice).?; | |
| 2965 | const len = payload.data.len.toUnsignedInt(mod); | |
| 2966 | ||
| 2967 | var elem_value_buf: ElemValueBuffer = undefined; | |
| 2968 | var i: usize = 0; | |
| 2969 | while (i < len) : (i += 1) { | |
| 2970 | const elem_val = payload.data.ptr.elemValueBuffer(mod, i, &elem_value_buf); | |
| 2971 | if (elem_val.anyUndef(mod)) return true; | |
| 2972 | } | |
| 2973 | }, | |
| 2977 | 2974 | |
| 2978 | .aggregate => { | |
| 2979 | const payload = self.castTag(.aggregate).?; | |
| 2980 | for (payload.data) |val| { | |
| 2981 | if (val.anyUndef(mod)) return true; | |
| 2982 | } | |
| 2975 | .aggregate => { | |
| 2976 | const payload = self.castTag(.aggregate).?; | |
| 2977 | for (payload.data) |val| { | |
| 2978 | if (val.anyUndef(mod)) return true; | |
| 2979 | } | |
| 2980 | }, | |
| 2981 | else => {}, | |
| 2983 | 2982 | }, |
| 2984 | ||
| 2985 | .undef => return true, | |
| 2986 | 2983 | else => {}, |
| 2987 | 2984 | } |
| 2988 | 2985 | |
| ... | ... | @@ -2992,30 +2989,33 @@ pub const Value = struct { |
| 2992 | 2989 | /// Asserts the value is not undefined and not unreachable. |
| 2993 | 2990 | /// Integer value 0 is considered null because of C pointers. |
| 2994 | 2991 | pub fn isNull(self: Value, mod: *const Module) bool { |
| 2995 | return switch (self.tag()) { | |
| 2992 | return switch (self.ip_index) { | |
| 2993 | .undef => unreachable, | |
| 2994 | .unreachable_value => unreachable, | |
| 2996 | 2995 | .null_value => true, |
| 2997 | .opt_payload => false, | |
| 2996 | .none => switch (self.tag()) { | |
| 2997 | .opt_payload => false, | |
| 2998 | 2998 | |
| 2999 | // If it's not one of those two tags then it must be a C pointer value, | |
| 3000 | // in which case the value 0 is null and other values are non-null. | |
| 2999 | // If it's not one of those two tags then it must be a C pointer value, | |
| 3000 | // in which case the value 0 is null and other values are non-null. | |
| 3001 | 3001 | |
| 3002 | .zero, | |
| 3003 | .the_only_possible_value, | |
| 3004 | => true, | |
| 3002 | .zero, | |
| 3003 | .the_only_possible_value, | |
| 3004 | => true, | |
| 3005 | 3005 | |
| 3006 | .one => false, | |
| 3006 | .one => false, | |
| 3007 | 3007 | |
| 3008 | .int_u64, | |
| 3009 | .int_i64, | |
| 3010 | .int_big_positive, | |
| 3011 | .int_big_negative, | |
| 3012 | => self.orderAgainstZero(mod).compare(.eq), | |
| 3008 | .int_u64, | |
| 3009 | .int_i64, | |
| 3010 | .int_big_positive, | |
| 3011 | .int_big_negative, | |
| 3012 | => self.orderAgainstZero(mod).compare(.eq), | |
| 3013 | 3013 | |
| 3014 | .undef => unreachable, | |
| 3015 | .unreachable_value => unreachable, | |
| 3016 | .inferred_alloc => unreachable, | |
| 3017 | .inferred_alloc_comptime => unreachable, | |
| 3014 | .inferred_alloc => unreachable, | |
| 3015 | .inferred_alloc_comptime => unreachable, | |
| 3018 | 3016 | |
| 3017 | else => false, | |
| 3018 | }, | |
| 3019 | 3019 | else => false, |
| 3020 | 3020 | }; |
| 3021 | 3021 | } |
| ... | ... | @@ -3025,18 +3025,21 @@ pub const Value = struct { |
| 3025 | 3025 | /// something is an error or not because it works without having to figure out the |
| 3026 | 3026 | /// string. |
| 3027 | 3027 | pub fn getError(self: Value) ?[]const u8 { |
| 3028 | return switch (self.tag()) { | |
| 3029 | .@"error" => self.castTag(.@"error").?.data.name, | |
| 3030 | .int_u64 => @panic("TODO"), | |
| 3031 | .int_i64 => @panic("TODO"), | |
| 3032 | .int_big_positive => @panic("TODO"), | |
| 3033 | .int_big_negative => @panic("TODO"), | |
| 3034 | .one => @panic("TODO"), | |
| 3028 | return switch (self.ip_index) { | |
| 3035 | 3029 | .undef => unreachable, |
| 3036 | 3030 | .unreachable_value => unreachable, |
| 3037 | .inferred_alloc => unreachable, | |
| 3038 | .inferred_alloc_comptime => unreachable, | |
| 3031 | .none => switch (self.tag()) { | |
| 3032 | .@"error" => self.castTag(.@"error").?.data.name, | |
| 3033 | .int_u64 => @panic("TODO"), | |
| 3034 | .int_i64 => @panic("TODO"), | |
| 3035 | .int_big_positive => @panic("TODO"), | |
| 3036 | .int_big_negative => @panic("TODO"), | |
| 3037 | .one => @panic("TODO"), | |
| 3038 | .inferred_alloc => unreachable, | |
| 3039 | .inferred_alloc_comptime => unreachable, | |
| 3039 | 3040 | |
| 3041 | else => null, | |
| 3042 | }, | |
| 3040 | 3043 | else => null, |
| 3041 | 3044 | }; |
| 3042 | 3045 | } |
| ... | ... | @@ -3044,13 +3047,16 @@ pub const Value = struct { |
| 3044 | 3047 | /// Assumes the type is an error union. Returns true if and only if the value is |
| 3045 | 3048 | /// the error union payload, not an error. |
| 3046 | 3049 | pub fn errorUnionIsPayload(val: Value) bool { |
| 3047 | return switch (val.tag()) { | |
| 3048 | .eu_payload => true, | |
| 3049 | else => false, | |
| 3050 | ||
| 3050 | return switch (val.ip_index) { | |
| 3051 | 3051 | .undef => unreachable, |
| 3052 | .inferred_alloc => unreachable, | |
| 3053 | .inferred_alloc_comptime => unreachable, | |
| 3052 | .none => switch (val.tag()) { | |
| 3053 | .eu_payload => true, | |
| 3054 | else => false, | |
| 3055 | ||
| 3056 | .inferred_alloc => unreachable, | |
| 3057 | .inferred_alloc_comptime => unreachable, | |
| 3058 | }, | |
| 3059 | else => false, | |
| 3054 | 3060 | }; |
| 3055 | 3061 | } |
| 3056 | 3062 | |
| ... | ... | @@ -3065,17 +3071,20 @@ pub const Value = struct { |
| 3065 | 3071 | |
| 3066 | 3072 | /// Valid for all types. Asserts the value is not undefined. |
| 3067 | 3073 | pub fn isFloat(self: Value) bool { |
| 3068 | return switch (self.tag()) { | |
| 3074 | return switch (self.ip_index) { | |
| 3069 | 3075 | .undef => unreachable, |
| 3070 | .inferred_alloc => unreachable, | |
| 3071 | .inferred_alloc_comptime => unreachable, | |
| 3076 | .none => switch (self.tag()) { | |
| 3077 | .inferred_alloc => unreachable, | |
| 3078 | .inferred_alloc_comptime => unreachable, | |
| 3072 | 3079 | |
| 3073 | .float_16, | |
| 3074 | .float_32, | |
| 3075 | .float_64, | |
| 3076 | .float_80, | |
| 3077 | .float_128, | |
| 3078 | => true, | |
| 3080 | .float_16, | |
| 3081 | .float_32, | |
| 3082 | .float_64, | |
| 3083 | .float_80, | |
| 3084 | .float_128, | |
| 3085 | => true, | |
| 3086 | else => false, | |
| 3087 | }, | |
| 3079 | 3088 | else => false, |
| 3080 | 3089 | }; |
| 3081 | 3090 | } |
| ... | ... | @@ -3102,40 +3111,44 @@ pub const Value = struct { |
| 3102 | 3111 | |
| 3103 | 3112 | pub fn intToFloatScalar(val: Value, arena: Allocator, float_ty: Type, mod: *Module, opt_sema: ?*Sema) !Value { |
| 3104 | 3113 | const target = mod.getTarget(); |
| 3105 | switch (val.tag()) { | |
| 3106 | .undef, .zero, .one => return val, | |
| 3107 | .the_only_possible_value => return Value.initTag(.zero), // for i0, u0 | |
| 3108 | .int_u64 => { | |
| 3109 | return intToFloatInner(val.castTag(.int_u64).?.data, arena, float_ty, target); | |
| 3110 | }, | |
| 3111 | .int_i64 => { | |
| 3112 | return intToFloatInner(val.castTag(.int_i64).?.data, arena, float_ty, target); | |
| 3113 | }, | |
| 3114 | .int_big_positive => { | |
| 3115 | const limbs = val.castTag(.int_big_positive).?.data; | |
| 3116 | const float = bigIntToFloat(limbs, true); | |
| 3117 | return floatToValue(float, arena, float_ty, target); | |
| 3118 | }, | |
| 3119 | .int_big_negative => { | |
| 3120 | const limbs = val.castTag(.int_big_negative).?.data; | |
| 3121 | const float = bigIntToFloat(limbs, false); | |
| 3122 | return floatToValue(float, arena, float_ty, target); | |
| 3123 | }, | |
| 3124 | .lazy_align => { | |
| 3125 | const ty = val.castTag(.lazy_align).?.data; | |
| 3126 | if (opt_sema) |sema| { | |
| 3127 | return intToFloatInner((try ty.abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar, arena, float_ty, target); | |
| 3128 | } else { | |
| 3129 | return intToFloatInner(ty.abiAlignment(mod), arena, float_ty, target); | |
| 3130 | } | |
| 3131 | }, | |
| 3132 | .lazy_size => { | |
| 3133 | const ty = val.castTag(.lazy_size).?.data; | |
| 3134 | if (opt_sema) |sema| { | |
| 3135 | return intToFloatInner((try ty.abiSizeAdvanced(mod, .{ .sema = sema })).scalar, arena, float_ty, target); | |
| 3136 | } else { | |
| 3137 | return intToFloatInner(ty.abiSize(mod), arena, float_ty, target); | |
| 3138 | } | |
| 3114 | switch (val.ip_index) { | |
| 3115 | .undef => return val, | |
| 3116 | .none => switch (val.tag()) { | |
| 3117 | .zero, .one => return val, | |
| 3118 | .the_only_possible_value => return Value.initTag(.zero), // for i0, u0 | |
| 3119 | .int_u64 => { | |
| 3120 | return intToFloatInner(val.castTag(.int_u64).?.data, arena, float_ty, target); | |
| 3121 | }, | |
| 3122 | .int_i64 => { | |
| 3123 | return intToFloatInner(val.castTag(.int_i64).?.data, arena, float_ty, target); | |
| 3124 | }, | |
| 3125 | .int_big_positive => { | |
| 3126 | const limbs = val.castTag(.int_big_positive).?.data; | |
| 3127 | const float = bigIntToFloat(limbs, true); | |
| 3128 | return floatToValue(float, arena, float_ty, target); | |
| 3129 | }, | |
| 3130 | .int_big_negative => { | |
| 3131 | const limbs = val.castTag(.int_big_negative).?.data; | |
| 3132 | const float = bigIntToFloat(limbs, false); | |
| 3133 | return floatToValue(float, arena, float_ty, target); | |
| 3134 | }, | |
| 3135 | .lazy_align => { | |
| 3136 | const ty = val.castTag(.lazy_align).?.data; | |
| 3137 | if (opt_sema) |sema| { | |
| 3138 | return intToFloatInner((try ty.abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar, arena, float_ty, target); | |
| 3139 | } else { | |
| 3140 | return intToFloatInner(ty.abiAlignment(mod), arena, float_ty, target); | |
| 3141 | } | |
| 3142 | }, | |
| 3143 | .lazy_size => { | |
| 3144 | const ty = val.castTag(.lazy_size).?.data; | |
| 3145 | if (opt_sema) |sema| { | |
| 3146 | return intToFloatInner((try ty.abiSizeAdvanced(mod, .{ .sema = sema })).scalar, arena, float_ty, target); | |
| 3147 | } else { | |
| 3148 | return intToFloatInner(ty.abiSize(mod), arena, float_ty, target); | |
| 3149 | } | |
| 3150 | }, | |
| 3151 | else => unreachable, | |
| 3139 | 3152 | }, |
| 3140 | 3153 | else => unreachable, |
| 3141 | 3154 | } |
| ... | ... | @@ -3381,7 +3394,7 @@ pub const Value = struct { |
| 3381 | 3394 | arena: Allocator, |
| 3382 | 3395 | mod: *Module, |
| 3383 | 3396 | ) !Value { |
| 3384 | if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef); | |
| 3397 | if (lhs.isUndef() or rhs.isUndef()) return Value.undef; | |
| 3385 | 3398 | |
| 3386 | 3399 | if (ty.zigTypeTag(mod) == .ComptimeInt) { |
| 3387 | 3400 | return intMul(lhs, rhs, ty, arena, mod); |
| ... | ... | @@ -3492,7 +3505,7 @@ pub const Value = struct { |
| 3492 | 3505 | |
| 3493 | 3506 | /// operands must be integers; handles undefined. |
| 3494 | 3507 | pub fn bitwiseNotScalar(val: Value, ty: Type, arena: Allocator, mod: *Module) !Value { |
| 3495 | if (val.isUndef()) return Value.initTag(.undef); | |
| 3508 | if (val.isUndef()) return Value.undef; | |
| 3496 | 3509 | |
| 3497 | 3510 | const info = ty.intInfo(mod); |
| 3498 | 3511 | |
| ... | ... | @@ -3532,7 +3545,7 @@ pub const Value = struct { |
| 3532 | 3545 | |
| 3533 | 3546 | /// operands must be integers; handles undefined. |
| 3534 | 3547 | pub fn bitwiseAndScalar(lhs: Value, rhs: Value, arena: Allocator, mod: *Module) !Value { |
| 3535 | if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef); | |
| 3548 | if (lhs.isUndef() or rhs.isUndef()) return Value.undef; | |
| 3536 | 3549 | |
| 3537 | 3550 | // TODO is this a performance issue? maybe we should try the operation without |
| 3538 | 3551 | // resorting to BigInt first. |
| ... | ... | @@ -3568,7 +3581,7 @@ pub const Value = struct { |
| 3568 | 3581 | |
| 3569 | 3582 | /// operands must be integers; handles undefined. |
| 3570 | 3583 | pub fn bitwiseNandScalar(lhs: Value, rhs: Value, ty: Type, arena: Allocator, mod: *Module) !Value { |
| 3571 | if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef); | |
| 3584 | if (lhs.isUndef() or rhs.isUndef()) return Value.undef; | |
| 3572 | 3585 | |
| 3573 | 3586 | const anded = try bitwiseAnd(lhs, rhs, ty, arena, mod); |
| 3574 | 3587 | |
| ... | ... | @@ -3598,7 +3611,7 @@ pub const Value = struct { |
| 3598 | 3611 | |
| 3599 | 3612 | /// operands must be integers; handles undefined. |
| 3600 | 3613 | pub fn bitwiseOrScalar(lhs: Value, rhs: Value, arena: Allocator, mod: *Module) !Value { |
| 3601 | if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef); | |
| 3614 | if (lhs.isUndef() or rhs.isUndef()) return Value.undef; | |
| 3602 | 3615 | |
| 3603 | 3616 | // TODO is this a performance issue? maybe we should try the operation without |
| 3604 | 3617 | // resorting to BigInt first. |
| ... | ... | @@ -3633,7 +3646,7 @@ pub const Value = struct { |
| 3633 | 3646 | |
| 3634 | 3647 | /// operands must be integers; handles undefined. |
| 3635 | 3648 | pub fn bitwiseXorScalar(lhs: Value, rhs: Value, arena: Allocator, mod: *Module) !Value { |
| 3636 | if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef); | |
| 3649 | if (lhs.isUndef() or rhs.isUndef()) return Value.undef; | |
| 3637 | 3650 | |
| 3638 | 3651 | // TODO is this a performance issue? maybe we should try the operation without |
| 3639 | 3652 | // resorting to BigInt first. |
| ... | ... | @@ -5393,11 +5406,12 @@ pub const Value = struct { |
| 5393 | 5406 | .ip_index = .none, |
| 5394 | 5407 | .legacy = .{ .ptr_otherwise = &negative_one_payload.base }, |
| 5395 | 5408 | }; |
| 5396 | pub const undef = initTag(.undef); | |
| 5409 | pub const undef: Value = .{ .ip_index = .undef, .legacy = undefined }; | |
| 5397 | 5410 | pub const @"void": Value = .{ .ip_index = .void_value, .legacy = undefined }; |
| 5398 | pub const @"null" = initTag(.null_value); | |
| 5411 | pub const @"null": Value = .{ .ip_index = .null_value, .legacy = undefined }; | |
| 5399 | 5412 | pub const @"false": Value = .{ .ip_index = .bool_false, .legacy = undefined }; |
| 5400 | 5413 | pub const @"true": Value = .{ .ip_index = .bool_true, .legacy = undefined }; |
| 5414 | pub const @"unreachable": Value = .{ .ip_index = .unreachable_value, .legacy = undefined }; | |
| 5401 | 5415 | |
| 5402 | 5416 | pub const generic_poison: Value = .{ .ip_index = .generic_poison, .legacy = undefined }; |
| 5403 | 5417 | pub const generic_poison_type: Value = .{ .ip_index = .generic_poison_type, .legacy = undefined }; |