Commit 6632d85e5f

Andrew Kelley <superjoe30@gmail.com>
2018-09-06 03:21:59
stage1: improve handling of generic fn proto type expr
closes #902
1 parent 1d8b8ad
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:
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
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(&param_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;
         }
 
     }
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 {}
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 {