Sema: improve auto generated union enum name

This commit is contained in:
Veikka Tuominen 2022-06-28 17:15:10 +03:00 committed by Jakub Konka
parent 2e7dc5e151
commit 6cadac18b8
3 changed files with 50 additions and 15 deletions

View File

@ -503,6 +503,8 @@ pub const Decl = struct {
alive: bool,
/// Whether the Decl is a `usingnamespace` declaration.
is_usingnamespace: bool,
/// If true `name` is already fully qualified.
name_fully_qualified: bool = false,
/// Represents the position of the code in the output file.
/// This is populated regardless of semantic analysis and code generation.
@ -686,6 +688,9 @@ pub const Decl = struct {
pub fn renderFullyQualifiedName(decl: Decl, mod: *Module, writer: anytype) !void {
const unqualified_name = mem.sliceTo(decl.name, 0);
if (decl.name_fully_qualified) {
return writer.writeAll(unqualified_name);
}
return decl.src_namespace.renderFullyQualifiedName(mod, unqualified_name, writer);
}

View File

@ -14883,7 +14883,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
union_obj.tag_ty = if (tag_type_val.optionalValue()) |payload_val| blk: {
var buffer: Value.ToTypeBuffer = undefined;
break :blk try payload_val.toType(&buffer).copy(new_decl_arena_allocator);
} else try sema.generateUnionTagTypeSimple(block, fields_len);
} else try sema.generateUnionTagTypeSimple(block, fields_len, null);
// Fields
if (fields_len > 0) {
@ -24237,7 +24237,7 @@ fn semaUnionFields(block: *Block, mod: *Module, union_obj: *Module.Union) Compil
if (small.auto_enum_tag) {
// The provided type is an integer type and we must construct the enum tag type here.
int_tag_ty = provided_ty;
union_obj.tag_ty = try sema.generateUnionTagTypeNumbered(&block_scope, fields_len, provided_ty);
union_obj.tag_ty = try sema.generateUnionTagTypeNumbered(&block_scope, fields_len, provided_ty, union_obj);
const enum_obj = union_obj.tag_ty.castTag(.enum_numbered).?.data;
enum_field_names = &enum_obj.fields;
enum_value_map = &enum_obj.values;
@ -24253,7 +24253,7 @@ fn semaUnionFields(block: *Block, mod: *Module, union_obj: *Module.Union) Compil
// If auto_enum_tag is false, this is an untagged union. However, for semantic analysis
// purposes, we still auto-generate an enum tag type the same way. That the union is
// untagged is represented by the Type tag (union vs union_tagged).
union_obj.tag_ty = try sema.generateUnionTagTypeSimple(&block_scope, fields_len);
union_obj.tag_ty = try sema.generateUnionTagTypeSimple(&block_scope, fields_len, union_obj);
enum_field_names = &union_obj.tag_ty.castTag(.enum_simple).?.data.fields;
}
@ -24422,6 +24422,7 @@ fn generateUnionTagTypeNumbered(
block: *Block,
fields_len: u32,
int_ty: Type,
union_obj: *Module.Union,
) !Type {
const mod = sema.mod;
@ -24437,13 +24438,24 @@ fn generateUnionTagTypeNumbered(
};
const enum_ty = Type.initPayload(&enum_ty_payload.base);
const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty);
// TODO better type name
const new_decl_index = try mod.createAnonymousDecl(block, .{
const src_decl = mod.declPtr(block.src_decl);
const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope);
errdefer mod.destroyDecl(new_decl_index);
const name = name: {
const fqn = try union_obj.getFullyQualifiedName(mod);
defer sema.gpa.free(fqn);
break :name try std.fmt.allocPrintZ(mod.gpa, "@typeInfo({s}).Union.tag_type.?", .{fqn});
};
try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, block.namespace, .{
.ty = Type.type,
.val = enum_val,
});
}, name);
sema.mod.declPtr(new_decl_index).name_fully_qualified = true;
const new_decl = mod.declPtr(new_decl_index);
new_decl.owns_tv = true;
new_decl.name_fully_qualified = true;
errdefer mod.abortAnonDecl(new_decl_index);
enum_obj.* = .{
@ -24463,7 +24475,7 @@ fn generateUnionTagTypeNumbered(
return enum_ty;
}
fn generateUnionTagTypeSimple(sema: *Sema, block: *Block, fields_len: usize) !Type {
fn generateUnionTagTypeSimple(sema: *Sema, block: *Block, fields_len: usize, maybe_union_obj: ?*Module.Union) !Type {
const mod = sema.mod;
var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
@ -24478,11 +24490,30 @@ fn generateUnionTagTypeSimple(sema: *Sema, block: *Block, fields_len: usize) !Ty
};
const enum_ty = Type.initPayload(&enum_ty_payload.base);
const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty);
// TODO better type name
const new_decl_index = try mod.createAnonymousDecl(block, .{
.ty = Type.type,
.val = enum_val,
});
const new_decl_index = new_decl_index: {
const union_obj = maybe_union_obj orelse {
break :new_decl_index try mod.createAnonymousDecl(block, .{
.ty = Type.type,
.val = enum_val,
});
};
const src_decl = mod.declPtr(block.src_decl);
const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope);
errdefer mod.destroyDecl(new_decl_index);
const name = name: {
const fqn = try union_obj.getFullyQualifiedName(mod);
defer sema.gpa.free(fqn);
break :name try std.fmt.allocPrintZ(mod.gpa, "@typeInfo({s}).Union.tag_type.?", .{fqn});
};
try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, block.namespace, .{
.ty = Type.type,
.val = enum_val,
}, name);
sema.mod.declPtr(new_decl_index).name_fully_qualified = true;
break :new_decl_index new_decl_index;
};
const new_decl = mod.declPtr(new_decl_index);
new_decl.owns_tv = true;
errdefer mod.abortAnonDecl(new_decl_index);

View File

@ -13,8 +13,7 @@ const InvalidToken = struct {};
const ExpectedVarDeclOrFn = struct {};
// error
// backend=stage1
// backend=stage2
// target=native
// is_test=1
//
// tmp.zig:4:9: error: expected type '@typeInfo(Error).Union.tag_type.?', found 'type'
// :4:9: error: expected type '@typeInfo(tmp.Error).Union.tag_type.?', found 'type'