authorgravatar for alex_naskos@hotmail.comAlexandros Naskos <alex_naskos@hotmail.com> 2020-10-02 09:44:27+03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-10-02 09:44:27+03:00
loge207031837cf3acbf21f92dc1e8b9e36c72a0f96
tree6a6096eb39d715dc8f4321fc0ab453113eb3bff6
parent0228887b943dd7e70f7c5cc56e3993769342abf2
parent183d1d4ba1a855cc85ac93f51dec5f4b2301ce1d
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #6402 from tadeokondrak/@Type(.Fn)

Implement @Type for Fn

5 files changed, 202 insertions(+), 22 deletions(-)

lib/std/builtin.zig+1
......@@ -343,6 +343,7 @@ pub const TypeInfo = union(enum) {
343343 /// therefore must be kept in sync with the compiler implementation.
344344 pub const Fn = struct {
345345 calling_convention: CallingConvention,
346 alignment: comptime_int,
346347 is_generic: bool,
347348 is_var_args: bool,
348349 return_type: ?type,
src/stage1/ir.cpp+120-21
......@@ -25564,7 +25564,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy
2556425564 result->special = ConstValSpecialStatic;
2556525565 result->type = ir_type_info_get_type(ira, "Fn", nullptr);
2556625566
25567 ZigValue **fields = alloc_const_vals_ptrs(ira->codegen, 5);
25567 ZigValue **fields = alloc_const_vals_ptrs(ira->codegen, 6);
2556825568 result->data.x_struct.fields = fields;
2556925569
2557025570 // calling_convention: TypeInfo.CallingConvention
......@@ -25572,38 +25572,42 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy
2557225572 fields[0]->special = ConstValSpecialStatic;
2557325573 fields[0]->type = get_builtin_type(ira->codegen, "CallingConvention");
2557425574 bigint_init_unsigned(&fields[0]->data.x_enum_tag, type_entry->data.fn.fn_type_id.cc);
25575 // alignment: u29
25576 ensure_field_index(result->type, "alignment", 1);
25577 fields[1]->special = ConstValSpecialStatic;
25578 fields[1]->type = ira->codegen->builtin_types.entry_num_lit_int;
25579 bigint_init_unsigned(&fields[1]->data.x_bigint, type_entry->data.fn.fn_type_id.alignment);
2557525580 // is_generic: bool
25576 ensure_field_index(result->type, "is_generic", 1);
25581 ensure_field_index(result->type, "is_generic", 2);
2557725582 bool is_generic = type_entry->data.fn.is_generic;
25578 fields[1]->special = ConstValSpecialStatic;
25579 fields[1]->type = ira->codegen->builtin_types.entry_bool;
25580 fields[1]->data.x_bool = is_generic;
25581 // is_varargs: bool
25582 ensure_field_index(result->type, "is_var_args", 2);
25583 bool is_varargs = type_entry->data.fn.fn_type_id.is_var_args;
2558425583 fields[2]->special = ConstValSpecialStatic;
2558525584 fields[2]->type = ira->codegen->builtin_types.entry_bool;
25586 fields[2]->data.x_bool = type_entry->data.fn.fn_type_id.is_var_args;
25587 // return_type: ?type
25588 ensure_field_index(result->type, "return_type", 3);
25585 fields[2]->data.x_bool = is_generic;
25586 // is_varargs: bool
25587 ensure_field_index(result->type, "is_var_args", 3);
25588 bool is_varargs = type_entry->data.fn.fn_type_id.is_var_args;
2558925589 fields[3]->special = ConstValSpecialStatic;
25590 fields[3]->type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_type);
25590 fields[3]->type = ira->codegen->builtin_types.entry_bool;
25591 fields[3]->data.x_bool = is_varargs;
25592 // return_type: ?type
25593 ensure_field_index(result->type, "return_type", 4);
25594 fields[4]->special = ConstValSpecialStatic;
25595 fields[4]->type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_type);
2559125596 if (type_entry->data.fn.fn_type_id.return_type == nullptr)
25592 fields[3]->data.x_optional = nullptr;
25597 fields[4]->data.x_optional = nullptr;
2559325598 else {
2559425599 ZigValue *return_type = ira->codegen->pass1_arena->create<ZigValue>();
2559525600 return_type->special = ConstValSpecialStatic;
2559625601 return_type->type = ira->codegen->builtin_types.entry_type;
2559725602 return_type->data.x_type = type_entry->data.fn.fn_type_id.return_type;
25598 fields[3]->data.x_optional = return_type;
25603 fields[4]->data.x_optional = return_type;
2559925604 }
2560025605 // args: []TypeInfo.FnArg
2560125606 ZigType *type_info_fn_arg_type = ir_type_info_get_type(ira, "FnArg", nullptr);
2560225607 if ((err = type_resolve(ira->codegen, type_info_fn_arg_type, ResolveStatusSizeKnown))) {
2560325608 zig_unreachable();
2560425609 }
25605 size_t fn_arg_count = type_entry->data.fn.fn_type_id.param_count -
25606 (is_varargs && type_entry->data.fn.fn_type_id.cc != CallingConventionC);
25610 size_t fn_arg_count = type_entry->data.fn.fn_type_id.param_count;
2560725611
2560825612 ZigValue *fn_arg_array = ira->codegen->pass1_arena->create<ZigValue>();
2560925613 fn_arg_array->special = ConstValSpecialStatic;
......@@ -25611,7 +25615,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy
2561125615 fn_arg_array->data.x_array.special = ConstArraySpecialNone;
2561225616 fn_arg_array->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate<ZigValue>(fn_arg_count);
2561325617
25614 init_const_slice(ira->codegen, fields[4], fn_arg_array, 0, fn_arg_count, false);
25618 init_const_slice(ira->codegen, fields[5], fn_arg_array, 0, fn_arg_count, false);
2561525619
2561625620 for (size_t fn_arg_index = 0; fn_arg_index < fn_arg_count; fn_arg_index++) {
2561725621 FnTypeParamInfo *fn_param_info = &type_entry->data.fn.fn_type_id.param_info[fn_arg_index];
......@@ -26327,10 +26331,105 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI
2632726331 return entry;
2632826332 }
2632926333 case ZigTypeIdFn:
26330 case ZigTypeIdBoundFn:
26331 ir_add_error(ira, source_instr, buf_sprintf(
26332 "@Type not available for 'TypeInfo.%s'", type_id_name(tagTypeId)));
26333 return ira->codegen->invalid_inst_gen->value->type;
26334 case ZigTypeIdBoundFn: {
26335 assert(payload->special == ConstValSpecialStatic);
26336 assert(payload->type == ir_type_info_get_type(ira, "Fn", nullptr));
26337
26338 ZigValue *cc_value = get_const_field(ira, source_instr->source_node, payload, "calling_convention", 0);
26339 if (cc_value == nullptr)
26340 return ira->codegen->invalid_inst_gen->value->type;
26341 assert(cc_value->special == ConstValSpecialStatic);
26342 assert(cc_value->type == get_builtin_type(ira->codegen, "CallingConvention"));
26343 CallingConvention cc = (CallingConvention)bigint_as_u32(&cc_value->data.x_enum_tag);
26344
26345 BigInt *alignment = get_const_field_lit_int(ira, source_instr->source_node, payload, "alignment", 1);
26346 if (alignment == nullptr)
26347 return ira->codegen->invalid_inst_gen->value->type;
26348
26349 Error err;
26350 bool is_generic;
26351 if ((err = get_const_field_bool(ira, source_instr->source_node, payload, "is_generic", 2, &is_generic)))
26352 return ira->codegen->invalid_inst_gen->value->type;
26353 if (is_generic) {
26354 ir_add_error(ira, source_instr, buf_sprintf("TypeInfo.Fn.is_generic must be false for @Type"));
26355 return ira->codegen->invalid_inst_gen->value->type;
26356 }
26357
26358 bool is_var_args;
26359 if ((err = get_const_field_bool(ira, source_instr->source_node, payload, "is_var_args", 3, &is_var_args)))
26360 return ira->codegen->invalid_inst_gen->value->type;
26361 if (is_var_args && cc != CallingConventionC) {
26362 ir_add_error(ira, source_instr, buf_sprintf("varargs functions must have C calling convention"));
26363 return ira->codegen->invalid_inst_gen->value->type;
26364 }
26365
26366 ZigType *return_type = get_const_field_meta_type_optional(ira, source_instr->source_node, payload, "return_type", 4);
26367 if (return_type == nullptr) {
26368 ir_add_error(ira, source_instr, buf_sprintf("TypeInfo.Fn.return_type must be non-null for @Type"));
26369 return ira->codegen->invalid_inst_gen->value->type;
26370 }
26371
26372 ZigValue *args_value = get_const_field(ira, source_instr->source_node, payload, "args", 5);
26373 if (args_value == nullptr)
26374 return ira->codegen->invalid_inst_gen->value->type;
26375 assert(args_value->special == ConstValSpecialStatic);
26376 assert(is_slice(args_value->type));
26377 ZigValue *args_ptr = args_value->data.x_struct.fields[slice_ptr_index];
26378 ZigValue *args_len_value = args_value->data.x_struct.fields[slice_len_index];
26379 size_t args_len = bigint_as_usize(&args_len_value->data.x_bigint);
26380
26381 FnTypeId fn_type_id = {};
26382 fn_type_id.return_type = return_type;
26383 fn_type_id.param_info = heap::c_allocator.allocate<FnTypeParamInfo>(args_len);
26384 fn_type_id.param_count = args_len;
26385 fn_type_id.next_param_index = args_len;
26386 fn_type_id.is_var_args = is_var_args;
26387 fn_type_id.cc = cc;
26388 fn_type_id.alignment = bigint_as_u32(alignment);
26389
26390 assert(args_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray);
26391 assert(args_ptr->data.x_ptr.data.base_array.elem_index == 0);
26392 ZigValue *args_arr = args_ptr->data.x_ptr.data.base_array.array_val;
26393 assert(args_arr->special == ConstValSpecialStatic);
26394 assert(args_arr->data.x_array.special == ConstArraySpecialNone);
26395 for (size_t i = 0; i < args_len; i++) {
26396 ZigValue *arg_value = &args_arr->data.x_array.data.s_none.elements[i];
26397 assert(arg_value->type == ir_type_info_get_type(ira, "FnArg", nullptr));
26398 FnTypeParamInfo *info = &fn_type_id.param_info[i];
26399 Error err;
26400 bool is_generic;
26401 if ((err = get_const_field_bool(ira, source_instr->source_node, arg_value, "is_generic", 0, &is_generic)))
26402 return ira->codegen->invalid_inst_gen->value->type;
26403 if (is_generic) {
26404 ir_add_error(ira, source_instr, buf_sprintf("TypeInfo.FnArg.is_generic must be false for @Type"));
26405 return ira->codegen->invalid_inst_gen->value->type;
26406 }
26407 if ((err = get_const_field_bool(ira, source_instr->source_node, arg_value, "is_noalias", 1, &info->is_noalias)))
26408 return ira->codegen->invalid_inst_gen->value->type;
26409 ZigType *type = get_const_field_meta_type_optional(
26410 ira, source_instr->source_node, arg_value, "arg_type", 2);
26411 if (type == nullptr) {
26412 ir_add_error(ira, source_instr, buf_sprintf("TypeInfo.FnArg.arg_type must be non-null for @Type"));
26413 return ira->codegen->invalid_inst_gen->value->type;
26414 }
26415 info->type = type;
26416 }
26417
26418 ZigType *entry = get_fn_type(ira->codegen, &fn_type_id);
26419
26420 switch (tagTypeId) {
26421 case ZigTypeIdFn:
26422 return entry;
26423 case ZigTypeIdBoundFn: {
26424 ZigType *bound_fn_entry = new_type_table_entry(ZigTypeIdBoundFn);
26425 bound_fn_entry->name = *buf_sprintf("(bound %s)", buf_ptr(&entry->name));
26426 bound_fn_entry->data.bound_fn.fn_type = entry;
26427 return bound_fn_entry;
26428 }
26429 default:
26430 zig_unreachable();
26431 }
26432 }
2633426433 }
2633526434 zig_unreachable();
2633626435}
test/compile_errors.zig+47
......@@ -72,6 +72,53 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
7272 "tmp.zig:15:23: error: enum field missing: 'arst'",
7373 "tmp.zig:27:24: note: referenced here",
7474 });
75 cases.add("@Type(.Fn) with is_generic = true",
76 \\const Foo = @Type(.{
77 \\ .Fn = .{
78 \\ .calling_convention = .Unspecified,
79 \\ .alignment = 0,
80 \\ .is_generic = true,
81 \\ .is_var_args = false,
82 \\ .return_type = u0,
83 \\ .args = &[_]@import("builtin").TypeInfo.FnArg{},
84 \\ },
85 \\});
86 \\comptime { _ = Foo; }
87 , &[_][]const u8{
88 "tmp.zig:1:20: error: TypeInfo.Fn.is_generic must be false for @Type",
89 });
90
91 cases.add("@Type(.Fn) with is_var_args = true and non-C callconv",
92 \\const Foo = @Type(.{
93 \\ .Fn = .{
94 \\ .calling_convention = .Unspecified,
95 \\ .alignment = 0,
96 \\ .is_generic = false,
97 \\ .is_var_args = true,
98 \\ .return_type = u0,
99 \\ .args = &[_]@import("builtin").TypeInfo.FnArg{},
100 \\ },
101 \\});
102 \\comptime { _ = Foo; }
103 , &[_][]const u8{
104 "tmp.zig:1:20: error: varargs functions must have C calling convention",
105 });
106
107 cases.add("@Type(.Fn) with return_type = null",
108 \\const Foo = @Type(.{
109 \\ .Fn = .{
110 \\ .calling_convention = .Unspecified,
111 \\ .alignment = 0,
112 \\ .is_generic = false,
113 \\ .is_var_args = false,
114 \\ .return_type = null,
115 \\ .args = &[_]@import("builtin").TypeInfo.FnArg{},
116 \\ },
117 \\});
118 \\comptime { _ = Foo; }
119 , &[_][]const u8{
120 "tmp.zig:1:20: error: TypeInfo.Fn.return_type must be non-null for @Type",
121 });
75122
76123 cases.add("@Type for union with opaque field",
77124 \\const TypeInfo = @import("builtin").TypeInfo;
test/stage1/behavior/type.zig+27
......@@ -416,3 +416,30 @@ test "Type.Union from regular enum" {
416416 _ = T;
417417 _ = @typeInfo(T).Union;
418418}
419
420test "Type.Fn" {
421 // wasm doesn't support align attributes on functions
422 if (builtin.arch == .wasm32 or builtin.arch == .wasm64) return error.SkipZigTest;
423
424 const foo = struct {
425 fn func(a: usize, b: bool) align(4) callconv(.C) usize {
426 return 0;
427 }
428 }.func;
429 const Foo = @Type(@typeInfo(@TypeOf(foo)));
430 const foo_2: Foo = foo;
431}
432
433test "Type.BoundFn" {
434 // wasm doesn't support align attributes on functions
435 if (builtin.arch == .wasm32 or builtin.arch == .wasm64) return error.SkipZigTest;
436
437 const TestStruct = packed struct {
438 pub fn foo(self: *const @This()) align(4) callconv(.Unspecified) void {}
439 };
440 const test_instance: TestStruct = undefined;
441 testing.expect(std.meta.eql(
442 @typeName(@TypeOf(test_instance.foo)),
443 @typeName(@Type(@typeInfo(@TypeOf(test_instance.foo)))),
444 ));
445}
test/stage1/behavior/type_info.zig+7-1
......@@ -266,6 +266,8 @@ const TestStruct = packed struct {
266266};
267267
268268test "type info: function type info" {
269 // wasm doesn't support align attributes on functions
270 if (builtin.arch == .wasm32 or builtin.arch == .wasm64) return error.SkipZigTest;
269271 testFunction();
270272 comptime testFunction();
271273}
......@@ -273,11 +275,14 @@ test "type info: function type info" {
273275fn testFunction() void {
274276 const fn_info = @typeInfo(@TypeOf(foo));
275277 expect(fn_info == .Fn);
278 expect(fn_info.Fn.alignment == 0);
276279 expect(fn_info.Fn.calling_convention == .C);
277280 expect(!fn_info.Fn.is_generic);
278281 expect(fn_info.Fn.args.len == 2);
279282 expect(fn_info.Fn.is_var_args);
280283 expect(fn_info.Fn.return_type.? == usize);
284 const fn_aligned_info = @typeInfo(@TypeOf(fooAligned));
285 expect(fn_aligned_info.Fn.alignment == 4);
281286
282287 const test_instance: TestStruct = undefined;
283288 const bound_fn_info = @typeInfo(@TypeOf(test_instance.foo));
......@@ -285,7 +290,8 @@ fn testFunction() void {
285290 expect(bound_fn_info.BoundFn.args[0].arg_type.? == *const TestStruct);
286291}
287292
288extern fn foo(a: usize, b: bool, ...) usize;
293extern fn foo(a: usize, b: bool, ...) callconv(.C) usize;
294extern fn fooAligned(a: usize, b: bool, ...) align(4) callconv(.C) usize;
289295
290296test "typeInfo with comptime parameter in struct fn def" {
291297 const S = struct {