authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-08-05 23:23:05-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-08-05 23:26:11-07:00
log7e9b23e6dce4d87615acd635f3731731a8601d39
tree392b32ff570328a8fcd984013ad844b063beaa77
parentc7dc451a2a06a0ade0bb44a48cb6e5cde6e237df

Sema: respect requiresComptime of function return types

When doing a function call, if the return type requires comptime, the function is analyzed as an inline/comptime call. There is an important TODO here. I will reproduce the comment from this commit: > In the case of a comptime/inline function call of a generic function, > the function return type needs to be the resolved return type based on > the function parameter type expressions being evaluated with comptime arguments > passed in. Otherwise, it ends up being .generic_poison and failing the > comptime/inline function call analysis.

4 files changed, 41 insertions(+), 22 deletions(-)

src/Sema.zig+18-9
......@@ -2461,7 +2461,8 @@ fn analyzeCall(
24612461
24622462 const gpa = sema.gpa;
24632463
2464 const is_comptime_call = block.is_comptime or modifier == .compile_time;
2464 const is_comptime_call = block.is_comptime or modifier == .compile_time or
2465 func_ty_info.return_type.requiresComptime();
24652466 const is_inline_call = is_comptime_call or modifier == .always_inline or
24662467 func_ty_info.cc == .Inline;
24672468 const result: Air.Inst.Ref = if (is_inline_call) res: {
......@@ -3609,6 +3610,8 @@ fn funcCommon(
36093610 return mod.fail(&block.base, src, "TODO implement support for function prototypes to have alignment specified", .{});
36103611 }
36113612
3613 is_generic = is_generic or bare_return_type.requiresComptime();
3614
36123615 const return_type = if (!inferred_error_set or bare_return_type.tag() == .generic_poison)
36133616 bare_return_type
36143617 else blk: {
......@@ -5334,18 +5337,18 @@ fn analyzeArithmetic(
53345337) CompileError!Air.Inst.Ref {
53355338 const lhs_ty = sema.typeOf(lhs);
53365339 const rhs_ty = sema.typeOf(rhs);
5337 if (lhs_ty.zigTypeTag() == .Vector and rhs_ty.zigTypeTag() == .Vector) {
5340 const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison();
5341 const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison();
5342 if (lhs_zig_ty_tag == .Vector and rhs_zig_ty_tag == .Vector) {
53385343 if (lhs_ty.arrayLen() != rhs_ty.arrayLen()) {
53395344 return sema.mod.fail(&block.base, src, "vector length mismatch: {d} and {d}", .{
5340 lhs_ty.arrayLen(),
5341 rhs_ty.arrayLen(),
5345 lhs_ty.arrayLen(), rhs_ty.arrayLen(),
53425346 });
53435347 }
53445348 return sema.mod.fail(&block.base, src, "TODO implement support for vectors in zirBinOp", .{});
5345 } else if (lhs_ty.zigTypeTag() == .Vector or rhs_ty.zigTypeTag() == .Vector) {
5349 } else if (lhs_zig_ty_tag == .Vector or rhs_zig_ty_tag == .Vector) {
53465350 return sema.mod.fail(&block.base, src, "mixed scalar and vector operands to binary expression: '{}' and '{}'", .{
5347 lhs_ty,
5348 rhs_ty,
5351 lhs_ty, rhs_ty,
53495352 });
53505353 }
53515354
......@@ -5365,7 +5368,9 @@ fn analyzeArithmetic(
53655368 const is_float = scalar_tag == .Float or scalar_tag == .ComptimeFloat;
53665369
53675370 if (!is_int and !(is_float and floatOpAllowed(zir_tag))) {
5368 return sema.mod.fail(&block.base, src, "invalid operands to binary expression: '{s}' and '{s}'", .{ @tagName(lhs_ty.zigTypeTag()), @tagName(rhs_ty.zigTypeTag()) });
5371 return sema.mod.fail(&block.base, src, "invalid operands to binary expression: '{s}' and '{s}'", .{
5372 @tagName(lhs_zig_ty_tag), @tagName(rhs_zig_ty_tag),
5373 });
53695374 }
53705375
53715376 if (try sema.resolveMaybeUndefVal(block, lhs_src, casted_lhs)) |lhs_val| {
......@@ -6164,6 +6169,10 @@ fn analyzeRet(
61646169 const casted_operand = if (!need_coercion) operand else op: {
61656170 const func = sema.func.?;
61666171 const fn_ty = func.owner_decl.ty;
6172 // TODO: In the case of a comptime/inline function call of a generic function,
6173 // this needs to be the resolved return type based on the function parameter type
6174 // expressions being evaluated with comptime arguments passed in. Otherwise, this
6175 // ends up being .generic_poison and failing the comptime/inline function call analysis.
61676176 const fn_ret_ty = fn_ty.fnReturnType();
61686177 break :op try sema.coerce(block, fn_ret_ty, operand, src);
61696178 };
......@@ -9093,7 +9102,7 @@ fn typeHasOnePossibleValue(
90939102
90949103 .inferred_alloc_const => unreachable,
90959104 .inferred_alloc_mut => unreachable,
9096 .generic_poison => unreachable,
9105 .generic_poison => return error.GenericPoison,
90979106 };
90989107}
90999108
src/Zir.zig+10-6
......@@ -4501,12 +4501,16 @@ const Writer = struct {
45014501 src: LazySrcLoc,
45024502 src_locs: Zir.Inst.Func.SrcLocs,
45034503 ) !void {
4504 try stream.writeAll("ret_ty={\n");
4505 self.indent += 2;
4506 try self.writeBody(stream, ret_ty_body);
4507 self.indent -= 2;
4508 try stream.writeByteNTimes(' ', self.indent);
4509 try stream.writeAll("}");
4504 if (ret_ty_body.len == 0) {
4505 try stream.writeAll("ret_ty=void");
4506 } else {
4507 try stream.writeAll("ret_ty={\n");
4508 self.indent += 2;
4509 try self.writeBody(stream, ret_ty_body);
4510 self.indent -= 2;
4511 try stream.writeByteNTimes(' ', self.indent);
4512 try stream.writeAll("}");
4513 }
45104514
45114515 try self.writeOptionalInstRef(stream, ", cc=", cc);
45124516 try self.writeOptionalInstRef(stream, ", align=", align_inst);
src/type.zig+10-4
......@@ -21,8 +21,14 @@ pub const Type = extern union {
2121 tag_if_small_enough: usize,
2222 ptr_otherwise: *Payload,
2323
24 pub fn zigTypeTag(self: Type) std.builtin.TypeId {
25 switch (self.tag()) {
24 pub fn zigTypeTag(ty: Type) std.builtin.TypeId {
25 return ty.zigTypeTagOrPoison() catch unreachable;
26 }
27
28 pub fn zigTypeTagOrPoison(ty: Type) error{GenericPoison}!std.builtin.TypeId {
29 switch (ty.tag()) {
30 .generic_poison => return error.GenericPoison,
31
2632 .u1,
2733 .u8,
2834 .i8,
......@@ -130,7 +136,6 @@ pub const Type = extern union {
130136 => return .Union,
131137
132138 .var_args_param => unreachable, // can be any type
133 .generic_poison => unreachable, // must be handled earlier
134139 }
135140 }
136141
......@@ -1096,6 +1101,7 @@ pub const Type = extern union {
10961101 }
10971102
10981103 /// Anything that reports hasCodeGenBits() false returns false here as well.
1104 /// `generic_poison` will return false.
10991105 pub fn requiresComptime(ty: Type) bool {
11001106 return switch (ty.tag()) {
11011107 .u1,
......@@ -1156,6 +1162,7 @@ pub const Type = extern union {
11561162 .error_set_single,
11571163 .error_set_inferred,
11581164 .@"opaque",
1165 .generic_poison,
11591166 => false,
11601167
11611168 .type,
......@@ -1167,7 +1174,6 @@ pub const Type = extern union {
11671174 .var_args_param => unreachable,
11681175 .inferred_alloc_mut => unreachable,
11691176 .inferred_alloc_const => unreachable,
1170 .generic_poison => unreachable,
11711177
11721178 .array_u8,
11731179 .array_u8_sentinel_0,
test/behavior/generics_stage1.zig+3-3
......@@ -13,16 +13,16 @@ test {
1313 comptime try expect(max_f64(1.2, 3.4) == 3.4);
1414}
1515
16fn max_var(a: anytype, b: anytype) @TypeOf(a + b) {
16fn max_anytype(a: anytype, b: anytype) @TypeOf(a + b) {
1717 return if (a > b) a else b;
1818}
1919
2020fn max_i32(a: i32, b: i32) i32 {
21 return max_var(a, b);
21 return max_anytype(a, b);
2222}
2323
2424fn max_f64(a: f64, b: f64) f64 {
25 return max_var(a, b);
25 return max_anytype(a, b);
2626}
2727
2828pub fn List(comptime T: type) type {