authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-07 11:26:07-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-07 11:26:07-07:00
log4e8fb9e6a5f9a65bbf6469e386e83ba469e7543b
tree804cac2f05b76ab8c76925b3104dd19ec0e4be44
parent01a39fa1d4d0d2e3305af8e6d6af1079f020db7f

Sema: DRY up enum field analysis and add "declared here" notes


5 files changed, 113 insertions(+), 71 deletions(-)

src/Module.zig+21
......@@ -366,6 +366,13 @@ pub const ErrorSet = struct {
366366 /// The string bytes are stored in the owner Decl arena.
367367 /// They are in the same order they appear in the AST.
368368 names_ptr: [*]const []const u8,
369
370 pub fn srcLoc(self: ErrorSet) SrcLoc {
371 return .{
372 .container = .{ .decl = self.owner_decl },
373 .lazy = .{ .node_offset = self.node_offset },
374 };
375 }
369376};
370377
371378/// Represents the data that a struct declaration provides.
......@@ -408,6 +415,13 @@ pub const EnumSimple = struct {
408415 fields: std.StringArrayHashMapUnmanaged(void),
409416 /// Offset from `owner_decl`, points to the enum decl AST node.
410417 node_offset: i32,
418
419 pub fn srcLoc(self: EnumSimple) SrcLoc {
420 return .{
421 .container = .{ .decl = self.owner_decl },
422 .lazy = .{ .node_offset = self.node_offset },
423 };
424 }
411425};
412426
413427/// Represents the data that an enum declaration provides, when there is
......@@ -429,6 +443,13 @@ pub const EnumFull = struct {
429443 node_offset: i32,
430444
431445 pub const ValueMap = std.ArrayHashMapUnmanaged(Value, void, Value.hash_u32, Value.eql, false);
446
447 pub fn srcLoc(self: EnumFull) SrcLoc {
448 return .{
449 .container = .{ .decl = self.owner_decl },
450 .lazy = .{ .node_offset = self.node_offset },
451 };
452 }
432453};
433454
434455/// Some Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator.
src/Sema.zig+48-66
......@@ -897,7 +897,7 @@ fn zirValidateStructInitPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Ind
897897 try mod.errNoteNonLazy(
898898 struct_obj.srcLoc(),
899899 msg,
900 "'{s}' declared here",
900 "struct '{s}' declared here",
901901 .{fqn},
902902 );
903903 return mod.failWithOwnedErrorMsg(&block.base, msg);
......@@ -925,7 +925,7 @@ fn failWithBadFieldAccess(
925925 .{ field_name, fqn },
926926 );
927927 errdefer msg.destroy(gpa);
928 try mod.errNoteNonLazy(struct_obj.srcLoc(), msg, "'{s}' declared here", .{fqn});
928 try mod.errNoteNonLazy(struct_obj.srcLoc(), msg, "struct declared here", .{});
929929 break :msg msg;
930930 };
931931 return mod.failWithOwnedErrorMsg(&block.base, msg);
......@@ -4479,21 +4479,24 @@ fn namedFieldPtr(
44794479 return sema.analyzeDeclRef(block, src, decl);
44804480 }
44814481 }
4482 const maybe_field_index: ?usize = switch (child_type.tag()) {
4483 .enum_full, .enum_nonexhaustive => blk: {
4484 const enum_full = child_type.castTag(.enum_full).?.data;
4485 break :blk enum_full.fields.getIndex(field_name);
4486 },
4487 .enum_simple => blk: {
4488 const enum_simple = child_type.castTag(.enum_simple).?.data;
4489 break :blk enum_simple.fields.getIndex(field_name);
4490 },
4491 else => unreachable,
4492 };
4493 const field_index = maybe_field_index orelse {
4494 return mod.fail(&block.base, src, "enum '{}' has no member named '{s}'", .{
4495 child_type, field_name,
4496 });
4482 const field_index = child_type.enumFieldIndex(field_name) orelse {
4483 const msg = msg: {
4484 const msg = try mod.errMsg(
4485 &block.base,
4486 src,
4487 "enum '{}' has no member named '{s}'",
4488 .{ child_type, field_name },
4489 );
4490 errdefer msg.destroy(sema.gpa);
4491 try mod.errNoteNonLazy(
4492 child_type.declSrcLoc(),
4493 msg,
4494 "enum declared here",
4495 .{},
4496 );
4497 break :msg msg;
4498 };
4499 return mod.failWithOwnedErrorMsg(&block.base, msg);
44974500 };
44984501 const field_index_u32 = @intCast(u32, field_index);
44994502 const enum_val = try Value.Tag.enum_field_index.create(arena, field_index_u32);
......@@ -4593,10 +4596,13 @@ fn coerce(
45934596 return sema.bitcast(block, dest_type, inst);
45944597 }
45954598
4599 const mod = sema.mod;
4600 const arena = sema.arena;
4601
45964602 // undefined to anything
45974603 if (inst.value()) |val| {
45984604 if (val.isUndef() or inst.ty.zigTypeTag() == .Undefined) {
4599 return sema.mod.constInst(sema.arena, inst_src, .{ .ty = dest_type, .val = val });
4605 return mod.constInst(arena, inst_src, .{ .ty = dest_type, .val = val });
46004606 }
46014607 }
46024608 assert(inst.ty.zigTypeTag() != .Undefined);
......@@ -4610,13 +4616,13 @@ fn coerce(
46104616 if (try sema.coerceNum(block, dest_type, inst)) |some|
46114617 return some;
46124618
4613 const target = sema.mod.getTarget();
4619 const target = mod.getTarget();
46144620
46154621 switch (dest_type.zigTypeTag()) {
46164622 .Optional => {
46174623 // null to ?T
46184624 if (inst.ty.zigTypeTag() == .Null) {
4619 return sema.mod.constInst(sema.arena, inst_src, .{ .ty = dest_type, .val = Value.initTag(.null_value) });
4625 return mod.constInst(arena, inst_src, .{ .ty = dest_type, .val = Value.initTag(.null_value) });
46204626 }
46214627
46224628 // T to ?T
......@@ -4703,63 +4709,39 @@ fn coerce(
47034709 }
47044710 },
47054711 .Enum => {
4712 // enum literal to enum
47064713 if (inst.ty.zigTypeTag() == .EnumLiteral) {
4707 const val = (try sema.resolveDefinedValue(block, inst_src, inst)).?;
4714 const val = try sema.resolveConstValue(block, inst_src, inst);
47084715 const bytes = val.castTag(.enum_literal).?.data;
4709 switch (dest_type.tag()) {
4710 .enum_full => {
4711 const enumeration = dest_type.castTag(.enum_full).?.data;
4712 const enum_fields = enumeration.fields;
4713 const i = enum_fields.getIndex(bytes) orelse return sema.mod.fail(
4716 const field_index = dest_type.enumFieldIndex(bytes) orelse {
4717 const msg = msg: {
4718 const msg = try mod.errMsg(
47144719 &block.base,
47154720 inst_src,
4716 "enum '{s}' has no field named '{s}'",
4717 .{ enumeration.owner_decl.name, bytes },
4721 "enum '{}' has no field named '{s}'",
4722 .{ dest_type, bytes },
47184723 );
4719 const val_pl = try Value.Tag.enum_field_index.create(sema.arena, @intCast(u32, i));
4720 return sema.mod.constInst(sema.arena, inst_src, .{
4721 .ty = dest_type,
4722 .val = val_pl,
4723 });
4724 },
4725 .enum_simple => {
4726 const enumeration = dest_type.castTag(.enum_simple).?.data;
4727 const enum_fields = enumeration.fields;
4728 const i = enum_fields.getIndex(bytes) orelse return sema.mod.fail(
4729 &block.base,
4730 inst_src,
4731 "enum '{s}' has no field named '{s}'",
4732 .{ enumeration.owner_decl.name, bytes },
4733 );
4734 const val_pl = try Value.Tag.enum_field_index.create(sema.arena, @intCast(u32, i));
4735 return sema.mod.constInst(sema.arena, inst_src, .{
4736 .ty = dest_type,
4737 .val = val_pl,
4738 });
4739 },
4740 .enum_nonexhaustive => {
4741 const enumeration = dest_type.castTag(.enum_nonexhaustive).?.data;
4742 const enum_fields = enumeration.fields;
4743 const i = enum_fields.getIndex(bytes) orelse return sema.mod.fail(
4744 &block.base,
4745 inst_src,
4746 "enum '{s}' has no field named '{s}'",
4747 .{ enumeration.owner_decl.name, bytes },
4724 errdefer msg.destroy(sema.gpa);
4725 try mod.errNoteNonLazy(
4726 dest_type.declSrcLoc(),
4727 msg,
4728 "enum declared here",
4729 .{},
47484730 );
4749 const val_pl = try Value.Tag.enum_field_index.create(sema.arena, @intCast(u32, i));
4750 return sema.mod.constInst(sema.arena, inst_src, .{
4751 .ty = dest_type,
4752 .val = val_pl,
4753 });
4754 },
4755 else => unreachable,
4756 }
4731 break :msg msg;
4732 };
4733 return mod.failWithOwnedErrorMsg(&block.base, msg);
4734 };
4735 return mod.constInst(arena, inst_src, .{
4736 .ty = dest_type,
4737 .val = try Value.Tag.enum_field_index.create(arena, @intCast(u32, field_index)),
4738 });
47574739 }
47584740 },
47594741 else => {},
47604742 }
47614743
4762 return sema.mod.fail(&block.base, inst_src, "expected {}, found {}", .{ dest_type, inst.ty });
4744 return mod.fail(&block.base, inst_src, "expected {}, found {}", .{ dest_type, inst.ty });
47634745}
47644746
47654747const InMemoryCoercionResult = enum {
src/type.zig+36
......@@ -2090,6 +2090,42 @@ pub const Type = extern union {
20902090 };
20912091 }
20922092
2093 pub fn enumFieldIndex(ty: Type, field_name: []const u8) ?usize {
2094 switch (ty.tag()) {
2095 .enum_full, .enum_nonexhaustive => {
2096 const enum_full = ty.cast(Payload.EnumFull).?.data;
2097 return enum_full.fields.getIndex(field_name);
2098 },
2099 .enum_simple => {
2100 const enum_simple = ty.castTag(.enum_simple).?.data;
2101 return enum_simple.fields.getIndex(field_name);
2102 },
2103 else => unreachable,
2104 }
2105 }
2106
2107 pub fn declSrcLoc(ty: Type) Module.SrcLoc {
2108 switch (ty.tag()) {
2109 .enum_full, .enum_nonexhaustive => {
2110 const enum_full = ty.cast(Payload.EnumFull).?.data;
2111 return enum_full.srcLoc();
2112 },
2113 .enum_simple => {
2114 const enum_simple = ty.castTag(.enum_simple).?.data;
2115 return enum_simple.srcLoc();
2116 },
2117 .@"struct" => {
2118 const struct_obj = ty.castTag(.@"struct").?.data;
2119 return struct_obj.srcLoc();
2120 },
2121 .error_set => {
2122 const error_set = ty.castTag(.error_set).?.data;
2123 return error_set.srcLoc();
2124 },
2125 else => unreachable,
2126 }
2127 }
2128
20932129 /// Asserts the type is an enum.
20942130 pub fn enumHasInt(ty: Type, int: Value, target: Target) bool {
20952131 const S = struct {
test/stage2/cbe.zig+2-2
......@@ -508,7 +508,7 @@ pub fn addCases(ctx: *TestContext) !void {
508508 \\}
509509 , &.{
510510 ":3:21: error: mising struct field: x",
511 ":1:15: note: 'Point' declared here",
511 ":1:15: note: struct 'Point' declared here",
512512 });
513513 case.addError(
514514 \\const Point = struct { x: i32, y: i32 };
......@@ -522,7 +522,7 @@ pub fn addCases(ctx: *TestContext) !void {
522522 \\}
523523 , &.{
524524 ":6:10: error: no field named 'z' in struct 'Point'",
525 ":1:15: note: 'Point' declared here",
525 ":1:15: note: struct declared here",
526526 });
527527 case.addCompareOutput(
528528 \\const Point = struct { x: i32, y: i32 };
test/stage2/test.zig+6-3
......@@ -1022,7 +1022,7 @@ pub fn addCases(ctx: *TestContext) !void {
10221022 "Hello, World!\n",
10231023 );
10241024 try case.files.append(.{
1025 .src =
1025 .src =
10261026 \\pub fn print() void {
10271027 \\ asm volatile ("syscall"
10281028 \\ :
......@@ -1621,11 +1621,11 @@ pub fn addCases(ctx: *TestContext) !void {
16211621 "",
16221622 );
16231623 case.addError(
1624 \\const E = enum { a, b };
16251624 \\export fn _start() noreturn {
16261625 \\ const a: E = .c;
16271626 \\ exit();
16281627 \\}
1628 \\const E = enum { a, b };
16291629 \\fn exit() noreturn {
16301630 \\ asm volatile ("syscall"
16311631 \\ :
......@@ -1635,6 +1635,9 @@ pub fn addCases(ctx: *TestContext) !void {
16351635 \\ );
16361636 \\ unreachable;
16371637 \\}
1638 , &.{":3:19: error: enum 'E' has no field named 'c'"});
1638 , &.{
1639 ":2:19: error: enum 'E' has no field named 'c'",
1640 ":5:11: note: enum declared here",
1641 });
16391642 }
16401643}