authorgravatar for me@tadeo.caTadeo Kondrak <me@tadeo.ca> 2020-09-23 13:12:26-06:00
committergravatar for me@tadeo.caTadeo Kondrak <me@tadeo.ca> 2020-10-01 18:01:38-06:00
loge18fdc12b06cb904814700a96dce5ba419d08364
tree84f1e0e344940bbfaf72d055371626f8d37c7337
parent97ab720d84ac6af5174ed93f371fedfa2331445d
signaturelock-open Commit is signed but in an unrecognized format.

stage1: Implement @Type for Fn and BoundFn


3 files changed, 179 insertions(+), 6 deletions(-)

src/stage1/ir.cpp+111-6
......@@ -25607,8 +25607,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy
2560725607 if ((err = type_resolve(ira->codegen, type_info_fn_arg_type, ResolveStatusSizeKnown))) {
2560825608 zig_unreachable();
2560925609 }
25610 size_t fn_arg_count = type_entry->data.fn.fn_type_id.param_count -
25611 (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;
2561225611
2561325612 ZigValue *fn_arg_array = ira->codegen->pass1_arena->create<ZigValue>();
2561425613 fn_arg_array->special = ConstValSpecialStatic;
......@@ -25757,6 +25756,17 @@ static Error get_const_field_bool(IrAnalyze *ira, AstNode *source_node, ZigValue
2575725756 return ErrorNone;
2575825757}
2575925758
25759static Error get_const_field_u29(IrAnalyze *ira, AstNode *source_node, ZigValue *struct_value,
25760 const char *name, size_t field_index, uint32_t *out)
25761{
25762 ZigValue *value = get_const_field(ira, source_node, struct_value, name, field_index);
25763 if (value == nullptr)
25764 return ErrorSemanticAnalyzeFail;
25765 assert(value->type == ira->codegen->builtin_types.entry_u29);
25766 *out = bigint_as_u32(&value->data.x_bigint);
25767 return ErrorNone;
25768}
25769
2576025770static BigInt *get_const_field_lit_int(IrAnalyze *ira, AstNode *source_node, ZigValue *struct_value, const char *name, size_t field_index)
2576125771{
2576225772 ZigValue *value = get_const_field(ira, source_node, struct_value, name, field_index);
......@@ -26332,10 +26342,105 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI
2633226342 return entry;
2633326343 }
2633426344 case ZigTypeIdFn:
26335 case ZigTypeIdBoundFn:
26336 ir_add_error(ira, source_instr, buf_sprintf(
26337 "@Type not available for 'TypeInfo.%s'", type_id_name(tagTypeId)));
26338 return ira->codegen->invalid_inst_gen->value->type;
26345 case ZigTypeIdBoundFn: {
26346 assert(payload->special == ConstValSpecialStatic);
26347 assert(payload->type == ir_type_info_get_type(ira, "Fn", nullptr));
26348
26349 ZigValue *cc_value = get_const_field(ira, source_instr->source_node, payload, "calling_convention", 0);
26350 if (cc_value == nullptr)
26351 return ira->codegen->invalid_inst_gen->value->type;
26352 assert(cc_value->special == ConstValSpecialStatic);
26353 assert(cc_value->type == get_builtin_type(ira->codegen, "CallingConvention"));
26354 CallingConvention cc = (CallingConvention)bigint_as_u32(&cc_value->data.x_enum_tag);
26355
26356 uint32_t alignment;
26357 if ((err = get_const_field_u29(ira, source_instr->source_node, payload, "alignment", 1, &alignment)))
26358 return ira->codegen->invalid_inst_gen->value->type;
26359
26360 Error err;
26361 bool is_generic;
26362 if ((err = get_const_field_bool(ira, source_instr->source_node, payload, "is_generic", 2, &is_generic)))
26363 return ira->codegen->invalid_inst_gen->value->type;
26364 if (is_generic) {
26365 ir_add_error(ira, source_instr, buf_sprintf("TypeInfo.Fn.is_generic must be false for @Type"));
26366 return ira->codegen->invalid_inst_gen->value->type;
26367 }
26368
26369 bool is_var_args;
26370 if ((err = get_const_field_bool(ira, source_instr->source_node, payload, "is_var_args", 3, &is_var_args)))
26371 return ira->codegen->invalid_inst_gen->value->type;
26372 if (is_var_args && cc != CallingConventionC) {
26373 ir_add_error(ira, source_instr, buf_sprintf("varargs functions must have C calling convention"));
26374 return ira->codegen->invalid_inst_gen->value->type;
26375 }
26376
26377 ZigType *return_type = get_const_field_meta_type_optional(ira, source_instr->source_node, payload, "return_type", 4);
26378 if (return_type == nullptr) {
26379 ir_add_error(ira, source_instr, buf_sprintf("TypeInfo.Fn.return_type must be non-null for @Type"));
26380 return ira->codegen->invalid_inst_gen->value->type;
26381 }
26382
26383 ZigValue *args_value = get_const_field(ira, source_instr->source_node, payload, "args", 5);
26384 if (args_value == nullptr)
26385 return ira->codegen->invalid_inst_gen->value->type;
26386 assert(args_value->special == ConstValSpecialStatic);
26387 assert(is_slice(args_value->type));
26388 ZigValue *args_ptr = args_value->data.x_struct.fields[slice_ptr_index];
26389 ZigValue *args_len_value = args_value->data.x_struct.fields[slice_len_index];
26390 size_t args_len = bigint_as_usize(&args_len_value->data.x_bigint);
26391
26392 FnTypeId fn_type_id = {};
26393 fn_type_id.return_type = return_type;
26394 fn_type_id.param_info = heap::c_allocator.allocate<FnTypeParamInfo>(args_len);
26395 fn_type_id.param_count = args_len;
26396 fn_type_id.next_param_index = args_len;
26397 fn_type_id.is_var_args = is_var_args;
26398 fn_type_id.cc = cc;
26399 fn_type_id.alignment = alignment;
26400
26401 assert(args_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray);
26402 assert(args_ptr->data.x_ptr.data.base_array.elem_index == 0);
26403 ZigValue *args_arr = args_ptr->data.x_ptr.data.base_array.array_val;
26404 assert(args_arr->special == ConstValSpecialStatic);
26405 assert(args_arr->data.x_array.special == ConstArraySpecialNone);
26406 for (size_t i = 0; i < args_len; i++) {
26407 ZigValue *arg_value = &args_arr->data.x_array.data.s_none.elements[i];
26408 assert(arg_value->type == ir_type_info_get_type(ira, "FnArg", nullptr));
26409 FnTypeParamInfo *info = &fn_type_id.param_info[i];
26410 Error err;
26411 bool is_generic;
26412 if ((err = get_const_field_bool(ira, source_instr->source_node, arg_value, "is_generic", 0, &is_generic)))
26413 return ira->codegen->invalid_inst_gen->value->type;
26414 if (is_generic) {
26415 ir_add_error(ira, source_instr, buf_sprintf("TypeInfo.FnArg.is_generic must be false for @Type"));
26416 return ira->codegen->invalid_inst_gen->value->type;
26417 }
26418 if ((err = get_const_field_bool(ira, source_instr->source_node, arg_value, "is_noalias", 1, &info->is_noalias)))
26419 return ira->codegen->invalid_inst_gen->value->type;
26420 ZigType *type = get_const_field_meta_type_optional(
26421 ira, source_instr->source_node, arg_value, "arg_type", 2);
26422 if (type == nullptr) {
26423 ir_add_error(ira, source_instr, buf_sprintf("TypeInfo.FnArg.arg_type must be non-null for @Type"));
26424 return ira->codegen->invalid_inst_gen->value->type;
26425 }
26426 info->type = type;
26427 }
26428
26429 ZigType *entry = get_fn_type(ira->codegen, &fn_type_id);
26430
26431 switch (tagTypeId) {
26432 case ZigTypeIdFn:
26433 return entry;
26434 case ZigTypeIdBoundFn: {
26435 ZigType *bound_fn_entry = new_type_table_entry(ZigTypeIdBoundFn);
26436 bound_fn_entry->name = *buf_sprintf("(bound %s)", buf_ptr(&entry->name));
26437 bound_fn_entry->data.bound_fn.fn_type = entry;
26438 return bound_fn_entry;
26439 }
26440 default:
26441 zig_unreachable();
26442 }
26443 }
2633926444 }
2634026445 zig_unreachable();
2634126446}
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+21
......@@ -416,3 +416,24 @@ test "Type.Union from regular enum" {
416416 _ = T;
417417 _ = @typeInfo(T).Union;
418418}
419
420test "Type.Fn" {
421 const foo = struct {
422 fn func(a: usize, b: bool) align(4) callconv(.C) usize {
423 return 0;
424 }
425 }.func;
426 const Foo = @Type(@typeInfo(@TypeOf(foo)));
427 const foo_2: Foo = foo;
428}
429
430test "Type.BoundFn" {
431 const TestStruct = packed struct {
432 pub fn foo(self: *const @This()) align(4) callconv(.Unspecified) void {}
433 };
434 const test_instance: TestStruct = undefined;
435 testing.expect(std.meta.eql(
436 @typeName(@TypeOf(test_instance.foo)),
437 @typeName(@Type(@typeInfo(@TypeOf(test_instance.foo)))),
438 ));
439}