parent
68add5d828
commit
fcdd808c5c
|
@ -2399,6 +2399,7 @@ struct IrInstructionFnProto {
|
|||
|
||||
IrInstruction **param_types;
|
||||
IrInstruction *return_type;
|
||||
bool is_var_args;
|
||||
};
|
||||
|
||||
// true if the target value is compile time known, false otherwise
|
||||
|
|
|
@ -987,7 +987,7 @@ TypeTableEntry *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) {
|
|||
return result->value.data.x_type;
|
||||
}
|
||||
|
||||
static TypeTableEntry *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
|
||||
TypeTableEntry *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
|
||||
TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);
|
||||
fn_type->is_copyable = false;
|
||||
buf_init_from_str(&fn_type->name, "fn(");
|
||||
|
@ -2504,7 +2504,11 @@ bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *
|
|||
if (expected_type->data.fn.fn_type_id.is_cold != actual_type->data.fn.fn_type_id.is_cold) {
|
||||
return false;
|
||||
}
|
||||
if (actual_type->data.fn.fn_type_id.return_type->id != TypeTableEntryIdUnreachable &&
|
||||
if (expected_type->data.fn.fn_type_id.is_var_args != actual_type->data.fn.fn_type_id.is_var_args) {
|
||||
return false;
|
||||
}
|
||||
if (!expected_type->data.fn.fn_type_id.is_var_args &&
|
||||
actual_type->data.fn.fn_type_id.return_type->id != TypeTableEntryIdUnreachable &&
|
||||
!types_match_const_cast_only(
|
||||
expected_type->data.fn.fn_type_id.return_type,
|
||||
actual_type->data.fn.fn_type_id.return_type))
|
||||
|
@ -2515,6 +2519,11 @@ bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *
|
|||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < expected_type->data.fn.fn_type_id.param_count; i += 1) {
|
||||
if (i == expected_type->data.fn.fn_type_id.param_count - 1 &&
|
||||
expected_type->data.fn.fn_type_id.is_var_args)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// note it's reversed for parameters
|
||||
FnTypeParamInfo *actual_param_info = &actual_type->data.fn.fn_type_id.param_info[i];
|
||||
FnTypeParamInfo *expected_param_info = &expected_type->data.fn.fn_type_id.param_info[i];
|
||||
|
|
|
@ -164,5 +164,6 @@ const char *type_id_name(TypeTableEntryId id);
|
|||
TypeTableEntryId type_id_at_index(size_t index);
|
||||
size_t type_id_len();
|
||||
size_t type_id_index(TypeTableEntryId id);
|
||||
TypeTableEntry *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id);
|
||||
|
||||
#endif
|
||||
|
|
31
src/ir.cpp
31
src/ir.cpp
|
@ -1857,14 +1857,17 @@ static IrInstruction *ir_build_unwrap_err_payload_from(IrBuilder *irb, IrInstruc
|
|||
}
|
||||
|
||||
static IrInstruction *ir_build_fn_proto(IrBuilder *irb, Scope *scope, AstNode *source_node,
|
||||
IrInstruction **param_types, IrInstruction *return_type)
|
||||
IrInstruction **param_types, IrInstruction *return_type, bool is_var_args)
|
||||
{
|
||||
IrInstructionFnProto *instruction = ir_build_instruction<IrInstructionFnProto>(irb, scope, source_node);
|
||||
instruction->param_types = param_types;
|
||||
instruction->return_type = return_type;
|
||||
instruction->is_var_args = is_var_args;
|
||||
|
||||
assert(source_node->type == NodeTypeFnProto);
|
||||
for (size_t i = 0; i < source_node->data.fn_proto.params.length; i += 1) {
|
||||
size_t param_count = source_node->data.fn_proto.params.length;
|
||||
if (is_var_args) param_count -= 1;
|
||||
for (size_t i = 0; i < param_count; i += 1) {
|
||||
ir_ref_instruction(param_types[i], irb->current_basic_block);
|
||||
}
|
||||
ir_ref_instruction(return_type, irb->current_basic_block);
|
||||
|
@ -5843,8 +5846,13 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo
|
|||
size_t param_count = node->data.fn_proto.params.length;
|
||||
IrInstruction **param_types = allocate<IrInstruction*>(param_count);
|
||||
|
||||
bool is_var_args = false;
|
||||
for (size_t i = 0; i < param_count; i += 1) {
|
||||
AstNode *param_node = node->data.fn_proto.params.at(i);
|
||||
if (param_node->data.param_decl.is_var_args) {
|
||||
is_var_args = true;
|
||||
break;
|
||||
}
|
||||
AstNode *type_node = param_node->data.param_decl.type;
|
||||
IrInstruction *type_value = ir_gen_node(irb, type_node, parent_scope);
|
||||
if (type_value == irb->codegen->invalid_instruction)
|
||||
|
@ -5856,7 +5864,7 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo
|
|||
if (return_type == irb->codegen->invalid_instruction)
|
||||
return irb->codegen->invalid_instruction;
|
||||
|
||||
return ir_build_fn_proto(irb, parent_scope, node, param_types, return_type);
|
||||
return ir_build_fn_proto(irb, parent_scope, node, param_types, return_type, is_var_args);
|
||||
}
|
||||
|
||||
static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope,
|
||||
|
@ -9039,7 +9047,11 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
|
|||
}
|
||||
|
||||
if (fn_type->data.fn.is_generic) {
|
||||
assert(fn_entry);
|
||||
if (!fn_entry) {
|
||||
ir_add_error(ira, call_instruction->fn_ref,
|
||||
buf_sprintf("calling a generic function requires compile-time known function value"));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
// Count the arguments of the function type id we are creating
|
||||
size_t new_fn_arg_count = first_arg_1_or_0;
|
||||
|
@ -13065,6 +13077,17 @@ static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruc
|
|||
AstNode *param_node = proto_node->data.fn_proto.params.at(fn_type_id.next_param_index);
|
||||
assert(param_node->type == NodeTypeParamDecl);
|
||||
|
||||
bool param_is_var_args = param_node->data.param_decl.is_var_args;
|
||||
if (param_is_var_args) {
|
||||
if (fn_type_id.is_extern) {
|
||||
fn_type_id.param_count = fn_type_id.next_param_index;
|
||||
continue;
|
||||
} else {
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
|
||||
out_val->data.x_type = get_generic_fn_type(ira->codegen, &fn_type_id);
|
||||
return ira->codegen->builtin_types.entry_type;
|
||||
}
|
||||
}
|
||||
IrInstruction *param_type_value = instruction->param_types[fn_type_id.next_param_index]->other;
|
||||
|
||||
FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index];
|
||||
|
|
|
@ -1892,4 +1892,16 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
|
|||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:9: error: cannot goto out of defer expression");
|
||||
|
||||
cases.add("calling a var args function only known at runtime",
|
||||
\\var foos = []fn(...) { foo1, foo2 };
|
||||
\\
|
||||
\\fn foo1(args: ...) {}
|
||||
\\fn foo2(args: ...) {}
|
||||
\\
|
||||
\\pub fn main() -> %void {
|
||||
\\ foos[0]();
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:7:9: error: calling a generic function requires compile-time known function value");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue