authorgravatar for liljaanton2001@gmail.comantlilja <liljaanton2001@gmail.com> 2022-08-06 13:17:09+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-08-06 14:17:09+03:00
log86d9c3de2b6b43329c16678f1bd7eaddd3d218d7
tree3697de6cee8439fbf0993d80645c5a51a9ec26ae
parent5c9826630dfb8a2f59663a569bb8e452359c9524
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Sema: fix infinite recursion in `explainWhyTypeIsComptime`

Co-authored-by: Veikka Tuominen <git@vexu.eu>

4 files changed, 84 insertions(+), 6 deletions(-)

src/Sema.zig+30-6
...@@ -19764,6 +19764,8 @@ fn validateRunTimeType(...@@ -19764,6 +19764,8 @@ fn validateRunTimeType(
19764 };19764 };
19765}19765}
1976619766
19767const TypeSet = std.HashMapUnmanaged(Type, void, Type.HashContext64, std.hash_map.default_max_load_percentage);
19768
19767fn explainWhyTypeIsComptime(19769fn explainWhyTypeIsComptime(
19768 sema: *Sema,19770 sema: *Sema,
19769 block: *Block,19771 block: *Block,
...@@ -19771,6 +19773,22 @@ fn explainWhyTypeIsComptime(...@@ -19771,6 +19773,22 @@ fn explainWhyTypeIsComptime(
19771 msg: *Module.ErrorMsg,19773 msg: *Module.ErrorMsg,
19772 src_loc: Module.SrcLoc,19774 src_loc: Module.SrcLoc,
19773 ty: Type,19775 ty: Type,
19776) CompileError!void {
19777 var type_set = TypeSet{};
19778 defer type_set.deinit(sema.gpa);
19779
19780 try sema.resolveTypeFully(block, src, ty);
19781 return sema.explainWhyTypeIsComptimeInner(block, src, msg, src_loc, ty, &type_set);
19782}
19783
19784fn explainWhyTypeIsComptimeInner(
19785 sema: *Sema,
19786 block: *Block,
19787 src: LazySrcLoc,
19788 msg: *Module.ErrorMsg,
19789 src_loc: Module.SrcLoc,
19790 ty: Type,
19791 type_set: *TypeSet,
19774) CompileError!void {19792) CompileError!void {
19775 const mod = sema.mod;19793 const mod = sema.mod;
19776 switch (ty.zigTypeTag()) {19794 switch (ty.zigTypeTag()) {
...@@ -19808,7 +19826,7 @@ fn explainWhyTypeIsComptime(...@@ -19808,7 +19826,7 @@ fn explainWhyTypeIsComptime(
19808 },19826 },
1980919827
19810 .Array, .Vector => {19828 .Array, .Vector => {
19811 try sema.explainWhyTypeIsComptime(block, src, msg, src_loc, ty.elemType());19829 try sema.explainWhyTypeIsComptimeInner(block, src, msg, src_loc, ty.elemType(), type_set);
19812 },19830 },
19813 .Pointer => {19831 .Pointer => {
19814 const elem_ty = ty.elemType2();19832 const elem_ty = ty.elemType2();
...@@ -19826,18 +19844,20 @@ fn explainWhyTypeIsComptime(...@@ -19826,18 +19844,20 @@ fn explainWhyTypeIsComptime(
19826 }19844 }
19827 return;19845 return;
19828 }19846 }
19829 try sema.explainWhyTypeIsComptime(block, src, msg, src_loc, ty.elemType());19847 try sema.explainWhyTypeIsComptimeInner(block, src, msg, src_loc, ty.elemType(), type_set);
19830 },19848 },
1983119849
19832 .Optional => {19850 .Optional => {
19833 var buf: Type.Payload.ElemType = undefined;19851 var buf: Type.Payload.ElemType = undefined;
19834 try sema.explainWhyTypeIsComptime(block, src, msg, src_loc, ty.optionalChild(&buf));19852 try sema.explainWhyTypeIsComptimeInner(block, src, msg, src_loc, ty.optionalChild(&buf), type_set);
19835 },19853 },
19836 .ErrorUnion => {19854 .ErrorUnion => {
19837 try sema.explainWhyTypeIsComptime(block, src, msg, src_loc, ty.errorUnionPayload());19855 try sema.explainWhyTypeIsComptimeInner(block, src, msg, src_loc, ty.errorUnionPayload(), type_set);
19838 },19856 },
1983919857
19840 .Struct => {19858 .Struct => {
19859 if ((try type_set.getOrPutContext(sema.gpa, ty, .{ .mod = mod })).found_existing) return;
19860
19841 if (ty.castTag(.@"struct")) |payload| {19861 if (ty.castTag(.@"struct")) |payload| {
19842 const struct_obj = payload.data;19862 const struct_obj = payload.data;
19843 for (struct_obj.fields.values()) |field, i| {19863 for (struct_obj.fields.values()) |field, i| {
...@@ -19845,9 +19865,10 @@ fn explainWhyTypeIsComptime(...@@ -19845,9 +19865,10 @@ fn explainWhyTypeIsComptime(
19845 .index = i,19865 .index = i,
19846 .range = .type,19866 .range = .type,
19847 });19867 });
19868
19848 if (try sema.typeRequiresComptime(block, src, field.ty)) {19869 if (try sema.typeRequiresComptime(block, src, field.ty)) {
19849 try mod.errNoteNonLazy(field_src_loc, msg, "struct requires comptime because of this field", .{});19870 try mod.errNoteNonLazy(field_src_loc, msg, "struct requires comptime because of this field", .{});
19850 try sema.explainWhyTypeIsComptime(block, src, msg, field_src_loc, field.ty);19871 try sema.explainWhyTypeIsComptimeInner(block, src, msg, field_src_loc, field.ty, type_set);
19851 }19872 }
19852 }19873 }
19853 }19874 }
...@@ -19855,6 +19876,8 @@ fn explainWhyTypeIsComptime(...@@ -19855,6 +19876,8 @@ fn explainWhyTypeIsComptime(
19855 },19876 },
1985619877
19857 .Union => {19878 .Union => {
19879 if ((try type_set.getOrPutContext(sema.gpa, ty, .{ .mod = mod })).found_existing) return;
19880
19858 if (ty.cast(Type.Payload.Union)) |payload| {19881 if (ty.cast(Type.Payload.Union)) |payload| {
19859 const union_obj = payload.data;19882 const union_obj = payload.data;
19860 for (union_obj.fields.values()) |field, i| {19883 for (union_obj.fields.values()) |field, i| {
...@@ -19862,9 +19885,10 @@ fn explainWhyTypeIsComptime(...@@ -19862,9 +19885,10 @@ fn explainWhyTypeIsComptime(
19862 .index = i,19885 .index = i,
19863 .range = .type,19886 .range = .type,
19864 });19887 });
19888
19865 if (try sema.typeRequiresComptime(block, src, field.ty)) {19889 if (try sema.typeRequiresComptime(block, src, field.ty)) {
19866 try mod.errNoteNonLazy(field_src_loc, msg, "union requires comptime because of this field", .{});19890 try mod.errNoteNonLazy(field_src_loc, msg, "union requires comptime because of this field", .{});
19867 try sema.explainWhyTypeIsComptime(block, src, msg, field_src_loc, field.ty);19891 try sema.explainWhyTypeIsComptimeInner(block, src, msg, field_src_loc, field.ty, type_set);
19868 }19892 }
19869 }19893 }
19870 }19894 }
test/cases/compile_errors/AstGen_comptime_known_struct_is_resolved_before_error.zig created+19
...@@ -0,0 +1,19 @@
1const S1 = struct {
2 a: S2,
3};
4const S2 = struct {
5 b: fn () void,
6};
7pub export fn entry() void {
8 var s: S1 = undefined;
9 _ = s;
10}
11
12// error
13// backend=stage2
14// target=native
15//
16// :8:12: error: variable of type 'tmp.S1' must be const or comptime
17// :2:8: note: struct requires comptime because of this field
18// :5:8: note: struct requires comptime because of this field
19// :5:8: note: use '*const fn() void' for a function pointer type
test/cases/compile_errors/self_referential_struct_requires_comptime.zig created+18
...@@ -0,0 +1,18 @@
1const S = struct {
2 a: fn () void,
3 b: *S,
4};
5pub export fn entry() void {
6 var s: S = undefined;
7 _ = s;
8}
9
10
11// error
12// backend=stage2
13// target=native
14//
15// :6:12: error: variable of type 'tmp.S' must be const or comptime
16// :2:8: note: struct requires comptime because of this field
17// :2:8: note: use '*const fn() void' for a function pointer type
18// :3:8: note: struct requires comptime because of this field
test/cases/compile_errors/self_referential_union_requires_comptime.zig created+17
...@@ -0,0 +1,17 @@
1const U = union {
2 a: fn () void,
3 b: *U,
4};
5pub export fn entry() void {
6 var u: U = undefined;
7 _ = u;
8}
9
10// error
11// backend=stage2
12// target=native
13//
14// :6:12: error: variable of type 'tmp.U' must be const or comptime
15// :2:8: note: union requires comptime because of this field
16// :2:8: note: use '*const fn() void' for a function pointer type
17// :3:8: note: union requires comptime because of this field