diff options
| -rw-r--r-- | src/AstGen.zig | 36 | ||||
| -rw-r--r-- | src/Module.zig | 45 | ||||
| -rw-r--r-- | src/Sema.zig | 312 | ||||
| -rw-r--r-- | test/behavior/enum.zig | 10 | ||||
| -rw-r--r-- | test/cases/compile_errors/enum_value_already_taken.zig | 2 |
5 files changed, 180 insertions, 225 deletions
diff --git a/src/AstGen.zig b/src/AstGen.zig index 91dea526dc..0540ca0146 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -2013,7 +2013,7 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn }, .local_val => scope = scope.cast(Scope.LocalVal).?.parent, .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, - .namespace => break, + .namespace, .enum_namespace => break, .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent, .top => unreachable, } @@ -2088,7 +2088,7 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) try parent_gz.addDefer(defer_scope.index, defer_scope.len); }, .defer_error => scope = scope.cast(Scope.Defer).?.parent, - .namespace => break, + .namespace, .enum_namespace => break, .top => unreachable, } } @@ -2179,7 +2179,7 @@ fn checkLabelRedefinition(astgen: *AstGen, parent_scope: *Scope, label: Ast.Toke .local_val => scope = scope.cast(Scope.LocalVal).?.parent, .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent, - .namespace => break, + .namespace, .enum_namespace => break, .top => unreachable, } } @@ -2729,7 +2729,7 @@ fn countDefers(outer_scope: *Scope, inner_scope: *Scope) struct { const have_err_payload = defer_scope.remapped_err_code != 0; need_err_code = need_err_code or have_err_payload; }, - .namespace => unreachable, + .namespace, .enum_namespace => unreachable, .top => unreachable, } } @@ -2799,7 +2799,7 @@ fn genDefers( .normal_only => continue, } }, - .namespace => unreachable, + .namespace, .enum_namespace => unreachable, .top => unreachable, } } @@ -2835,7 +2835,7 @@ fn checkUsed(gz: *GenZir, outer_scope: *Scope, inner_scope: *Scope) InnerError!v scope = s.parent; }, .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent, - .namespace => unreachable, + .namespace, .enum_namespace => unreachable, .top => unreachable, } } @@ -4278,7 +4278,7 @@ fn testDecl( .local_val, .local_ptr => unreachable, // a test cannot be in a local scope .gen_zir => s = s.cast(GenZir).?.parent, .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, - .namespace => { + .namespace, .enum_namespace => { const ns = s.cast(Scope.Namespace).?; if (ns.decls.get(name_str_index)) |i| { if (found_already) |f| { @@ -4963,6 +4963,7 @@ fn containerDecl( defer block_scope.unstack(); _ = try astgen.scanDecls(&namespace, container_decl.ast.members); + namespace.base.tag = .enum_namespace; const arg_inst: Zir.Inst.Ref = if (container_decl.ast.arg != 0) try comptimeExpr(&block_scope, &namespace.base, .{ .rl = .{ .ty = .type_type } }, container_decl.ast.arg) @@ -4977,6 +4978,7 @@ fn containerDecl( for (container_decl.ast.members) |member_node| { if (member_node == counts.nonexhaustive_node) continue; + namespace.base.tag = .namespace; var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) { .decl => continue, .field => |field| field, @@ -5010,6 +5012,7 @@ fn containerDecl( }, ); } + namespace.base.tag = .enum_namespace; const tag_value_inst = try expr(&block_scope, &namespace.base, .{ .rl = .{ .ty = arg_inst } }, member.ast.value_expr); wip_members.appendToField(@enumToInt(tag_value_inst)); } @@ -7296,7 +7299,7 @@ fn localVarRef( }, .gen_zir => s = s.cast(GenZir).?.parent, .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, - .namespace => { + .namespace, .enum_namespace => { const ns = s.cast(Scope.Namespace).?; if (ns.decls.get(name_str_index)) |i| { if (found_already) |f| { @@ -7308,7 +7311,7 @@ fn localVarRef( // We found a match but must continue looking for ambiguous references to decls. found_already = i; } - num_namespaces_out += 1; + if (s.tag == .namespace) num_namespaces_out += 1; capturing_namespace = ns; s = ns.parent; }, @@ -7935,7 +7938,7 @@ fn builtinCall( }, .gen_zir => s = s.cast(GenZir).?.parent, .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, - .namespace => { + .namespace, .enum_namespace => { const ns = s.cast(Scope.Namespace).?; if (ns.decls.get(decl_name)) |i| { if (found_already) |f| { @@ -10547,6 +10550,12 @@ const Scope = struct { else => return null, } } + if (T == Namespace) { + switch (base.tag) { + .namespace, .enum_namespace => return @fieldParentPtr(T, "base", base), + else => return null, + } + } if (base.tag != T.base_tag) return null; @@ -10559,7 +10568,7 @@ const Scope = struct { .local_val => base.cast(LocalVal).?.parent, .local_ptr => base.cast(LocalPtr).?.parent, .defer_normal, .defer_error => base.cast(Defer).?.parent, - .namespace => base.cast(Namespace).?.parent, + .namespace, .enum_namespace => base.cast(Namespace).?.parent, .top => null, }; } @@ -10571,6 +10580,7 @@ const Scope = struct { defer_normal, defer_error, namespace, + enum_namespace, top, }; @@ -12247,7 +12257,7 @@ fn detectLocalShadowing( } s = local_ptr.parent; }, - .namespace => { + .namespace, .enum_namespace => { outer_scope = true; const ns = s.cast(Scope.Namespace).?; const decl_node = ns.decls.get(ident_name) orelse { @@ -12415,7 +12425,7 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast. } s = local_ptr.parent; }, - .namespace => s = s.cast(Scope.Namespace).?.parent, + .namespace, .enum_namespace => s = s.cast(Scope.Namespace).?.parent, .gen_zir => s = s.cast(GenZir).?.parent, .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, .top => break, diff --git a/src/Module.zig b/src/Module.zig index bf54fc01fd..0853a2e204 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -1194,6 +1194,49 @@ pub const EnumFull = struct { .lazy = LazySrcLoc.nodeOffset(0), }; } + + pub fn fieldSrcLoc(e: EnumFull, mod: *Module, query: FieldSrcQuery) SrcLoc { + @setCold(true); + const owner_decl = mod.declPtr(e.owner_decl); + const file = owner_decl.getFileScope(); + const tree = file.getTree(mod.gpa) catch |err| { + // In this case we emit a warning + a less precise source location. + log.warn("unable to load {s}: {s}", .{ + file.sub_file_path, @errorName(err), + }); + return e.srcLoc(mod); + }; + const node = owner_decl.relativeToNodeIndex(0); + const node_tags = tree.nodes.items(.tag); + switch (node_tags[node]) { + .container_decl, + .container_decl_trailing, + => return queryFieldSrc(tree.*, query, file, tree.containerDecl(node)), + .container_decl_two, .container_decl_two_trailing => { + var buffer: [2]Ast.Node.Index = undefined; + return queryFieldSrc(tree.*, query, file, tree.containerDeclTwo(&buffer, node)); + }, + .container_decl_arg, + .container_decl_arg_trailing, + => return queryFieldSrc(tree.*, query, file, tree.containerDeclArg(node)), + + .tagged_union, + .tagged_union_trailing, + => return queryFieldSrc(tree.*, query, file, tree.taggedUnion(node)), + .tagged_union_two, .tagged_union_two_trailing => { + var buffer: [2]Ast.Node.Index = undefined; + return queryFieldSrc(tree.*, query, file, tree.taggedUnionTwo(&buffer, node)); + }, + .tagged_union_enum_tag, + .tagged_union_enum_tag_trailing, + => return queryFieldSrc(tree.*, query, file, tree.taggedUnionEnumTag(node)), + + .root => return queryFieldSrc(tree.*, query, file, tree.containerDeclRoot()), + + // This struct was generated using @Type + else => return e.srcLoc(mod), + } + } }; pub const Union = struct { @@ -6171,7 +6214,7 @@ pub const PeerTypeCandidateSrc = union(enum) { const FieldSrcQuery = struct { index: usize, - range: enum { name, type, value, alignment }, + range: enum { name, type, value, alignment } = .name, }; fn queryFieldSrc( diff --git a/src/Sema.zig b/src/Sema.zig index cba14396f9..63f177e401 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -2094,16 +2094,12 @@ fn failWithInvalidComptimeFieldStore(sema: *Sema, block: *Block, init_src: LazyS const msg = try sema.errMsg(block, init_src, "value stored in comptime field does not match the default value of the field", .{}); errdefer msg.destroy(sema.gpa); - const decl_index = container_ty.getOwnerDeclOrNull() orelse break :msg msg; - const decl = sema.mod.declPtr(decl_index); - const tree = decl.getFileScope().getTree(sema.gpa) catch |err| { - log.err("unable to load AST to report compile error: {s}", .{@errorName(err)}); - return error.AnalysisFail; - }; - const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_index); - const default_value_src: LazySrcLoc = .{ .node_offset_field_default = field_src.node_offset.x }; - - try sema.mod.errNoteNonLazy(default_value_src.toSrcLoc(decl), msg, "default value set here", .{}); + const struct_ty = container_ty.castTag(.@"struct") orelse break :msg msg; + const default_value_src = struct_ty.data.fieldSrcLoc(sema.mod, .{ + .index = field_index, + .range = .value, + }); + try sema.mod.errNoteNonLazy(default_value_src, msg, "default value set here", .{}); break :msg msg; }; return sema.failWithOwnedErrorMsg(msg); @@ -2141,15 +2137,61 @@ fn addFieldErrNote( comptime format: []const u8, args: anytype, ) !void { + @setCold(true); const mod = sema.mod; const decl_index = container_ty.getOwnerDecl(); const decl = mod.declPtr(decl_index); - const tree = decl.getFileScope().getTree(sema.gpa) catch |err| { - log.err("unable to load AST to report compile error: {s}", .{@errorName(err)}); - return error.AnalysisFail; + + const field_src = blk: { + const tree = decl.getFileScope().getTree(sema.gpa) catch |err| { + log.err("unable to load AST to report compile error: {s}", .{@errorName(err)}); + break :blk decl.srcLoc(); + }; + + const container_node = decl.relativeToNodeIndex(0); + const node_tags = tree.nodes.items(.tag); + var buffer: [2]std.zig.Ast.Node.Index = undefined; + const container_decl = switch (node_tags[container_node]) { + .root => tree.containerDeclRoot(), + .container_decl, + .container_decl_trailing, + => tree.containerDecl(container_node), + .container_decl_two, + .container_decl_two_trailing, + => tree.containerDeclTwo(&buffer, container_node), + .container_decl_arg, + .container_decl_arg_trailing, + => tree.containerDeclArg(container_node), + .tagged_union, + .tagged_union_trailing, + => tree.taggedUnion(container_node), + .tagged_union_two, + .tagged_union_two_trailing, + => tree.taggedUnionTwo(&buffer, container_node), + .tagged_union_enum_tag, + .tagged_union_enum_tag_trailing, + => tree.taggedUnionEnumTag(container_node), + else => break :blk decl.srcLoc(), + }; + + var it_index: usize = 0; + for (container_decl.ast.members) |member_node| { + switch (node_tags[member_node]) { + .container_field_init, + .container_field_align, + .container_field, + => { + if (it_index == field_index) { + break :blk decl.nodeOffsetSrcLoc(decl.nodeIndexToRelative(member_node)); + } + it_index += 1; + }, + else => continue, + } + } + unreachable; }; - const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_index); - try mod.errNoteNonLazy(field_src.toSrcLoc(decl), parent, format, args); + try mod.errNoteNonLazy(field_src, parent, format, args); } fn errMsg( @@ -2863,7 +2905,7 @@ fn zirEnumDecl( .inlining = null, .is_comptime = true, }; - defer assert(enum_block.instructions.items.len == 0); // should all be comptime instructions + defer enum_block.instructions.deinit(sema.gpa); if (body.len != 0) { try sema.analyzeBody(&enum_block, body); @@ -2929,13 +2971,12 @@ fn zirEnumDecl( const gop_field = enum_obj.fields.getOrPutAssumeCapacity(field_name); if (gop_field.found_existing) { - const tree = try sema.getAstTree(block); - const field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, field_i); - const other_tag_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, gop_field.index); + const field_src = enum_obj.fieldSrcLoc(sema.mod, .{ .index = field_i }).lazy; + const other_field_src = enum_obj.fieldSrcLoc(sema.mod, .{ .index = gop_field.index }).lazy; const msg = msg: { const msg = try sema.errMsg(block, field_src, "duplicate enum field '{s}'", .{field_name}); errdefer msg.destroy(gpa); - try sema.errNote(block, other_tag_src, msg, "other field here", .{}); + try sema.errNote(block, other_field_src, msg, "other field here", .{}); break :msg msg; }; return sema.failWithOwnedErrorMsg(msg); @@ -2944,10 +2985,18 @@ fn zirEnumDecl( if (has_tag_value) { const tag_val_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); extra_index += 1; - // TODO: if we need to report an error here, use a source location - // that points to this default value expression rather than the struct. - // But only resolve the source location if we need to emit a compile error. - const tag_val = (try sema.resolveInstConst(block, src, tag_val_ref, "enum tag value must be comptime-known")).val; + const tag_inst = try sema.resolveInst(tag_val_ref); + const tag_val = sema.resolveConstValue(block, .unneeded, tag_inst, "") catch |err| switch (err) { + error.NeededSourceLocation => { + const value_src = enum_obj.fieldSrcLoc(sema.mod, .{ + .index = field_i, + .range = .value, + }).lazy; + _ = try sema.resolveConstValue(block, value_src, tag_inst, "enum tag value must be comptime-known"); + unreachable; + }, + else => |e| return e, + }; last_tag_val = tag_val; const copied_tag_val = try tag_val.copy(decl_arena_allocator); const gop_val = enum_obj.values.getOrPutAssumeCapacityContext(copied_tag_val, .{ @@ -2955,11 +3004,13 @@ fn zirEnumDecl( .mod = mod, }); if (gop_val.found_existing) { - const tree = try sema.getAstTree(block); - const field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, field_i); - const other_field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, gop_val.index); + const value_src = enum_obj.fieldSrcLoc(sema.mod, .{ + .index = field_i, + .range = .value, + }).lazy; + const other_field_src = enum_obj.fieldSrcLoc(sema.mod, .{ .index = gop_val.index }).lazy; const msg = msg: { - const msg = try sema.errMsg(block, field_src, "enum tag value {} already taken", .{tag_val.fmtValue(enum_obj.tag_ty, sema.mod)}); + const msg = try sema.errMsg(block, value_src, "enum tag value {} already taken", .{tag_val.fmtValue(enum_obj.tag_ty, sema.mod)}); errdefer msg.destroy(gpa); try sema.errNote(block, other_field_src, msg, "other occurrence here", .{}); break :msg msg; @@ -2978,9 +3029,8 @@ fn zirEnumDecl( .mod = mod, }); if (gop_val.found_existing) { - const tree = try sema.getAstTree(block); - const field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, field_i); - const other_field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, gop_val.index); + const field_src = enum_obj.fieldSrcLoc(sema.mod, .{ .index = field_i }).lazy; + const other_field_src = enum_obj.fieldSrcLoc(sema.mod, .{ .index = gop_val.index }).lazy; const msg = msg: { const msg = try sema.errMsg(block, field_src, "enum tag value {} already taken", .{tag_val.fmtValue(enum_obj.tag_ty, sema.mod)}); errdefer msg.destroy(gpa); @@ -2998,9 +3048,11 @@ fn zirEnumDecl( } if (!(try sema.intFitsInType(last_tag_val.?, enum_obj.tag_ty, null))) { - const tree = try sema.getAstTree(block); - const field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, field_i); - const msg = try sema.errMsg(block, field_src, "enumeration value '{}' too large for type '{}'", .{ + const value_src = enum_obj.fieldSrcLoc(sema.mod, .{ + .index = field_i, + .range = if (has_tag_value) .value else .name, + }).lazy; + const msg = try sema.errMsg(block, value_src, "enumeration value '{}' too large for type '{}'", .{ last_tag_val.?.fmtValue(enum_obj.tag_ty, mod), enum_obj.tag_ty.fmt(mod), }); return sema.failWithOwnedErrorMsg(msg); @@ -30623,18 +30675,12 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name); if (gop.found_existing) { const msg = msg: { - const field_src = struct_obj.fieldSrcLoc(sema.mod, .{ - .index = field_i, - .range = .name, - }).lazy; + const field_src = struct_obj.fieldSrcLoc(sema.mod, .{ .index = field_i }).lazy; const msg = try sema.errMsg(&block_scope, field_src, "duplicate struct field: '{s}'", .{field_name}); errdefer msg.destroy(gpa); const prev_field_index = struct_obj.fields.getIndex(field_name).?; - const prev_field_src = struct_obj.fieldSrcLoc(sema.mod, .{ - .index = prev_field_index, - .range = .name, - }); + const prev_field_src = struct_obj.fieldSrcLoc(sema.mod, .{ .index = prev_field_index }); try sema.mod.errNoteNonLazy(prev_field_src, msg, "other field here", .{}); try sema.errNote(&block_scope, src, msg, "struct declared here", .{}); break :msg msg; @@ -30787,26 +30833,30 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void if (any_inits) { extra_index = bodies_index; - for (fields) |zir_field, i| { + for (fields) |zir_field, field_i| { extra_index += zir_field.type_body_len; extra_index += zir_field.align_body_len; if (zir_field.init_body_len > 0) { const body = zir.extra[extra_index..][0..zir_field.init_body_len]; extra_index += body.len; const init = try sema.resolveBody(&block_scope, body, struct_obj.zir_index); - const field = &struct_obj.fields.values()[i]; + const field = &struct_obj.fields.values()[field_i]; const coerced = sema.coerce(&block_scope, field.ty, init, .unneeded) catch |err| switch (err) { error.NeededSourceLocation => { - const tree = try sema.getAstTree(&block_scope); - const init_src = containerFieldInitSrcLoc(decl, tree.*, 0, i); + const init_src = struct_obj.fieldSrcLoc(sema.mod, .{ + .index = field_i, + .range = .value, + }).lazy; _ = try sema.coerce(&block_scope, field.ty, init, init_src); unreachable; }, else => |e| return e, }; const default_val = (try sema.resolveMaybeUndefVal(coerced)) orelse { - const tree = try sema.getAstTree(&block_scope); - const init_src = containerFieldInitSrcLoc(decl, tree.*, 0, i); + const init_src = struct_obj.fieldSrcLoc(sema.mod, .{ + .index = field_i, + .range = .value, + }).lazy; return sema.failWithNeededComptime(&block_scope, init_src, "struct field default value must be comptime-known"); }; field.default_val = try default_val.copy(decl_arena_allocator); @@ -31052,14 +31102,8 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { .mod = mod, }); if (gop.found_existing) { - const field_src = union_obj.fieldSrcLoc(sema.mod, .{ - .index = field_i, - .range = .name, - }).lazy; - const other_field_src = union_obj.fieldSrcLoc(sema.mod, .{ - .index = gop.index, - .range = .name, - }).lazy; + const field_src = union_obj.fieldSrcLoc(sema.mod, .{ .index = field_i }).lazy; + const other_field_src = union_obj.fieldSrcLoc(sema.mod, .{ .index = gop.index }).lazy; const msg = msg: { const msg = try sema.errMsg(&block_scope, field_src, "enum tag value {} already taken", .{copied_val.fmtValue(int_tag_ty, sema.mod)}); errdefer msg.destroy(gpa); @@ -31100,18 +31144,12 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { const gop = union_obj.fields.getOrPutAssumeCapacity(field_name); if (gop.found_existing) { const msg = msg: { - const field_src = union_obj.fieldSrcLoc(sema.mod, .{ - .index = field_i, - .range = .name, - }).lazy; + const field_src = union_obj.fieldSrcLoc(sema.mod, .{ .index = field_i }).lazy; const msg = try sema.errMsg(&block_scope, field_src, "duplicate union field: '{s}'", .{field_name}); errdefer msg.destroy(gpa); const prev_field_index = union_obj.fields.getIndex(field_name).?; - const prev_field_src = union_obj.fieldSrcLoc(sema.mod, .{ - .index = prev_field_index, - .range = .name, - }).lazy; + const prev_field_src = union_obj.fieldSrcLoc(sema.mod, .{ .index = prev_field_index }).lazy; try sema.mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl), msg, "other field here", .{}); try sema.errNote(&block_scope, src, msg, "union declared here", .{}); break :msg msg; @@ -31651,102 +31689,6 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { } } -fn getAstTree(sema: *Sema, block: *Block) CompileError!*const std.zig.Ast { - return block.namespace.file_scope.getTree(sema.gpa) catch |err| { - log.err("unable to load AST to report compile error: {s}", .{@errorName(err)}); - return error.AnalysisFail; - }; -} - -fn enumFieldSrcLoc( - decl: *Decl, - tree: std.zig.Ast, - node_offset: i32, - field_index: usize, -) LazySrcLoc { - @setCold(true); - const field_node = containerFieldNode(decl, tree, node_offset, field_index) orelse - return LazySrcLoc.nodeOffset(0); - return decl.nodeSrcLoc(field_node); -} - -fn containerFieldInitSrcLoc( - decl: *Decl, - tree: std.zig.Ast, - node_offset: i32, - field_index: usize, -) LazySrcLoc { - @setCold(true); - const node_tags = tree.nodes.items(.tag); - const field_node = containerFieldNode(decl, tree, node_offset, field_index) orelse - return LazySrcLoc.nodeOffset(0); - const node_data = tree.nodes.items(.data)[field_node]; - - const init_node = switch (node_tags[field_node]) { - .container_field_init => node_data.rhs, - .container_field => blk: { - const extra_data = tree.extraData(node_data.rhs, std.zig.Ast.Node.ContainerField); - break :blk extra_data.value_expr; - }, - else => unreachable, - }; - - return decl.nodeSrcLoc(init_node); -} - -fn containerFieldNode( - decl: *Decl, - tree: std.zig.Ast, - node_offset: i32, - field_index: usize, -) ?std.zig.Ast.Node.Index { - @setCold(true); - const enum_node = decl.relativeToNodeIndex(node_offset); - const node_tags = tree.nodes.items(.tag); - var buffer: [2]std.zig.Ast.Node.Index = undefined; - const container_decl = switch (node_tags[enum_node]) { - .root => tree.containerDeclRoot(), - - .container_decl, - .container_decl_trailing, - => tree.containerDecl(enum_node), - - .container_decl_two, - .container_decl_two_trailing, - => tree.containerDeclTwo(&buffer, enum_node), - - .container_decl_arg, - .container_decl_arg_trailing, - => tree.containerDeclArg(enum_node), - - .tagged_union, - .tagged_union_trailing, - => tree.taggedUnion(enum_node), - .tagged_union_two, - .tagged_union_two_trailing, - => tree.taggedUnionTwo(&buffer, enum_node), - .tagged_union_enum_tag, - .tagged_union_enum_tag_trailing, - => tree.taggedUnionEnumTag(enum_node), - - else => return null, - }; - var it_index: usize = 0; - for (container_decl.ast.members) |member_node| { - switch (node_tags[member_node]) { - .container_field_init, - .container_field_align, - .container_field, - => { - if (it_index == field_index) return member_node; - it_index += 1; - }, - - else => continue, - } - } else unreachable; -} - /// Returns the type of the AIR instruction. fn typeOf(sema: *Sema, inst: Air.Inst.Ref) Type { return sema.getTmpAir().typeOf(inst); @@ -31836,14 +31778,6 @@ fn addIntUnsigned(sema: *Sema, ty: Type, int: u64) CompileError!Air.Inst.Ref { return sema.addConstant(ty, try Value.Tag.int_u64.create(sema.arena, int)); } -fn addBool(sema: *Sema, ty: Type, boolean: bool) CompileError!Air.Inst.Ref { - return switch (ty.zigTypeTag()) { - .Vector => sema.addConstant(ty, try Value.Tag.repeated.create(sema.arena, Value.makeBool(boolean))), - .Bool => try sema.resolveInst(if (boolean) .bool_true else .bool_false), - else => unreachable, - }; -} - fn addConstUndef(sema: *Sema, ty: Type) CompileError!Air.Inst.Ref { return sema.addConstant(ty, Value.undef); } @@ -32487,27 +32421,6 @@ fn intAddScalar(sema: *Sema, lhs: Value, rhs: Value) !Value { return Value.fromBigInt(sema.arena, result_bigint.toConst()); } -/// Supports both (vectors of) floats and ints; handles undefined scalars. -fn numberAddWrap( - sema: *Sema, - lhs: Value, - rhs: Value, - ty: Type, -) !Value { - if (ty.zigTypeTag() == .Vector) { - const result_data = try sema.arena.alloc(Value, ty.vectorLen()); - for (result_data) |*scalar, i| { - var lhs_buf: Value.ElemValueBuffer = undefined; - var rhs_buf: Value.ElemValueBuffer = undefined; - const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf); - const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf); - scalar.* = try sema.numberAddWrapScalar(lhs_elem, rhs_elem, ty.scalarType()); - } - return Value.Tag.aggregate.create(sema.arena, result_data); - } - return sema.numberAddWrapScalar(lhs, rhs, ty); -} - /// Supports both floats and ints; handles undefined. fn numberAddWrapScalar( sema: *Sema, @@ -32566,27 +32479,6 @@ fn intSubScalar(sema: *Sema, lhs: Value, rhs: Value) !Value { return Value.fromBigInt(sema.arena, result_bigint.toConst()); } -/// Supports both (vectors of) floats and ints; handles undefined scalars. -fn numberSubWrap( - sema: *Sema, - lhs: Value, - rhs: Value, - ty: Type, -) !Value { - if (ty.zigTypeTag() == .Vector) { - const result_data = try sema.arena.alloc(Value, ty.vectorLen()); - for (result_data) |*scalar, i| { - var lhs_buf: Value.ElemValueBuffer = undefined; - var rhs_buf: Value.ElemValueBuffer = undefined; - const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf); - const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf); - scalar.* = try sema.numberSubWrapScalar(lhs_elem, rhs_elem, ty.scalarType()); - } - return Value.Tag.aggregate.create(sema.arena, result_data); - } - return sema.numberSubWrapScalar(lhs, rhs, ty); -} - /// Supports both floats and ints; handles undefined. fn numberSubWrapScalar( sema: *Sema, diff --git a/test/behavior/enum.zig b/test/behavior/enum.zig index a398d5ec22..095f3b740b 100644 --- a/test/behavior/enum.zig +++ b/test/behavior/enum.zig @@ -1185,3 +1185,13 @@ test "runtime int to enum with one possible value" { @compileError("test failed"); } } + +test "enum tag from a local variable" { + const S = struct { + fn Int(comptime Inner: type) type { + return enum(Inner) { _ }; + } + }; + const i = @intToEnum(S.Int(u32), 0); + try std.testing.expect(@enumToInt(i) == 0); +} diff --git a/test/cases/compile_errors/enum_value_already_taken.zig b/test/cases/compile_errors/enum_value_already_taken.zig index 4d660dc1e0..733585a748 100644 --- a/test/cases/compile_errors/enum_value_already_taken.zig +++ b/test/cases/compile_errors/enum_value_already_taken.zig @@ -14,5 +14,5 @@ export fn entry() void { // backend=stage2 // target=native // -// :6:5: error: enum tag value 60 already taken +// :6:9: error: enum tag value 60 already taken // :4:5: note: other occurrence here |
