| ... | ... | @@ -1991,23 +1991,21 @@ fn resolveMaybeUndefValAllowVariablesMaybeRuntime( |
| 1991 | 1991 | const i = int - InternPool.static_len; |
| 1992 | 1992 | const air_tags = sema.air_instructions.items(.tag); |
| 1993 | 1993 | if (try sema.typeHasOnePossibleValue(sema.typeOf(inst))) |opv| { |
| 1994 | | if (air_tags[i] == .constant) { |
| 1995 | | const ty_pl = sema.air_instructions.items(.data)[i].ty_pl; |
| 1996 | | const val = sema.air_values.items[ty_pl.payload]; |
| 1994 | if (air_tags[i] == .interned) { |
| 1995 | const interned = sema.air_instructions.items(.data)[i].interned; |
| 1996 | const val = interned.toValue(); |
| 1997 | 1997 | if (val.getVariable(sema.mod) != null) return val; |
| 1998 | 1998 | } |
| 1999 | 1999 | return opv; |
| 2000 | 2000 | } |
| 2001 | 2001 | const air_datas = sema.air_instructions.items(.data); |
| 2002 | 2002 | switch (air_tags[i]) { |
| 2003 | | .constant => { |
| 2004 | | const ty_pl = air_datas[i].ty_pl; |
| 2005 | | const val = sema.air_values.items[ty_pl.payload]; |
| 2003 | .interned => { |
| 2004 | const val = air_datas[i].interned.toValue(); |
| 2006 | 2005 | if (val.isRuntimeValue(sema.mod)) make_runtime.* = true; |
| 2007 | 2006 | if (val.isPtrToThreadLocal(sema.mod)) make_runtime.* = true; |
| 2008 | 2007 | return val; |
| 2009 | 2008 | }, |
| 2010 | | .interned => return air_datas[i].interned.toValue(), |
| 2011 | 2009 | else => return null, |
| 2012 | 2010 | } |
| 2013 | 2011 | } |
| ... | ... | @@ -2440,64 +2438,64 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 2440 | 2438 | const addr_space = target_util.defaultAddressSpace(target, .local); |
| 2441 | 2439 | |
| 2442 | 2440 | if (Air.refToIndex(ptr)) |ptr_inst| { |
| 2443 | | if (sema.air_instructions.items(.tag)[ptr_inst] == .constant) { |
| 2444 | | const air_datas = sema.air_instructions.items(.data); |
| 2445 | | const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload]; |
| 2446 | | switch (ptr_val.tag()) { |
| 2447 | | .inferred_alloc => { |
| 2448 | | const inferred_alloc = &ptr_val.castTag(.inferred_alloc).?.data; |
| 2449 | | // Add the stored instruction to the set we will use to resolve peer types |
| 2450 | | // for the inferred allocation. |
| 2451 | | // This instruction will not make it to codegen; it is only to participate |
| 2452 | | // in the `stored_inst_list` of the `inferred_alloc`. |
| 2453 | | var trash_block = block.makeSubBlock(); |
| 2454 | | defer trash_block.instructions.deinit(sema.gpa); |
| 2455 | | const operand = try trash_block.addBitCast(pointee_ty, .void_value); |
| 2456 | | |
| 2457 | | const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ |
| 2458 | | .pointee_type = pointee_ty, |
| 2459 | | .@"align" = inferred_alloc.alignment, |
| 2460 | | .@"addrspace" = addr_space, |
| 2461 | | }); |
| 2462 | | const bitcasted_ptr = try block.addBitCast(ptr_ty, ptr); |
| 2441 | switch (sema.air_instructions.items(.tag)[ptr_inst]) { |
| 2442 | .inferred_alloc => { |
| 2443 | const air_datas = sema.air_instructions.items(.data); |
| 2444 | const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload]; |
| 2445 | const inferred_alloc = &ptr_val.castTag(.inferred_alloc).?.data; |
| 2446 | // Add the stored instruction to the set we will use to resolve peer types |
| 2447 | // for the inferred allocation. |
| 2448 | // This instruction will not make it to codegen; it is only to participate |
| 2449 | // in the `stored_inst_list` of the `inferred_alloc`. |
| 2450 | var trash_block = block.makeSubBlock(); |
| 2451 | defer trash_block.instructions.deinit(sema.gpa); |
| 2452 | const operand = try trash_block.addBitCast(pointee_ty, .void_value); |
| 2453 | |
| 2454 | const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ |
| 2455 | .pointee_type = pointee_ty, |
| 2456 | .@"align" = inferred_alloc.alignment, |
| 2457 | .@"addrspace" = addr_space, |
| 2458 | }); |
| 2459 | const bitcasted_ptr = try block.addBitCast(ptr_ty, ptr); |
| 2463 | 2460 | |
| 2464 | | try inferred_alloc.prongs.append(sema.arena, .{ |
| 2465 | | .stored_inst = operand, |
| 2466 | | .placeholder = Air.refToIndex(bitcasted_ptr).?, |
| 2467 | | }); |
| 2461 | try inferred_alloc.prongs.append(sema.arena, .{ |
| 2462 | .stored_inst = operand, |
| 2463 | .placeholder = Air.refToIndex(bitcasted_ptr).?, |
| 2464 | }); |
| 2468 | 2465 | |
| 2469 | | return bitcasted_ptr; |
| 2470 | | }, |
| 2471 | | .inferred_alloc_comptime => { |
| 2472 | | const iac = ptr_val.castTag(.inferred_alloc_comptime).?; |
| 2473 | | // There will be only one coerce_result_ptr because we are running at comptime. |
| 2474 | | // The alloc will turn into a Decl. |
| 2475 | | var anon_decl = try block.startAnonDecl(); |
| 2476 | | defer anon_decl.deinit(); |
| 2477 | | iac.data.decl_index = try anon_decl.finish( |
| 2478 | | pointee_ty, |
| 2479 | | Value.undef, |
| 2480 | | iac.data.alignment, |
| 2481 | | ); |
| 2482 | | if (iac.data.alignment != 0) { |
| 2483 | | try sema.resolveTypeLayout(pointee_ty); |
| 2484 | | } |
| 2485 | | const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ |
| 2486 | | .pointee_type = pointee_ty, |
| 2487 | | .@"align" = iac.data.alignment, |
| 2488 | | .@"addrspace" = addr_space, |
| 2489 | | }); |
| 2490 | | try sema.maybeQueueFuncBodyAnalysis(iac.data.decl_index); |
| 2491 | | return sema.addConstant(ptr_ty, (try sema.mod.intern(.{ .ptr = .{ |
| 2492 | | .ty = ptr_ty.toIntern(), |
| 2493 | | .addr = .{ .mut_decl = .{ |
| 2494 | | .decl = iac.data.decl_index, |
| 2495 | | .runtime_index = block.runtime_index, |
| 2496 | | } }, |
| 2497 | | } })).toValue()); |
| 2498 | | }, |
| 2499 | | else => {}, |
| 2500 | | } |
| 2466 | return bitcasted_ptr; |
| 2467 | }, |
| 2468 | .inferred_alloc_comptime => { |
| 2469 | const air_datas = sema.air_instructions.items(.data); |
| 2470 | const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload]; |
| 2471 | const iac = ptr_val.castTag(.inferred_alloc_comptime).?; |
| 2472 | // There will be only one coerce_result_ptr because we are running at comptime. |
| 2473 | // The alloc will turn into a Decl. |
| 2474 | var anon_decl = try block.startAnonDecl(); |
| 2475 | defer anon_decl.deinit(); |
| 2476 | iac.data.decl_index = try anon_decl.finish( |
| 2477 | pointee_ty, |
| 2478 | Value.undef, |
| 2479 | iac.data.alignment, |
| 2480 | ); |
| 2481 | if (iac.data.alignment != 0) { |
| 2482 | try sema.resolveTypeLayout(pointee_ty); |
| 2483 | } |
| 2484 | const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ |
| 2485 | .pointee_type = pointee_ty, |
| 2486 | .@"align" = iac.data.alignment, |
| 2487 | .@"addrspace" = addr_space, |
| 2488 | }); |
| 2489 | try sema.maybeQueueFuncBodyAnalysis(iac.data.decl_index); |
| 2490 | return sema.addConstant(ptr_ty, (try sema.mod.intern(.{ .ptr = .{ |
| 2491 | .ty = ptr_ty.toIntern(), |
| 2492 | .addr = .{ .mut_decl = .{ |
| 2493 | .decl = iac.data.decl_index, |
| 2494 | .runtime_index = block.runtime_index, |
| 2495 | } }, |
| 2496 | } })).toValue()); |
| 2497 | }, |
| 2498 | else => {}, |
| 2501 | 2499 | } |
| 2502 | 2500 | } |
| 2503 | 2501 | |
| ... | ... | @@ -3458,6 +3456,7 @@ fn zirAllocExtended( |
| 3458 | 3456 | block: *Block, |
| 3459 | 3457 | extended: Zir.Inst.Extended.InstData, |
| 3460 | 3458 | ) CompileError!Air.Inst.Ref { |
| 3459 | const gpa = sema.gpa; |
| 3461 | 3460 | const extra = sema.code.extraData(Zir.Inst.AllocExtended, extended.operand); |
| 3462 | 3461 | const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = extra.data.src_node }; |
| 3463 | 3462 | const align_src: LazySrcLoc = .{ .node_offset_var_decl_align = extra.data.src_node }; |
| ... | ... | @@ -3487,13 +3486,19 @@ fn zirAllocExtended( |
| 3487 | 3486 | if (small.has_type) { |
| 3488 | 3487 | return sema.analyzeComptimeAlloc(block, var_ty, alignment); |
| 3489 | 3488 | } else { |
| 3490 | | return sema.addConstant( |
| 3491 | | inferred_alloc_ty, |
| 3492 | | try Value.Tag.inferred_alloc_comptime.create(sema.arena, .{ |
| 3493 | | .decl_index = undefined, |
| 3494 | | .alignment = alignment, |
| 3495 | | }), |
| 3496 | | ); |
| 3489 | const ty_inst = try sema.addType(inferred_alloc_ty); |
| 3490 | try sema.air_values.append(gpa, try Value.Tag.inferred_alloc_comptime.create(sema.arena, .{ |
| 3491 | .decl_index = undefined, |
| 3492 | .alignment = alignment, |
| 3493 | })); |
| 3494 | try sema.air_instructions.append(gpa, .{ |
| 3495 | .tag = .inferred_alloc_comptime, |
| 3496 | .data = .{ .ty_pl = .{ |
| 3497 | .ty = ty_inst, |
| 3498 | .payload = @intCast(u32, sema.air_values.items.len - 1), |
| 3499 | } }, |
| 3500 | }); |
| 3501 | return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1)); |
| 3497 | 3502 | } |
| 3498 | 3503 | } |
| 3499 | 3504 | |
| ... | ... | @@ -3511,17 +3516,19 @@ fn zirAllocExtended( |
| 3511 | 3516 | return block.addTy(.alloc, ptr_type); |
| 3512 | 3517 | } |
| 3513 | 3518 | |
| 3514 | | // `Sema.addConstant` does not add the instruction to the block because it is |
| 3515 | | // not needed in the case of constant values. However here, we plan to "downgrade" |
| 3516 | | // to a normal instruction when we hit `resolve_inferred_alloc`. So we append |
| 3517 | | // to the block even though it is currently a `.constant`. |
| 3518 | | const result = try sema.addConstant( |
| 3519 | | inferred_alloc_ty, |
| 3520 | | try Value.Tag.inferred_alloc.create(sema.arena, .{ .alignment = alignment }), |
| 3521 | | ); |
| 3522 | | try block.instructions.append(sema.gpa, Air.refToIndex(result).?); |
| 3523 | | try sema.unresolved_inferred_allocs.putNoClobber(sema.gpa, Air.refToIndex(result).?, {}); |
| 3524 | | return result; |
| 3519 | const ty_inst = try sema.addType(inferred_alloc_ty); |
| 3520 | try sema.air_values.append(gpa, try Value.Tag.inferred_alloc.create(sema.arena, .{ |
| 3521 | .alignment = alignment, |
| 3522 | })); |
| 3523 | const result_index = try block.addInstAsIndex(.{ |
| 3524 | .tag = .inferred_alloc, |
| 3525 | .data = .{ .ty_pl = .{ |
| 3526 | .ty = ty_inst, |
| 3527 | .payload = @intCast(u32, sema.air_values.items.len - 1), |
| 3528 | } }, |
| 3529 | }); |
| 3530 | try sema.unresolved_inferred_allocs.putNoClobber(gpa, result_index, {}); |
| 3531 | return Air.indexToRef(result_index); |
| 3525 | 3532 | } |
| 3526 | 3533 | |
| 3527 | 3534 | fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -3616,16 +3623,24 @@ fn zirAllocInferredComptime( |
| 3616 | 3623 | inst: Zir.Inst.Index, |
| 3617 | 3624 | inferred_alloc_ty: Type, |
| 3618 | 3625 | ) CompileError!Air.Inst.Ref { |
| 3626 | const gpa = sema.gpa; |
| 3619 | 3627 | const src_node = sema.code.instructions.items(.data)[inst].node; |
| 3620 | 3628 | const src = LazySrcLoc.nodeOffset(src_node); |
| 3621 | 3629 | sema.src = src; |
| 3622 | | return sema.addConstant( |
| 3623 | | inferred_alloc_ty, |
| 3624 | | try Value.Tag.inferred_alloc_comptime.create(sema.arena, .{ |
| 3625 | | .decl_index = undefined, |
| 3626 | | .alignment = 0, |
| 3627 | | }), |
| 3628 | | ); |
| 3630 | |
| 3631 | const ty_inst = try sema.addType(inferred_alloc_ty); |
| 3632 | try sema.air_values.append(gpa, try Value.Tag.inferred_alloc_comptime.create(sema.arena, .{ |
| 3633 | .decl_index = undefined, |
| 3634 | .alignment = 0, |
| 3635 | })); |
| 3636 | try sema.air_instructions.append(gpa, .{ |
| 3637 | .tag = .inferred_alloc_comptime, |
| 3638 | .data = .{ .ty_pl = .{ |
| 3639 | .ty = ty_inst, |
| 3640 | .payload = @intCast(u32, sema.air_values.items.len - 1), |
| 3641 | } }, |
| 3642 | }); |
| 3643 | return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1)); |
| 3629 | 3644 | } |
| 3630 | 3645 | |
| 3631 | 3646 | fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -3676,31 +3691,39 @@ fn zirAllocInferred( |
| 3676 | 3691 | const tracy = trace(@src()); |
| 3677 | 3692 | defer tracy.end(); |
| 3678 | 3693 | |
| 3694 | const gpa = sema.gpa; |
| 3679 | 3695 | const src_node = sema.code.instructions.items(.data)[inst].node; |
| 3680 | 3696 | const src = LazySrcLoc.nodeOffset(src_node); |
| 3681 | 3697 | sema.src = src; |
| 3682 | 3698 | |
| 3699 | const ty_inst = try sema.addType(inferred_alloc_ty); |
| 3683 | 3700 | if (block.is_comptime) { |
| 3684 | | return sema.addConstant( |
| 3685 | | inferred_alloc_ty, |
| 3686 | | try Value.Tag.inferred_alloc_comptime.create(sema.arena, .{ |
| 3687 | | .decl_index = undefined, |
| 3688 | | .alignment = 0, |
| 3689 | | }), |
| 3690 | | ); |
| 3701 | try sema.air_values.append(gpa, try Value.Tag.inferred_alloc_comptime.create(sema.arena, .{ |
| 3702 | .decl_index = undefined, |
| 3703 | .alignment = 0, |
| 3704 | })); |
| 3705 | try sema.air_instructions.append(gpa, .{ |
| 3706 | .tag = .inferred_alloc_comptime, |
| 3707 | .data = .{ .ty_pl = .{ |
| 3708 | .ty = ty_inst, |
| 3709 | .payload = @intCast(u32, sema.air_values.items.len - 1), |
| 3710 | } }, |
| 3711 | }); |
| 3712 | return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1)); |
| 3691 | 3713 | } |
| 3692 | 3714 | |
| 3693 | | // `Sema.addConstant` does not add the instruction to the block because it is |
| 3694 | | // not needed in the case of constant values. However here, we plan to "downgrade" |
| 3695 | | // to a normal instruction when we hit `resolve_inferred_alloc`. So we append |
| 3696 | | // to the block even though it is currently a `.constant`. |
| 3697 | | const result = try sema.addConstant( |
| 3698 | | inferred_alloc_ty, |
| 3699 | | try Value.Tag.inferred_alloc.create(sema.arena, .{ .alignment = 0 }), |
| 3700 | | ); |
| 3701 | | try block.instructions.append(sema.gpa, Air.refToIndex(result).?); |
| 3702 | | try sema.unresolved_inferred_allocs.putNoClobber(sema.gpa, Air.refToIndex(result).?, {}); |
| 3703 | | return result; |
| 3715 | try sema.air_values.append(gpa, try Value.Tag.inferred_alloc.create(sema.arena, .{ |
| 3716 | .alignment = 0, |
| 3717 | })); |
| 3718 | const result_index = try block.addInstAsIndex(.{ |
| 3719 | .tag = .inferred_alloc, |
| 3720 | .data = .{ .ty_pl = .{ |
| 3721 | .ty = ty_inst, |
| 3722 | .payload = @intCast(u32, sema.air_values.items.len - 1), |
| 3723 | } }, |
| 3724 | }); |
| 3725 | try sema.unresolved_inferred_allocs.putNoClobber(gpa, result_index, {}); |
| 3726 | return Air.indexToRef(result_index); |
| 3704 | 3727 | } |
| 3705 | 3728 | |
| 3706 | 3729 | fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { |
| ... | ... | @@ -3712,7 +3735,6 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 3712 | 3735 | const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node }; |
| 3713 | 3736 | const ptr = try sema.resolveInst(inst_data.operand); |
| 3714 | 3737 | const ptr_inst = Air.refToIndex(ptr).?; |
| 3715 | | assert(sema.air_instructions.items(.tag)[ptr_inst] == .constant); |
| 3716 | 3738 | const value_index = sema.air_instructions.items(.data)[ptr_inst].ty_pl.payload; |
| 3717 | 3739 | const ptr_val = sema.air_values.items[value_index]; |
| 3718 | 3740 | const var_is_mut = switch (sema.typeOf(ptr).toIntern()) { |
| ... | ... | @@ -3722,7 +3744,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 3722 | 3744 | }; |
| 3723 | 3745 | const target = sema.mod.getTarget(); |
| 3724 | 3746 | |
| 3725 | | switch (ptr_val.tag()) { |
| 3747 | switch (sema.air_instructions.items(.tag)[ptr_inst]) { |
| 3726 | 3748 | .inferred_alloc_comptime => { |
| 3727 | 3749 | const iac = ptr_val.castTag(.inferred_alloc_comptime).?; |
| 3728 | 3750 | const decl_index = iac.data.decl_index; |
| ... | ... | @@ -3767,7 +3789,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 3767 | 3789 | // Detect if the value is comptime-known. In such case, the |
| 3768 | 3790 | // last 3 AIR instructions of the block will look like this: |
| 3769 | 3791 | // |
| 3770 | | // %a = constant |
| 3792 | // %a = interned |
| 3771 | 3793 | // %b = bitcast(%a) |
| 3772 | 3794 | // %c = store(%b, %d) |
| 3773 | 3795 | // |
| ... | ... | @@ -3814,7 +3836,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 3814 | 3836 | const candidate = block.instructions.items[search_index]; |
| 3815 | 3837 | switch (air_tags[candidate]) { |
| 3816 | 3838 | .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue, |
| 3817 | | .constant => break candidate, |
| 3839 | .interned => break candidate, |
| 3818 | 3840 | else => break :ct, |
| 3819 | 3841 | } |
| 3820 | 3842 | }; |
| ... | ... | @@ -4981,15 +5003,15 @@ fn zirStoreToBlockPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 4981 | 5003 | const src: LazySrcLoc = sema.src; |
| 4982 | 5004 | blk: { |
| 4983 | 5005 | const ptr_inst = Air.refToIndex(ptr) orelse break :blk; |
| 4984 | | if (sema.air_instructions.items(.tag)[ptr_inst] != .constant) break :blk; |
| 4985 | | const air_datas = sema.air_instructions.items(.data); |
| 4986 | | const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload]; |
| 4987 | | switch (ptr_val.tag()) { |
| 5006 | const air_data = sema.air_instructions.items(.data)[ptr_inst]; |
| 5007 | switch (sema.air_instructions.items(.tag)[ptr_inst]) { |
| 4988 | 5008 | .inferred_alloc_comptime => { |
| 5009 | const ptr_val = sema.air_values.items[air_data.ty_pl.payload]; |
| 4989 | 5010 | const iac = ptr_val.castTag(.inferred_alloc_comptime).?; |
| 4990 | 5011 | return sema.storeToInferredAllocComptime(block, src, operand, iac); |
| 4991 | 5012 | }, |
| 4992 | 5013 | .inferred_alloc => { |
| 5014 | const ptr_val = sema.air_values.items[air_data.ty_pl.payload]; |
| 4993 | 5015 | const inferred_alloc = ptr_val.castTag(.inferred_alloc).?; |
| 4994 | 5016 | return sema.storeToInferredAlloc(block, ptr, operand, inferred_alloc); |
| 4995 | 5017 | }, |
| ... | ... | @@ -5009,11 +5031,10 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi |
| 5009 | 5031 | const ptr = try sema.resolveInst(bin_inst.lhs); |
| 5010 | 5032 | const operand = try sema.resolveInst(bin_inst.rhs); |
| 5011 | 5033 | const ptr_inst = Air.refToIndex(ptr).?; |
| 5012 | | assert(sema.air_instructions.items(.tag)[ptr_inst] == .constant); |
| 5013 | 5034 | const air_datas = sema.air_instructions.items(.data); |
| 5014 | 5035 | const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload]; |
| 5015 | 5036 | |
| 5016 | | switch (ptr_val.tag()) { |
| 5037 | switch (sema.air_instructions.items(.tag)[ptr_inst]) { |
| 5017 | 5038 | .inferred_alloc_comptime => { |
| 5018 | 5039 | const iac = ptr_val.castTag(.inferred_alloc_comptime).?; |
| 5019 | 5040 | return sema.storeToInferredAllocComptime(block, src, operand, iac); |
| ... | ... | @@ -6988,16 +7009,7 @@ fn analyzeCall( |
| 6988 | 7009 | const res2: Air.Inst.Ref = res2: { |
| 6989 | 7010 | if (should_memoize and is_comptime_call) { |
| 6990 | 7011 | if (mod.memoized_calls.getContext(memoized_call_key, .{ .module = mod })) |result| { |
| 6991 | | const ty_inst = try sema.addType(fn_ret_ty); |
| 6992 | | try sema.air_values.append(gpa, result.val); |
| 6993 | | sema.air_instructions.set(block_inst, .{ |
| 6994 | | .tag = .constant, |
| 6995 | | .data = .{ .ty_pl = .{ |
| 6996 | | .ty = ty_inst, |
| 6997 | | .payload = @intCast(u32, sema.air_values.items.len - 1), |
| 6998 | | } }, |
| 6999 | | }); |
| 7000 | | break :res2 Air.indexToRef(block_inst); |
| 7012 | break :res2 try sema.addConstant(fn_ret_ty, result.val); |
| 7001 | 7013 | } |
| 7002 | 7014 | } |
| 7003 | 7015 | |
| ... | ... | @@ -9407,7 +9419,7 @@ fn zirParam( |
| 9407 | 9419 | if (is_comptime) { |
| 9408 | 9420 | // If this is a comptime parameter we can add a constant generic_poison |
| 9409 | 9421 | // since this is also a generic parameter. |
| 9410 | | const result = try sema.addConstant(param_ty, Value.generic_poison); |
| 9422 | const result = try sema.addConstant(Type.generic_poison, Value.generic_poison); |
| 9411 | 9423 | sema.inst_map.putAssumeCapacityNoClobber(inst, result); |
| 9412 | 9424 | } else { |
| 9413 | 9425 | // Otherwise we need a dummy runtime instruction. |
| ... | ... | @@ -15104,7 +15116,7 @@ fn analyzePtrArithmetic( |
| 15104 | 15116 | if (air_tag == .ptr_sub) { |
| 15105 | 15117 | return sema.fail(block, op_src, "TODO implement Sema comptime pointer subtraction", .{}); |
| 15106 | 15118 | } |
| 15107 | | const new_ptr_val = try ptr_val.elemPtr(ptr_ty, offset_int, sema.mod); |
| 15119 | const new_ptr_val = try ptr_val.elemPtr(new_ptr_ty, offset_int, sema.mod); |
| 15108 | 15120 | return sema.addConstant(new_ptr_ty, new_ptr_val); |
| 15109 | 15121 | } else break :rs offset_src; |
| 15110 | 15122 | } else break :rs ptr_src; |
| ... | ... | @@ -25378,8 +25390,8 @@ fn elemPtrOneLayerOnly( |
| 25378 | 25390 | const ptr_val = maybe_ptr_val orelse break :rs indexable_src; |
| 25379 | 25391 | const index_val = maybe_index_val orelse break :rs elem_index_src; |
| 25380 | 25392 | const index = @intCast(usize, index_val.toUnsignedInt(mod)); |
| 25381 | | const elem_ptr = try ptr_val.elemPtr(indexable_ty, index, mod); |
| 25382 | 25393 | const result_ty = try sema.elemPtrType(indexable_ty, index); |
| 25394 | const elem_ptr = try ptr_val.elemPtr(result_ty, index, mod); |
| 25383 | 25395 | return sema.addConstant(result_ty, elem_ptr); |
| 25384 | 25396 | }; |
| 25385 | 25397 | const result_ty = try sema.elemPtrType(indexable_ty, null); |
| ... | ... | @@ -25424,8 +25436,9 @@ fn elemVal( |
| 25424 | 25436 | const indexable_val = maybe_indexable_val orelse break :rs indexable_src; |
| 25425 | 25437 | const index_val = maybe_index_val orelse break :rs elem_index_src; |
| 25426 | 25438 | const index = @intCast(usize, index_val.toUnsignedInt(mod)); |
| 25427 | | const elem_ptr_val = try indexable_val.elemPtr(indexable_ty, index, mod); |
| 25428 | | if (try sema.pointerDeref(block, indexable_src, elem_ptr_val, indexable_ty)) |elem_val| { |
| 25439 | const elem_ptr_ty = try sema.elemPtrType(indexable_ty, index); |
| 25440 | const elem_ptr_val = try indexable_val.elemPtr(elem_ptr_ty, index, mod); |
| 25441 | if (try sema.pointerDeref(block, indexable_src, elem_ptr_val, elem_ptr_ty)) |elem_val| { |
| 25429 | 25442 | return sema.addConstant(indexable_ty.elemType2(mod), elem_val); |
| 25430 | 25443 | } |
| 25431 | 25444 | break :rs indexable_src; |
| ... | ... | @@ -25684,7 +25697,7 @@ fn elemPtrArray( |
| 25684 | 25697 | return sema.addConstUndef(elem_ptr_ty); |
| 25685 | 25698 | } |
| 25686 | 25699 | if (offset) |index| { |
| 25687 | | const elem_ptr = try array_ptr_val.elemPtr(array_ptr_ty, index, mod); |
| 25700 | const elem_ptr = try array_ptr_val.elemPtr(elem_ptr_ty, index, mod); |
| 25688 | 25701 | return sema.addConstant(elem_ptr_ty, elem_ptr); |
| 25689 | 25702 | } |
| 25690 | 25703 | } |
| ... | ... | @@ -25740,8 +25753,9 @@ fn elemValSlice( |
| 25740 | 25753 | const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else ""; |
| 25741 | 25754 | return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label }); |
| 25742 | 25755 | } |
| 25743 | | const elem_ptr_val = try slice_val.elemPtr(slice_ty, index, mod); |
| 25744 | | if (try sema.pointerDeref(block, slice_src, elem_ptr_val, slice_ty)) |elem_val| { |
| 25756 | const elem_ptr_ty = try sema.elemPtrType(slice_ty, index); |
| 25757 | const elem_ptr_val = try slice_val.elemPtr(elem_ptr_ty, index, mod); |
| 25758 | if (try sema.pointerDeref(block, slice_src, elem_ptr_val, elem_ptr_ty)) |elem_val| { |
| 25745 | 25759 | return sema.addConstant(elem_ty, elem_val); |
| 25746 | 25760 | } |
| 25747 | 25761 | runtime_src = slice_src; |
| ... | ... | @@ -25800,7 +25814,7 @@ fn elemPtrSlice( |
| 25800 | 25814 | const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else ""; |
| 25801 | 25815 | return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label }); |
| 25802 | 25816 | } |
| 25803 | | const elem_ptr_val = try slice_val.elemPtr(slice_ty, index, mod); |
| 25817 | const elem_ptr_val = try slice_val.elemPtr(elem_ptr_ty, index, mod); |
| 25804 | 25818 | return sema.addConstant(elem_ptr_ty, elem_ptr_val); |
| 25805 | 25819 | } |
| 25806 | 25820 | } |
| ... | ... | @@ -25916,7 +25930,10 @@ fn coerceExtra( |
| 25916 | 25930 | |
| 25917 | 25931 | // null to ?T |
| 25918 | 25932 | if (inst_ty.zigTypeTag(mod) == .Null) { |
| 25919 | | return sema.addConstant(dest_ty, Value.null); |
| 25933 | return sema.addConstant(dest_ty, (try mod.intern(.{ .opt = .{ |
| 25934 | .ty = dest_ty.toIntern(), |
| 25935 | .val = .none, |
| 25936 | } })).toValue()); |
| 25920 | 25937 | } |
| 25921 | 25938 | |
| 25922 | 25939 | // cast from ?*T and ?[*]T to ?*anyopaque |
| ... | ... | @@ -27665,43 +27682,40 @@ fn storePtrVal( |
| 27665 | 27682 | switch (mut_kit.pointee) { |
| 27666 | 27683 | .direct => |val_ptr| { |
| 27667 | 27684 | if (mut_kit.mut_decl.runtime_index == .comptime_field_ptr) { |
| 27668 | | if (!operand_val.eql(val_ptr.*, operand_ty, sema.mod)) { |
| 27685 | if (!operand_val.eql(val_ptr.*, operand_ty, mod)) { |
| 27669 | 27686 | // TODO use failWithInvalidComptimeFieldStore |
| 27670 | 27687 | return sema.fail(block, src, "value stored in comptime field does not match the default value of the field", .{}); |
| 27671 | 27688 | } |
| 27672 | 27689 | return; |
| 27673 | 27690 | } |
| 27674 | | const arena = mut_kit.beginArena(sema.mod); |
| 27675 | | defer mut_kit.finishArena(sema.mod); |
| 27676 | | |
| 27677 | | val_ptr.* = try operand_val.copy(arena); |
| 27691 | val_ptr.* = (try operand_val.intern(operand_ty, mod)).toValue(); |
| 27678 | 27692 | }, |
| 27679 | 27693 | .reinterpret => |reinterpret| { |
| 27680 | 27694 | const abi_size = try sema.usizeCast(block, src, mut_kit.ty.abiSize(mod)); |
| 27681 | 27695 | const buffer = try sema.gpa.alloc(u8, abi_size); |
| 27682 | 27696 | defer sema.gpa.free(buffer); |
| 27683 | | reinterpret.val_ptr.*.writeToMemory(mut_kit.ty, sema.mod, buffer) catch |err| switch (err) { |
| 27697 | reinterpret.val_ptr.*.writeToMemory(mut_kit.ty, mod, buffer) catch |err| switch (err) { |
| 27684 | 27698 | error.OutOfMemory => return error.OutOfMemory, |
| 27685 | 27699 | error.ReinterpretDeclRef => unreachable, |
| 27686 | 27700 | error.IllDefinedMemoryLayout => unreachable, // Sema was supposed to emit a compile error already |
| 27687 | | error.Unimplemented => return sema.fail(block, src, "TODO: implement writeToMemory for type '{}'", .{mut_kit.ty.fmt(sema.mod)}), |
| 27701 | error.Unimplemented => return sema.fail(block, src, "TODO: implement writeToMemory for type '{}'", .{mut_kit.ty.fmt(mod)}), |
| 27688 | 27702 | }; |
| 27689 | | operand_val.writeToMemory(operand_ty, sema.mod, buffer[reinterpret.byte_offset..]) catch |err| switch (err) { |
| 27703 | operand_val.writeToMemory(operand_ty, mod, buffer[reinterpret.byte_offset..]) catch |err| switch (err) { |
| 27690 | 27704 | error.OutOfMemory => return error.OutOfMemory, |
| 27691 | 27705 | error.ReinterpretDeclRef => unreachable, |
| 27692 | 27706 | error.IllDefinedMemoryLayout => unreachable, // Sema was supposed to emit a compile error already |
| 27693 | | error.Unimplemented => return sema.fail(block, src, "TODO: implement writeToMemory for type '{}'", .{mut_kit.ty.fmt(sema.mod)}), |
| 27707 | error.Unimplemented => return sema.fail(block, src, "TODO: implement writeToMemory for type '{}'", .{mut_kit.ty.fmt(mod)}), |
| 27694 | 27708 | }; |
| 27695 | 27709 | |
| 27696 | | const arena = mut_kit.beginArena(sema.mod); |
| 27697 | | defer mut_kit.finishArena(sema.mod); |
| 27710 | const arena = mut_kit.beginArena(mod); |
| 27711 | defer mut_kit.finishArena(mod); |
| 27698 | 27712 | |
| 27699 | | reinterpret.val_ptr.* = try Value.readFromMemory(mut_kit.ty, sema.mod, buffer, arena); |
| 27713 | reinterpret.val_ptr.* = (try (try Value.readFromMemory(mut_kit.ty, mod, buffer, arena)).intern(mut_kit.ty, mod)).toValue(); |
| 27700 | 27714 | }, |
| 27701 | 27715 | .bad_decl_ty, .bad_ptr_ty => { |
| 27702 | 27716 | // TODO show the decl declaration site in a note and explain whether the decl |
| 27703 | 27717 | // or the pointer is the problematic type |
| 27704 | | return sema.fail(block, src, "comptime mutation of a reinterpreted pointer requires type '{}' to have a well-defined memory layout", .{mut_kit.ty.fmt(sema.mod)}); |
| 27718 | return sema.fail(block, src, "comptime mutation of a reinterpreted pointer requires type '{}' to have a well-defined memory layout", .{mut_kit.ty.fmt(mod)}); |
| 27705 | 27719 | }, |
| 27706 | 27720 | } |
| 27707 | 27721 | } |
| ... | ... | @@ -27754,7 +27768,7 @@ fn beginComptimePtrMutation( |
| 27754 | 27768 | const mod = sema.mod; |
| 27755 | 27769 | const ptr = mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr; |
| 27756 | 27770 | switch (ptr.addr) { |
| 27757 | | .decl => unreachable, // isComptimeMutablePtr has been checked already |
| 27771 | .decl, .int => unreachable, // isComptimeMutablePtr has been checked already |
| 27758 | 27772 | .mut_decl => |mut_decl| { |
| 27759 | 27773 | const decl = mod.declPtr(mut_decl.decl); |
| 27760 | 27774 | return sema.beginComptimePtrMutationInner(block, src, decl.ty, &decl.val, ptr_elem_ty, mut_decl); |
| ... | ... | @@ -27767,546 +27781,472 @@ fn beginComptimePtrMutation( |
| 27767 | 27781 | .runtime_index = .comptime_field_ptr, |
| 27768 | 27782 | }); |
| 27769 | 27783 | }, |
| 27770 | | else => unreachable, |
| 27771 | | } |
| 27772 | | if (true) unreachable; |
| 27773 | | switch (ptr_val.toIntern()) { |
| 27774 | | .none => switch (ptr_val.tag()) { |
| 27775 | | .decl_ref_mut => { |
| 27776 | | const decl_ref_mut = ptr_val.castTag(.decl_ref_mut).?.data; |
| 27777 | | const decl = sema.mod.declPtr(decl_ref_mut.decl_index); |
| 27778 | | return sema.beginComptimePtrMutationInner(block, src, decl.ty, &decl.val, ptr_elem_ty, decl_ref_mut); |
| 27779 | | }, |
| 27780 | | .comptime_field_ptr => { |
| 27781 | | const payload = ptr_val.castTag(.comptime_field_ptr).?.data; |
| 27782 | | const duped = try sema.arena.create(Value); |
| 27783 | | duped.* = payload.field_val; |
| 27784 | | return sema.beginComptimePtrMutationInner(block, src, payload.field_ty, duped, ptr_elem_ty, .{ |
| 27785 | | .decl_index = @intToEnum(Module.Decl.Index, 0), |
| 27786 | | .runtime_index = .comptime_field_ptr, |
| 27787 | | }); |
| 27788 | | }, |
| 27789 | | .elem_ptr => { |
| 27790 | | const elem_ptr = ptr_val.castTag(.elem_ptr).?.data; |
| 27791 | | var parent = try sema.beginComptimePtrMutation(block, src, elem_ptr.array_ptr, elem_ptr.elem_ty); |
| 27792 | | |
| 27793 | | switch (parent.pointee) { |
| 27794 | | .direct => |val_ptr| switch (parent.ty.zigTypeTag(mod)) { |
| 27795 | | .Array, .Vector => { |
| 27796 | | const check_len = parent.ty.arrayLenIncludingSentinel(mod); |
| 27797 | | if (elem_ptr.index >= check_len) { |
| 27798 | | // TODO have the parent include the decl so we can say "declared here" |
| 27799 | | return sema.fail(block, src, "comptime store of index {d} out of bounds of array length {d}", .{ |
| 27800 | | elem_ptr.index, check_len, |
| 27801 | | }); |
| 27802 | | } |
| 27803 | | const elem_ty = parent.ty.childType(mod); |
| 27804 | | |
| 27805 | | // We might have a pointer to multiple elements of the array (e.g. a pointer |
| 27806 | | // to a sub-array). In this case, we just have to reinterpret the relevant |
| 27807 | | // bytes of the whole array rather than any single element. |
| 27808 | | const elem_abi_size_u64 = try sema.typeAbiSize(elem_ptr.elem_ty); |
| 27809 | | if (elem_abi_size_u64 < try sema.typeAbiSize(ptr_elem_ty)) { |
| 27810 | | const elem_abi_size = try sema.usizeCast(block, src, elem_abi_size_u64); |
| 27811 | | return .{ |
| 27812 | | .decl_ref_mut = parent.decl_ref_mut, |
| 27813 | | .pointee = .{ .reinterpret = .{ |
| 27814 | | .val_ptr = val_ptr, |
| 27815 | | .byte_offset = elem_abi_size * elem_ptr.index, |
| 27816 | | } }, |
| 27817 | | .ty = parent.ty, |
| 27818 | | }; |
| 27819 | | } |
| 27784 | .eu_payload => |eu_ptr| { |
| 27785 | const eu_ty = mod.intern_pool.typeOf(eu_ptr).toType().childType(mod); |
| 27786 | var parent = try sema.beginComptimePtrMutation(block, src, eu_ptr.toValue(), eu_ty); |
| 27787 | switch (parent.pointee) { |
| 27788 | .direct => |val_ptr| { |
| 27789 | const payload_ty = parent.ty.errorUnionPayload(mod); |
| 27790 | if (val_ptr.ip_index == .none and val_ptr.tag() == .eu_payload) { |
| 27791 | return ComptimePtrMutationKit{ |
| 27792 | .mut_decl = parent.mut_decl, |
| 27793 | .pointee = .{ .direct = &val_ptr.castTag(.eu_payload).?.data }, |
| 27794 | .ty = payload_ty, |
| 27795 | }; |
| 27796 | } else { |
| 27797 | // An error union has been initialized to undefined at comptime and now we |
| 27798 | // are for the first time setting the payload. We must change the |
| 27799 | // representation of the error union from `undef` to `opt_payload`. |
| 27800 | const arena = parent.beginArena(sema.mod); |
| 27801 | defer parent.finishArena(sema.mod); |
| 27802 | |
| 27803 | const payload = try arena.create(Value.Payload.SubValue); |
| 27804 | payload.* = .{ |
| 27805 | .base = .{ .tag = .eu_payload }, |
| 27806 | .data = Value.undef, |
| 27807 | }; |
| 27820 | 27808 | |
| 27821 | | switch (val_ptr.toIntern()) { |
| 27822 | | .undef => { |
| 27823 | | // An array has been initialized to undefined at comptime and now we |
| 27824 | | // are for the first time setting an element. We must change the representation |
| 27825 | | // of the array from `undef` to `array`. |
| 27826 | | const arena = parent.beginArena(sema.mod); |
| 27827 | | defer parent.finishArena(sema.mod); |
| 27809 | val_ptr.* = Value.initPayload(&payload.base); |
| 27828 | 27810 | |
| 27829 | | const array_len_including_sentinel = |
| 27830 | | try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel(mod)); |
| 27831 | | const elems = try arena.alloc(Value, array_len_including_sentinel); |
| 27832 | | @memset(elems, Value.undef); |
| 27811 | return ComptimePtrMutationKit{ |
| 27812 | .mut_decl = parent.mut_decl, |
| 27813 | .pointee = .{ .direct = &payload.data }, |
| 27814 | .ty = payload_ty, |
| 27815 | }; |
| 27816 | } |
| 27817 | }, |
| 27818 | .bad_decl_ty, .bad_ptr_ty => return parent, |
| 27819 | // Even though the parent value type has well-defined memory layout, our |
| 27820 | // pointer type does not. |
| 27821 | .reinterpret => return ComptimePtrMutationKit{ |
| 27822 | .mut_decl = parent.mut_decl, |
| 27823 | .pointee = .bad_ptr_ty, |
| 27824 | .ty = eu_ty, |
| 27825 | }, |
| 27826 | } |
| 27827 | }, |
| 27828 | .opt_payload => |opt_ptr| { |
| 27829 | const opt_ty = mod.intern_pool.typeOf(opt_ptr).toType().childType(mod); |
| 27830 | var parent = try sema.beginComptimePtrMutation(block, src, opt_ptr.toValue(), opt_ty); |
| 27831 | switch (parent.pointee) { |
| 27832 | .direct => |val_ptr| { |
| 27833 | const payload_ty = parent.ty.optionalChild(mod); |
| 27834 | switch (val_ptr.ip_index) { |
| 27835 | .undef, .null_value => { |
| 27836 | // An optional has been initialized to undefined at comptime and now we |
| 27837 | // are for the first time setting the payload. We must change the |
| 27838 | // representation of the optional from `undef` to `opt_payload`. |
| 27839 | const arena = parent.beginArena(sema.mod); |
| 27840 | defer parent.finishArena(sema.mod); |
| 27833 | 27841 | |
| 27834 | | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); |
| 27842 | const payload = try arena.create(Value.Payload.SubValue); |
| 27843 | payload.* = .{ |
| 27844 | .base = .{ .tag = .opt_payload }, |
| 27845 | .data = Value.undef, |
| 27846 | }; |
| 27835 | 27847 | |
| 27836 | | return beginComptimePtrMutationInner( |
| 27837 | | sema, |
| 27838 | | block, |
| 27839 | | src, |
| 27840 | | elem_ty, |
| 27841 | | &elems[elem_ptr.index], |
| 27842 | | ptr_elem_ty, |
| 27843 | | parent.decl_ref_mut, |
| 27844 | | ); |
| 27845 | | }, |
| 27846 | | .none => switch (val_ptr.tag()) { |
| 27847 | | .bytes => { |
| 27848 | | // An array is memory-optimized to store a slice of bytes, but we are about |
| 27849 | | // to modify an individual field and the representation has to change. |
| 27850 | | // If we wanted to avoid this, there would need to be special detection |
| 27851 | | // elsewhere to identify when writing a value to an array element that is stored |
| 27852 | | // using the `bytes` tag, and handle it without making a call to this function. |
| 27853 | | const arena = parent.beginArena(sema.mod); |
| 27854 | | defer parent.finishArena(sema.mod); |
| 27855 | | |
| 27856 | | const bytes = val_ptr.castTag(.bytes).?.data; |
| 27857 | | const dest_len = parent.ty.arrayLenIncludingSentinel(mod); |
| 27858 | | // bytes.len may be one greater than dest_len because of the case when |
| 27859 | | // assigning `[N:S]T` to `[N]T`. This is allowed; the sentinel is omitted. |
| 27860 | | assert(bytes.len >= dest_len); |
| 27861 | | const elems = try arena.alloc(Value, @intCast(usize, dest_len)); |
| 27862 | | for (elems, 0..) |*elem, i| { |
| 27863 | | elem.* = try mod.intValue(elem_ty, bytes[i]); |
| 27864 | | } |
| 27865 | | |
| 27866 | | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); |
| 27867 | | |
| 27868 | | return beginComptimePtrMutationInner( |
| 27869 | | sema, |
| 27870 | | block, |
| 27871 | | src, |
| 27872 | | elem_ty, |
| 27873 | | &elems[elem_ptr.index], |
| 27874 | | ptr_elem_ty, |
| 27875 | | parent.decl_ref_mut, |
| 27876 | | ); |
| 27877 | | }, |
| 27878 | | .str_lit => { |
| 27879 | | // An array is memory-optimized to store a slice of bytes, but we are about |
| 27880 | | // to modify an individual field and the representation has to change. |
| 27881 | | // If we wanted to avoid this, there would need to be special detection |
| 27882 | | // elsewhere to identify when writing a value to an array element that is stored |
| 27883 | | // using the `str_lit` tag, and handle it without making a call to this function. |
| 27884 | | const arena = parent.beginArena(sema.mod); |
| 27885 | | defer parent.finishArena(sema.mod); |
| 27886 | | |
| 27887 | | const str_lit = val_ptr.castTag(.str_lit).?.data; |
| 27888 | | const dest_len = parent.ty.arrayLenIncludingSentinel(mod); |
| 27889 | | const bytes = sema.mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; |
| 27890 | | const elems = try arena.alloc(Value, @intCast(usize, dest_len)); |
| 27891 | | for (bytes, 0..) |byte, i| { |
| 27892 | | elems[i] = try mod.intValue(elem_ty, byte); |
| 27893 | | } |
| 27894 | | if (parent.ty.sentinel(mod)) |sent_val| { |
| 27895 | | assert(elems.len == bytes.len + 1); |
| 27896 | | elems[bytes.len] = sent_val; |
| 27897 | | } |
| 27898 | | |
| 27899 | | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); |
| 27900 | | |
| 27901 | | return beginComptimePtrMutationInner( |
| 27902 | | sema, |
| 27903 | | block, |
| 27904 | | src, |
| 27905 | | elem_ty, |
| 27906 | | &elems[elem_ptr.index], |
| 27907 | | ptr_elem_ty, |
| 27908 | | parent.decl_ref_mut, |
| 27909 | | ); |
| 27910 | | }, |
| 27911 | | .repeated => { |
| 27912 | | // An array is memory-optimized to store only a single element value, and |
| 27913 | | // that value is understood to be the same for the entire length of the array. |
| 27914 | | // However, now we want to modify an individual field and so the |
| 27915 | | // representation has to change. If we wanted to avoid this, there would |
| 27916 | | // need to be special detection elsewhere to identify when writing a value to an |
| 27917 | | // array element that is stored using the `repeated` tag, and handle it |
| 27918 | | // without making a call to this function. |
| 27919 | | const arena = parent.beginArena(sema.mod); |
| 27920 | | defer parent.finishArena(sema.mod); |
| 27921 | | |
| 27922 | | const repeated_val = try val_ptr.castTag(.repeated).?.data.copy(arena); |
| 27923 | | const array_len_including_sentinel = |
| 27924 | | try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel(mod)); |
| 27925 | | const elems = try arena.alloc(Value, array_len_including_sentinel); |
| 27926 | | if (elems.len > 0) elems[0] = repeated_val; |
| 27927 | | for (elems[1..]) |*elem| { |
| 27928 | | elem.* = try repeated_val.copy(arena); |
| 27929 | | } |
| 27930 | | |
| 27931 | | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); |
| 27932 | | |
| 27933 | | return beginComptimePtrMutationInner( |
| 27934 | | sema, |
| 27935 | | block, |
| 27936 | | src, |
| 27937 | | elem_ty, |
| 27938 | | &elems[elem_ptr.index], |
| 27939 | | ptr_elem_ty, |
| 27940 | | parent.decl_ref_mut, |
| 27941 | | ); |
| 27942 | | }, |
| 27943 | | |
| 27944 | | .aggregate => return beginComptimePtrMutationInner( |
| 27945 | | sema, |
| 27946 | | block, |
| 27947 | | src, |
| 27948 | | elem_ty, |
| 27949 | | &val_ptr.castTag(.aggregate).?.data[elem_ptr.index], |
| 27950 | | ptr_elem_ty, |
| 27951 | | parent.decl_ref_mut, |
| 27952 | | ), |
| 27848 | val_ptr.* = Value.initPayload(&payload.base); |
| 27953 | 27849 | |
| 27954 | | .the_only_possible_value => { |
| 27955 | | const duped = try sema.arena.create(Value); |
| 27956 | | duped.* = Value.initTag(.the_only_possible_value); |
| 27957 | | return beginComptimePtrMutationInner( |
| 27958 | | sema, |
| 27959 | | block, |
| 27960 | | src, |
| 27961 | | elem_ty, |
| 27962 | | duped, |
| 27963 | | ptr_elem_ty, |
| 27964 | | parent.decl_ref_mut, |
| 27965 | | ); |
| 27966 | | }, |
| 27850 | return ComptimePtrMutationKit{ |
| 27851 | .mut_decl = parent.mut_decl, |
| 27852 | .pointee = .{ .direct = &payload.data }, |
| 27853 | .ty = payload_ty, |
| 27854 | }; |
| 27855 | }, |
| 27856 | .none => switch (val_ptr.tag()) { |
| 27857 | .opt_payload => return ComptimePtrMutationKit{ |
| 27858 | .mut_decl = parent.mut_decl, |
| 27859 | .pointee = .{ .direct = &val_ptr.castTag(.opt_payload).?.data }, |
| 27860 | .ty = payload_ty, |
| 27861 | }, |
| 27967 | 27862 | |
| 27968 | | else => unreachable, |
| 27969 | | }, |
| 27970 | | else => unreachable, |
| 27971 | | } |
| 27863 | else => return ComptimePtrMutationKit{ |
| 27864 | .mut_decl = parent.mut_decl, |
| 27865 | .pointee = .{ .direct = val_ptr }, |
| 27866 | .ty = payload_ty, |
| 27867 | }, |
| 27972 | 27868 | }, |
| 27973 | | else => { |
| 27974 | | if (elem_ptr.index != 0) { |
| 27975 | | // TODO include a "declared here" note for the decl |
| 27976 | | return sema.fail(block, src, "out of bounds comptime store of index {d}", .{ |
| 27977 | | elem_ptr.index, |
| 27978 | | }); |
| 27979 | | } |
| 27980 | | return beginComptimePtrMutationInner( |
| 27981 | | sema, |
| 27982 | | block, |
| 27983 | | src, |
| 27984 | | parent.ty, |
| 27985 | | val_ptr, |
| 27986 | | ptr_elem_ty, |
| 27987 | | parent.decl_ref_mut, |
| 27988 | | ); |
| 27869 | else => return ComptimePtrMutationKit{ |
| 27870 | .mut_decl = parent.mut_decl, |
| 27871 | .pointee = .{ .direct = val_ptr }, |
| 27872 | .ty = payload_ty, |
| 27989 | 27873 | }, |
| 27990 | | }, |
| 27991 | | .reinterpret => |reinterpret| { |
| 27992 | | if (!elem_ptr.elem_ty.hasWellDefinedLayout(mod)) { |
| 27993 | | // Even though the parent value type has well-defined memory layout, our |
| 27994 | | // pointer type does not. |
| 27995 | | return ComptimePtrMutationKit{ |
| 27996 | | .decl_ref_mut = parent.decl_ref_mut, |
| 27997 | | .pointee = .bad_ptr_ty, |
| 27998 | | .ty = elem_ptr.elem_ty, |
| 27874 | } |
| 27875 | }, |
| 27876 | .bad_decl_ty, .bad_ptr_ty => return parent, |
| 27877 | // Even though the parent value type has well-defined memory layout, our |
| 27878 | // pointer type does not. |
| 27879 | .reinterpret => return ComptimePtrMutationKit{ |
| 27880 | .mut_decl = parent.mut_decl, |
| 27881 | .pointee = .bad_ptr_ty, |
| 27882 | .ty = opt_ty, |
| 27883 | }, |
| 27884 | } |
| 27885 | }, |
| 27886 | .elem => |elem_ptr| { |
| 27887 | const base_elem_ty = mod.intern_pool.typeOf(elem_ptr.base).toType().elemType2(mod); |
| 27888 | var parent = try sema.beginComptimePtrMutation(block, src, elem_ptr.base.toValue(), base_elem_ty); |
| 27889 | |
| 27890 | switch (parent.pointee) { |
| 27891 | .direct => |val_ptr| switch (parent.ty.zigTypeTag(mod)) { |
| 27892 | .Array, .Vector => { |
| 27893 | const check_len = parent.ty.arrayLenIncludingSentinel(mod); |
| 27894 | if (elem_ptr.index >= check_len) { |
| 27895 | // TODO have the parent include the decl so we can say "declared here" |
| 27896 | return sema.fail(block, src, "comptime store of index {d} out of bounds of array length {d}", .{ |
| 27897 | elem_ptr.index, check_len, |
| 27898 | }); |
| 27899 | } |
| 27900 | const elem_ty = parent.ty.childType(mod); |
| 27901 | |
| 27902 | // We might have a pointer to multiple elements of the array (e.g. a pointer |
| 27903 | // to a sub-array). In this case, we just have to reinterpret the relevant |
| 27904 | // bytes of the whole array rather than any single element. |
| 27905 | const elem_abi_size_u64 = try sema.typeAbiSize(base_elem_ty); |
| 27906 | if (elem_abi_size_u64 < try sema.typeAbiSize(ptr_elem_ty)) { |
| 27907 | const elem_abi_size = try sema.usizeCast(block, src, elem_abi_size_u64); |
| 27908 | return .{ |
| 27909 | .mut_decl = parent.mut_decl, |
| 27910 | .pointee = .{ .reinterpret = .{ |
| 27911 | .val_ptr = val_ptr, |
| 27912 | .byte_offset = elem_abi_size * elem_ptr.index, |
| 27913 | } }, |
| 27914 | .ty = parent.ty, |
| 27999 | 27915 | }; |
| 28000 | 27916 | } |
| 28001 | 27917 | |
| 28002 | | const elem_abi_size_u64 = try sema.typeAbiSize(elem_ptr.elem_ty); |
| 28003 | | const elem_abi_size = try sema.usizeCast(block, src, elem_abi_size_u64); |
| 28004 | | return ComptimePtrMutationKit{ |
| 28005 | | .decl_ref_mut = parent.decl_ref_mut, |
| 28006 | | .pointee = .{ .reinterpret = .{ |
| 28007 | | .val_ptr = reinterpret.val_ptr, |
| 28008 | | .byte_offset = reinterpret.byte_offset + elem_abi_size * elem_ptr.index, |
| 28009 | | } }, |
| 28010 | | .ty = parent.ty, |
| 28011 | | }; |
| 28012 | | }, |
| 28013 | | .bad_decl_ty, .bad_ptr_ty => return parent, |
| 28014 | | } |
| 28015 | | }, |
| 28016 | | .field_ptr => { |
| 28017 | | const field_ptr = ptr_val.castTag(.field_ptr).?.data; |
| 28018 | | const field_index = @intCast(u32, field_ptr.field_index); |
| 27918 | switch (val_ptr.ip_index) { |
| 27919 | .undef => { |
| 27920 | // An array has been initialized to undefined at comptime and now we |
| 27921 | // are for the first time setting an element. We must change the representation |
| 27922 | // of the array from `undef` to `array`. |
| 27923 | const arena = parent.beginArena(sema.mod); |
| 27924 | defer parent.finishArena(sema.mod); |
| 28019 | 27925 | |
| 28020 | | var parent = try sema.beginComptimePtrMutation(block, src, field_ptr.container_ptr, field_ptr.container_ty); |
| 28021 | | switch (parent.pointee) { |
| 28022 | | .direct => |val_ptr| switch (val_ptr.toIntern()) { |
| 28023 | | .undef => { |
| 28024 | | // A struct or union has been initialized to undefined at comptime and now we |
| 28025 | | // are for the first time setting a field. We must change the representation |
| 28026 | | // of the struct/union from `undef` to `struct`/`union`. |
| 28027 | | const arena = parent.beginArena(sema.mod); |
| 28028 | | defer parent.finishArena(sema.mod); |
| 27926 | const array_len_including_sentinel = |
| 27927 | try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel(mod)); |
| 27928 | const elems = try arena.alloc(Value, array_len_including_sentinel); |
| 27929 | @memset(elems, Value.undef); |
| 28029 | 27930 | |
| 28030 | | switch (parent.ty.zigTypeTag(mod)) { |
| 28031 | | .Struct => { |
| 28032 | | const fields = try arena.alloc(Value, parent.ty.structFieldCount(mod)); |
| 28033 | | @memset(fields, Value.undef); |
| 27931 | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); |
| 28034 | 27932 | |
| 28035 | | val_ptr.* = try Value.Tag.aggregate.create(arena, fields); |
| 27933 | return beginComptimePtrMutationInner( |
| 27934 | sema, |
| 27935 | block, |
| 27936 | src, |
| 27937 | elem_ty, |
| 27938 | &elems[elem_ptr.index], |
| 27939 | ptr_elem_ty, |
| 27940 | parent.mut_decl, |
| 27941 | ); |
| 27942 | }, |
| 27943 | .none => switch (val_ptr.tag()) { |
| 27944 | .bytes => { |
| 27945 | // An array is memory-optimized to store a slice of bytes, but we are about |
| 27946 | // to modify an individual field and the representation has to change. |
| 27947 | // If we wanted to avoid this, there would need to be special detection |
| 27948 | // elsewhere to identify when writing a value to an array element that is stored |
| 27949 | // using the `bytes` tag, and handle it without making a call to this function. |
| 27950 | const arena = parent.beginArena(sema.mod); |
| 27951 | defer parent.finishArena(sema.mod); |
| 27952 | |
| 27953 | const bytes = val_ptr.castTag(.bytes).?.data; |
| 27954 | const dest_len = parent.ty.arrayLenIncludingSentinel(mod); |
| 27955 | // bytes.len may be one greater than dest_len because of the case when |
| 27956 | // assigning `[N:S]T` to `[N]T`. This is allowed; the sentinel is omitted. |
| 27957 | assert(bytes.len >= dest_len); |
| 27958 | const elems = try arena.alloc(Value, @intCast(usize, dest_len)); |
| 27959 | for (elems, 0..) |*elem, i| { |
| 27960 | elem.* = try mod.intValue(elem_ty, bytes[i]); |
| 27961 | } |
| 27962 | |
| 27963 | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); |
| 28036 | 27964 | |
| 28037 | 27965 | return beginComptimePtrMutationInner( |
| 28038 | 27966 | sema, |
| 28039 | 27967 | block, |
| 28040 | 27968 | src, |
| 28041 | | parent.ty.structFieldType(field_index, mod), |
| 28042 | | &fields[field_index], |
| 27969 | elem_ty, |
| 27970 | &elems[elem_ptr.index], |
| 28043 | 27971 | ptr_elem_ty, |
| 28044 | | parent.decl_ref_mut, |
| 27972 | parent.mut_decl, |
| 28045 | 27973 | ); |
| 28046 | 27974 | }, |
| 28047 | | .Union => { |
| 28048 | | const payload = try arena.create(Value.Payload.Union); |
| 28049 | | const tag_ty = parent.ty.unionTagTypeHypothetical(mod); |
| 28050 | | payload.* = .{ .data = .{ |
| 28051 | | .tag = try mod.enumValueFieldIndex(tag_ty, field_index), |
| 28052 | | .val = Value.undef, |
| 28053 | | } }; |
| 27975 | .repeated => { |
| 27976 | // An array is memory-optimized to store only a single element value, and |
| 27977 | // that value is understood to be the same for the entire length of the array. |
| 27978 | // However, now we want to modify an individual field and so the |
| 27979 | // representation has to change. If we wanted to avoid this, there would |
| 27980 | // need to be special detection elsewhere to identify when writing a value to an |
| 27981 | // array element that is stored using the `repeated` tag, and handle it |
| 27982 | // without making a call to this function. |
| 27983 | const arena = parent.beginArena(sema.mod); |
| 27984 | defer parent.finishArena(sema.mod); |
| 27985 | |
| 27986 | const repeated_val = try val_ptr.castTag(.repeated).?.data.copy(arena); |
| 27987 | const array_len_including_sentinel = |
| 27988 | try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel(mod)); |
| 27989 | const elems = try arena.alloc(Value, array_len_including_sentinel); |
| 27990 | if (elems.len > 0) elems[0] = repeated_val; |
| 27991 | for (elems[1..]) |*elem| { |
| 27992 | elem.* = try repeated_val.copy(arena); |
| 27993 | } |
| 28054 | 27994 | |
| 28055 | | val_ptr.* = Value.initPayload(&payload.base); |
| 27995 | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); |
| 28056 | 27996 | |
| 28057 | 27997 | return beginComptimePtrMutationInner( |
| 28058 | 27998 | sema, |
| 28059 | 27999 | block, |
| 28060 | 28000 | src, |
| 28061 | | parent.ty.structFieldType(field_index, mod), |
| 28062 | | &payload.data.val, |
| 28001 | elem_ty, |
| 28002 | &elems[elem_ptr.index], |
| 28063 | 28003 | ptr_elem_ty, |
| 28064 | | parent.decl_ref_mut, |
| 28004 | parent.mut_decl, |
| 28065 | 28005 | ); |
| 28066 | 28006 | }, |
| 28067 | | .Pointer => { |
| 28068 | | assert(parent.ty.isSlice(mod)); |
| 28069 | | val_ptr.* = try Value.Tag.slice.create(arena, .{ |
| 28070 | | .ptr = Value.undef, |
| 28071 | | .len = Value.undef, |
| 28072 | | }); |
| 28073 | | |
| 28074 | | switch (field_index) { |
| 28075 | | Value.Payload.Slice.ptr_index => return beginComptimePtrMutationInner( |
| 28076 | | sema, |
| 28077 | | block, |
| 28078 | | src, |
| 28079 | | parent.ty.slicePtrFieldType(mod), |
| 28080 | | &val_ptr.castTag(.slice).?.data.ptr, |
| 28081 | | ptr_elem_ty, |
| 28082 | | parent.decl_ref_mut, |
| 28083 | | ), |
| 28084 | | Value.Payload.Slice.len_index => return beginComptimePtrMutationInner( |
| 28085 | | sema, |
| 28086 | | block, |
| 28087 | | src, |
| 28088 | | Type.usize, |
| 28089 | | &val_ptr.castTag(.slice).?.data.len, |
| 28090 | | ptr_elem_ty, |
| 28091 | | parent.decl_ref_mut, |
| 28092 | | ), |
| 28093 | | |
| 28094 | | else => unreachable, |
| 28095 | | } |
| 28096 | | }, |
| 28007 | |
| 28008 | .aggregate => return beginComptimePtrMutationInner( |
| 28009 | sema, |
| 28010 | block, |
| 28011 | src, |
| 28012 | elem_ty, |
| 28013 | &val_ptr.castTag(.aggregate).?.data[elem_ptr.index], |
| 28014 | ptr_elem_ty, |
| 28015 | parent.mut_decl, |
| 28016 | ), |
| 28017 | |
| 28097 | 28018 | else => unreachable, |
| 28098 | | } |
| 28099 | | }, |
| 28100 | | .empty_struct => { |
| 28101 | | const duped = try sema.arena.create(Value); |
| 28102 | | duped.* = Value.initTag(.the_only_possible_value); |
| 28103 | | return beginComptimePtrMutationInner( |
| 28104 | | sema, |
| 28105 | | block, |
| 28106 | | src, |
| 28107 | | parent.ty.structFieldType(field_index, mod), |
| 28108 | | duped, |
| 28109 | | ptr_elem_ty, |
| 28110 | | parent.decl_ref_mut, |
| 28111 | | ); |
| 28112 | | }, |
| 28113 | | .none => switch (val_ptr.tag()) { |
| 28114 | | .aggregate => return beginComptimePtrMutationInner( |
| 28115 | | sema, |
| 28116 | | block, |
| 28117 | | src, |
| 28118 | | parent.ty.structFieldType(field_index, mod), |
| 28119 | | &val_ptr.castTag(.aggregate).?.data[field_index], |
| 28120 | | ptr_elem_ty, |
| 28121 | | parent.decl_ref_mut, |
| 28122 | | ), |
| 28123 | | .repeated => { |
| 28124 | | const arena = parent.beginArena(sema.mod); |
| 28125 | | defer parent.finishArena(sema.mod); |
| 28019 | }, |
| 28020 | else => unreachable, |
| 28021 | } |
| 28022 | }, |
| 28023 | else => { |
| 28024 | if (elem_ptr.index != 0) { |
| 28025 | // TODO include a "declared here" note for the decl |
| 28026 | return sema.fail(block, src, "out of bounds comptime store of index {d}", .{ |
| 28027 | elem_ptr.index, |
| 28028 | }); |
| 28029 | } |
| 28030 | return beginComptimePtrMutationInner( |
| 28031 | sema, |
| 28032 | block, |
| 28033 | src, |
| 28034 | parent.ty, |
| 28035 | val_ptr, |
| 28036 | ptr_elem_ty, |
| 28037 | parent.mut_decl, |
| 28038 | ); |
| 28039 | }, |
| 28040 | }, |
| 28041 | .reinterpret => |reinterpret| { |
| 28042 | if (!base_elem_ty.hasWellDefinedLayout(mod)) { |
| 28043 | // Even though the parent value type has well-defined memory layout, our |
| 28044 | // pointer type does not. |
| 28045 | return ComptimePtrMutationKit{ |
| 28046 | .mut_decl = parent.mut_decl, |
| 28047 | .pointee = .bad_ptr_ty, |
| 28048 | .ty = base_elem_ty, |
| 28049 | }; |
| 28050 | } |
| 28126 | 28051 | |
| 28127 | | const elems = try arena.alloc(Value, parent.ty.structFieldCount(mod)); |
| 28128 | | @memset(elems, val_ptr.castTag(.repeated).?.data); |
| 28129 | | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); |
| 28052 | const elem_abi_size_u64 = try sema.typeAbiSize(base_elem_ty); |
| 28053 | const elem_abi_size = try sema.usizeCast(block, src, elem_abi_size_u64); |
| 28054 | return ComptimePtrMutationKit{ |
| 28055 | .mut_decl = parent.mut_decl, |
| 28056 | .pointee = .{ .reinterpret = .{ |
| 28057 | .val_ptr = reinterpret.val_ptr, |
| 28058 | .byte_offset = reinterpret.byte_offset + elem_abi_size * elem_ptr.index, |
| 28059 | } }, |
| 28060 | .ty = parent.ty, |
| 28061 | }; |
| 28062 | }, |
| 28063 | .bad_decl_ty, .bad_ptr_ty => return parent, |
| 28064 | } |
| 28065 | }, |
| 28066 | .field => |field_ptr| { |
| 28067 | const base_child_ty = mod.intern_pool.typeOf(field_ptr.base).toType().childType(mod); |
| 28068 | const field_index = @intCast(u32, field_ptr.index); |
| 28069 | |
| 28070 | var parent = try sema.beginComptimePtrMutation(block, src, field_ptr.base.toValue(), base_child_ty); |
| 28071 | switch (parent.pointee) { |
| 28072 | .direct => |val_ptr| switch (val_ptr.ip_index) { |
| 28073 | .undef => { |
| 28074 | // A struct or union has been initialized to undefined at comptime and now we |
| 28075 | // are for the first time setting a field. We must change the representation |
| 28076 | // of the struct/union from `undef` to `struct`/`union`. |
| 28077 | const arena = parent.beginArena(sema.mod); |
| 28078 | defer parent.finishArena(sema.mod); |
| 28079 | |
| 28080 | switch (parent.ty.zigTypeTag(mod)) { |
| 28081 | .Struct => { |
| 28082 | const fields = try arena.alloc(Value, parent.ty.structFieldCount(mod)); |
| 28083 | @memset(fields, Value.undef); |
| 28084 | |
| 28085 | val_ptr.* = try Value.Tag.aggregate.create(arena, fields); |
| 28130 | 28086 | |
| 28131 | 28087 | return beginComptimePtrMutationInner( |
| 28132 | 28088 | sema, |
| 28133 | 28089 | block, |
| 28134 | 28090 | src, |
| 28135 | 28091 | parent.ty.structFieldType(field_index, mod), |
| 28136 | | &elems[field_index], |
| 28092 | &fields[field_index], |
| 28137 | 28093 | ptr_elem_ty, |
| 28138 | | parent.decl_ref_mut, |
| 28094 | parent.mut_decl, |
| 28139 | 28095 | ); |
| 28140 | 28096 | }, |
| 28141 | | .@"union" => { |
| 28142 | | // We need to set the active field of the union. |
| 28143 | | const union_tag_ty = field_ptr.container_ty.unionTagTypeHypothetical(mod); |
| 28097 | .Union => { |
| 28098 | const payload = try arena.create(Value.Payload.Union); |
| 28099 | const tag_ty = parent.ty.unionTagTypeHypothetical(mod); |
| 28100 | payload.* = .{ .data = .{ |
| 28101 | .tag = try mod.enumValueFieldIndex(tag_ty, field_index), |
| 28102 | .val = Value.undef, |
| 28103 | } }; |
| 28144 | 28104 | |
| 28145 | | const payload = &val_ptr.castTag(.@"union").?.data; |
| 28146 | | payload.tag = try mod.enumValueFieldIndex(union_tag_ty, field_index); |
| 28105 | val_ptr.* = Value.initPayload(&payload.base); |
| 28147 | 28106 | |
| 28148 | 28107 | return beginComptimePtrMutationInner( |
| 28149 | 28108 | sema, |
| 28150 | 28109 | block, |
| 28151 | 28110 | src, |
| 28152 | 28111 | parent.ty.structFieldType(field_index, mod), |
| 28153 | | &payload.val, |
| 28112 | &payload.data.val, |
| 28154 | 28113 | ptr_elem_ty, |
| 28155 | | parent.decl_ref_mut, |
| 28114 | parent.mut_decl, |
| 28156 | 28115 | ); |
| 28157 | 28116 | }, |
| 28158 | | .slice => switch (field_index) { |
| 28159 | | Value.Payload.Slice.ptr_index => return beginComptimePtrMutationInner( |
| 28160 | | sema, |
| 28161 | | block, |
| 28162 | | src, |
| 28163 | | parent.ty.slicePtrFieldType(mod), |
| 28164 | | &val_ptr.castTag(.slice).?.data.ptr, |
| 28165 | | ptr_elem_ty, |
| 28166 | | parent.decl_ref_mut, |
| 28167 | | ), |
| 28117 | .Pointer => { |
| 28118 | assert(parent.ty.isSlice(mod)); |
| 28119 | val_ptr.* = try Value.Tag.slice.create(arena, .{ |
| 28120 | .ptr = Value.undef, |
| 28121 | .len = Value.undef, |
| 28122 | }); |
| 28168 | 28123 | |
| 28169 | | Value.Payload.Slice.len_index => return beginComptimePtrMutationInner( |
| 28170 | | sema, |
| 28171 | | block, |
| 28172 | | src, |
| 28173 | | Type.usize, |
| 28174 | | &val_ptr.castTag(.slice).?.data.len, |
| 28175 | | ptr_elem_ty, |
| 28176 | | parent.decl_ref_mut, |
| 28177 | | ), |
| 28124 | switch (field_index) { |
| 28125 | Value.slice_ptr_index => return beginComptimePtrMutationInner( |
| 28126 | sema, |
| 28127 | block, |
| 28128 | src, |
| 28129 | parent.ty.slicePtrFieldType(mod), |
| 28130 | &val_ptr.castTag(.slice).?.data.ptr, |
| 28131 | ptr_elem_ty, |
| 28132 | parent.mut_decl, |
| 28133 | ), |
| 28134 | Value.slice_len_index => return beginComptimePtrMutationInner( |
| 28135 | sema, |
| 28136 | block, |
| 28137 | src, |
| 28138 | Type.usize, |
| 28139 | &val_ptr.castTag(.slice).?.data.len, |
| 28140 | ptr_elem_ty, |
| 28141 | parent.mut_decl, |
| 28142 | ), |
| 28178 | 28143 | |
| 28179 | | else => unreachable, |
| 28144 | else => unreachable, |
| 28145 | } |
| 28180 | 28146 | }, |
| 28181 | | |
| 28182 | 28147 | else => unreachable, |
| 28183 | | }, |
| 28184 | | else => unreachable, |
| 28148 | } |
| 28185 | 28149 | }, |
| 28186 | | .reinterpret => |reinterpret| { |
| 28187 | | const field_offset_u64 = field_ptr.container_ty.structFieldOffset(field_index, mod); |
| 28188 | | const field_offset = try sema.usizeCast(block, src, field_offset_u64); |
| 28189 | | return ComptimePtrMutationKit{ |
| 28190 | | .decl_ref_mut = parent.decl_ref_mut, |
| 28191 | | .pointee = .{ .reinterpret = .{ |
| 28192 | | .val_ptr = reinterpret.val_ptr, |
| 28193 | | .byte_offset = reinterpret.byte_offset + field_offset, |
| 28194 | | } }, |
| 28195 | | .ty = parent.ty, |
| 28196 | | }; |
| 28150 | .empty_struct => { |
| 28151 | const duped = try sema.arena.create(Value); |
| 28152 | duped.* = val_ptr.*; |
| 28153 | return beginComptimePtrMutationInner( |
| 28154 | sema, |
| 28155 | block, |
| 28156 | src, |
| 28157 | parent.ty.structFieldType(field_index, mod), |
| 28158 | duped, |
| 28159 | ptr_elem_ty, |
| 28160 | parent.mut_decl, |
| 28161 | ); |
| 28197 | 28162 | }, |
| 28198 | | .bad_decl_ty, .bad_ptr_ty => return parent, |
| 28199 | | } |
| 28200 | | }, |
| 28201 | | .eu_payload_ptr => { |
| 28202 | | const eu_ptr = ptr_val.castTag(.eu_payload_ptr).?.data; |
| 28203 | | var parent = try sema.beginComptimePtrMutation(block, src, eu_ptr.container_ptr, eu_ptr.container_ty); |
| 28204 | | switch (parent.pointee) { |
| 28205 | | .direct => |val_ptr| { |
| 28206 | | const payload_ty = parent.ty.errorUnionPayload(mod); |
| 28207 | | if (val_ptr.ip_index == .none and val_ptr.tag() == .eu_payload) { |
| 28208 | | return ComptimePtrMutationKit{ |
| 28209 | | .decl_ref_mut = parent.decl_ref_mut, |
| 28210 | | .pointee = .{ .direct = &val_ptr.castTag(.eu_payload).?.data }, |
| 28211 | | .ty = payload_ty, |
| 28212 | | }; |
| 28213 | | } else { |
| 28214 | | // An error union has been initialized to undefined at comptime and now we |
| 28215 | | // are for the first time setting the payload. We must change the |
| 28216 | | // representation of the error union from `undef` to `opt_payload`. |
| 28163 | .none => switch (val_ptr.tag()) { |
| 28164 | .aggregate => return beginComptimePtrMutationInner( |
| 28165 | sema, |
| 28166 | block, |
| 28167 | src, |
| 28168 | parent.ty.structFieldType(field_index, mod), |
| 28169 | &val_ptr.castTag(.aggregate).?.data[field_index], |
| 28170 | ptr_elem_ty, |
| 28171 | parent.mut_decl, |
| 28172 | ), |
| 28173 | .repeated => { |
| 28217 | 28174 | const arena = parent.beginArena(sema.mod); |
| 28218 | 28175 | defer parent.finishArena(sema.mod); |
| 28219 | 28176 | |
| 28220 | | const payload = try arena.create(Value.Payload.SubValue); |
| 28221 | | payload.* = .{ |
| 28222 | | .base = .{ .tag = .eu_payload }, |
| 28223 | | .data = Value.undef, |
| 28224 | | }; |
| 28177 | const elems = try arena.alloc(Value, parent.ty.structFieldCount(mod)); |
| 28178 | @memset(elems, val_ptr.castTag(.repeated).?.data); |
| 28179 | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); |
| 28225 | 28180 | |
| 28226 | | val_ptr.* = Value.initPayload(&payload.base); |
| 28181 | return beginComptimePtrMutationInner( |
| 28182 | sema, |
| 28183 | block, |
| 28184 | src, |
| 28185 | parent.ty.structFieldType(field_index, mod), |
| 28186 | &elems[field_index], |
| 28187 | ptr_elem_ty, |
| 28188 | parent.mut_decl, |
| 28189 | ); |
| 28190 | }, |
| 28191 | .@"union" => { |
| 28192 | // We need to set the active field of the union. |
| 28193 | const union_tag_ty = base_child_ty.unionTagTypeHypothetical(mod); |
| 28227 | 28194 | |
| 28228 | | return ComptimePtrMutationKit{ |
| 28229 | | .decl_ref_mut = parent.decl_ref_mut, |
| 28230 | | .pointee = .{ .direct = &payload.data }, |
| 28231 | | .ty = payload_ty, |
| 28232 | | }; |
| 28233 | | } |
| 28234 | | }, |
| 28235 | | .bad_decl_ty, .bad_ptr_ty => return parent, |
| 28236 | | // Even though the parent value type has well-defined memory layout, our |
| 28237 | | // pointer type does not. |
| 28238 | | .reinterpret => return ComptimePtrMutationKit{ |
| 28239 | | .decl_ref_mut = parent.decl_ref_mut, |
| 28240 | | .pointee = .bad_ptr_ty, |
| 28241 | | .ty = eu_ptr.container_ty, |
| 28242 | | }, |
| 28243 | | } |
| 28244 | | }, |
| 28245 | | .opt_payload_ptr => { |
| 28246 | | const opt_ptr = if (ptr_val.castTag(.opt_payload_ptr)) |some| some.data else { |
| 28247 | | return sema.beginComptimePtrMutation(block, src, ptr_val, ptr_elem_ty.optionalChild(mod)); |
| 28248 | | }; |
| 28249 | | var parent = try sema.beginComptimePtrMutation(block, src, opt_ptr.container_ptr, opt_ptr.container_ty); |
| 28250 | | switch (parent.pointee) { |
| 28251 | | .direct => |val_ptr| { |
| 28252 | | const payload_ty = parent.ty.optionalChild(mod); |
| 28253 | | switch (val_ptr.toIntern()) { |
| 28254 | | .undef, .null_value => { |
| 28255 | | // An optional has been initialized to undefined at comptime and now we |
| 28256 | | // are for the first time setting the payload. We must change the |
| 28257 | | // representation of the optional from `undef` to `opt_payload`. |
| 28258 | | const arena = parent.beginArena(sema.mod); |
| 28259 | | defer parent.finishArena(sema.mod); |
| 28195 | const payload = &val_ptr.castTag(.@"union").?.data; |
| 28196 | payload.tag = try mod.enumValueFieldIndex(union_tag_ty, field_index); |
| 28260 | 28197 | |
| 28261 | | const payload = try arena.create(Value.Payload.SubValue); |
| 28262 | | payload.* = .{ |
| 28263 | | .base = .{ .tag = .opt_payload }, |
| 28264 | | .data = Value.undef, |
| 28265 | | }; |
| 28198 | return beginComptimePtrMutationInner( |
| 28199 | sema, |
| 28200 | block, |
| 28201 | src, |
| 28202 | parent.ty.structFieldType(field_index, mod), |
| 28203 | &payload.val, |
| 28204 | ptr_elem_ty, |
| 28205 | parent.mut_decl, |
| 28206 | ); |
| 28207 | }, |
| 28208 | .slice => switch (field_index) { |
| 28209 | Value.slice_ptr_index => return beginComptimePtrMutationInner( |
| 28210 | sema, |
| 28211 | block, |
| 28212 | src, |
| 28213 | parent.ty.slicePtrFieldType(mod), |
| 28214 | &val_ptr.castTag(.slice).?.data.ptr, |
| 28215 | ptr_elem_ty, |
| 28216 | parent.mut_decl, |
| 28217 | ), |
| 28266 | 28218 | |
| 28267 | | val_ptr.* = Value.initPayload(&payload.base); |
| 28219 | Value.slice_len_index => return beginComptimePtrMutationInner( |
| 28220 | sema, |
| 28221 | block, |
| 28222 | src, |
| 28223 | Type.usize, |
| 28224 | &val_ptr.castTag(.slice).?.data.len, |
| 28225 | ptr_elem_ty, |
| 28226 | parent.mut_decl, |
| 28227 | ), |
| 28268 | 28228 | |
| 28269 | | return ComptimePtrMutationKit{ |
| 28270 | | .decl_ref_mut = parent.decl_ref_mut, |
| 28271 | | .pointee = .{ .direct = &payload.data }, |
| 28272 | | .ty = payload_ty, |
| 28273 | | }; |
| 28274 | | }, |
| 28275 | | .none => switch (val_ptr.tag()) { |
| 28276 | | .opt_payload => return ComptimePtrMutationKit{ |
| 28277 | | .decl_ref_mut = parent.decl_ref_mut, |
| 28278 | | .pointee = .{ .direct = &val_ptr.castTag(.opt_payload).?.data }, |
| 28279 | | .ty = payload_ty, |
| 28280 | | }, |
| 28229 | else => unreachable, |
| 28230 | }, |
| 28281 | 28231 | |
| 28282 | | else => return ComptimePtrMutationKit{ |
| 28283 | | .decl_ref_mut = parent.decl_ref_mut, |
| 28284 | | .pointee = .{ .direct = val_ptr }, |
| 28285 | | .ty = payload_ty, |
| 28286 | | }, |
| 28287 | | }, |
| 28288 | | else => return ComptimePtrMutationKit{ |
| 28289 | | .decl_ref_mut = parent.decl_ref_mut, |
| 28290 | | .pointee = .{ .direct = val_ptr }, |
| 28291 | | .ty = payload_ty, |
| 28292 | | }, |
| 28293 | | } |
| 28294 | | }, |
| 28295 | | .bad_decl_ty, .bad_ptr_ty => return parent, |
| 28296 | | // Even though the parent value type has well-defined memory layout, our |
| 28297 | | // pointer type does not. |
| 28298 | | .reinterpret => return ComptimePtrMutationKit{ |
| 28299 | | .decl_ref_mut = parent.decl_ref_mut, |
| 28300 | | .pointee = .bad_ptr_ty, |
| 28301 | | .ty = opt_ptr.container_ty, |
| 28232 | else => unreachable, |
| 28302 | 28233 | }, |
| 28303 | | } |
| 28304 | | }, |
| 28305 | | .decl_ref => unreachable, // isComptimeMutablePtr has been checked already |
| 28306 | | else => unreachable, |
| 28307 | | }, |
| 28308 | | else => switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr) { |
| 28309 | | else => unreachable, |
| 28234 | else => unreachable, |
| 28235 | }, |
| 28236 | .reinterpret => |reinterpret| { |
| 28237 | const field_offset_u64 = base_child_ty.structFieldOffset(field_index, mod); |
| 28238 | const field_offset = try sema.usizeCast(block, src, field_offset_u64); |
| 28239 | return ComptimePtrMutationKit{ |
| 28240 | .mut_decl = parent.mut_decl, |
| 28241 | .pointee = .{ .reinterpret = .{ |
| 28242 | .val_ptr = reinterpret.val_ptr, |
| 28243 | .byte_offset = reinterpret.byte_offset + field_offset, |
| 28244 | } }, |
| 28245 | .ty = parent.ty, |
| 28246 | }; |
| 28247 | }, |
| 28248 | .bad_decl_ty, .bad_ptr_ty => return parent, |
| 28249 | } |
| 28310 | 28250 | }, |
| 28311 | 28251 | } |
| 28312 | 28252 | } |
| ... | ... | @@ -28418,6 +28358,7 @@ fn beginComptimePtrLoad( |
| 28418 | 28358 | .mut_decl => |mut_decl| mut_decl.decl, |
| 28419 | 28359 | else => unreachable, |
| 28420 | 28360 | }; |
| 28361 | const is_mutable = ptr.addr == .mut_decl; |
| 28421 | 28362 | const decl = mod.declPtr(decl_index); |
| 28422 | 28363 | const decl_tv = try decl.typedValue(); |
| 28423 | 28364 | if (decl.getVariable(mod) != null) return error.RuntimeLoad; |
| ... | ... | @@ -28426,7 +28367,7 @@ fn beginComptimePtrLoad( |
| 28426 | 28367 | break :blk ComptimePtrLoadKit{ |
| 28427 | 28368 | .parent = if (layout_defined) .{ .tv = decl_tv, .byte_offset = 0 } else null, |
| 28428 | 28369 | .pointee = decl_tv, |
| 28429 | | .is_mutable = false, |
| 28370 | .is_mutable = is_mutable, |
| 28430 | 28371 | .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null, |
| 28431 | 28372 | }; |
| 28432 | 28373 | }, |
| ... | ... | @@ -29411,7 +29352,7 @@ fn analyzeDeclVal( |
| 29411 | 29352 | const decl_ref = try sema.analyzeDeclRefInner(decl_index, false); |
| 29412 | 29353 | const result = try sema.analyzeLoad(block, src, decl_ref, src); |
| 29413 | 29354 | if (Air.refToIndex(result)) |index| { |
| 29414 | | if (sema.air_instructions.items(.tag)[index] == .constant and !block.is_typeof) { |
| 29355 | if (sema.air_instructions.items(.tag)[index] == .interned and !block.is_typeof) { |
| 29415 | 29356 | try sema.decl_val_table.put(sema.gpa, decl_index, result); |
| 29416 | 29357 | } |
| 29417 | 29358 | } |
| ... | ... | @@ -30049,8 +29990,8 @@ fn analyzeSlice( |
| 30049 | 29990 | const end_int = end_val.getUnsignedInt(mod).?; |
| 30050 | 29991 | const sentinel_index = try sema.usizeCast(block, end_src, end_int - start_int); |
| 30051 | 29992 | |
| 30052 | | const elem_ptr = try ptr_val.elemPtr(new_ptr_ty, sentinel_index, sema.mod); |
| 30053 | | const res = try sema.pointerDerefExtra(block, src, elem_ptr, elem_ty, false); |
| 29993 | const elem_ptr = try ptr_val.elemPtr(try sema.elemPtrType(new_ptr_ty, sentinel_index), sentinel_index, sema.mod); |
| 29994 | const res = try sema.pointerDerefExtra(block, src, elem_ptr, elem_ty); |
| 30054 | 29995 | const actual_sentinel = switch (res) { |
| 30055 | 29996 | .runtime_load => break :sentinel_check, |
| 30056 | 29997 | .val => |v| v, |
| ... | ... | @@ -33421,35 +33362,24 @@ fn addConstUndef(sema: *Sema, ty: Type) CompileError!Air.Inst.Ref { |
| 33421 | 33362 | } |
| 33422 | 33363 | |
| 33423 | 33364 | pub fn addConstant(sema: *Sema, ty: Type, val: Value) SemaError!Air.Inst.Ref { |
| 33365 | const mod = sema.mod; |
| 33424 | 33366 | const gpa = sema.gpa; |
| 33425 | | if (val.ip_index != .none) { |
| 33426 | | if (@enumToInt(val.toIntern()) < Air.ref_start_index) |
| 33427 | | return @intToEnum(Air.Inst.Ref, @enumToInt(val.toIntern())); |
| 33428 | | try sema.air_instructions.append(gpa, .{ |
| 33429 | | .tag = .interned, |
| 33430 | | .data = .{ .interned = val.toIntern() }, |
| 33431 | | }); |
| 33432 | | const result = Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1)); |
| 33433 | | // This assertion can be removed when the `ty` parameter is removed from |
| 33434 | | // this function thanks to the InternPool transition being complete. |
| 33435 | | if (std.debug.runtime_safety) { |
| 33436 | | const val_ty = sema.typeOf(result); |
| 33437 | | if (!Type.eql(val_ty, ty, sema.mod)) { |
| 33438 | | std.debug.panic("addConstant type mismatch: '{}' vs '{}'\n", .{ |
| 33439 | | ty.fmt(sema.mod), val_ty.fmt(sema.mod), |
| 33440 | | }); |
| 33441 | | } |
| 33367 | |
| 33368 | // This assertion can be removed when the `ty` parameter is removed from |
| 33369 | // this function thanks to the InternPool transition being complete. |
| 33370 | if (std.debug.runtime_safety) { |
| 33371 | const val_ty = mod.intern_pool.typeOf(val.toIntern()); |
| 33372 | if (ty.toIntern() != val_ty) { |
| 33373 | std.debug.panic("addConstant type mismatch: '{}' vs '{}'\n", .{ |
| 33374 | ty.fmt(mod), val_ty.toType().fmt(mod), |
| 33375 | }); |
| 33442 | 33376 | } |
| 33443 | | return result; |
| 33444 | 33377 | } |
| 33445 | | const ty_inst = try sema.addType(ty); |
| 33446 | | try sema.air_values.append(gpa, val); |
| 33378 | if (@enumToInt(val.toIntern()) < Air.ref_start_index) |
| 33379 | return @intToEnum(Air.Inst.Ref, @enumToInt(val.toIntern())); |
| 33447 | 33380 | try sema.air_instructions.append(gpa, .{ |
| 33448 | | .tag = .constant, |
| 33449 | | .data = .{ .ty_pl = .{ |
| 33450 | | .ty = ty_inst, |
| 33451 | | .payload = @intCast(u32, sema.air_values.items.len - 1), |
| 33452 | | } }, |
| 33381 | .tag = .interned, |
| 33382 | .data = .{ .interned = val.toIntern() }, |
| 33453 | 33383 | }); |
| 33454 | 33384 | return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1)); |
| 33455 | 33385 | } |
| ... | ... | @@ -33606,7 +33536,7 @@ pub fn analyzeAddressSpace( |
| 33606 | 33536 | fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr_ty: Type) CompileError!?Value { |
| 33607 | 33537 | const mod = sema.mod; |
| 33608 | 33538 | const load_ty = ptr_ty.childType(mod); |
| 33609 | | const res = try sema.pointerDerefExtra(block, src, ptr_val, load_ty, true); |
| 33539 | const res = try sema.pointerDerefExtra(block, src, ptr_val, load_ty); |
| 33610 | 33540 | switch (res) { |
| 33611 | 33541 | .runtime_load => return null, |
| 33612 | 33542 | .val => |v| return v, |
| ... | ... | @@ -33632,7 +33562,7 @@ const DerefResult = union(enum) { |
| 33632 | 33562 | out_of_bounds: Type, |
| 33633 | 33563 | }; |
| 33634 | 33564 | |
| 33635 | | fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, load_ty: Type, want_mutable: bool) CompileError!DerefResult { |
| 33565 | fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, load_ty: Type) CompileError!DerefResult { |
| 33636 | 33566 | const mod = sema.mod; |
| 33637 | 33567 | const target = mod.getTarget(); |
| 33638 | 33568 | const deref = sema.beginComptimePtrLoad(block, src, ptr_val, load_ty) catch |err| switch (err) { |
| ... | ... | @@ -33647,13 +33577,8 @@ fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value |
| 33647 | 33577 | if (coerce_in_mem_ok) { |
| 33648 | 33578 | // We have a Value that lines up in virtual memory exactly with what we want to load, |
| 33649 | 33579 | // and it is in-memory coercible to load_ty. It may be returned without modifications. |
| 33650 | | if (deref.is_mutable and want_mutable) { |
| 33651 | | // The decl whose value we are obtaining here may be overwritten with |
| 33652 | | // a different value upon further semantic analysis, which would |
| 33653 | | // invalidate this memory. So we must copy here. |
| 33654 | | return DerefResult{ .val = try tv.val.copy(sema.arena) }; |
| 33655 | | } |
| 33656 | | return DerefResult{ .val = tv.val }; |
| 33580 | // Move mutable decl values to the InternPool and assert other decls are already in the InternPool. |
| 33581 | return .{ .val = (if (deref.is_mutable) try tv.val.intern(tv.ty, mod) else tv.val.toIntern()).toValue() }; |
| 33657 | 33582 | } |
| 33658 | 33583 | } |
| 33659 | 33584 | |