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
signature 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 {...@@ -3286,7 +3286,8 @@ struct IrInstGenUnreachable {
3286struct IrInstSrcTypeOf {3286struct IrInstSrcTypeOf {
3287 IrInstSrc base;3287 IrInstSrc base;
32883288
3289 IrInstSrc *value;3289 IrInstSrc **values;
3290 size_t value_count;
3290};3291};
32913292
3292struct IrInstSrcSetCold {3293struct IrInstSrcSetCold {
src/codegen.cpp+1-1
...@@ -8142,7 +8142,7 @@ static void define_builtin_fns(CodeGen *g) {...@@ -8142,7 +8142,7 @@ static void define_builtin_fns(CodeGen *g) {
8142 create_builtin_fn(g, BuiltinFnIdTypeInfo, "typeInfo", 1);8142 create_builtin_fn(g, BuiltinFnIdTypeInfo, "typeInfo", 1);
8143 create_builtin_fn(g, BuiltinFnIdType, "Type", 1);8143 create_builtin_fn(g, BuiltinFnIdType, "Type", 1);
8144 create_builtin_fn(g, BuiltinFnIdHasField, "hasField", 2);8144 create_builtin_fn(g, BuiltinFnIdHasField, "hasField", 2);
8145 create_builtin_fn(g, BuiltinFnIdTypeof, "TypeOf", 1);8145 create_builtin_fn(g, BuiltinFnIdTypeof, "TypeOf", SIZE_MAX);
8146 create_builtin_fn(g, BuiltinFnIdAddWithOverflow, "addWithOverflow", 4);8146 create_builtin_fn(g, BuiltinFnIdAddWithOverflow, "addWithOverflow", 4);
8147 create_builtin_fn(g, BuiltinFnIdSubWithOverflow, "subWithOverflow", 4);8147 create_builtin_fn(g, BuiltinFnIdSubWithOverflow, "subWithOverflow", 4);
8148 create_builtin_fn(g, BuiltinFnIdMulWithOverflow, "mulWithOverflow", 4);8148 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...@@ -2766,11 +2766,13 @@ static IrInstGen *ir_build_load_ptr_gen(IrAnalyze *ira, IrInst *source_instructi
2766 return &instruction->base;2766 return &instruction->base;
2767}2767}
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) {
2770 IrInstSrcTypeOf *instruction = ir_build_instruction<IrInstSrcTypeOf>(irb, scope, source_node);2770 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
2775 return &instruction->base;2777 return &instruction->base;
2776}2778}
...@@ -6043,7 +6045,9 @@ static IrInstSrc *ir_gen_fn_call_with_args(IrBuilderSrc *irb, Scope *scope, AstN...@@ -6043,7 +6045,9 @@ static IrInstSrc *ir_gen_fn_call_with_args(IrBuilderSrc *irb, Scope *scope, AstN
6043 if (fn_ref == irb->codegen->invalid_inst_src)6045 if (fn_ref == irb->codegen->invalid_inst_src)
6044 return fn_ref;6046 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
6048 IrInstSrc **args = heap::c_allocator.allocate<IrInstSrc*>(args_len);6052 IrInstSrc **args = heap::c_allocator.allocate<IrInstSrc*>(args_len);
6049 for (size_t i = 0; i < args_len; i += 1) {6053 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...@@ -6104,12 +6108,24 @@ static IrInstSrc *ir_gen_builtin_fn_call(IrBuilderSrc *irb, Scope *scope, AstNod
6104 {6108 {
6105 Scope *sub_scope = create_typeof_scope(irb->codegen, node, scope);6109 Scope *sub_scope = create_typeof_scope(irb->codegen, node, scope);
61066110
6107 AstNode *arg_node = node->data.fn_call_expr.params.at(0);6111 size_t arg_count = node->data.fn_call_expr.params.length;
6108 IrInstSrc *arg = ir_gen_node(irb, arg_node, sub_scope);6112
6109 if (arg == irb->codegen->invalid_inst_src)6113 if (arg_count < 1) {
6110 return arg;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);
6113 return ir_lval_wrap(irb, scope, type_of, lval, result_loc);6129 return ir_lval_wrap(irb, scope, type_of, lval, result_loc);
6114 }6130 }
6115 case BuiltinFnIdSetCold:6131 case BuiltinFnIdSetCold:
...@@ -21662,10 +21678,31 @@ static IrInstGen *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstSrcLoadP...@@ -21662,10 +21678,31 @@ static IrInstGen *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstSrcLoadP
21662}21678}
2166321679
21664static IrInstGen *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstSrcTypeOf *typeof_instruction) {21680static IrInstGen *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstSrcTypeOf *typeof_instruction) {
21665 IrInstGen *expr_value = typeof_instruction->value->child;21681 ZigType *type_entry;
21666 ZigType *type_entry = expr_value->value->type;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
21667 if (type_is_invalid(type_entry))21703 if (type_is_invalid(type_entry))
21668 return ira->codegen->invalid_inst_gen;21704 return ira->codegen->invalid_inst_gen;
21705
21669 return ir_const_type(ira, &typeof_instruction->base.base, type_entry);21706 return ir_const_type(ira, &typeof_instruction->base.base, type_entry);
21670}21707}
2167121708
src/ir_print.cpp+1-1
...@@ -1118,7 +1118,7 @@ static void ir_print_vector_store_elem(IrPrintGen *irp, IrInstGenVectorStoreElem...@@ -1118,7 +1118,7 @@ static void ir_print_vector_store_elem(IrPrintGen *irp, IrInstGenVectorStoreElem
11181118
1119static void ir_print_typeof(IrPrintSrc *irp, IrInstSrcTypeOf *instruction) {1119static void ir_print_typeof(IrPrintSrc *irp, IrInstSrcTypeOf *instruction) {
1120 fprintf(irp->f, "@TypeOf(");1120 fprintf(irp->f, "@TypeOf(");
1121 ir_print_other_inst_src(irp, instruction->value);1121 // ir_print_other_inst_src(irp, instruction->value);
1122 fprintf(irp->f, ")");1122 fprintf(irp->f, ")");
1123}1123}
11241124
test/compile_errors.zig+18
...@@ -2,6 +2,24 @@ const tests = @import("tests.zig");...@@ -2,6 +2,24 @@ const tests = @import("tests.zig");
2const std = @import("std");2const std = @import("std");
33
4pub fn addCases(cases: *tests.CompileErrorContext) void {4pub 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
5 cases.addTest("type mismatch with tuple concatenation",23 cases.addTest("type mismatch with tuple concatenation",
6 \\export fn entry() void {24 \\export fn entry() void {
7 \\ var x = .{};25 \\ var x = .{};
test/stage1/behavior/sizeof_and_typeof.zig+23
...@@ -105,6 +105,29 @@ test "@TypeOf() has no runtime side effects" {...@@ -105,6 +105,29 @@ test "@TypeOf() has no runtime side effects" {
105 expect(data == 0);105 expect(data == 0);
106}106}
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
108test "branching logic inside @TypeOf" {131test "branching logic inside @TypeOf" {
109 const S = struct {132 const S = struct {
110 var data: i32 = 0;133 var data: i32 = 0;