authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-11 18:56:56-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-11 18:56:56-07:00
logd7567c06fd8bc1777f98e33abfe3070f698782ec
treecd0fd60109b7fe69e495c27019e2eef04942a96c
parent7873e4f5889f9e1b4d5b5f62d7701d7914b64ab1

Sema: implement duplicate enum tag compile error


2 files changed, 73 insertions(+), 4 deletions(-)

BRANCH_TODO+3
...@@ -62,3 +62,6 @@...@@ -62,3 +62,6 @@
62 - avoid the global atomic integer for the number because of contention62 - avoid the global atomic integer for the number because of contention
6363
64 * AstGen memory leak with `block_gz.labeled_store_to_block_ptr_list.append`64 * AstGen memory leak with `block_gz.labeled_store_to_block_ptr_list.append`
65
66 * in SwitchProng resolve, make sure AST tree gets loaded.
67 It will be unloaded if using cached ZIR.
src/Sema.zig+70-4
...@@ -715,6 +715,7 @@ fn zirStructDecl(...@@ -715,6 +715,7 @@ fn zirStructDecl(
715 } else sema.src;715 } else sema.src;
716716
717 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);717 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
718 errdefer new_decl_arena.deinit();
718719
719 const struct_obj = try new_decl_arena.allocator.create(Module.Struct);720 const struct_obj = try new_decl_arena.allocator.create(Module.Struct);
720 const struct_ty = try Type.Tag.@"struct".create(&new_decl_arena.allocator, struct_obj);721 const struct_ty = try Type.Tag.@"struct".create(&new_decl_arena.allocator, struct_obj);
...@@ -779,6 +780,7 @@ fn zirEnumDecl(...@@ -779,6 +780,7 @@ fn zirEnumDecl(
779 const tracy = trace(@src());780 const tracy = trace(@src());
780 defer tracy.end();781 defer tracy.end();
781782
783 const mod = sema.mod;
782 const gpa = sema.gpa;784 const gpa = sema.gpa;
783 const small = @bitCast(Zir.Inst.EnumDecl.Small, extended.small);785 const small = @bitCast(Zir.Inst.EnumDecl.Small, extended.small);
784 var extra_index: usize = extended.operand;786 var extra_index: usize = extended.operand;
...@@ -814,6 +816,7 @@ fn zirEnumDecl(...@@ -814,6 +816,7 @@ fn zirEnumDecl(
814 } else 0;816 } else 0;
815817
816 var new_decl_arena = std.heap.ArenaAllocator.init(gpa);818 var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
819 errdefer new_decl_arena.deinit();
817820
818 const tag_ty = blk: {821 const tag_ty = blk: {
819 if (tag_type_ref != .none) {822 if (tag_type_ref != .none) {
...@@ -835,7 +838,7 @@ fn zirEnumDecl(...@@ -835,7 +838,7 @@ fn zirEnumDecl(
835 const enum_ty = Type.initPayload(&enum_ty_payload.base);838 const enum_ty = Type.initPayload(&enum_ty_payload.base);
836 const enum_val = try Value.Tag.ty.create(&new_decl_arena.allocator, enum_ty);839 const enum_val = try Value.Tag.ty.create(&new_decl_arena.allocator, enum_ty);
837 const type_name = try sema.createTypeName(block, small.name_strategy);840 const type_name = try sema.createTypeName(block, small.name_strategy);
838 const new_decl = try sema.mod.createAnonymousDeclNamed(&block.base, .{841 const new_decl = try mod.createAnonymousDeclNamed(&block.base, .{
839 .ty = Type.initTag(.type),842 .ty = Type.initTag(.type),
840 .val = enum_val,843 .val = enum_val,
841 }, type_name);844 }, type_name);
...@@ -855,7 +858,7 @@ fn zirEnumDecl(...@@ -855,7 +858,7 @@ fn zirEnumDecl(
855 &enum_obj.namespace, new_decl, new_decl.name,858 &enum_obj.namespace, new_decl, new_decl.name,
856 });859 });
857860
858 extra_index = try sema.mod.scanNamespace(&enum_obj.namespace, extra_index, decls_len, new_decl);861 extra_index = try mod.scanNamespace(&enum_obj.namespace, extra_index, decls_len, new_decl);
859862
860 const body = sema.code.extra[extra_index..][0..body_len];863 const body = sema.code.extra[extra_index..][0..body_len];
861 if (fields_len == 0) {864 if (fields_len == 0) {
...@@ -883,7 +886,7 @@ fn zirEnumDecl(...@@ -883,7 +886,7 @@ fn zirEnumDecl(
883 // Within the field type, default value, and alignment expressions, the "owner decl"886 // Within the field type, default value, and alignment expressions, the "owner decl"
884 // should be the enum itself. Thus we need a new Sema.887 // should be the enum itself. Thus we need a new Sema.
885 var enum_sema: Sema = .{888 var enum_sema: Sema = .{
886 .mod = sema.mod,889 .mod = mod,
887 .gpa = gpa,890 .gpa = gpa,
888 .arena = &new_decl_arena.allocator,891 .arena = &new_decl_arena.allocator,
889 .code = sema.code,892 .code = sema.code,
...@@ -932,7 +935,18 @@ fn zirEnumDecl(...@@ -932,7 +935,18 @@ fn zirEnumDecl(
932 const field_name = try new_decl_arena.allocator.dupe(u8, field_name_zir);935 const field_name = try new_decl_arena.allocator.dupe(u8, field_name_zir);
933936
934 const gop = enum_obj.fields.getOrPutAssumeCapacity(field_name);937 const gop = enum_obj.fields.getOrPutAssumeCapacity(field_name);
935 assert(!gop.found_existing);938 if (gop.found_existing) {
939 const tree = try sema.getAstTree(block);
940 const field_src = enumFieldSrcLoc(block.src_decl, tree.*, src.node_offset, field_i);
941 const other_tag_src = enumFieldSrcLoc(block.src_decl, tree.*, src.node_offset, gop.index);
942 const msg = msg: {
943 const msg = try mod.errMsg(&block.base, field_src, "duplicate enum tag", .{});
944 errdefer msg.destroy(gpa);
945 try mod.errNote(&block.base, other_tag_src, msg, "other tag here", .{});
946 break :msg msg;
947 };
948 return mod.failWithOwnedErrorMsg(&block.base, msg);
949 }
936950
937 if (has_tag_value) {951 if (has_tag_value) {
938 const tag_val_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);952 const tag_val_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
...@@ -981,6 +995,7 @@ fn zirUnionDecl(...@@ -981,6 +995,7 @@ fn zirUnionDecl(
981 } else 0;995 } else 0;
982996
983 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);997 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
998 errdefer new_decl_arena.deinit();
984999
985 const union_obj = try new_decl_arena.allocator.create(Module.Union);1000 const union_obj = try new_decl_arena.allocator.create(Module.Union);
986 const union_ty = try Type.Tag.@"union".create(&new_decl_arena.allocator, union_obj);1001 const union_ty = try Type.Tag.@"union".create(&new_decl_arena.allocator, union_obj);
...@@ -1046,6 +1061,7 @@ fn zirErrorSetDecl(...@@ -1046,6 +1061,7 @@ fn zirErrorSetDecl(
1046 const fields = sema.code.extra[extra.end..][0..extra.data.fields_len];1061 const fields = sema.code.extra[extra.end..][0..extra.data.fields_len];
10471062
1048 var new_decl_arena = std.heap.ArenaAllocator.init(gpa);1063 var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
1064 errdefer new_decl_arena.deinit();
10491065
1050 const error_set = try new_decl_arena.allocator.create(Module.ErrorSet);1066 const error_set = try new_decl_arena.allocator.create(Module.ErrorSet);
1051 const error_set_ty = try Type.Tag.error_set.create(&new_decl_arena.allocator, error_set);1067 const error_set_ty = try Type.Tag.error_set.create(&new_decl_arena.allocator, error_set);
...@@ -7446,3 +7462,53 @@ fn typeHasOnePossibleValue(...@@ -7446,3 +7462,53 @@ fn typeHasOnePossibleValue(
7446 .inferred_alloc_mut => unreachable,7462 .inferred_alloc_mut => unreachable,
7447 };7463 };
7448}7464}
7465
7466fn getAstTree(sema: *Sema, block: *Scope.Block) InnerError!*const std.zig.ast.Tree {
7467 return block.src_decl.namespace.file_scope.getTree(sema.gpa) catch |err| {
7468 log.err("unable to load AST to report compile error: {s}", .{@errorName(err)});
7469 return error.AnalysisFail;
7470 };
7471}
7472
7473fn enumFieldSrcLoc(
7474 decl: *Decl,
7475 tree: std.zig.ast.Tree,
7476 node_offset: i32,
7477 field_index: usize,
7478) LazySrcLoc {
7479 @setCold(true);
7480 const enum_node = decl.relativeToNodeIndex(node_offset);
7481 const node_tags = tree.nodes.items(.tag);
7482 var buffer: [2]std.zig.ast.Node.Index = undefined;
7483 const container_decl = switch (node_tags[enum_node]) {
7484 .container_decl,
7485 .container_decl_trailing,
7486 => tree.containerDecl(enum_node),
7487
7488 .container_decl_two,
7489 .container_decl_two_trailing,
7490 => tree.containerDeclTwo(&buffer, enum_node),
7491
7492 .container_decl_arg,
7493 .container_decl_arg_trailing,
7494 => tree.containerDeclArg(enum_node),
7495
7496 else => unreachable,
7497 };
7498 var it_index: usize = 0;
7499 for (container_decl.ast.members) |member_node| {
7500 switch (node_tags[member_node]) {
7501 .container_field_init,
7502 .container_field_align,
7503 .container_field,
7504 => {
7505 if (it_index == field_index) {
7506 return .{ .node_offset = decl.nodeIndexToRelative(member_node) };
7507 }
7508 it_index += 1;
7509 },
7510
7511 else => continue,
7512 }
7513 } else unreachable;
7514}