authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-24 19:36:36-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-24 19:36:36-07:00
logbb0e28a54ff60581c30156707eeeba1a6bd2b28f
treef7a1fd645bff8dedf1c95f38b22ab706aa6b7fe2
parent7cfa97aa4ee9eb49d97d7d3b88488387bf6d175f

Sema: fix generic function with void parameters

This also fixes a bug that I didn't see causing any problems yet in generic function instantiation where it would read from a GetOrPutResult too late. Also it delays full resolution of generic function type parameters until after the function body is finished being analyzed. closes #11291

2 files changed, 31 insertions(+), 4 deletions(-)

src/Sema.zig+18-4
...@@ -5149,7 +5149,7 @@ fn instantiateGenericCall(...@@ -5149,7 +5149,7 @@ fn instantiateGenericCall(
5149 .target = target,5149 .target = target,
5150 };5150 };
5151 const gop = try mod.monomorphed_funcs.getOrPutContextAdapted(gpa, {}, adapter, .{ .target = target });5151 const gop = try mod.monomorphed_funcs.getOrPutContextAdapted(gpa, {}, adapter, .{ .target = target });
5152 if (!gop.found_existing) {5152 const callee = if (!gop.found_existing) callee: {
5153 const new_module_func = try gpa.create(Module.Fn);5153 const new_module_func = try gpa.create(Module.Fn);
5154 gop.key_ptr.* = new_module_func;5154 gop.key_ptr.* = new_module_func;
5155 errdefer gpa.destroy(new_module_func);5155 errdefer gpa.destroy(new_module_func);
...@@ -5357,9 +5357,9 @@ fn instantiateGenericCall(...@@ -5357,9 +5357,9 @@ fn instantiateGenericCall(
5357 try mod.comp.work_queue.writeItem(.{ .codegen_func = new_func });5357 try mod.comp.work_queue.writeItem(.{ .codegen_func = new_func });
53585358
5359 try new_decl.finalizeNewArena(&new_decl_arena);5359 try new_decl.finalizeNewArena(&new_decl_arena);
5360 }5360 break :callee new_func;
5361 } else gop.key_ptr.*;
53615362
5362 const callee = gop.key_ptr.*;
5363 const callee_inst = try sema.analyzeDeclVal(block, func_src, callee.owner_decl);5363 const callee_inst = try sema.analyzeDeclVal(block, func_src, callee.owner_decl);
53645364
5365 // Make a runtime call to the new function, making sure to omit the comptime args.5365 // Make a runtime call to the new function, making sure to omit the comptime args.
...@@ -5397,8 +5397,8 @@ fn instantiateGenericCall(...@@ -5397,8 +5397,8 @@ fn instantiateGenericCall(
5397 const param_ty = new_fn_info.param_types[runtime_i];5397 const param_ty = new_fn_info.param_types[runtime_i];
5398 const arg_src = call_src; // TODO: better source location5398 const arg_src = call_src; // TODO: better source location
5399 const uncasted_arg = uncasted_args[total_i];5399 const uncasted_arg = uncasted_args[total_i];
5400 try sema.resolveTypeFully(block, arg_src, param_ty);
5401 const casted_arg = try sema.coerce(block, param_ty, uncasted_arg, arg_src);5400 const casted_arg = try sema.coerce(block, param_ty, uncasted_arg, arg_src);
5401 try sema.queueFullTypeResolution(param_ty);
5402 runtime_args[runtime_i] = casted_arg;5402 runtime_args[runtime_i] = casted_arg;
5403 runtime_i += 1;5403 runtime_i += 1;
5404 }5404 }
...@@ -6474,10 +6474,13 @@ fn zirParam(...@@ -6474,10 +6474,13 @@ fn zirParam(
6474 const err = err: {6474 const err = err: {
6475 // Make sure any nested param instructions don't clobber our work.6475 // Make sure any nested param instructions don't clobber our work.
6476 const prev_params = block.params;6476 const prev_params = block.params;
6477 const prev_preallocated_new_func = sema.preallocated_new_func;
6477 block.params = .{};6478 block.params = .{};
6479 sema.preallocated_new_func = null;
6478 defer {6480 defer {
6479 block.params.deinit(sema.gpa);6481 block.params.deinit(sema.gpa);
6480 block.params = prev_params;6482 block.params = prev_params;
6483 sema.preallocated_new_func = prev_preallocated_new_func;
6481 }6484 }
64826485
6483 if (sema.resolveBody(block, body, inst)) |param_ty_inst| {6486 if (sema.resolveBody(block, body, inst)) |param_ty_inst| {
...@@ -6524,6 +6527,17 @@ fn zirParam(...@@ -6524,6 +6527,17 @@ fn zirParam(
6524 assert(sema.inst_map.remove(inst));6527 assert(sema.inst_map.remove(inst));
6525 }6528 }
65266529
6530 if (sema.preallocated_new_func != null) {
6531 if (try sema.typeHasOnePossibleValue(block, src, param_ty)) |opv| {
6532 // In this case we are instantiating a generic function call with a non-comptime
6533 // non-anytype parameter that ended up being a one-possible-type.
6534 // We don't want the parameter to be part of the instantiated function type.
6535 const result = try sema.addConstant(param_ty, opv);
6536 try sema.inst_map.put(sema.gpa, inst, result);
6537 return;
6538 }
6539 }
6540
6527 try block.params.append(sema.gpa, .{6541 try block.params.append(sema.gpa, .{
6528 .ty = param_ty,6542 .ty = param_ty,
6529 .is_comptime = is_comptime,6543 .is_comptime = is_comptime,
test/behavior/generics.zig+13
...@@ -277,3 +277,16 @@ test "generic function instantiation turns into comptime call" {...@@ -277,3 +277,16 @@ test "generic function instantiation turns into comptime call" {
277 };277 };
278 try S.doTheTest();278 try S.doTheTest();
279}279}
280
281test "generic function with void and comptime parameter" {
282 const S = struct { x: i32 };
283 const namespace = struct {
284 fn foo(v: void, s: *S, comptime T: type) !void {
285 _ = @as(void, v);
286 try expect(s.x == 1234);
287 try expect(T == u8);
288 }
289 };
290 var s: S = .{ .x = 1234 };
291 try namespace.foo({}, &s, u8);
292}