stage2: get rid of "unable to monomorphize function" error

This commit solves the problem in a much simpler way: putting
runtime-known values in place of non-comptime arguments when
instantiating a generic function.
This commit is contained in:
Andrew Kelley 2021-08-06 17:26:37 -07:00
parent ede76f4fe3
commit e974d4c429
2 changed files with 43 additions and 22 deletions

View File

@ -1376,6 +1376,16 @@ pub const Scope = struct {
});
}
pub fn addArg(block: *Block, ty: Type, name: u32) error{OutOfMemory}!Air.Inst.Ref {
return block.addInst(.{
.tag = .arg,
.data = .{ .ty_str = .{
.ty = try block.sema.addType(ty),
.str = name,
} },
});
}
pub fn addInst(block: *Block, inst: Air.Inst) error{OutOfMemory}!Air.Inst.Ref {
return Air.indexToRef(try block.addInstAsIndex(inst));
}

View File

@ -2793,16 +2793,24 @@ fn analyzeCall(
} else if (is_comptime) {
return sema.failWithNeededComptime(block, arg_src);
} else if (is_anytype) {
const child_arg = try child_sema.addConstant(
sema.typeOf(arg),
Value.initTag(.generic_poison),
);
// We insert into the map an instruction which is runtime-known
// but has the type of the comptime argument.
const child_arg = try child_block.addArg(sema.typeOf(arg), 0);
child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);
}
arg_i += 1;
}
const new_func_inst = try child_sema.resolveBody(&child_block, fn_info.param_body);
const new_func_val = try child_sema.resolveConstValue(&child_block, .unneeded, new_func_inst);
const new_func_inst = child_sema.resolveBody(&child_block, fn_info.param_body) catch |err| {
// TODO look up the compile error that happened here and attach a note to it
// pointing here, at the generic instantiation callsite.
if (sema.owner_func) |owner_func| {
owner_func.state = .dependency_failure;
} else {
sema.owner_decl.analysis = .dependency_failure;
}
return err;
};
const new_func_val = child_sema.resolveConstValue(&child_block, .unneeded, new_func_inst) catch unreachable;
const new_func = new_func_val.castTag(.function).?.data;
assert(new_func == new_module_func);
@ -2813,12 +2821,22 @@ fn analyzeCall(
else => continue,
}
const arg = child_sema.inst_map.get(inst).?;
const arg_val = (child_sema.resolveMaybeUndefValAllowVariables(&child_block, .unneeded, arg) catch unreachable).?;
child_sema.comptime_args[arg_i] = .{
.ty = try child_sema.typeOf(arg).copy(&new_decl_arena.allocator),
.val = try arg_val.copy(&new_decl_arena.allocator),
};
const copied_arg_ty = try child_sema.typeOf(arg).copy(&new_decl_arena.allocator);
if (child_sema.resolveMaybeUndefValAllowVariables(
&child_block,
.unneeded,
arg,
) catch unreachable) |arg_val| {
child_sema.comptime_args[arg_i] = .{
.ty = copied_arg_ty,
.val = try arg_val.copy(&new_decl_arena.allocator),
};
} else {
child_sema.comptime_args[arg_i] = .{
.ty = copied_arg_ty,
.val = Value.initTag(.generic_poison),
};
}
arg_i += 1;
}
@ -2828,17 +2846,10 @@ fn analyzeCall(
new_decl.val = try Value.Tag.function.create(&new_decl_arena.allocator, new_func);
new_decl.analysis = .complete;
if (new_decl.ty.fnInfo().is_generic) {
// TODO improve this error message. This can happen because of the parameter
// type expression or return type expression depending on runtime-provided values.
// The error message should be emitted in zirParam or funcCommon when it
// is determined that we are trying to instantiate a generic function.
return mod.fail(&block.base, call_src, "unable to monomorphize function", .{});
}
log.debug("generic function '{s}' instantiated with type {}", .{
new_decl.name, new_decl.ty,
});
assert(!new_decl.ty.fnInfo().is_generic);
// The generic function Decl is guaranteed to be the first dependency
// of each of its instantiations.
@ -8371,8 +8382,8 @@ fn analyzeDeclVal(
fn analyzeDeclRef(sema: *Sema, decl: *Decl) CompileError!Air.Inst.Ref {
try sema.mod.declareDeclDependency(sema.owner_decl, decl);
sema.mod.ensureDeclAnalyzed(decl) catch |err| {
if (sema.func) |func| {
func.state = .dependency_failure;
if (sema.owner_func) |owner_func| {
owner_func.state = .dependency_failure;
} else {
sema.owner_decl.analysis = .dependency_failure;
}