From 6632d85e5f1120784b3eb0a7ab8be0792ba27b85 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 5 Sep 2018 21:21:59 -0400 Subject: [PATCH] stage1: improve handling of generic fn proto type expr closes #902 --- src/analyze.cpp | 4 ++-- src/analyze.hpp | 3 +++ src/ir.cpp | 21 +++++++++++++++++++-- test/cases/eval.zig | 8 ++++++++ test/compile_errors.zig | 11 +++++++++++ 5 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 58fe9e7392..aa4fda7624 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1013,7 +1013,7 @@ bool calling_convention_does_first_arg_return(CallingConvention cc) { return cc == CallingConventionUnspecified; } -static const char *calling_convention_name(CallingConvention cc) { +const char *calling_convention_name(CallingConvention cc) { switch (cc) { case CallingConventionUnspecified: return "undefined"; case CallingConventionC: return "ccc"; @@ -1037,7 +1037,7 @@ static const char *calling_convention_fn_type_str(CallingConvention cc) { zig_unreachable(); } -static bool calling_convention_allows_zig_types(CallingConvention cc) { +bool calling_convention_allows_zig_types(CallingConvention cc) { switch (cc) { case CallingConventionUnspecified: case CallingConventionAsync: diff --git a/src/analyze.hpp b/src/analyze.hpp index 357312f2dc..41cc50916e 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -207,4 +207,7 @@ AstNode *type_decl_node(ZigType *type_entry); ZigType *get_primitive_type(CodeGen *g, Buf *name); +bool calling_convention_allows_zig_types(CallingConvention cc); +const char *calling_convention_name(CallingConvention cc); + #endif diff --git a/src/ir.cpp b/src/ir.cpp index 4e9c8d2bc7..0269c29b1a 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -19595,6 +19595,7 @@ static ZigType *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, } static ZigType *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstructionFnProto *instruction) { + Error err; AstNode *proto_node = instruction->base.source_node; assert(proto_node->type == NodeTypeFnProto); @@ -19636,9 +19637,25 @@ static ZigType *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstructionFnP IrInstruction *param_type_value = instruction->param_types[fn_type_id.next_param_index]->other; if (type_is_invalid(param_type_value->value.type)) return ira->codegen->builtin_types.entry_invalid; - param_info->type = ir_resolve_type(ira, param_type_value); - if (type_is_invalid(param_info->type)) + ZigType *param_type = ir_resolve_type(ira, param_type_value); + if (type_is_invalid(param_type)) return ira->codegen->builtin_types.entry_invalid; + if ((err = type_ensure_zero_bits_known(ira->codegen, param_type))) + return ira->codegen->builtin_types.entry_invalid; + if (type_requires_comptime(param_type)) { + if (!calling_convention_allows_zig_types(fn_type_id.cc)) { + ir_add_error(ira, &instruction->base, + buf_sprintf("parameter of type '%s' not allowed in function with calling convention '%s'", + buf_ptr(¶m_type->name), calling_convention_name(fn_type_id.cc))); + return ira->codegen->builtin_types.entry_invalid; + } + param_info->type = param_type; + fn_type_id.next_param_index += 1; + 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; + } + param_info->type = param_type; } } diff --git a/test/cases/eval.zig b/test/cases/eval.zig index 695cd4df77..b8d80bda02 100644 --- a/test/cases/eval.zig +++ b/test/cases/eval.zig @@ -674,3 +674,11 @@ test "inline for with same type but different values" { } assert(res == 5); } + +test "refer to the type of a generic function" { + const Func = fn (type) void; + const f: Func = doNothingWithType; + f(i32); +} + +fn doNothingWithType(comptime T: type) void {} diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 24d977c218..faf17d2c05 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,17 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.add( + "refer to the type of a generic function", + \\export fn entry() void { + \\ const Func = fn (type) void; + \\ const f: Func = undefined; + \\ f(i32); + \\} + , + ".tmp_source.zig:4:5: error: use of undefined value", + ); + cases.add( "accessing runtime parameter from outer function", \\fn outer(y: u32) fn (u32) u32 {