Skip to content

Commit 0c310f0

Browse files
LemonBoyandrewrk
authored andcommitted
ir: Implement @typeof with multiple arguments
Closes #439
1 parent 24fc69a commit 0c310f0

File tree

6 files changed

+93
-14
lines changed

6 files changed

+93
-14
lines changed

src/all_types.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3286,7 +3286,8 @@ struct IrInstGenUnreachable {
32863286
struct IrInstSrcTypeOf {
32873287
IrInstSrc base;
32883288

3289-
IrInstSrc *value;
3289+
IrInstSrc **values;
3290+
size_t value_count;
32903291
};
32913292

32923293
struct IrInstSrcSetCold {

src/codegen.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2766,11 +2766,13 @@ static IrInstGen *ir_build_load_ptr_gen(IrAnalyze *ira, IrInst *source_instructi
27662766
return &instruction->base;
27672767
}
27682768

2769-
static IrInstSrc *ir_build_typeof(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *value) {
2769+
static 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

2166421680
static 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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1118,7 +1118,7 @@ static void ir_print_vector_store_elem(IrPrintGen *irp, IrInstGenVectorStoreElem
11181118

11191119
static 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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,24 @@ const tests = @import("tests.zig");
22
const std = @import("std");
33

44
pub 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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,29 @@ test "@TypeOf() has no runtime side effects" {
105105
expect(data == 0);
106106
}
107107

108+
test "@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+
108131
test "branching logic inside @TypeOf" {
109132
const S = struct {
110133
var data: i32 = 0;

0 commit comments

Comments
 (0)