authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-20 15:36:40-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-20 16:17:16-07:00
log4fccc95b0152aefeb40912768ec045b57a2fdc2b
tree711ec4766c0cd236b239eb448398d2162c770068
parente86ff712a666ab5be54fa763cc12a5f245718117

Sema: fix requiresComptime infinite recursion

When asking a struct or union whether the type requires comptime, it may need to ask itself recursively, for example because of a field which is a pointer to itself. This commit adds a field to each to keep track of when computing the "requires comptime" value and returns `false` if the check is already ongoing.

2 files changed, 37 insertions(+), 11 deletions(-)

src/Module.zig+4
......@@ -821,6 +821,8 @@ pub const ErrorSet = struct {
821821 }
822822};
823823
824pub const RequiresComptime = enum { no, yes, unknown, wip };
825
824826/// Represents the data that a struct declaration provides.
825827pub const Struct = struct {
826828 /// The Decl that corresponds to the struct itself.
......@@ -849,6 +851,7 @@ pub const Struct = struct {
849851 /// If true, definitely nonzero size at runtime. If false, resolving the fields
850852 /// is necessary to determine whether it has bits at runtime.
851853 known_has_bits: bool,
854 requires_comptime: RequiresComptime = .unknown,
852855
853856 pub const Fields = std.StringArrayHashMapUnmanaged(Field);
854857
......@@ -1038,6 +1041,7 @@ pub const Union = struct {
10381041 // which `have_layout` does not ensure.
10391042 fully_resolved,
10401043 },
1044 requires_comptime: RequiresComptime = .unknown,
10411045
10421046 pub const Field = struct {
10431047 /// undefined until `status` is `have_field_types` or `have_layout`.
src/type.zig+33-11
......@@ -1544,22 +1544,40 @@ pub const Type = extern union {
15441544
15451545 .@"struct" => {
15461546 const struct_obj = ty.castTag(.@"struct").?.data;
1547 for (struct_obj.fields.values()) |field| {
1548 if (requiresComptime(field.ty)) {
1549 return true;
1550 }
1547 switch (struct_obj.requires_comptime) {
1548 .no, .wip => return false,
1549 .yes => return true,
1550 .unknown => {
1551 struct_obj.requires_comptime = .wip;
1552 for (struct_obj.fields.values()) |field| {
1553 if (requiresComptime(field.ty)) {
1554 struct_obj.requires_comptime = .yes;
1555 return true;
1556 }
1557 }
1558 struct_obj.requires_comptime = .no;
1559 return false;
1560 },
15511561 }
1552 return false;
15531562 },
15541563
15551564 .@"union", .union_tagged => {
15561565 const union_obj = ty.cast(Payload.Union).?.data;
1557 for (union_obj.fields.values()) |field| {
1558 if (requiresComptime(field.ty)) {
1559 return true;
1560 }
1566 switch (union_obj.requires_comptime) {
1567 .no, .wip => return false,
1568 .yes => return true,
1569 .unknown => {
1570 union_obj.requires_comptime = .wip;
1571 for (union_obj.fields.values()) |field| {
1572 if (requiresComptime(field.ty)) {
1573 union_obj.requires_comptime = .yes;
1574 return true;
1575 }
1576 }
1577 union_obj.requires_comptime = .no;
1578 return false;
1579 },
15611580 }
1562 return false;
15631581 },
15641582
15651583 .error_union => return requiresComptime(errorUnionPayload(ty)),
......@@ -3661,7 +3679,7 @@ pub const Type = extern union {
36613679 .Slice, .Many, .C => true,
36623680 .One => ty.elemType().zigTypeTag() == .Array,
36633681 },
3664 .Struct => ty.tag() == .tuple,
3682 .Struct => ty.isTuple(),
36653683 else => false,
36663684 };
36673685 }
......@@ -4501,6 +4519,10 @@ pub const Type = extern union {
45014519 }
45024520 };
45034521
4522 pub fn isTuple(ty: Type) bool {
4523 return ty.tag() == .tuple;
4524 }
4525
45044526 /// The sub-types are named after what fields they contain.
45054527 pub const Payload = struct {
45064528 tag: Tag,