Skip to content

Commit 034d387

Browse files
Resolve bound type parameters in generic union declarations
1 parent 4820d2e commit 034d387

2 files changed

Lines changed: 84 additions & 17 deletions

File tree

src/analysis.zig

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -834,7 +834,8 @@ pub fn resolveFieldAccess(analyser: *Analyser, lhs: Type, field_name: []const u8
834834
pub fn resolveFieldAccessBinding(analyser: *Analyser, lhs_binding: Binding, field_name: []const u8) !?Binding {
835835
const lhs = lhs_binding.type;
836836

837-
if (try analyser.resolveUnionFieldBinding(lhs, field_name)) |b| return b;
837+
if (try analyser.resolveUnionTagAccess(lhs, field_name)) |t|
838+
return .{ .type = t, .is_const = true };
838839

839840
// If we are accessing a pointer type, remove one pointerness level :)
840841
const left_type = (try analyser.resolveDerefType(lhs)) orelse lhs;
@@ -995,7 +996,7 @@ pub fn resolveUnwrapErrorUnionType(analyser: *Analyser, ty: Type, side: ErrorUni
995996
};
996997
}
997998

998-
fn resolveUnionFieldBinding(analyser: *Analyser, ty: Type, symbol: []const u8) error{OutOfMemory}!?Binding {
999+
fn resolveUnionTagAccess(analyser: *Analyser, ty: Type, symbol: []const u8) error{OutOfMemory}!?Type {
9991000
if (!ty.is_type_val)
10001001
return null;
10011002

@@ -1020,24 +1021,14 @@ fn resolveUnionFieldBinding(analyser: *Analyser, ty: Type, symbol: []const u8) e
10201021
return null;
10211022

10221023
if (child.decl != .ast_node or !child.handle.tree.nodeTag(child.decl.ast_node).isContainerField())
1023-
return .{
1024-
.type = try child.resolveType(analyser) orelse return null,
1025-
.is_const = child.isConst(),
1026-
};
1024+
return null;
10271025

1028-
if (container_decl.ast.enum_token != null) {
1029-
return .{
1030-
.type = .{ .data = .{ .union_tag = try analyser.allocType(ty) }, .is_type_val = false },
1031-
.is_const = true,
1032-
};
1033-
}
1026+
if (container_decl.ast.enum_token != null)
1027+
return .{ .data = .{ .union_tag = try analyser.allocType(ty) }, .is_type_val = false };
10341028

10351029
if (container_decl.ast.arg.unwrap()) |arg| {
10361030
const tag_type = (try analyser.resolveTypeOfNode(.of(arg, handle))) orelse return null;
1037-
return .{
1038-
.type = tag_type.instanceTypeVal(analyser) orelse return null,
1039-
.is_const = true,
1040-
};
1031+
return tag_type.instanceTypeVal(analyser) orelse return null;
10411032
}
10421033

10431034
return null;
@@ -3773,7 +3764,7 @@ pub const Type = struct {
37733764
}
37743765
try writer.print("!{}", .{info.payload.fmtTypeVal(analyser, ctx.options)});
37753766
},
3776-
.union_tag => |t| try writer.print("@typeInfo({}).Union.tag_type.?", .{t.fmtTypeVal(analyser, ctx.options)}),
3767+
.union_tag => |t| try writer.print("@typeInfo({}).@\"union\".tag_type.?", .{t.fmtTypeVal(analyser, ctx.options)}),
37773768
.container => |info| {
37783769
const scope_handle = info.scope_handle;
37793770
const handle = scope_handle.handle;

tests/analysis/generics.zig

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,79 @@ const option_default: Option(u8) = .default;
107107
// TODO this should be `fn () Option(u8)`
108108
const option_init: Option(u8) = .init();
109109
// ^^^^^ (fn () Option(T))()
110+
111+
fn GenericUnion(T: type) type {
112+
return union {
113+
field: T,
114+
const decl: T = undefined;
115+
};
116+
}
117+
118+
const generic_union_decl = GenericUnion(u8).decl;
119+
// ^^^^^^^^^^^^^^^^^^ (u8)()
120+
121+
const generic_union: GenericUnion(u8) = .{ .field = 1 };
122+
// ^^^^^^^^^^^^^ (GenericUnion(u8))()
123+
124+
const generic_union_field = generic_union.field;
125+
// ^^^^^^^^^^^^^^^^^^^ (u8)()
126+
127+
const generic_union_tag = GenericUnion(u8).field;
128+
// ^^^^^^^^^^^^^^^^^ (unknown)()
129+
130+
fn GenericTaggedUnion(T: type) type {
131+
return union(enum) {
132+
field: T,
133+
const decl: T = undefined;
134+
};
135+
}
136+
137+
const generic_tagged_union_decl = GenericTaggedUnion(u8).decl;
138+
// ^^^^^^^^^^^^^^^^^^^^^^^^^ (u8)()
139+
140+
const generic_tagged_union: GenericTaggedUnion(u8) = .{ .field = 1 };
141+
// ^^^^^^^^^^^^^^^^^^^^ (GenericTaggedUnion(u8))()
142+
143+
const generic_tagged_union_field = generic_tagged_union.field;
144+
// ^^^^^^^^^^^^^^^^^^^^^^^^^^ (u8)()
145+
146+
const generic_tagged_union_tag = GenericTaggedUnion(u8).field;
147+
// ^^^^^^^^^^^^^^^^^^^^^^^^ (@typeInfo(GenericTaggedUnion(u8)).@"union".tag_type.?)()
148+
149+
fn GenericEnum(T: type) type {
150+
return enum {
151+
field,
152+
const decl: T = undefined;
153+
};
154+
}
155+
156+
const generic_enum_decl = GenericEnum(u8).decl;
157+
// ^^^^^^^^^^^^^^^^^ (u8)()
158+
159+
const generic_enum: GenericEnum(u8) = .field;
160+
// ^^^^^^^^^^^^ (GenericEnum(u8))()
161+
162+
const generic_enum_field = generic_enum.field;
163+
// ^^^^^^^^^^^^^^^^^^ (unknown)()
164+
165+
const generic_enum_tag = GenericEnum(u8).field;
166+
// ^^^^^^^^^^^^^^^^ (GenericEnum(u8))()
167+
168+
fn GenericStruct(T: type) type {
169+
return struct {
170+
field: T,
171+
const decl: T = undefined;
172+
};
173+
}
174+
175+
const generic_struct_decl = GenericStruct(u8).decl;
176+
// ^^^^^^^^^^^^^^^^^^^ (u8)()
177+
178+
const generic_struct: GenericStruct(u8) = .{ .field = 1 };
179+
// ^^^^^^^^^^^^^^ (GenericStruct(u8))()
180+
181+
const generic_struct_field = generic_struct.field;
182+
// ^^^^^^^^^^^^^^^^^^^^ (u8)()
183+
184+
const generic_struct_tag = GenericStruct(u8).field;
185+
// ^^^^^^^^^^^^^^^^^^ (unknown)()

0 commit comments

Comments
 (0)