| author | |
| committer | |
| log | 7e9b23e6dce4d87615acd635f3731731a8601d39 |
| tree | 392b32ff570328a8fcd984013ad844b063beaa77 |
| parent | c7dc451a2a06a0ade0bb44a48cb6e5cde6e237df |
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 | 2461 | |
| 2462 | 2462 | const gpa = sema.gpa; |
| 2463 | 2463 | |
| 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 | 2466 | const is_inline_call = is_comptime_call or modifier == .always_inline or |
| 2466 | 2467 | func_ty_info.cc == .Inline; |
| 2467 | 2468 | const result: Air.Inst.Ref = if (is_inline_call) res: { |
| ... | ... | @@ -3609,6 +3610,8 @@ fn funcCommon( |
| 3609 | 3610 | return mod.fail(&block.base, src, "TODO implement support for function prototypes to have alignment specified", .{}); |
| 3610 | 3611 | } |
| 3611 | 3612 | |
| 3613 | is_generic = is_generic or bare_return_type.requiresComptime(); | |
| 3614 | ||
| 3612 | 3615 | const return_type = if (!inferred_error_set or bare_return_type.tag() == .generic_poison) |
| 3613 | 3616 | bare_return_type |
| 3614 | 3617 | else blk: { |
| ... | ... | @@ -5334,18 +5337,18 @@ fn analyzeArithmetic( |
| 5334 | 5337 | ) CompileError!Air.Inst.Ref { |
| 5335 | 5338 | const lhs_ty = sema.typeOf(lhs); |
| 5336 | 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 | 5343 | if (lhs_ty.arrayLen() != rhs_ty.arrayLen()) { |
| 5339 | 5344 | 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(), | |
| 5342 | 5346 | }); |
| 5343 | 5347 | } |
| 5344 | 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 | 5350 | 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, | |
| 5349 | 5352 | }); |
| 5350 | 5353 | } |
| 5351 | 5354 | |
| ... | ... | @@ -5365,7 +5368,9 @@ fn analyzeArithmetic( |
| 5365 | 5368 | const is_float = scalar_tag == .Float or scalar_tag == .ComptimeFloat; |
| 5366 | 5369 | |
| 5367 | 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 | } |
| 5370 | 5375 | |
| 5371 | 5376 | if (try sema.resolveMaybeUndefVal(block, lhs_src, casted_lhs)) |lhs_val| { |
| ... | ... | @@ -6164,6 +6169,10 @@ fn analyzeRet( |
| 6164 | 6169 | const casted_operand = if (!need_coercion) operand else op: { |
| 6165 | 6170 | const func = sema.func.?; |
| 6166 | 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 | 6176 | const fn_ret_ty = fn_ty.fnReturnType(); |
| 6168 | 6177 | break :op try sema.coerce(block, fn_ret_ty, operand, src); |
| 6169 | 6178 | }; |
| ... | ... | @@ -9093,7 +9102,7 @@ fn typeHasOnePossibleValue( |
| 9093 | 9102 | |
| 9094 | 9103 | .inferred_alloc_const => unreachable, |
| 9095 | 9104 | .inferred_alloc_mut => unreachable, |
| 9096 | .generic_poison => unreachable, | |
| 9105 | .generic_poison => return error.GenericPoison, | |
| 9097 | 9106 | }; |
| 9098 | 9107 | } |
| 9099 | 9108 |
src/Zir.zig+10-6| ... | ... | @@ -4501,12 +4501,16 @@ const Writer = struct { |
| 4501 | 4501 | src: LazySrcLoc, |
| 4502 | 4502 | src_locs: Zir.Inst.Func.SrcLocs, |
| 4503 | 4503 | ) !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 | } | |
| 4510 | 4514 | |
| 4511 | 4515 | try self.writeOptionalInstRef(stream, ", cc=", cc); |
| 4512 | 4516 | try self.writeOptionalInstRef(stream, ", align=", align_inst); |
src/type.zig+10-4| ... | ... | @@ -21,8 +21,14 @@ pub const Type = extern union { |
| 21 | 21 | tag_if_small_enough: usize, |
| 22 | 22 | ptr_otherwise: *Payload, |
| 23 | 23 | |
| 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 | ||
| 26 | 32 | .u1, |
| 27 | 33 | .u8, |
| 28 | 34 | .i8, |
| ... | ... | @@ -130,7 +136,6 @@ pub const Type = extern union { |
| 130 | 136 | => return .Union, |
| 131 | 137 | |
| 132 | 138 | .var_args_param => unreachable, // can be any type |
| 133 | .generic_poison => unreachable, // must be handled earlier | |
| 134 | 139 | } |
| 135 | 140 | } |
| 136 | 141 | |
| ... | ... | @@ -1096,6 +1101,7 @@ pub const Type = extern union { |
| 1096 | 1101 | } |
| 1097 | 1102 | |
| 1098 | 1103 | /// Anything that reports hasCodeGenBits() false returns false here as well. |
| 1104 | /// `generic_poison` will return false. | |
| 1099 | 1105 | pub fn requiresComptime(ty: Type) bool { |
| 1100 | 1106 | return switch (ty.tag()) { |
| 1101 | 1107 | .u1, |
| ... | ... | @@ -1156,6 +1162,7 @@ pub const Type = extern union { |
| 1156 | 1162 | .error_set_single, |
| 1157 | 1163 | .error_set_inferred, |
| 1158 | 1164 | .@"opaque", |
| 1165 | .generic_poison, | |
| 1159 | 1166 | => false, |
| 1160 | 1167 | |
| 1161 | 1168 | .type, |
| ... | ... | @@ -1167,7 +1174,6 @@ pub const Type = extern union { |
| 1167 | 1174 | .var_args_param => unreachable, |
| 1168 | 1175 | .inferred_alloc_mut => unreachable, |
| 1169 | 1176 | .inferred_alloc_const => unreachable, |
| 1170 | .generic_poison => unreachable, | |
| 1171 | 1177 | |
| 1172 | 1178 | .array_u8, |
| 1173 | 1179 | .array_u8_sentinel_0, |
test/behavior/generics_stage1.zig+3-3| ... | ... | @@ -13,16 +13,16 @@ test { |
| 13 | 13 | comptime try expect(max_f64(1.2, 3.4) == 3.4); |
| 14 | 14 | } |
| 15 | 15 | |
| 16 | fn max_var(a: anytype, b: anytype) @TypeOf(a + b) { | |
| 16 | fn max_anytype(a: anytype, b: anytype) @TypeOf(a + b) { | |
| 17 | 17 | return if (a > b) a else b; |
| 18 | 18 | } |
| 19 | 19 | |
| 20 | 20 | fn max_i32(a: i32, b: i32) i32 { |
| 21 | return max_var(a, b); | |
| 21 | return max_anytype(a, b); | |
| 22 | 22 | } |
| 23 | 23 | |
| 24 | 24 | fn max_f64(a: f64, b: f64) f64 { |
| 25 | return max_var(a, b); | |
| 25 | return max_anytype(a, b); | |
| 26 | 26 | } |
| 27 | 27 | |
| 28 | 28 | pub fn List(comptime T: type) type { |