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(...@@ -2461,7 +2461,8 @@ fn analyzeCall(
24612461
2462 const gpa = sema.gpa;2462 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();
2465 const is_inline_call = is_comptime_call or modifier == .always_inline or2466 const is_inline_call = is_comptime_call or modifier == .always_inline or
2466 func_ty_info.cc == .Inline;2467 func_ty_info.cc == .Inline;
2467 const result: Air.Inst.Ref = if (is_inline_call) res: {2468 const result: Air.Inst.Ref = if (is_inline_call) res: {
...@@ -3609,6 +3610,8 @@ fn funcCommon(...@@ -3609,6 +3610,8 @@ fn funcCommon(
3609 return mod.fail(&block.base, src, "TODO implement support for function prototypes to have alignment specified", .{});3610 return mod.fail(&block.base, src, "TODO implement support for function prototypes to have alignment specified", .{});
3610 }3611 }
36113612
3613 is_generic = is_generic or bare_return_type.requiresComptime();
3614
3612 const return_type = if (!inferred_error_set or bare_return_type.tag() == .generic_poison)3615 const return_type = if (!inferred_error_set or bare_return_type.tag() == .generic_poison)
3613 bare_return_type3616 bare_return_type
3614 else blk: {3617 else blk: {
...@@ -5334,18 +5337,18 @@ fn analyzeArithmetic(...@@ -5334,18 +5337,18 @@ fn analyzeArithmetic(
5334) CompileError!Air.Inst.Ref {5337) CompileError!Air.Inst.Ref {
5335 const lhs_ty = sema.typeOf(lhs);5338 const lhs_ty = sema.typeOf(lhs);
5336 const rhs_ty = sema.typeOf(rhs);5339 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) {
5338 if (lhs_ty.arrayLen() != rhs_ty.arrayLen()) {5343 if (lhs_ty.arrayLen() != rhs_ty.arrayLen()) {
5339 return sema.mod.fail(&block.base, src, "vector length mismatch: {d} and {d}", .{5344 return sema.mod.fail(&block.base, src, "vector length mismatch: {d} and {d}", .{
5340 lhs_ty.arrayLen(),5345 lhs_ty.arrayLen(), rhs_ty.arrayLen(),
5341 rhs_ty.arrayLen(),
5342 });5346 });
5343 }5347 }
5344 return sema.mod.fail(&block.base, src, "TODO implement support for vectors in zirBinOp", .{});5348 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) {
5346 return sema.mod.fail(&block.base, src, "mixed scalar and vector operands to binary expression: '{}' and '{}'", .{5350 return sema.mod.fail(&block.base, src, "mixed scalar and vector operands to binary expression: '{}' and '{}'", .{
5347 lhs_ty,5351 lhs_ty, rhs_ty,
5348 rhs_ty,
5349 });5352 });
5350 }5353 }
53515354
...@@ -5365,7 +5368,9 @@ fn analyzeArithmetic(...@@ -5365,7 +5368,9 @@ fn analyzeArithmetic(
5365 const is_float = scalar_tag == .Float or scalar_tag == .ComptimeFloat;5368 const is_float = scalar_tag == .Float or scalar_tag == .ComptimeFloat;
53665369
5367 if (!is_int and !(is_float and floatOpAllowed(zir_tag))) {5370 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 });
5369 }5374 }
53705375
5371 if (try sema.resolveMaybeUndefVal(block, lhs_src, casted_lhs)) |lhs_val| {5376 if (try sema.resolveMaybeUndefVal(block, lhs_src, casted_lhs)) |lhs_val| {
...@@ -6164,6 +6169,10 @@ fn analyzeRet(...@@ -6164,6 +6169,10 @@ fn analyzeRet(
6164 const casted_operand = if (!need_coercion) operand else op: {6169 const casted_operand = if (!need_coercion) operand else op: {
6165 const func = sema.func.?;6170 const func = sema.func.?;
6166 const fn_ty = func.owner_decl.ty;6171 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.
6167 const fn_ret_ty = fn_ty.fnReturnType();6176 const fn_ret_ty = fn_ty.fnReturnType();
6168 break :op try sema.coerce(block, fn_ret_ty, operand, src);6177 break :op try sema.coerce(block, fn_ret_ty, operand, src);
6169 };6178 };
...@@ -9093,7 +9102,7 @@ fn typeHasOnePossibleValue(...@@ -9093,7 +9102,7 @@ fn typeHasOnePossibleValue(
90939102
9094 .inferred_alloc_const => unreachable,9103 .inferred_alloc_const => unreachable,
9095 .inferred_alloc_mut => unreachable,9104 .inferred_alloc_mut => unreachable,
9096 .generic_poison => unreachable,9105 .generic_poison => return error.GenericPoison,
9097 };9106 };
9098}9107}
90999108
src/Zir.zig+10-6
...@@ -4501,12 +4501,16 @@ const Writer = struct {...@@ -4501,12 +4501,16 @@ const Writer = struct {
4501 src: LazySrcLoc,4501 src: LazySrcLoc,
4502 src_locs: Zir.Inst.Func.SrcLocs,4502 src_locs: Zir.Inst.Func.SrcLocs,
4503 ) !void {4503 ) !void {
4504 try stream.writeAll("ret_ty={\n");4504 if (ret_ty_body.len == 0) {
4505 self.indent += 2;4505 try stream.writeAll("ret_ty=void");
4506 try self.writeBody(stream, ret_ty_body);4506 } else {
4507 self.indent -= 2;4507 try stream.writeAll("ret_ty={\n");
4508 try stream.writeByteNTimes(' ', self.indent);4508 self.indent += 2;
4509 try stream.writeAll("}");4509 try self.writeBody(stream, ret_ty_body);
4510 self.indent -= 2;
4511 try stream.writeByteNTimes(' ', self.indent);
4512 try stream.writeAll("}");
4513 }
45104514
4511 try self.writeOptionalInstRef(stream, ", cc=", cc);4515 try self.writeOptionalInstRef(stream, ", cc=", cc);
4512 try self.writeOptionalInstRef(stream, ", align=", align_inst);4516 try self.writeOptionalInstRef(stream, ", align=", align_inst);
src/type.zig+10-4
...@@ -21,8 +21,14 @@ pub const Type = extern union {...@@ -21,8 +21,14 @@ pub const Type = extern union {
21 tag_if_small_enough: usize,21 tag_if_small_enough: usize,
22 ptr_otherwise: *Payload,22 ptr_otherwise: *Payload,
2323
24 pub fn zigTypeTag(self: Type) std.builtin.TypeId {24 pub fn zigTypeTag(ty: Type) std.builtin.TypeId {
25 switch (self.tag()) {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
26 .u1,32 .u1,
27 .u8,33 .u8,
28 .i8,34 .i8,
...@@ -130,7 +136,6 @@ pub const Type = extern union {...@@ -130,7 +136,6 @@ pub const Type = extern union {
130 => return .Union,136 => return .Union,
131137
132 .var_args_param => unreachable, // can be any type138 .var_args_param => unreachable, // can be any type
133 .generic_poison => unreachable, // must be handled earlier
134 }139 }
135 }140 }
136141
...@@ -1096,6 +1101,7 @@ pub const Type = extern union {...@@ -1096,6 +1101,7 @@ pub const Type = extern union {
1096 }1101 }
10971102
1098 /// Anything that reports hasCodeGenBits() false returns false here as well.1103 /// Anything that reports hasCodeGenBits() false returns false here as well.
1104 /// `generic_poison` will return false.
1099 pub fn requiresComptime(ty: Type) bool {1105 pub fn requiresComptime(ty: Type) bool {
1100 return switch (ty.tag()) {1106 return switch (ty.tag()) {
1101 .u1,1107 .u1,
...@@ -1156,6 +1162,7 @@ pub const Type = extern union {...@@ -1156,6 +1162,7 @@ pub const Type = extern union {
1156 .error_set_single,1162 .error_set_single,
1157 .error_set_inferred,1163 .error_set_inferred,
1158 .@"opaque",1164 .@"opaque",
1165 .generic_poison,
1159 => false,1166 => false,
11601167
1161 .type,1168 .type,
...@@ -1167,7 +1174,6 @@ pub const Type = extern union {...@@ -1167,7 +1174,6 @@ pub const Type = extern union {
1167 .var_args_param => unreachable,1174 .var_args_param => unreachable,
1168 .inferred_alloc_mut => unreachable,1175 .inferred_alloc_mut => unreachable,
1169 .inferred_alloc_const => unreachable,1176 .inferred_alloc_const => unreachable,
1170 .generic_poison => unreachable,
11711177
1172 .array_u8,1178 .array_u8,
1173 .array_u8_sentinel_0,1179 .array_u8_sentinel_0,
test/behavior/generics_stage1.zig+3-3
...@@ -13,16 +13,16 @@ test {...@@ -13,16 +13,16 @@ test {
13 comptime try expect(max_f64(1.2, 3.4) == 3.4);13 comptime try expect(max_f64(1.2, 3.4) == 3.4);
14}14}
1515
16fn max_var(a: anytype, b: anytype) @TypeOf(a + b) {16fn max_anytype(a: anytype, b: anytype) @TypeOf(a + b) {
17 return if (a > b) a else b;17 return if (a > b) a else b;
18}18}
1919
20fn max_i32(a: i32, b: i32) i32 {20fn max_i32(a: i32, b: i32) i32 {
21 return max_var(a, b);21 return max_anytype(a, b);
22}22}
2323
24fn max_f64(a: f64, b: f64) f64 {24fn max_f64(a: f64, b: f64) f64 {
25 return max_var(a, b);25 return max_anytype(a, b);
26}26}
2727
28pub fn List(comptime T: type) type {28pub fn List(comptime T: type) type {