authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-03-04 18:05:34-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-03-04 18:05:34-05:00
log378bf1c3b71fdcc823fb9a5382400ec0a659fc00
tree412c9f53fcefcb5117b89323cbf526289a4a90a0
parent24fc69acad303d9049a99683d3bf1f41185d22db
parent116e2a93f1ab068ee46f4b7cce6b3306334cdec6
signaturelock-open Commit is signed but in an unrecognized format.

Merge branch 'LemonBoy-fix-439'


8 files changed, 128 insertions(+), 18 deletions(-)

doc/langref.html.in+6-4
...@@ -8371,12 +8371,14 @@ test "integer truncation" {...@@ -8371,12 +8371,14 @@ test "integer truncation" {
8371 {#header_close#}8371 {#header_close#}
83728372
8373 {#header_open|@TypeOf#}8373 {#header_open|@TypeOf#}
8374 <pre>{#syntax#}@TypeOf(expression) type{#endsyntax#}</pre>8374 <pre>{#syntax#}@TypeOf(...) type{#endsyntax#}</pre>
8375 <p>8375 <p>
8376 This function returns a compile-time constant, which is the type of the8376 {#syntax#}@TypeOf{#endsyntax#} is a special builtin function that takes any (nonzero) number of expressions
8377 expression passed as an argument. The expression is evaluated.8377 as parameters and returns the type of the result, using {#link|Peer Type Resolution#}.
8378 </p>
8379 <p>
8380 The expressions are evaluated, however they are guaranteed to have no <em>runtime</em> side-effects:
8378 </p>8381 </p>
8379 <p>{#syntax#}@TypeOf{#endsyntax#} guarantees no run-time side-effects within the expression:</p>
8380 {#code_begin|test#}8382 {#code_begin|test#}
8381const std = @import("std");8383const std = @import("std");
8382const assert = std.debug.assert;8384const assert = std.debug.assert;
lib/std/math.zig+1-1
...@@ -293,7 +293,7 @@ test "math.min" {...@@ -293,7 +293,7 @@ test "math.min" {
293 }293 }
294}294}
295295
296pub fn max(x: var, y: var) @TypeOf(x + y) {296pub fn max(x: var, y: var) @TypeOf(x, y) {
297 return if (x > y) x else y;297 return if (x > y) x else y;
298}298}
299299
src/all_types.hpp+5-1
...@@ -3286,7 +3286,11 @@ struct IrInstGenUnreachable {...@@ -3286,7 +3286,11 @@ struct IrInstGenUnreachable {
3286struct IrInstSrcTypeOf {3286struct IrInstSrcTypeOf {
3287 IrInstSrc base;3287 IrInstSrc base;
32883288
3289 IrInstSrc *value;3289 union {
3290 IrInstSrc *scalar; // value_count == 1
3291 IrInstSrc **list; // value_count > 1
3292 } value;
3293 size_t value_count;
3290};3294};
32913295
3292struct IrInstSrcSetCold {3296struct 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+67-10
...@@ -2766,9 +2766,24 @@ static IrInstGen *ir_build_load_ptr_gen(IrAnalyze *ira, IrInst *source_instructi...@@ -2766,9 +2766,24 @@ 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_n(IrBuilderSrc *irb, Scope *scope, AstNode *source_node,
2770 IrInstSrc **values, size_t value_count)
2771{
2772 assert(value_count >= 2);
2773
2770 IrInstSrcTypeOf *instruction = ir_build_instruction<IrInstSrcTypeOf>(irb, scope, source_node);2774 IrInstSrcTypeOf *instruction = ir_build_instruction<IrInstSrcTypeOf>(irb, scope, source_node);
2771 instruction->value = value;2775 instruction->value.list = values;
2776 instruction->value_count = value_count;
2777
2778 for (size_t i = 0; i < value_count; i++)
2779 ir_ref_instruction(values[i], irb->current_basic_block);
2780
2781 return &instruction->base;
2782}
2783
2784static IrInstSrc *ir_build_typeof_1(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *value) {
2785 IrInstSrcTypeOf *instruction = ir_build_instruction<IrInstSrcTypeOf>(irb, scope, source_node);
2786 instruction->value.scalar = value;
27722787
2773 ir_ref_instruction(value, irb->current_basic_block);2788 ir_ref_instruction(value, irb->current_basic_block);
27742789
...@@ -6043,7 +6058,7 @@ static IrInstSrc *ir_gen_fn_call_with_args(IrBuilderSrc *irb, Scope *scope, AstN...@@ -6043,7 +6058,7 @@ static IrInstSrc *ir_gen_fn_call_with_args(IrBuilderSrc *irb, Scope *scope, AstN
6043 if (fn_ref == irb->codegen->invalid_inst_src)6058 if (fn_ref == irb->codegen->invalid_inst_src)
6044 return fn_ref;6059 return fn_ref;
60456060
6046 IrInstSrc *fn_type = ir_build_typeof(irb, scope, source_node, fn_ref);6061 IrInstSrc *fn_type = ir_build_typeof_1(irb, scope, source_node, fn_ref);
60476062
6048 IrInstSrc **args = heap::c_allocator.allocate<IrInstSrc*>(args_len);6063 IrInstSrc **args = heap::c_allocator.allocate<IrInstSrc*>(args_len);
6049 for (size_t i = 0; i < args_len; i += 1) {6064 for (size_t i = 0; i < args_len; i += 1) {
...@@ -6104,12 +6119,33 @@ static IrInstSrc *ir_gen_builtin_fn_call(IrBuilderSrc *irb, Scope *scope, AstNod...@@ -6104,12 +6119,33 @@ static IrInstSrc *ir_gen_builtin_fn_call(IrBuilderSrc *irb, Scope *scope, AstNod
6104 {6119 {
6105 Scope *sub_scope = create_typeof_scope(irb->codegen, node, scope);6120 Scope *sub_scope = create_typeof_scope(irb->codegen, node, scope);
61066121
6107 AstNode *arg_node = node->data.fn_call_expr.params.at(0);6122 size_t arg_count = node->data.fn_call_expr.params.length;
6108 IrInstSrc *arg = ir_gen_node(irb, arg_node, sub_scope);6123
6109 if (arg == irb->codegen->invalid_inst_src)6124 IrInstSrc *type_of;
6110 return arg;6125
6126 if (arg_count == 0) {
6127 add_node_error(irb->codegen, node,
6128 buf_sprintf("expected at least 1 argument, found 0"));
6129 return irb->codegen->invalid_inst_src;
6130 } else if (arg_count == 1) {
6131 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
6132 IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, sub_scope);
6133 if (arg0_value == irb->codegen->invalid_inst_src)
6134 return arg0_value;
61116135
6112 IrInstSrc *type_of = ir_build_typeof(irb, scope, node, arg);6136 type_of = ir_build_typeof_1(irb, scope, node, arg0_value);
6137 } else {
6138 IrInstSrc **args = heap::c_allocator.allocate<IrInstSrc*>(arg_count);
6139 for (size_t i = 0; i < arg_count; i += 1) {
6140 AstNode *arg_node = node->data.fn_call_expr.params.at(i);
6141 IrInstSrc *arg = ir_gen_node(irb, arg_node, sub_scope);
6142 if (arg == irb->codegen->invalid_inst_src)
6143 return irb->codegen->invalid_inst_src;
6144 args[i] = arg;
6145 }
6146
6147 type_of = ir_build_typeof_n(irb, scope, node, args, arg_count);
6148 }
6113 return ir_lval_wrap(irb, scope, type_of, lval, result_loc);6149 return ir_lval_wrap(irb, scope, type_of, lval, result_loc);
6114 }6150 }
6115 case BuiltinFnIdSetCold:6151 case BuiltinFnIdSetCold:
...@@ -21662,10 +21698,31 @@ static IrInstGen *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstSrcLoadP...@@ -21662,10 +21698,31 @@ static IrInstGen *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstSrcLoadP
21662}21698}
2166321699
21664static IrInstGen *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstSrcTypeOf *typeof_instruction) {21700static IrInstGen *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstSrcTypeOf *typeof_instruction) {
21665 IrInstGen *expr_value = typeof_instruction->value->child;21701 ZigType *type_entry;
21666 ZigType *type_entry = expr_value->value->type;21702
21703 const size_t value_count = typeof_instruction->value_count;
21704
21705 // Fast path for the common case of TypeOf with a single argument
21706 if (value_count < 2) {
21707 type_entry = typeof_instruction->value.scalar->child->value->type;
21708 } else {
21709 IrInstGen **args = heap::c_allocator.allocate<IrInstGen*>(value_count);
21710 for (size_t i = 0; i < value_count; i += 1) {
21711 IrInstGen *value = typeof_instruction->value.list[i]->child;
21712 if (type_is_invalid(value->value->type))
21713 return ira->codegen->invalid_inst_gen;
21714 args[i] = value;
21715 }
21716
21717 type_entry = ir_resolve_peer_types(ira, typeof_instruction->base.base.source_node,
21718 nullptr, args, value_count);
21719
21720 heap::c_allocator.deallocate(args, value_count);
21721 }
21722
21667 if (type_is_invalid(type_entry))21723 if (type_is_invalid(type_entry))
21668 return ira->codegen->invalid_inst_gen;21724 return ira->codegen->invalid_inst_gen;
21725
21669 return ir_const_type(ira, &typeof_instruction->base.base, type_entry);21726 return ir_const_type(ira, &typeof_instruction->base.base, type_entry);
21670}21727}
2167121728
src/ir_print.cpp+7-1
...@@ -1118,7 +1118,13 @@ static void ir_print_vector_store_elem(IrPrintGen *irp, IrInstGenVectorStoreElem...@@ -1118,7 +1118,13 @@ 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 if (instruction->value_count == 1) {
1122 ir_print_other_inst_src(irp, instruction->value.scalar);
1123 } else {
1124 for (size_t i = 0; i < instruction->value_count; i += 1) {
1125 ir_print_other_inst_src(irp, instruction->value.list[i]);
1126 }
1127 }
1122 fprintf(irp->f, ")");1128 fprintf(irp->f, ")");
1123}1129}
11241130
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;