| ... | @@ -805,7 +805,12 @@ pub fn analyzeBody( | ... | @@ -805,7 +805,12 @@ pub fn analyzeBody( |
| 805 | continue; | 805 | continue; |
| 806 | }, | 806 | }, |
| 807 | .validate_struct_init => { | 807 | .validate_struct_init => { |
| 808 | try sema.zirValidateStructInit(block, inst); | 808 | try sema.zirValidateStructInit(block, inst, false); |
| | 809 | i += 1; |
| | 810 | continue; |
| | 811 | }, |
| | 812 | .validate_struct_init_comptime => { |
| | 813 | try sema.zirValidateStructInit(block, inst, true); |
| 809 | i += 1; | 814 | i += 1; |
| 810 | continue; | 815 | continue; |
| 811 | }, | 816 | }, |
| ... | @@ -2438,7 +2443,12 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com | ... | @@ -2438,7 +2443,12 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 2438 | } | 2443 | } |
| 2439 | } | 2444 | } |
| 2440 | | 2445 | |
| 2441 | fn zirValidateStructInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { | 2446 | fn zirValidateStructInit( |
| | 2447 | sema: *Sema, |
| | 2448 | block: *Block, |
| | 2449 | inst: Zir.Inst.Index, |
| | 2450 | is_comptime: bool, |
| | 2451 | ) CompileError!void { |
| 2442 | const tracy = trace(@src()); | 2452 | const tracy = trace(@src()); |
| 2443 | defer tracy.end(); | 2453 | defer tracy.end(); |
| 2444 | | 2454 | |
| ... | @@ -2456,6 +2466,7 @@ fn zirValidateStructInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi | ... | @@ -2456,6 +2466,7 @@ fn zirValidateStructInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi |
| 2456 | agg_ty.castTag(.@"struct").?.data, | 2466 | agg_ty.castTag(.@"struct").?.data, |
| 2457 | init_src, | 2467 | init_src, |
| 2458 | instrs, | 2468 | instrs, |
| | 2469 | is_comptime, |
| 2459 | ), | 2470 | ), |
| 2460 | .Union => return sema.validateUnionInit( | 2471 | .Union => return sema.validateUnionInit( |
| 2461 | block, | 2472 | block, |
| ... | @@ -2529,6 +2540,7 @@ fn validateStructInit( | ... | @@ -2529,6 +2540,7 @@ fn validateStructInit( |
| 2529 | struct_obj: *Module.Struct, | 2540 | struct_obj: *Module.Struct, |
| 2530 | init_src: LazySrcLoc, | 2541 | init_src: LazySrcLoc, |
| 2531 | instrs: []const Zir.Inst.Index, | 2542 | instrs: []const Zir.Inst.Index, |
| | 2543 | is_comptime: bool, |
| 2532 | ) CompileError!void { | 2544 | ) CompileError!void { |
| 2533 | const gpa = sema.gpa; | 2545 | const gpa = sema.gpa; |
| 2534 | | 2546 | |
| ... | @@ -2537,10 +2549,13 @@ fn validateStructInit( | ... | @@ -2537,10 +2549,13 @@ fn validateStructInit( |
| 2537 | defer gpa.free(found_fields); | 2549 | defer gpa.free(found_fields); |
| 2538 | mem.set(Zir.Inst.Index, found_fields, 0); | 2550 | mem.set(Zir.Inst.Index, found_fields, 0); |
| 2539 | | 2551 | |
| | 2552 | var struct_ptr_zir_ref: Zir.Inst.Ref = undefined; |
| | 2553 | |
| 2540 | for (instrs) |field_ptr| { | 2554 | for (instrs) |field_ptr| { |
| 2541 | const field_ptr_data = sema.code.instructions.items(.data)[field_ptr].pl_node; | 2555 | const field_ptr_data = sema.code.instructions.items(.data)[field_ptr].pl_node; |
| 2542 | const field_src: LazySrcLoc = .{ .node_offset_back2tok = field_ptr_data.src_node }; | 2556 | const field_src: LazySrcLoc = .{ .node_offset_back2tok = field_ptr_data.src_node }; |
| 2543 | const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data; | 2557 | const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data; |
| | 2558 | struct_ptr_zir_ref = field_ptr_extra.lhs; |
| 2544 | const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start); | 2559 | const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start); |
| 2545 | const field_index = struct_obj.fields.getIndex(field_name) orelse | 2560 | const field_index = struct_obj.fields.getIndex(field_name) orelse |
| 2546 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name); | 2561 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name); |
| ... | @@ -2561,19 +2576,127 @@ fn validateStructInit( | ... | @@ -2561,19 +2576,127 @@ fn validateStructInit( |
| 2561 | | 2576 | |
| 2562 | var root_msg: ?*Module.ErrorMsg = null; | 2577 | var root_msg: ?*Module.ErrorMsg = null; |
| 2563 | | 2578 | |
| 2564 | // TODO handle default struct field values | 2579 | const fields = struct_obj.fields.values(); |
| | 2580 | const struct_ptr = sema.resolveInst(struct_ptr_zir_ref); |
| | 2581 | const struct_ty = sema.typeOf(struct_ptr).childType(); |
| | 2582 | |
| | 2583 | if (is_comptime or block.is_comptime) { |
| | 2584 | // In this case the only thing we need to do is evaluate the implicit |
| | 2585 | // store instructions for default field values, and report any missing fields. |
| | 2586 | // Avoid the cost of the extra machinery for detecting a comptime struct init value. |
| | 2587 | for (found_fields) |field_ptr, i| { |
| | 2588 | if (field_ptr != 0) continue; |
| | 2589 | |
| | 2590 | const field = fields[i]; |
| | 2591 | const field_name = struct_obj.fields.keys()[i]; |
| | 2592 | |
| | 2593 | if (field.default_val.tag() == .unreachable_value) { |
| | 2594 | const template = "missing struct field: {s}"; |
| | 2595 | const args = .{field_name}; |
| | 2596 | if (root_msg) |msg| { |
| | 2597 | try sema.errNote(block, init_src, msg, template, args); |
| | 2598 | } else { |
| | 2599 | root_msg = try sema.errMsg(block, init_src, template, args); |
| | 2600 | } |
| | 2601 | continue; |
| | 2602 | } |
| | 2603 | |
| | 2604 | const default_field_ptr = try sema.structFieldPtr(block, init_src, struct_ptr, field_name, init_src, struct_ty); |
| | 2605 | const init = try sema.addConstant(field.ty, field.default_val); |
| | 2606 | const field_src = init_src; // TODO better source location |
| | 2607 | try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store); |
| | 2608 | } |
| | 2609 | |
| | 2610 | if (root_msg) |msg| { |
| | 2611 | const fqn = try struct_obj.getFullyQualifiedName(gpa); |
| | 2612 | defer gpa.free(fqn); |
| | 2613 | try sema.mod.errNoteNonLazy( |
| | 2614 | struct_obj.srcLoc(), |
| | 2615 | msg, |
| | 2616 | "struct '{s}' declared here", |
| | 2617 | .{fqn}, |
| | 2618 | ); |
| | 2619 | return sema.failWithOwnedErrorMsg(msg); |
| | 2620 | } |
| | 2621 | |
| | 2622 | return; |
| | 2623 | } |
| | 2624 | |
| | 2625 | var struct_is_comptime = true; |
| | 2626 | var first_block_index: usize = std.math.maxInt(u32); |
| | 2627 | |
| | 2628 | const air_tags = sema.air_instructions.items(.tag); |
| | 2629 | const air_datas = sema.air_instructions.items(.data); |
| | 2630 | |
| | 2631 | // We collect the comptime field values in case the struct initialization |
| | 2632 | // ends up being comptime-known. |
| | 2633 | const field_values = try sema.arena.alloc(Value, fields.len); |
| | 2634 | |
| 2565 | for (found_fields) |field_ptr, i| { | 2635 | for (found_fields) |field_ptr, i| { |
| 2566 | if (field_ptr != 0) continue; | 2636 | const field = fields[i]; |
| | 2637 | |
| | 2638 | if (field_ptr != 0) { |
| | 2639 | const field_ptr_data = sema.code.instructions.items(.data)[field_ptr].pl_node; |
| | 2640 | const field_src: LazySrcLoc = .{ .node_offset_back2tok = field_ptr_data.src_node }; |
| | 2641 | |
| | 2642 | // Determine whether the value stored to this pointer is comptime-known. |
| | 2643 | if (try sema.typeHasOnePossibleValue(block, field_src, field.ty)) |opv| { |
| | 2644 | field_values[i] = opv; |
| | 2645 | continue; |
| | 2646 | } |
| | 2647 | |
| | 2648 | const field_ptr_air_ref = sema.inst_map.get(field_ptr).?; |
| | 2649 | const field_ptr_air_inst = Air.refToIndex(field_ptr_air_ref).?; |
| | 2650 | // Find the block index of the field_ptr so that we can look at the next |
| | 2651 | // instruction after it within the same block. |
| | 2652 | // Possible performance enhancement: save the `block_index` between iterations |
| | 2653 | // of the for loop. |
| | 2654 | const next_air_inst = inst: { |
| | 2655 | var block_index = block.instructions.items.len - 1; |
| | 2656 | while (block.instructions.items[block_index] != field_ptr_air_inst) { |
| | 2657 | block_index -= 1; |
| | 2658 | } |
| | 2659 | first_block_index = @minimum(first_block_index, block_index); |
| | 2660 | break :inst block.instructions.items[block_index + 1]; |
| | 2661 | }; |
| | 2662 | |
| | 2663 | // If the next instructon is a store with a comptime operand, this field |
| | 2664 | // is comptime. |
| | 2665 | switch (air_tags[next_air_inst]) { |
| | 2666 | .store => { |
| | 2667 | const bin_op = air_datas[next_air_inst].bin_op; |
| | 2668 | if (bin_op.lhs != field_ptr_air_ref) { |
| | 2669 | struct_is_comptime = false; |
| | 2670 | continue; |
| | 2671 | } |
| | 2672 | if (try sema.resolveMaybeUndefValAllowVariables(block, field_src, bin_op.rhs)) |val| { |
| | 2673 | field_values[i] = val; |
| | 2674 | } else { |
| | 2675 | struct_is_comptime = false; |
| | 2676 | } |
| | 2677 | continue; |
| | 2678 | }, |
| | 2679 | else => { |
| | 2680 | struct_is_comptime = false; |
| | 2681 | continue; |
| | 2682 | }, |
| | 2683 | } |
| | 2684 | } |
| 2567 | | 2685 | |
| 2568 | const field_name = struct_obj.fields.keys()[i]; | 2686 | const field_name = struct_obj.fields.keys()[i]; |
| 2569 | const template = "missing struct field: {s}"; | 2687 | |
| 2570 | const args = .{field_name}; | 2688 | if (field.default_val.tag() == .unreachable_value) { |
| 2571 | if (root_msg) |msg| { | 2689 | const template = "missing struct field: {s}"; |
| 2572 | try sema.errNote(block, init_src, msg, template, args); | 2690 | const args = .{field_name}; |
| 2573 | } else { | 2691 | if (root_msg) |msg| { |
| 2574 | root_msg = try sema.errMsg(block, init_src, template, args); | 2692 | try sema.errNote(block, init_src, msg, template, args); |
| | 2693 | } else { |
| | 2694 | root_msg = try sema.errMsg(block, init_src, template, args); |
| | 2695 | } |
| | 2696 | continue; |
| 2575 | } | 2697 | } |
| 2576 | } | 2698 | } |
| | 2699 | |
| 2577 | if (root_msg) |msg| { | 2700 | if (root_msg) |msg| { |
| 2578 | const fqn = try struct_obj.getFullyQualifiedName(gpa); | 2701 | const fqn = try struct_obj.getFullyQualifiedName(gpa); |
| 2579 | defer gpa.free(fqn); | 2702 | defer gpa.free(fqn); |
| ... | @@ -2585,6 +2708,40 @@ fn validateStructInit( | ... | @@ -2585,6 +2708,40 @@ fn validateStructInit( |
| 2585 | ); | 2708 | ); |
| 2586 | return sema.failWithOwnedErrorMsg(msg); | 2709 | return sema.failWithOwnedErrorMsg(msg); |
| 2587 | } | 2710 | } |
| | 2711 | |
| | 2712 | if (struct_is_comptime) { |
| | 2713 | // Our task is to delete all the `field_ptr` and `store` instructions, and insert |
| | 2714 | // instead a single `store` to the struct_ptr with a comptime struct value. |
| | 2715 | |
| | 2716 | block.instructions.shrinkRetainingCapacity(first_block_index); |
| | 2717 | |
| | 2718 | // The `field_values` array has been populated for all the non-default struct |
| | 2719 | // fields. Here we fill in the default field values. |
| | 2720 | for (found_fields) |field_ptr, i| { |
| | 2721 | if (field_ptr != 0) continue; |
| | 2722 | |
| | 2723 | field_values[i] = fields[i].default_val; |
| | 2724 | } |
| | 2725 | |
| | 2726 | const struct_val = try Value.Tag.@"struct".create(sema.arena, field_values); |
| | 2727 | const struct_init = try sema.addConstant(struct_ty, struct_val); |
| | 2728 | try sema.storePtr2(block, init_src, struct_ptr, init_src, struct_init, init_src, .store); |
| | 2729 | return; |
| | 2730 | } |
| | 2731 | |
| | 2732 | // Our task is to insert `store` instructions for all the default field values. |
| | 2733 | |
| | 2734 | for (found_fields) |field_ptr, i| { |
| | 2735 | if (field_ptr != 0) continue; |
| | 2736 | |
| | 2737 | const field = fields[i]; |
| | 2738 | const field_name = struct_obj.fields.keys()[i]; |
| | 2739 | const default_field_ptr = try sema.structFieldPtr(block, init_src, struct_ptr, field_name, init_src, struct_ty); |
| | 2740 | |
| | 2741 | const init = try sema.addConstant(field.ty, field.default_val); |
| | 2742 | const field_src = init_src; // TODO better source location |
| | 2743 | try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store); |
| | 2744 | } |
| 2588 | } | 2745 | } |
| 2589 | | 2746 | |
| 2590 | fn zirValidateArrayInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { | 2747 | fn zirValidateArrayInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { |