diff options
| author | Veikka Tuominen <git@vexu.eu> | 2022-07-28 14:58:20 +0300 |
|---|---|---|
| committer | Veikka Tuominen <git@vexu.eu> | 2022-07-29 10:12:36 +0300 |
| commit | fdaf9c40d6a351477aacb1af27871f3de12d485e (patch) | |
| tree | 1060d38a06a0889cd89eed6bd0522d487772d37c /src/Sema.zig | |
| parent | 9e0a930ce3be01923602adbfee13b50842da08b7 (diff) | |
| download | zig-fdaf9c40d6a351477aacb1af27871f3de12d485e.tar.gz zig-fdaf9c40d6a351477aacb1af27871f3de12d485e.zip | |
stage2: handle tuple init edge cases
Diffstat (limited to 'src/Sema.zig')
| -rw-r--r-- | src/Sema.zig | 126 |
1 files changed, 105 insertions, 21 deletions
diff --git a/src/Sema.zig b/src/Sema.zig index 5a70679b8d..74c8f0b48d 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -3493,19 +3493,43 @@ fn validateArrayInitTy( block: *Block, inst: Zir.Inst.Index, ) CompileError!void { - const inst_data = sema.code.instructions.items(.data)[inst].un_node; + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; const src = inst_data.src(); - const ty = try sema.resolveType(block, src, inst_data.operand); + const ty_src: LazySrcLoc = .{ .node_offset_init_ty = inst_data.src_node }; + const extra = sema.code.extraData(Zir.Inst.ArrayInit, inst_data.payload_index).data; + const ty = try sema.resolveType(block, ty_src, extra.ty); switch (ty.zigTypeTag()) { - .Array, .Vector => return, + .Array => { + const array_len = ty.arrayLen(); + if (extra.init_count != array_len) { + return sema.fail(block, src, "expected {d} array elements; found {d}", .{ + array_len, extra.init_count, + }); + } + return; + }, + .Vector => { + const array_len = ty.arrayLen(); + if (extra.init_count != array_len) { + return sema.fail(block, src, "expected {d} vector elements; found {d}", .{ + array_len, extra.init_count, + }); + } + return; + }, .Struct => if (ty.isTuple()) { - // TODO validate element count + const array_len = ty.arrayLen(); + if (extra.init_count > array_len) { + return sema.fail(block, src, "expected at most {d} tuple fields; found {d}", .{ + array_len, extra.init_count, + }); + } return; }, else => {}, } - return sema.failWithArrayInitNotSupported(block, src, ty); + return sema.failWithArrayInitNotSupported(block, ty_src, ty); } fn validateStructInitTy( @@ -3741,6 +3765,15 @@ fn validateStructInit( const default_val = struct_ty.structFieldDefaultValue(i); if (default_val.tag() == .unreachable_value) { + if (struct_ty.isTuple()) { + const template = "missing tuple field with index {d}"; + if (root_msg) |msg| { + try sema.errNote(block, init_src, msg, template, .{i}); + } else { + root_msg = try sema.errMsg(block, init_src, template, .{i}); + } + continue; + } const field_name = struct_ty.structFieldName(i); const template = "missing struct field: {s}"; const args = .{field_name}; @@ -3753,7 +3786,10 @@ fn validateStructInit( } const field_src = init_src; // TODO better source location - const default_field_ptr = try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(u32, i), field_src, struct_ty, true); + const default_field_ptr = if (struct_ty.isTuple()) + try sema.tupleFieldPtr(block, init_src, struct_ptr, field_src, @intCast(u32, i), true) + else + try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(u32, i), field_src, struct_ty, true); const field_ty = sema.typeOf(default_field_ptr).childType(); const init = try sema.addConstant(field_ty, default_val); try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store); @@ -3868,6 +3904,15 @@ fn validateStructInit( const default_val = struct_ty.structFieldDefaultValue(i); if (default_val.tag() == .unreachable_value) { + if (struct_ty.isTuple()) { + const template = "missing tuple field with index {d}"; + if (root_msg) |msg| { + try sema.errNote(block, init_src, msg, template, .{i}); + } else { + root_msg = try sema.errMsg(block, init_src, template, .{i}); + } + continue; + } const field_name = struct_ty.structFieldName(i); const template = "missing struct field: {s}"; const args = .{field_name}; @@ -3911,7 +3956,10 @@ fn validateStructInit( if (field_ptr != 0) continue; const field_src = init_src; // TODO better source location - const default_field_ptr = try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(u32, i), field_src, struct_ty, true); + const default_field_ptr = if (struct_ty.isTuple()) + try sema.tupleFieldPtr(block, init_src, struct_ptr, field_src, @intCast(u32, i), true) + else + try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(u32, i), field_src, struct_ty, true); const field_ty = sema.typeOf(default_field_ptr).childType(); const init = try sema.addConstant(field_ty, field_values[i]); try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store); @@ -3934,15 +3982,24 @@ fn zirValidateArrayInit( const array_ty = sema.typeOf(array_ptr).childType(); const array_len = array_ty.arrayLen(); - if (instrs.len != array_len) { - if (array_ty.zigTypeTag() == .Array) { - return sema.fail(block, init_src, "expected {d} array elements; found {d}", .{ - array_len, instrs.len, - }); - } else { - return sema.fail(block, init_src, "expected {d} vector elements; found {d}", .{ - array_len, instrs.len, - }); + if (instrs.len != array_len and array_ty.isTuple()) { + const struct_obj = array_ty.castTag(.tuple).?.data; + var root_msg: ?*Module.ErrorMsg = null; + for (struct_obj.values) |default_val, i| { + if (i < instrs.len) continue; + + if (default_val.tag() == .unreachable_value) { + const template = "missing tuple field with index {d}"; + if (root_msg) |msg| { + try sema.errNote(block, init_src, msg, template, .{i}); + } else { + root_msg = try sema.errMsg(block, init_src, template, .{i}); + } + } + } + + if (root_msg) |msg| { + return sema.failWithOwnedErrorMsg(block, msg); } } @@ -3995,10 +4052,17 @@ fn zirValidateArrayInit( } first_block_index = @minimum(first_block_index, block_index); - // Array has one possible value, so value is always comptime-known - if (opt_opv) |opv| { - element_vals[i] = opv; - continue; + if (array_ty.isTuple()) { + if (array_ty.structFieldValueComptime(i)) |opv| { + element_vals[i] = opv; + continue; + } + } else { + // Array has one possible value, so value is always comptime-known + if (opt_opv) |opv| { + element_vals[i] = opv; + continue; + } } // If the next instructon is a store with a comptime operand, this element @@ -14710,6 +14774,22 @@ fn finishStructInit( field_inits[i] = try sema.addConstant(struct_obj.types[i], default_val); } } + } else if (struct_ty.isTuple()) { + const struct_obj = struct_ty.castTag(.tuple).?.data; + for (struct_obj.values) |default_val, i| { + if (field_inits[i] != .none) continue; + + if (default_val.tag() == .unreachable_value) { + const template = "missing tuple field with index {d}"; + if (root_msg) |msg| { + try sema.errNote(block, init_src, msg, template, .{i}); + } else { + root_msg = try sema.errMsg(block, init_src, template, .{i}); + } + } else { + field_inits[i] = try sema.addConstant(struct_obj.types[i], default_val); + } + } } else { const struct_obj = struct_ty.castTag(.@"struct").?.data; for (struct_obj.fields.values()) |field, i| { @@ -20255,7 +20335,7 @@ fn tupleFieldVal( return tupleFieldValByIndex(sema, block, src, tuple_byval, field_index, tuple_ty); } -/// Don't forget to check for "len" before calling this. +/// Asserts that `field_name` is not "len". fn tupleFieldIndex( sema: *Sema, block: *Block, @@ -20263,8 +20343,12 @@ fn tupleFieldIndex( field_name: []const u8, field_name_src: LazySrcLoc, ) CompileError!u32 { + assert(!std.mem.eql(u8, field_name, "len")); if (std.fmt.parseUnsigned(u32, field_name, 10)) |field_index| { if (field_index < tuple_ty.structFieldCount()) return field_index; + return sema.fail(block, field_name_src, "index '{s}' out of bounds of tuple '{}'", .{ + field_name, tuple_ty.fmt(sema.mod), + }); } else |_| {} return sema.fail(block, field_name_src, "no field named '{s}' in tuple '{}'", .{ |
