diff --git a/src/Sema.zig b/src/Sema.zig index 6d684781c1..e675690a1e 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -14515,6 +14515,16 @@ fn zirStructInit( } found_fields[field_index] = item.data.field_type; field_inits[field_index] = try sema.resolveInst(item.data.init); + if (resolved_ty.structFieldValueComptime(field_index)) |default_value| { + const init_val = (try sema.resolveMaybeUndefVal(block, field_src, field_inits[field_index])) orelse { + return sema.failWithNeededComptime(block, field_src, "value stored in comptime field must be comptime known"); + }; + + if (!init_val.eql(default_value, resolved_ty.structFieldType(field_index), sema.mod)) { + // TODO add note showing where default value is provided + return sema.fail(block, field_src, "value stored in comptime field does not match the default value of the field", .{}); + } + } } return sema.finishStructInit(block, src, src, field_inits, resolved_ty, is_ref); @@ -23688,6 +23698,7 @@ fn coerceTupleToStruct( const struct_ty = try sema.resolveTypeFields(block, dest_ty_src, dest_ty); if (struct_ty.isTupleOrAnonStruct()) { + // NOTE remember to handle comptime fields return sema.fail(block, dest_ty_src, "TODO: implement coercion from tuples to tuples", .{}); } @@ -23708,12 +23719,19 @@ fn coerceTupleToStruct( try std.fmt.allocPrint(sema.arena, "{d}", .{i}); const field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src); const field = fields.values()[field_index]; - if (field.is_comptime) { - return sema.fail(block, dest_ty_src, "TODO: implement coercion from tuples to structs when one of the destination struct fields is comptime", .{}); - } const elem_ref = try tupleField(sema, block, inst_src, inst, field_src, i); const coerced = try sema.coerce(block, field.ty, elem_ref, field_src); field_refs[field_index] = coerced; + if (field.is_comptime) { + const init_val = (try sema.resolveMaybeUndefVal(block, field_src, coerced)) orelse { + return sema.failWithNeededComptime(block, field_src, "value stored in comptime field must be comptime known"); + }; + + if (!init_val.eql(field.default_val, field.ty, sema.mod)) { + // TODO add note showing where default value is provided + return sema.fail(block, field_src, "value stored in comptime field does not match the default value of the field", .{}); + } + } if (runtime_src == null) { if (try sema.resolveMaybeUndefVal(block, field_src, coerced)) |field_val| { field_vals[field_index] = field_val; diff --git a/test/cases/compile_errors/invalid_store_to_comptime_field.zig b/test/cases/compile_errors/invalid_store_to_comptime_field.zig index 7ae68692d7..63d83c01d1 100644 --- a/test/cases/compile_errors/invalid_store_to_comptime_field.zig +++ b/test/cases/compile_errors/invalid_store_to_comptime_field.zig @@ -20,6 +20,35 @@ pub export fn entry2() void { _ = list2; _ = list3; } +pub export fn entry3() void { + const U = struct { + comptime foo: u32 = 1, + bar: u32, + fn foo(x: @This()) void { + _ = x; + } + }; + _ = U.foo(U{ .foo = 2, .bar = 2 }); +} +pub export fn entry4() void { + const U = struct { + comptime foo: u32 = 1, + bar: u32, + fn foo(x: @This()) void { + _ = x; + } + }; + _ = U.foo(.{ .foo = 2, .bar = 2 }); +} +// pub export fn entry5() void { +// var x: u32 = 15; +// const T = @TypeOf(.{ @as(i32, -1234), @as(u32, 5678), x }); +// const S = struct { +// fn foo(_: T) void {} +// }; +// _ = S.foo(.{ -1234, 5679, x }); +// } + // error // target=native @@ -28,3 +57,5 @@ pub export fn entry2() void { // :6:19: error: value stored in comptime field does not match the default value of the field // :14:19: error: value stored in comptime field does not match the default value of the field // :19:38: error: value stored in comptime field does not match the default value of the field +// :31:19: error: value stored in comptime field does not match the default value of the field +// :41:14: error: value stored in comptime field does not match the default value of the field