authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-03-04 10:55:34+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-03-04 17:21:10-05:00
log0c310f0fbf5ccbfff6c8235aa1a315589f9d8cf9
tree44564a884b29411a7bc4cba7a95f1f374f5f164d
parent24fc69acad303d9049a99683d3bf1f41185d22db
signaturelock-open Commit is signed but in an unrecognized format.

ir: Implement @TypeOf with multiple arguments

Closes #439

6 files changed, 93 insertions(+), 14 deletions(-)

src/all_types.hpp+2-1
......@@ -3286,7 +3286,8 @@ struct IrInstGenUnreachable {
32863286struct IrInstSrcTypeOf {
32873287 IrInstSrc base;
32883288
3289 IrInstSrc *value;
3289 IrInstSrc **values;
3290 size_t value_count;
32903291};
32913292
32923293struct IrInstSrcSetCold {
src/codegen.cpp+1-1
......@@ -8142,7 +8142,7 @@ static void define_builtin_fns(CodeGen *g) {
81428142 create_builtin_fn(g, BuiltinFnIdTypeInfo, "typeInfo", 1);
81438143 create_builtin_fn(g, BuiltinFnIdType, "Type", 1);
81448144 create_builtin_fn(g, BuiltinFnIdHasField, "hasField", 2);
8145 create_builtin_fn(g, BuiltinFnIdTypeof, "TypeOf", 1);
8145 create_builtin_fn(g, BuiltinFnIdTypeof, "TypeOf", SIZE_MAX);
81468146 create_builtin_fn(g, BuiltinFnIdAddWithOverflow, "addWithOverflow", 4);
81478147 create_builtin_fn(g, BuiltinFnIdSubWithOverflow, "subWithOverflow", 4);
81488148 create_builtin_fn(g, BuiltinFnIdMulWithOverflow, "mulWithOverflow", 4);
src/ir.cpp+48-11
......@@ -2766,11 +2766,13 @@ static IrInstGen *ir_build_load_ptr_gen(IrAnalyze *ira, IrInst *source_instructi
27662766 return &instruction->base;
27672767}
27682768
2769static IrInstSrc *ir_build_typeof(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *value) {
2769static IrInstSrc *ir_build_typeof(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc **values, size_t value_count) {
27702770 IrInstSrcTypeOf *instruction = ir_build_instruction<IrInstSrcTypeOf>(irb, scope, source_node);
2771 instruction->value = value;
2771 instruction->values = values;
2772 instruction->value_count = value_count;
27722773
2773 ir_ref_instruction(value, irb->current_basic_block);
2774 for (size_t i = 0; i < value_count; i++)
2775 ir_ref_instruction(values[i], irb->current_basic_block);
27742776
27752777 return &instruction->base;
27762778}
......@@ -6043,7 +6045,9 @@ static IrInstSrc *ir_gen_fn_call_with_args(IrBuilderSrc *irb, Scope *scope, AstN
60436045 if (fn_ref == irb->codegen->invalid_inst_src)
60446046 return fn_ref;
60456047
6046 IrInstSrc *fn_type = ir_build_typeof(irb, scope, source_node, fn_ref);
6048 IrInstSrc **typeof_args = heap::c_allocator.allocate<IrInstSrc*>(1);
6049 typeof_args[0] = fn_ref;
6050 IrInstSrc *fn_type = ir_build_typeof(irb, scope, source_node, typeof_args, 1);
60476051
60486052 IrInstSrc **args = heap::c_allocator.allocate<IrInstSrc*>(args_len);
60496053 for (size_t i = 0; i < args_len; i += 1) {
......@@ -6104,12 +6108,24 @@ static IrInstSrc *ir_gen_builtin_fn_call(IrBuilderSrc *irb, Scope *scope, AstNod
61046108 {
61056109 Scope *sub_scope = create_typeof_scope(irb->codegen, node, scope);
61066110
6107 AstNode *arg_node = node->data.fn_call_expr.params.at(0);
6108 IrInstSrc *arg = ir_gen_node(irb, arg_node, sub_scope);
6109 if (arg == irb->codegen->invalid_inst_src)
6110 return arg;
6111 size_t arg_count = node->data.fn_call_expr.params.length;
6112
6113 if (arg_count < 1) {
6114 add_node_error(irb->codegen, node,
6115 buf_sprintf("expected at least 1 argument, found 0"));
6116 return irb->codegen->invalid_inst_src;
6117 }
6118
6119 IrInstSrc **args = heap::c_allocator.allocate<IrInstSrc*>(arg_count);
6120 for (size_t i = 0; i < arg_count; i += 1) {
6121 AstNode *arg_node = node->data.fn_call_expr.params.at(i);
6122 IrInstSrc *arg = ir_gen_node(irb, arg_node, sub_scope);
6123 if (arg == irb->codegen->invalid_inst_src)
6124 return irb->codegen->invalid_inst_src;
6125 args[i] = arg;
6126 }
61116127
6112 IrInstSrc *type_of = ir_build_typeof(irb, scope, node, arg);
6128 IrInstSrc *type_of = ir_build_typeof(irb, scope, node, args, arg_count);
61136129 return ir_lval_wrap(irb, scope, type_of, lval, result_loc);
61146130 }
61156131 case BuiltinFnIdSetCold:
......@@ -21662,10 +21678,31 @@ static IrInstGen *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstSrcLoadP
2166221678}
2166321679
2166421680static IrInstGen *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstSrcTypeOf *typeof_instruction) {
21665 IrInstGen *expr_value = typeof_instruction->value->child;
21666 ZigType *type_entry = expr_value->value->type;
21681 ZigType *type_entry;
21682
21683 const size_t value_count = typeof_instruction->value_count;
21684
21685 // Fast path for the common case of TypeOf with a single argument
21686 if (value_count < 2) {
21687 type_entry = typeof_instruction->values[0]->child->value->type;
21688 } else {
21689 IrInstGen **args = heap::c_allocator.allocate<IrInstGen*>(value_count);
21690 for (size_t i = 0; i < value_count; i += 1) {
21691 IrInstGen *value = typeof_instruction->values[i]->child;
21692 if (type_is_invalid(value->value->type))
21693 return ira->codegen->invalid_inst_gen;
21694 args[i] = value;
21695 }
21696
21697 type_entry = ir_resolve_peer_types(ira, typeof_instruction->base.base.source_node,
21698 nullptr, args, value_count);
21699
21700 heap::c_allocator.deallocate(args, value_count);
21701 }
21702
2166721703 if (type_is_invalid(type_entry))
2166821704 return ira->codegen->invalid_inst_gen;
21705
2166921706 return ir_const_type(ira, &typeof_instruction->base.base, type_entry);
2167021707}
2167121708
src/ir_print.cpp+1-1
......@@ -1118,7 +1118,7 @@ static void ir_print_vector_store_elem(IrPrintGen *irp, IrInstGenVectorStoreElem
11181118
11191119static void ir_print_typeof(IrPrintSrc *irp, IrInstSrcTypeOf *instruction) {
11201120 fprintf(irp->f, "@TypeOf(");
1121 ir_print_other_inst_src(irp, instruction->value);
1121 // ir_print_other_inst_src(irp, instruction->value);
11221122 fprintf(irp->f, ")");
11231123}
11241124
test/compile_errors.zig+18
......@@ -2,6 +2,24 @@ const tests = @import("tests.zig");
22const std = @import("std");
33
44pub fn addCases(cases: *tests.CompileErrorContext) void {
5 cases.addTest("@TypeOf with no arguments",
6 \\export fn entry() void {
7 \\ _ = @TypeOf();
8 \\}
9 , &[_][]const u8{
10 "tmp.zig:2:9: error: expected at least 1 argument, found 0",
11 });
12
13 cases.addTest("@TypeOf with incompatible arguments",
14 \\export fn entry() void {
15 \\ var var_1: f32 = undefined;
16 \\ var var_2: u32 = undefined;
17 \\ _ = @TypeOf(var_1, var_2);
18 \\}
19 , &[_][]const u8{
20 "tmp.zig:4:9: error: incompatible types: 'f32' and 'u32'",
21 });
22
523 cases.addTest("type mismatch with tuple concatenation",
624 \\export fn entry() void {
725 \\ var x = .{};
test/stage1/behavior/sizeof_and_typeof.zig+23
......@@ -105,6 +105,29 @@ test "@TypeOf() has no runtime side effects" {
105105 expect(data == 0);
106106}
107107
108test "@TypeOf() with multiple arguments" {
109 {
110 var var_1: u32 = undefined;
111 var var_2: u8 = undefined;
112 var var_3: u64 = undefined;
113 comptime expect(@TypeOf(var_1, var_2, var_3) == u64);
114 }
115 {
116 var var_1: f16 = undefined;
117 var var_2: f32 = undefined;
118 var var_3: f64 = undefined;
119 comptime expect(@TypeOf(var_1, var_2, var_3) == f64);
120 }
121 {
122 var var_1: u16 = undefined;
123 comptime expect(@TypeOf(var_1, 0xffff) == u16);
124 }
125 {
126 var var_1: f32 = undefined;
127 comptime expect(@TypeOf(var_1, 3.1415) == f32);
128 }
129}
130
108131test "branching logic inside @TypeOf" {
109132 const S = struct {
110133 var data: i32 = 0;