authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2023-01-05 21:37:30+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2023-01-05 22:03:32+02:00
logf2faa303a541f5adddbba26d04dc2749991e0075
tree5761621aa62e2a36551a33138c4f90a38f3795c0
parent8c4727f9ab61e4c99ab2a00f5751f9b11d274fbe

Sema: handle enum expressions referencing local variables

Closes #12272

5 files changed, 180 insertions(+), 225 deletions(-)

src/AstGen.zig+23-13
...@@ -2013,7 +2013,7 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn...@@ -2013,7 +2013,7 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn
2013 },2013 },
2014 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,2014 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
2015 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,2015 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
2016 .namespace => break,2016 .namespace, .enum_namespace => break,
2017 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent,2017 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent,
2018 .top => unreachable,2018 .top => unreachable,
2019 }2019 }
...@@ -2088,7 +2088,7 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index)...@@ -2088,7 +2088,7 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index)
2088 try parent_gz.addDefer(defer_scope.index, defer_scope.len);2088 try parent_gz.addDefer(defer_scope.index, defer_scope.len);
2089 },2089 },
2090 .defer_error => scope = scope.cast(Scope.Defer).?.parent,2090 .defer_error => scope = scope.cast(Scope.Defer).?.parent,
2091 .namespace => break,2091 .namespace, .enum_namespace => break,
2092 .top => unreachable,2092 .top => unreachable,
2093 }2093 }
2094 }2094 }
...@@ -2179,7 +2179,7 @@ fn checkLabelRedefinition(astgen: *AstGen, parent_scope: *Scope, label: Ast.Toke...@@ -2179,7 +2179,7 @@ fn checkLabelRedefinition(astgen: *AstGen, parent_scope: *Scope, label: Ast.Toke
2179 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,2179 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
2180 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,2180 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
2181 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent,2181 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent,
2182 .namespace => break,2182 .namespace, .enum_namespace => break,
2183 .top => unreachable,2183 .top => unreachable,
2184 }2184 }
2185 }2185 }
...@@ -2729,7 +2729,7 @@ fn countDefers(outer_scope: *Scope, inner_scope: *Scope) struct {...@@ -2729,7 +2729,7 @@ fn countDefers(outer_scope: *Scope, inner_scope: *Scope) struct {
2729 const have_err_payload = defer_scope.remapped_err_code != 0;2729 const have_err_payload = defer_scope.remapped_err_code != 0;
2730 need_err_code = need_err_code or have_err_payload;2730 need_err_code = need_err_code or have_err_payload;
2731 },2731 },
2732 .namespace => unreachable,2732 .namespace, .enum_namespace => unreachable,
2733 .top => unreachable,2733 .top => unreachable,
2734 }2734 }
2735 }2735 }
...@@ -2799,7 +2799,7 @@ fn genDefers(...@@ -2799,7 +2799,7 @@ fn genDefers(
2799 .normal_only => continue,2799 .normal_only => continue,
2800 }2800 }
2801 },2801 },
2802 .namespace => unreachable,2802 .namespace, .enum_namespace => unreachable,
2803 .top => unreachable,2803 .top => unreachable,
2804 }2804 }
2805 }2805 }
...@@ -2835,7 +2835,7 @@ fn checkUsed(gz: *GenZir, outer_scope: *Scope, inner_scope: *Scope) InnerError!v...@@ -2835,7 +2835,7 @@ fn checkUsed(gz: *GenZir, outer_scope: *Scope, inner_scope: *Scope) InnerError!v
2835 scope = s.parent;2835 scope = s.parent;
2836 },2836 },
2837 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent,2837 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent,
2838 .namespace => unreachable,2838 .namespace, .enum_namespace => unreachable,
2839 .top => unreachable,2839 .top => unreachable,
2840 }2840 }
2841 }2841 }
...@@ -4278,7 +4278,7 @@ fn testDecl(...@@ -4278,7 +4278,7 @@ fn testDecl(
4278 .local_val, .local_ptr => unreachable, // a test cannot be in a local scope4278 .local_val, .local_ptr => unreachable, // a test cannot be in a local scope
4279 .gen_zir => s = s.cast(GenZir).?.parent,4279 .gen_zir => s = s.cast(GenZir).?.parent,
4280 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,4280 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
4281 .namespace => {4281 .namespace, .enum_namespace => {
4282 const ns = s.cast(Scope.Namespace).?;4282 const ns = s.cast(Scope.Namespace).?;
4283 if (ns.decls.get(name_str_index)) |i| {4283 if (ns.decls.get(name_str_index)) |i| {
4284 if (found_already) |f| {4284 if (found_already) |f| {
...@@ -4963,6 +4963,7 @@ fn containerDecl(...@@ -4963,6 +4963,7 @@ fn containerDecl(
4963 defer block_scope.unstack();4963 defer block_scope.unstack();
49644964
4965 _ = try astgen.scanDecls(&namespace, container_decl.ast.members);4965 _ = try astgen.scanDecls(&namespace, container_decl.ast.members);
4966 namespace.base.tag = .enum_namespace;
49664967
4967 const arg_inst: Zir.Inst.Ref = if (container_decl.ast.arg != 0)4968 const arg_inst: Zir.Inst.Ref = if (container_decl.ast.arg != 0)
4968 try comptimeExpr(&block_scope, &namespace.base, .{ .rl = .{ .ty = .type_type } }, container_decl.ast.arg)4969 try comptimeExpr(&block_scope, &namespace.base, .{ .rl = .{ .ty = .type_type } }, container_decl.ast.arg)
...@@ -4977,6 +4978,7 @@ fn containerDecl(...@@ -4977,6 +4978,7 @@ fn containerDecl(
4977 for (container_decl.ast.members) |member_node| {4978 for (container_decl.ast.members) |member_node| {
4978 if (member_node == counts.nonexhaustive_node)4979 if (member_node == counts.nonexhaustive_node)
4979 continue;4980 continue;
4981 namespace.base.tag = .namespace;
4980 var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) {4982 var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) {
4981 .decl => continue,4983 .decl => continue,
4982 .field => |field| field,4984 .field => |field| field,
...@@ -5010,6 +5012,7 @@ fn containerDecl(...@@ -5010,6 +5012,7 @@ fn containerDecl(
5010 },5012 },
5011 );5013 );
5012 }5014 }
5015 namespace.base.tag = .enum_namespace;
5013 const tag_value_inst = try expr(&block_scope, &namespace.base, .{ .rl = .{ .ty = arg_inst } }, member.ast.value_expr);5016 const tag_value_inst = try expr(&block_scope, &namespace.base, .{ .rl = .{ .ty = arg_inst } }, member.ast.value_expr);
5014 wip_members.appendToField(@enumToInt(tag_value_inst));5017 wip_members.appendToField(@enumToInt(tag_value_inst));
5015 }5018 }
...@@ -7296,7 +7299,7 @@ fn localVarRef(...@@ -7296,7 +7299,7 @@ fn localVarRef(
7296 },7299 },
7297 .gen_zir => s = s.cast(GenZir).?.parent,7300 .gen_zir => s = s.cast(GenZir).?.parent,
7298 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,7301 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
7299 .namespace => {7302 .namespace, .enum_namespace => {
7300 const ns = s.cast(Scope.Namespace).?;7303 const ns = s.cast(Scope.Namespace).?;
7301 if (ns.decls.get(name_str_index)) |i| {7304 if (ns.decls.get(name_str_index)) |i| {
7302 if (found_already) |f| {7305 if (found_already) |f| {
...@@ -7308,7 +7311,7 @@ fn localVarRef(...@@ -7308,7 +7311,7 @@ fn localVarRef(
7308 // We found a match but must continue looking for ambiguous references to decls.7311 // We found a match but must continue looking for ambiguous references to decls.
7309 found_already = i;7312 found_already = i;
7310 }7313 }
7311 num_namespaces_out += 1;7314 if (s.tag == .namespace) num_namespaces_out += 1;
7312 capturing_namespace = ns;7315 capturing_namespace = ns;
7313 s = ns.parent;7316 s = ns.parent;
7314 },7317 },
...@@ -7935,7 +7938,7 @@ fn builtinCall(...@@ -7935,7 +7938,7 @@ fn builtinCall(
7935 },7938 },
7936 .gen_zir => s = s.cast(GenZir).?.parent,7939 .gen_zir => s = s.cast(GenZir).?.parent,
7937 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,7940 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
7938 .namespace => {7941 .namespace, .enum_namespace => {
7939 const ns = s.cast(Scope.Namespace).?;7942 const ns = s.cast(Scope.Namespace).?;
7940 if (ns.decls.get(decl_name)) |i| {7943 if (ns.decls.get(decl_name)) |i| {
7941 if (found_already) |f| {7944 if (found_already) |f| {
...@@ -10547,6 +10550,12 @@ const Scope = struct {...@@ -10547,6 +10550,12 @@ const Scope = struct {
10547 else => return null,10550 else => return null,
10548 }10551 }
10549 }10552 }
10553 if (T == Namespace) {
10554 switch (base.tag) {
10555 .namespace, .enum_namespace => return @fieldParentPtr(T, "base", base),
10556 else => return null,
10557 }
10558 }
10550 if (base.tag != T.base_tag)10559 if (base.tag != T.base_tag)
10551 return null;10560 return null;
1055210561
...@@ -10559,7 +10568,7 @@ const Scope = struct {...@@ -10559,7 +10568,7 @@ const Scope = struct {
10559 .local_val => base.cast(LocalVal).?.parent,10568 .local_val => base.cast(LocalVal).?.parent,
10560 .local_ptr => base.cast(LocalPtr).?.parent,10569 .local_ptr => base.cast(LocalPtr).?.parent,
10561 .defer_normal, .defer_error => base.cast(Defer).?.parent,10570 .defer_normal, .defer_error => base.cast(Defer).?.parent,
10562 .namespace => base.cast(Namespace).?.parent,10571 .namespace, .enum_namespace => base.cast(Namespace).?.parent,
10563 .top => null,10572 .top => null,
10564 };10573 };
10565 }10574 }
...@@ -10571,6 +10580,7 @@ const Scope = struct {...@@ -10571,6 +10580,7 @@ const Scope = struct {
10571 defer_normal,10580 defer_normal,
10572 defer_error,10581 defer_error,
10573 namespace,10582 namespace,
10583 enum_namespace,
10574 top,10584 top,
10575 };10585 };
1057610586
...@@ -12247,7 +12257,7 @@ fn detectLocalShadowing(...@@ -12247,7 +12257,7 @@ fn detectLocalShadowing(
12247 }12257 }
12248 s = local_ptr.parent;12258 s = local_ptr.parent;
12249 },12259 },
12250 .namespace => {12260 .namespace, .enum_namespace => {
12251 outer_scope = true;12261 outer_scope = true;
12252 const ns = s.cast(Scope.Namespace).?;12262 const ns = s.cast(Scope.Namespace).?;
12253 const decl_node = ns.decls.get(ident_name) orelse {12263 const decl_node = ns.decls.get(ident_name) orelse {
...@@ -12415,7 +12425,7 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast....@@ -12415,7 +12425,7 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast.
12415 }12425 }
12416 s = local_ptr.parent;12426 s = local_ptr.parent;
12417 },12427 },
12418 .namespace => s = s.cast(Scope.Namespace).?.parent,12428 .namespace, .enum_namespace => s = s.cast(Scope.Namespace).?.parent,
12419 .gen_zir => s = s.cast(GenZir).?.parent,12429 .gen_zir => s = s.cast(GenZir).?.parent,
12420 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,12430 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
12421 .top => break,12431 .top => break,
src/Module.zig+44-1
...@@ -1194,6 +1194,49 @@ pub const EnumFull = struct {...@@ -1194,6 +1194,49 @@ pub const EnumFull = struct {
1194 .lazy = LazySrcLoc.nodeOffset(0),1194 .lazy = LazySrcLoc.nodeOffset(0),
1195 };1195 };
1196 }1196 }
1197
1198 pub fn fieldSrcLoc(e: EnumFull, mod: *Module, query: FieldSrcQuery) SrcLoc {
1199 @setCold(true);
1200 const owner_decl = mod.declPtr(e.owner_decl);
1201 const file = owner_decl.getFileScope();
1202 const tree = file.getTree(mod.gpa) catch |err| {
1203 // In this case we emit a warning + a less precise source location.
1204 log.warn("unable to load {s}: {s}", .{
1205 file.sub_file_path, @errorName(err),
1206 });
1207 return e.srcLoc(mod);
1208 };
1209 const node = owner_decl.relativeToNodeIndex(0);
1210 const node_tags = tree.nodes.items(.tag);
1211 switch (node_tags[node]) {
1212 .container_decl,
1213 .container_decl_trailing,
1214 => return queryFieldSrc(tree.*, query, file, tree.containerDecl(node)),
1215 .container_decl_two, .container_decl_two_trailing => {
1216 var buffer: [2]Ast.Node.Index = undefined;
1217 return queryFieldSrc(tree.*, query, file, tree.containerDeclTwo(&buffer, node));
1218 },
1219 .container_decl_arg,
1220 .container_decl_arg_trailing,
1221 => return queryFieldSrc(tree.*, query, file, tree.containerDeclArg(node)),
1222
1223 .tagged_union,
1224 .tagged_union_trailing,
1225 => return queryFieldSrc(tree.*, query, file, tree.taggedUnion(node)),
1226 .tagged_union_two, .tagged_union_two_trailing => {
1227 var buffer: [2]Ast.Node.Index = undefined;
1228 return queryFieldSrc(tree.*, query, file, tree.taggedUnionTwo(&buffer, node));
1229 },
1230 .tagged_union_enum_tag,
1231 .tagged_union_enum_tag_trailing,
1232 => return queryFieldSrc(tree.*, query, file, tree.taggedUnionEnumTag(node)),
1233
1234 .root => return queryFieldSrc(tree.*, query, file, tree.containerDeclRoot()),
1235
1236 // This struct was generated using @Type
1237 else => return e.srcLoc(mod),
1238 }
1239 }
1197};1240};
11981241
1199pub const Union = struct {1242pub const Union = struct {
...@@ -6171,7 +6214,7 @@ pub const PeerTypeCandidateSrc = union(enum) {...@@ -6171,7 +6214,7 @@ pub const PeerTypeCandidateSrc = union(enum) {
61716214
6172const FieldSrcQuery = struct {6215const FieldSrcQuery = struct {
6173 index: usize,6216 index: usize,
6174 range: enum { name, type, value, alignment },6217 range: enum { name, type, value, alignment } = .name,
6175};6218};
61766219
6177fn queryFieldSrc(6220fn queryFieldSrc(
src/Sema.zig+102-210
...@@ -2094,16 +2094,12 @@ fn failWithInvalidComptimeFieldStore(sema: *Sema, block: *Block, init_src: LazyS...@@ -2094,16 +2094,12 @@ fn failWithInvalidComptimeFieldStore(sema: *Sema, block: *Block, init_src: LazyS
2094 const msg = try sema.errMsg(block, init_src, "value stored in comptime field does not match the default value of the field", .{});2094 const msg = try sema.errMsg(block, init_src, "value stored in comptime field does not match the default value of the field", .{});
2095 errdefer msg.destroy(sema.gpa);2095 errdefer msg.destroy(sema.gpa);
20962096
2097 const decl_index = container_ty.getOwnerDeclOrNull() orelse break :msg msg;2097 const struct_ty = container_ty.castTag(.@"struct") orelse break :msg msg;
2098 const decl = sema.mod.declPtr(decl_index);2098 const default_value_src = struct_ty.data.fieldSrcLoc(sema.mod, .{
2099 const tree = decl.getFileScope().getTree(sema.gpa) catch |err| {2099 .index = field_index,
2100 log.err("unable to load AST to report compile error: {s}", .{@errorName(err)});2100 .range = .value,
2101 return error.AnalysisFail;2101 });
2102 };2102 try sema.mod.errNoteNonLazy(default_value_src, msg, "default value set here", .{});
2103 const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_index);
2104 const default_value_src: LazySrcLoc = .{ .node_offset_field_default = field_src.node_offset.x };
2105
2106 try sema.mod.errNoteNonLazy(default_value_src.toSrcLoc(decl), msg, "default value set here", .{});
2107 break :msg msg;2103 break :msg msg;
2108 };2104 };
2109 return sema.failWithOwnedErrorMsg(msg);2105 return sema.failWithOwnedErrorMsg(msg);
...@@ -2141,15 +2137,61 @@ fn addFieldErrNote(...@@ -2141,15 +2137,61 @@ fn addFieldErrNote(
2141 comptime format: []const u8,2137 comptime format: []const u8,
2142 args: anytype,2138 args: anytype,
2143) !void {2139) !void {
2140 @setCold(true);
2144 const mod = sema.mod;2141 const mod = sema.mod;
2145 const decl_index = container_ty.getOwnerDecl();2142 const decl_index = container_ty.getOwnerDecl();
2146 const decl = mod.declPtr(decl_index);2143 const decl = mod.declPtr(decl_index);
2147 const tree = decl.getFileScope().getTree(sema.gpa) catch |err| {2144
2148 log.err("unable to load AST to report compile error: {s}", .{@errorName(err)});2145 const field_src = blk: {
2149 return error.AnalysisFail;2146 const tree = decl.getFileScope().getTree(sema.gpa) catch |err| {
2147 log.err("unable to load AST to report compile error: {s}", .{@errorName(err)});
2148 break :blk decl.srcLoc();
2149 };
2150
2151 const container_node = decl.relativeToNodeIndex(0);
2152 const node_tags = tree.nodes.items(.tag);
2153 var buffer: [2]std.zig.Ast.Node.Index = undefined;
2154 const container_decl = switch (node_tags[container_node]) {
2155 .root => tree.containerDeclRoot(),
2156 .container_decl,
2157 .container_decl_trailing,
2158 => tree.containerDecl(container_node),
2159 .container_decl_two,
2160 .container_decl_two_trailing,
2161 => tree.containerDeclTwo(&buffer, container_node),
2162 .container_decl_arg,
2163 .container_decl_arg_trailing,
2164 => tree.containerDeclArg(container_node),
2165 .tagged_union,
2166 .tagged_union_trailing,
2167 => tree.taggedUnion(container_node),
2168 .tagged_union_two,
2169 .tagged_union_two_trailing,
2170 => tree.taggedUnionTwo(&buffer, container_node),
2171 .tagged_union_enum_tag,
2172 .tagged_union_enum_tag_trailing,
2173 => tree.taggedUnionEnumTag(container_node),
2174 else => break :blk decl.srcLoc(),
2175 };
2176
2177 var it_index: usize = 0;
2178 for (container_decl.ast.members) |member_node| {
2179 switch (node_tags[member_node]) {
2180 .container_field_init,
2181 .container_field_align,
2182 .container_field,
2183 => {
2184 if (it_index == field_index) {
2185 break :blk decl.nodeOffsetSrcLoc(decl.nodeIndexToRelative(member_node));
2186 }
2187 it_index += 1;
2188 },
2189 else => continue,
2190 }
2191 }
2192 unreachable;
2150 };2193 };
2151 const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_index);2194 try mod.errNoteNonLazy(field_src, parent, format, args);
2152 try mod.errNoteNonLazy(field_src.toSrcLoc(decl), parent, format, args);
2153}2195}
21542196
2155fn errMsg(2197fn errMsg(
...@@ -2863,7 +2905,7 @@ fn zirEnumDecl(...@@ -2863,7 +2905,7 @@ fn zirEnumDecl(
2863 .inlining = null,2905 .inlining = null,
2864 .is_comptime = true,2906 .is_comptime = true,
2865 };2907 };
2866 defer assert(enum_block.instructions.items.len == 0); // should all be comptime instructions2908 defer enum_block.instructions.deinit(sema.gpa);
28672909
2868 if (body.len != 0) {2910 if (body.len != 0) {
2869 try sema.analyzeBody(&enum_block, body);2911 try sema.analyzeBody(&enum_block, body);
...@@ -2929,13 +2971,12 @@ fn zirEnumDecl(...@@ -2929,13 +2971,12 @@ fn zirEnumDecl(
29292971
2930 const gop_field = enum_obj.fields.getOrPutAssumeCapacity(field_name);2972 const gop_field = enum_obj.fields.getOrPutAssumeCapacity(field_name);
2931 if (gop_field.found_existing) {2973 if (gop_field.found_existing) {
2932 const tree = try sema.getAstTree(block);2974 const field_src = enum_obj.fieldSrcLoc(sema.mod, .{ .index = field_i }).lazy;
2933 const field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, field_i);2975 const other_field_src = enum_obj.fieldSrcLoc(sema.mod, .{ .index = gop_field.index }).lazy;
2934 const other_tag_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, gop_field.index);
2935 const msg = msg: {2976 const msg = msg: {
2936 const msg = try sema.errMsg(block, field_src, "duplicate enum field '{s}'", .{field_name});2977 const msg = try sema.errMsg(block, field_src, "duplicate enum field '{s}'", .{field_name});
2937 errdefer msg.destroy(gpa);2978 errdefer msg.destroy(gpa);
2938 try sema.errNote(block, other_tag_src, msg, "other field here", .{});2979 try sema.errNote(block, other_field_src, msg, "other field here", .{});
2939 break :msg msg;2980 break :msg msg;
2940 };2981 };
2941 return sema.failWithOwnedErrorMsg(msg);2982 return sema.failWithOwnedErrorMsg(msg);
...@@ -2944,10 +2985,18 @@ fn zirEnumDecl(...@@ -2944,10 +2985,18 @@ fn zirEnumDecl(
2944 if (has_tag_value) {2985 if (has_tag_value) {
2945 const tag_val_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);2986 const tag_val_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
2946 extra_index += 1;2987 extra_index += 1;
2947 // TODO: if we need to report an error here, use a source location2988 const tag_inst = try sema.resolveInst(tag_val_ref);
2948 // that points to this default value expression rather than the struct.2989 const tag_val = sema.resolveConstValue(block, .unneeded, tag_inst, "") catch |err| switch (err) {
2949 // But only resolve the source location if we need to emit a compile error.2990 error.NeededSourceLocation => {
2950 const tag_val = (try sema.resolveInstConst(block, src, tag_val_ref, "enum tag value must be comptime-known")).val;2991 const value_src = enum_obj.fieldSrcLoc(sema.mod, .{
2992 .index = field_i,
2993 .range = .value,
2994 }).lazy;
2995 _ = try sema.resolveConstValue(block, value_src, tag_inst, "enum tag value must be comptime-known");
2996 unreachable;
2997 },
2998 else => |e| return e,
2999 };
2951 last_tag_val = tag_val;3000 last_tag_val = tag_val;
2952 const copied_tag_val = try tag_val.copy(decl_arena_allocator);3001 const copied_tag_val = try tag_val.copy(decl_arena_allocator);
2953 const gop_val = enum_obj.values.getOrPutAssumeCapacityContext(copied_tag_val, .{3002 const gop_val = enum_obj.values.getOrPutAssumeCapacityContext(copied_tag_val, .{
...@@ -2955,11 +3004,13 @@ fn zirEnumDecl(...@@ -2955,11 +3004,13 @@ fn zirEnumDecl(
2955 .mod = mod,3004 .mod = mod,
2956 });3005 });
2957 if (gop_val.found_existing) {3006 if (gop_val.found_existing) {
2958 const tree = try sema.getAstTree(block);3007 const value_src = enum_obj.fieldSrcLoc(sema.mod, .{
2959 const field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, field_i);3008 .index = field_i,
2960 const other_field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, gop_val.index);3009 .range = .value,
3010 }).lazy;
3011 const other_field_src = enum_obj.fieldSrcLoc(sema.mod, .{ .index = gop_val.index }).lazy;
2961 const msg = msg: {3012 const msg = msg: {
2962 const msg = try sema.errMsg(block, field_src, "enum tag value {} already taken", .{tag_val.fmtValue(enum_obj.tag_ty, sema.mod)});3013 const msg = try sema.errMsg(block, value_src, "enum tag value {} already taken", .{tag_val.fmtValue(enum_obj.tag_ty, sema.mod)});
2963 errdefer msg.destroy(gpa);3014 errdefer msg.destroy(gpa);
2964 try sema.errNote(block, other_field_src, msg, "other occurrence here", .{});3015 try sema.errNote(block, other_field_src, msg, "other occurrence here", .{});
2965 break :msg msg;3016 break :msg msg;
...@@ -2978,9 +3029,8 @@ fn zirEnumDecl(...@@ -2978,9 +3029,8 @@ fn zirEnumDecl(
2978 .mod = mod,3029 .mod = mod,
2979 });3030 });
2980 if (gop_val.found_existing) {3031 if (gop_val.found_existing) {
2981 const tree = try sema.getAstTree(block);3032 const field_src = enum_obj.fieldSrcLoc(sema.mod, .{ .index = field_i }).lazy;
2982 const field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, field_i);3033 const other_field_src = enum_obj.fieldSrcLoc(sema.mod, .{ .index = gop_val.index }).lazy;
2983 const other_field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, gop_val.index);
2984 const msg = msg: {3034 const msg = msg: {
2985 const msg = try sema.errMsg(block, field_src, "enum tag value {} already taken", .{tag_val.fmtValue(enum_obj.tag_ty, sema.mod)});3035 const msg = try sema.errMsg(block, field_src, "enum tag value {} already taken", .{tag_val.fmtValue(enum_obj.tag_ty, sema.mod)});
2986 errdefer msg.destroy(gpa);3036 errdefer msg.destroy(gpa);
...@@ -2998,9 +3048,11 @@ fn zirEnumDecl(...@@ -2998,9 +3048,11 @@ fn zirEnumDecl(
2998 }3048 }
29993049
3000 if (!(try sema.intFitsInType(last_tag_val.?, enum_obj.tag_ty, null))) {3050 if (!(try sema.intFitsInType(last_tag_val.?, enum_obj.tag_ty, null))) {
3001 const tree = try sema.getAstTree(block);3051 const value_src = enum_obj.fieldSrcLoc(sema.mod, .{
3002 const field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, field_i);3052 .index = field_i,
3003 const msg = try sema.errMsg(block, field_src, "enumeration value '{}' too large for type '{}'", .{3053 .range = if (has_tag_value) .value else .name,
3054 }).lazy;
3055 const msg = try sema.errMsg(block, value_src, "enumeration value '{}' too large for type '{}'", .{
3004 last_tag_val.?.fmtValue(enum_obj.tag_ty, mod), enum_obj.tag_ty.fmt(mod),3056 last_tag_val.?.fmtValue(enum_obj.tag_ty, mod), enum_obj.tag_ty.fmt(mod),
3005 });3057 });
3006 return sema.failWithOwnedErrorMsg(msg);3058 return sema.failWithOwnedErrorMsg(msg);
...@@ -30623,18 +30675,12 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -30623,18 +30675,12 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
30623 const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name);30675 const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name);
30624 if (gop.found_existing) {30676 if (gop.found_existing) {
30625 const msg = msg: {30677 const msg = msg: {
30626 const field_src = struct_obj.fieldSrcLoc(sema.mod, .{30678 const field_src = struct_obj.fieldSrcLoc(sema.mod, .{ .index = field_i }).lazy;
30627 .index = field_i,
30628 .range = .name,
30629 }).lazy;
30630 const msg = try sema.errMsg(&block_scope, field_src, "duplicate struct field: '{s}'", .{field_name});30679 const msg = try sema.errMsg(&block_scope, field_src, "duplicate struct field: '{s}'", .{field_name});
30631 errdefer msg.destroy(gpa);30680 errdefer msg.destroy(gpa);
3063230681
30633 const prev_field_index = struct_obj.fields.getIndex(field_name).?;30682 const prev_field_index = struct_obj.fields.getIndex(field_name).?;
30634 const prev_field_src = struct_obj.fieldSrcLoc(sema.mod, .{30683 const prev_field_src = struct_obj.fieldSrcLoc(sema.mod, .{ .index = prev_field_index });
30635 .index = prev_field_index,
30636 .range = .name,
30637 });
30638 try sema.mod.errNoteNonLazy(prev_field_src, msg, "other field here", .{});30684 try sema.mod.errNoteNonLazy(prev_field_src, msg, "other field here", .{});
30639 try sema.errNote(&block_scope, src, msg, "struct declared here", .{});30685 try sema.errNote(&block_scope, src, msg, "struct declared here", .{});
30640 break :msg msg;30686 break :msg msg;
...@@ -30787,26 +30833,30 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -30787,26 +30833,30 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3078730833
30788 if (any_inits) {30834 if (any_inits) {
30789 extra_index = bodies_index;30835 extra_index = bodies_index;
30790 for (fields) |zir_field, i| {30836 for (fields) |zir_field, field_i| {
30791 extra_index += zir_field.type_body_len;30837 extra_index += zir_field.type_body_len;
30792 extra_index += zir_field.align_body_len;30838 extra_index += zir_field.align_body_len;
30793 if (zir_field.init_body_len > 0) {30839 if (zir_field.init_body_len > 0) {
30794 const body = zir.extra[extra_index..][0..zir_field.init_body_len];30840 const body = zir.extra[extra_index..][0..zir_field.init_body_len];
30795 extra_index += body.len;30841 extra_index += body.len;
30796 const init = try sema.resolveBody(&block_scope, body, struct_obj.zir_index);30842 const init = try sema.resolveBody(&block_scope, body, struct_obj.zir_index);
30797 const field = &struct_obj.fields.values()[i];30843 const field = &struct_obj.fields.values()[field_i];
30798 const coerced = sema.coerce(&block_scope, field.ty, init, .unneeded) catch |err| switch (err) {30844 const coerced = sema.coerce(&block_scope, field.ty, init, .unneeded) catch |err| switch (err) {
30799 error.NeededSourceLocation => {30845 error.NeededSourceLocation => {
30800 const tree = try sema.getAstTree(&block_scope);30846 const init_src = struct_obj.fieldSrcLoc(sema.mod, .{
30801 const init_src = containerFieldInitSrcLoc(decl, tree.*, 0, i);30847 .index = field_i,
30848 .range = .value,
30849 }).lazy;
30802 _ = try sema.coerce(&block_scope, field.ty, init, init_src);30850 _ = try sema.coerce(&block_scope, field.ty, init, init_src);
30803 unreachable;30851 unreachable;
30804 },30852 },
30805 else => |e| return e,30853 else => |e| return e,
30806 };30854 };
30807 const default_val = (try sema.resolveMaybeUndefVal(coerced)) orelse {30855 const default_val = (try sema.resolveMaybeUndefVal(coerced)) orelse {
30808 const tree = try sema.getAstTree(&block_scope);30856 const init_src = struct_obj.fieldSrcLoc(sema.mod, .{
30809 const init_src = containerFieldInitSrcLoc(decl, tree.*, 0, i);30857 .index = field_i,
30858 .range = .value,
30859 }).lazy;
30810 return sema.failWithNeededComptime(&block_scope, init_src, "struct field default value must be comptime-known");30860 return sema.failWithNeededComptime(&block_scope, init_src, "struct field default value must be comptime-known");
30811 };30861 };
30812 field.default_val = try default_val.copy(decl_arena_allocator);30862 field.default_val = try default_val.copy(decl_arena_allocator);
...@@ -31052,14 +31102,8 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -31052,14 +31102,8 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
31052 .mod = mod,31102 .mod = mod,
31053 });31103 });
31054 if (gop.found_existing) {31104 if (gop.found_existing) {
31055 const field_src = union_obj.fieldSrcLoc(sema.mod, .{31105 const field_src = union_obj.fieldSrcLoc(sema.mod, .{ .index = field_i }).lazy;
31056 .index = field_i,31106 const other_field_src = union_obj.fieldSrcLoc(sema.mod, .{ .index = gop.index }).lazy;
31057 .range = .name,
31058 }).lazy;
31059 const other_field_src = union_obj.fieldSrcLoc(sema.mod, .{
31060 .index = gop.index,
31061 .range = .name,
31062 }).lazy;
31063 const msg = msg: {31107 const msg = msg: {
31064 const msg = try sema.errMsg(&block_scope, field_src, "enum tag value {} already taken", .{copied_val.fmtValue(int_tag_ty, sema.mod)});31108 const msg = try sema.errMsg(&block_scope, field_src, "enum tag value {} already taken", .{copied_val.fmtValue(int_tag_ty, sema.mod)});
31065 errdefer msg.destroy(gpa);31109 errdefer msg.destroy(gpa);
...@@ -31100,18 +31144,12 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -31100,18 +31144,12 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
31100 const gop = union_obj.fields.getOrPutAssumeCapacity(field_name);31144 const gop = union_obj.fields.getOrPutAssumeCapacity(field_name);
31101 if (gop.found_existing) {31145 if (gop.found_existing) {
31102 const msg = msg: {31146 const msg = msg: {
31103 const field_src = union_obj.fieldSrcLoc(sema.mod, .{31147 const field_src = union_obj.fieldSrcLoc(sema.mod, .{ .index = field_i }).lazy;
31104 .index = field_i,
31105 .range = .name,
31106 }).lazy;
31107 const msg = try sema.errMsg(&block_scope, field_src, "duplicate union field: '{s}'", .{field_name});31148 const msg = try sema.errMsg(&block_scope, field_src, "duplicate union field: '{s}'", .{field_name});
31108 errdefer msg.destroy(gpa);31149 errdefer msg.destroy(gpa);
3110931150
31110 const prev_field_index = union_obj.fields.getIndex(field_name).?;31151 const prev_field_index = union_obj.fields.getIndex(field_name).?;
31111 const prev_field_src = union_obj.fieldSrcLoc(sema.mod, .{31152 const prev_field_src = union_obj.fieldSrcLoc(sema.mod, .{ .index = prev_field_index }).lazy;
31112 .index = prev_field_index,
31113 .range = .name,
31114 }).lazy;
31115 try sema.mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl), msg, "other field here", .{});31153 try sema.mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl), msg, "other field here", .{});
31116 try sema.errNote(&block_scope, src, msg, "union declared here", .{});31154 try sema.errNote(&block_scope, src, msg, "union declared here", .{});
31117 break :msg msg;31155 break :msg msg;
...@@ -31651,102 +31689,6 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {...@@ -31651,102 +31689,6 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
31651 }31689 }
31652}31690}
3165331691
31654fn getAstTree(sema: *Sema, block: *Block) CompileError!*const std.zig.Ast {
31655 return block.namespace.file_scope.getTree(sema.gpa) catch |err| {
31656 log.err("unable to load AST to report compile error: {s}", .{@errorName(err)});
31657 return error.AnalysisFail;
31658 };
31659}
31660
31661fn enumFieldSrcLoc(
31662 decl: *Decl,
31663 tree: std.zig.Ast,
31664 node_offset: i32,
31665 field_index: usize,
31666) LazySrcLoc {
31667 @setCold(true);
31668 const field_node = containerFieldNode(decl, tree, node_offset, field_index) orelse
31669 return LazySrcLoc.nodeOffset(0);
31670 return decl.nodeSrcLoc(field_node);
31671}
31672
31673fn containerFieldInitSrcLoc(
31674 decl: *Decl,
31675 tree: std.zig.Ast,
31676 node_offset: i32,
31677 field_index: usize,
31678) LazySrcLoc {
31679 @setCold(true);
31680 const node_tags = tree.nodes.items(.tag);
31681 const field_node = containerFieldNode(decl, tree, node_offset, field_index) orelse
31682 return LazySrcLoc.nodeOffset(0);
31683 const node_data = tree.nodes.items(.data)[field_node];
31684
31685 const init_node = switch (node_tags[field_node]) {
31686 .container_field_init => node_data.rhs,
31687 .container_field => blk: {
31688 const extra_data = tree.extraData(node_data.rhs, std.zig.Ast.Node.ContainerField);
31689 break :blk extra_data.value_expr;
31690 },
31691 else => unreachable,
31692 };
31693
31694 return decl.nodeSrcLoc(init_node);
31695}
31696
31697fn containerFieldNode(
31698 decl: *Decl,
31699 tree: std.zig.Ast,
31700 node_offset: i32,
31701 field_index: usize,
31702) ?std.zig.Ast.Node.Index {
31703 @setCold(true);
31704 const enum_node = decl.relativeToNodeIndex(node_offset);
31705 const node_tags = tree.nodes.items(.tag);
31706 var buffer: [2]std.zig.Ast.Node.Index = undefined;
31707 const container_decl = switch (node_tags[enum_node]) {
31708 .root => tree.containerDeclRoot(),
31709
31710 .container_decl,
31711 .container_decl_trailing,
31712 => tree.containerDecl(enum_node),
31713
31714 .container_decl_two,
31715 .container_decl_two_trailing,
31716 => tree.containerDeclTwo(&buffer, enum_node),
31717
31718 .container_decl_arg,
31719 .container_decl_arg_trailing,
31720 => tree.containerDeclArg(enum_node),
31721
31722 .tagged_union,
31723 .tagged_union_trailing,
31724 => tree.taggedUnion(enum_node),
31725 .tagged_union_two,
31726 .tagged_union_two_trailing,
31727 => tree.taggedUnionTwo(&buffer, enum_node),
31728 .tagged_union_enum_tag,
31729 .tagged_union_enum_tag_trailing,
31730 => tree.taggedUnionEnumTag(enum_node),
31731
31732 else => return null,
31733 };
31734 var it_index: usize = 0;
31735 for (container_decl.ast.members) |member_node| {
31736 switch (node_tags[member_node]) {
31737 .container_field_init,
31738 .container_field_align,
31739 .container_field,
31740 => {
31741 if (it_index == field_index) return member_node;
31742 it_index += 1;
31743 },
31744
31745 else => continue,
31746 }
31747 } else unreachable;
31748}
31749
31750/// Returns the type of the AIR instruction.31692/// Returns the type of the AIR instruction.
31751fn typeOf(sema: *Sema, inst: Air.Inst.Ref) Type {31693fn typeOf(sema: *Sema, inst: Air.Inst.Ref) Type {
31752 return sema.getTmpAir().typeOf(inst);31694 return sema.getTmpAir().typeOf(inst);
...@@ -31836,14 +31778,6 @@ fn addIntUnsigned(sema: *Sema, ty: Type, int: u64) CompileError!Air.Inst.Ref {...@@ -31836,14 +31778,6 @@ fn addIntUnsigned(sema: *Sema, ty: Type, int: u64) CompileError!Air.Inst.Ref {
31836 return sema.addConstant(ty, try Value.Tag.int_u64.create(sema.arena, int));31778 return sema.addConstant(ty, try Value.Tag.int_u64.create(sema.arena, int));
31837}31779}
3183831780
31839fn addBool(sema: *Sema, ty: Type, boolean: bool) CompileError!Air.Inst.Ref {
31840 return switch (ty.zigTypeTag()) {
31841 .Vector => sema.addConstant(ty, try Value.Tag.repeated.create(sema.arena, Value.makeBool(boolean))),
31842 .Bool => try sema.resolveInst(if (boolean) .bool_true else .bool_false),
31843 else => unreachable,
31844 };
31845}
31846
31847fn addConstUndef(sema: *Sema, ty: Type) CompileError!Air.Inst.Ref {31781fn addConstUndef(sema: *Sema, ty: Type) CompileError!Air.Inst.Ref {
31848 return sema.addConstant(ty, Value.undef);31782 return sema.addConstant(ty, Value.undef);
31849}31783}
...@@ -32487,27 +32421,6 @@ fn intAddScalar(sema: *Sema, lhs: Value, rhs: Value) !Value {...@@ -32487,27 +32421,6 @@ fn intAddScalar(sema: *Sema, lhs: Value, rhs: Value) !Value {
32487 return Value.fromBigInt(sema.arena, result_bigint.toConst());32421 return Value.fromBigInt(sema.arena, result_bigint.toConst());
32488}32422}
3248932423
32490/// Supports both (vectors of) floats and ints; handles undefined scalars.
32491fn numberAddWrap(
32492 sema: *Sema,
32493 lhs: Value,
32494 rhs: Value,
32495 ty: Type,
32496) !Value {
32497 if (ty.zigTypeTag() == .Vector) {
32498 const result_data = try sema.arena.alloc(Value, ty.vectorLen());
32499 for (result_data) |*scalar, i| {
32500 var lhs_buf: Value.ElemValueBuffer = undefined;
32501 var rhs_buf: Value.ElemValueBuffer = undefined;
32502 const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf);
32503 const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf);
32504 scalar.* = try sema.numberAddWrapScalar(lhs_elem, rhs_elem, ty.scalarType());
32505 }
32506 return Value.Tag.aggregate.create(sema.arena, result_data);
32507 }
32508 return sema.numberAddWrapScalar(lhs, rhs, ty);
32509}
32510
32511/// Supports both floats and ints; handles undefined.32424/// Supports both floats and ints; handles undefined.
32512fn numberAddWrapScalar(32425fn numberAddWrapScalar(
32513 sema: *Sema,32426 sema: *Sema,
...@@ -32566,27 +32479,6 @@ fn intSubScalar(sema: *Sema, lhs: Value, rhs: Value) !Value {...@@ -32566,27 +32479,6 @@ fn intSubScalar(sema: *Sema, lhs: Value, rhs: Value) !Value {
32566 return Value.fromBigInt(sema.arena, result_bigint.toConst());32479 return Value.fromBigInt(sema.arena, result_bigint.toConst());
32567}32480}
3256832481
32569/// Supports both (vectors of) floats and ints; handles undefined scalars.
32570fn numberSubWrap(
32571 sema: *Sema,
32572 lhs: Value,
32573 rhs: Value,
32574 ty: Type,
32575) !Value {
32576 if (ty.zigTypeTag() == .Vector) {
32577 const result_data = try sema.arena.alloc(Value, ty.vectorLen());
32578 for (result_data) |*scalar, i| {
32579 var lhs_buf: Value.ElemValueBuffer = undefined;
32580 var rhs_buf: Value.ElemValueBuffer = undefined;
32581 const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf);
32582 const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf);
32583 scalar.* = try sema.numberSubWrapScalar(lhs_elem, rhs_elem, ty.scalarType());
32584 }
32585 return Value.Tag.aggregate.create(sema.arena, result_data);
32586 }
32587 return sema.numberSubWrapScalar(lhs, rhs, ty);
32588}
32589
32590/// Supports both floats and ints; handles undefined.32482/// Supports both floats and ints; handles undefined.
32591fn numberSubWrapScalar(32483fn numberSubWrapScalar(
32592 sema: *Sema,32484 sema: *Sema,
test/behavior/enum.zig+10
...@@ -1185,3 +1185,13 @@ test "runtime int to enum with one possible value" {...@@ -1185,3 +1185,13 @@ test "runtime int to enum with one possible value" {
1185 @compileError("test failed");1185 @compileError("test failed");
1186 }1186 }
1187}1187}
1188
1189test "enum tag from a local variable" {
1190 const S = struct {
1191 fn Int(comptime Inner: type) type {
1192 return enum(Inner) { _ };
1193 }
1194 };
1195 const i = @intToEnum(S.Int(u32), 0);
1196 try std.testing.expect(@enumToInt(i) == 0);
1197}
test/cases/compile_errors/enum_value_already_taken.zig+1-1
...@@ -14,5 +14,5 @@ export fn entry() void {...@@ -14,5 +14,5 @@ export fn entry() void {
14// backend=stage214// backend=stage2
15// target=native15// target=native
16//16//
17// :6:5: error: enum tag value 60 already taken17// :6:9: error: enum tag value 60 already taken
18// :4:5: note: other occurrence here18// :4:5: note: other occurrence here