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
This commit is contained in:
Andrew Kelley 2022-03-24 19:36:36 -07:00
parent 7cfa97aa4e
commit bb0e28a54f
2 changed files with 31 additions and 4 deletions

View File

@ -5149,7 +5149,7 @@ fn instantiateGenericCall(
.target = target,
};
const gop = try mod.monomorphed_funcs.getOrPutContextAdapted(gpa, {}, adapter, .{ .target = target });
if (!gop.found_existing) {
const callee = if (!gop.found_existing) callee: {
const new_module_func = try gpa.create(Module.Fn);
gop.key_ptr.* = new_module_func;
errdefer gpa.destroy(new_module_func);
@ -5357,9 +5357,9 @@ fn instantiateGenericCall(
try mod.comp.work_queue.writeItem(.{ .codegen_func = new_func });
try new_decl.finalizeNewArena(&new_decl_arena);
}
break :callee new_func;
} else gop.key_ptr.*;
const callee = gop.key_ptr.*;
const callee_inst = try sema.analyzeDeclVal(block, func_src, callee.owner_decl);
// Make a runtime call to the new function, making sure to omit the comptime args.
@ -5397,8 +5397,8 @@ fn instantiateGenericCall(
const param_ty = new_fn_info.param_types[runtime_i];
const arg_src = call_src; // TODO: better source location
const uncasted_arg = uncasted_args[total_i];
try sema.resolveTypeFully(block, arg_src, param_ty);
const casted_arg = try sema.coerce(block, param_ty, uncasted_arg, arg_src);
try sema.queueFullTypeResolution(param_ty);
runtime_args[runtime_i] = casted_arg;
runtime_i += 1;
}
@ -6474,10 +6474,13 @@ fn zirParam(
const err = err: {
// Make sure any nested param instructions don't clobber our work.
const prev_params = block.params;
const prev_preallocated_new_func = sema.preallocated_new_func;
block.params = .{};
sema.preallocated_new_func = null;
defer {
block.params.deinit(sema.gpa);
block.params = prev_params;
sema.preallocated_new_func = prev_preallocated_new_func;
}
if (sema.resolveBody(block, body, inst)) |param_ty_inst| {
@ -6524,6 +6527,17 @@ fn zirParam(
assert(sema.inst_map.remove(inst));
}
if (sema.preallocated_new_func != null) {
if (try sema.typeHasOnePossibleValue(block, src, param_ty)) |opv| {
// In this case we are instantiating a generic function call with a non-comptime
// non-anytype parameter that ended up being a one-possible-type.
// We don't want the parameter to be part of the instantiated function type.
const result = try sema.addConstant(param_ty, opv);
try sema.inst_map.put(sema.gpa, inst, result);
return;
}
}
try block.params.append(sema.gpa, .{
.ty = param_ty,
.is_comptime = is_comptime,

View File

@ -277,3 +277,16 @@ test "generic function instantiation turns into comptime call" {
};
try S.doTheTest();
}
test "generic function with void and comptime parameter" {
const S = struct { x: i32 };
const namespace = struct {
fn foo(v: void, s: *S, comptime T: type) !void {
_ = @as(void, v);
try expect(s.x == 1234);
try expect(T == u8);
}
};
var s: S = .{ .x = 1234 };
try namespace.foo({}, &s, u8);
}