Skip to content

Commit f0d7551

Browse files
committedNov 4, 2017
add compile-time reflection for function arg types
See #383
1 parent 4a6df04 commit f0d7551

File tree

6 files changed

+125
-3
lines changed

6 files changed

+125
-3
lines changed
 

‎src/all_types.hpp

+9
Original file line numberDiff line numberDiff line change
@@ -1261,6 +1261,7 @@ enum BuiltinFnId {
12611261
BuiltinFnIdAlignCast,
12621262
BuiltinFnIdOpaqueType,
12631263
BuiltinFnIdSetAlignStack,
1264+
BuiltinFnIdArgType,
12641265
};
12651266

12661267
struct BuiltinFnEntry {
@@ -1882,6 +1883,7 @@ enum IrInstructionId {
18821883
IrInstructionIdAlignCast,
18831884
IrInstructionIdOpaqueType,
18841885
IrInstructionIdSetAlignStack,
1886+
IrInstructionIdArgType,
18851887
};
18861888

18871889
struct IrInstruction {
@@ -2682,6 +2684,13 @@ struct IrInstructionSetAlignStack {
26822684
IrInstruction *align_bytes;
26832685
};
26842686

2687+
struct IrInstructionArgType {
2688+
IrInstruction base;
2689+
2690+
IrInstruction *fn_type;
2691+
IrInstruction *arg_index;
2692+
};
2693+
26852694
static const size_t slice_ptr_index = 0;
26862695
static const size_t slice_len_index = 1;
26872696

‎src/codegen.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -3401,6 +3401,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
34013401
case IrInstructionIdPtrTypeOf:
34023402
case IrInstructionIdOpaqueType:
34033403
case IrInstructionIdSetAlignStack:
3404+
case IrInstructionIdArgType:
34043405
zig_unreachable();
34053406
case IrInstructionIdReturn:
34063407
return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
@@ -4866,7 +4867,7 @@ static void define_builtin_fns(CodeGen *g) {
48664867
create_builtin_fn(g, BuiltinFnIdMaxValue, "maxValue", 1);
48674868
create_builtin_fn(g, BuiltinFnIdMinValue, "minValue", 1);
48684869
create_builtin_fn(g, BuiltinFnIdMemberCount, "memberCount", 1);
4869-
create_builtin_fn(g, BuiltinFnIdTypeof, "typeOf", 1);
4870+
create_builtin_fn(g, BuiltinFnIdTypeof, "typeOf", 1); // TODO rename to TypeOf
48704871
create_builtin_fn(g, BuiltinFnIdAddWithOverflow, "addWithOverflow", 4);
48714872
create_builtin_fn(g, BuiltinFnIdSubWithOverflow, "subWithOverflow", 4);
48724873
create_builtin_fn(g, BuiltinFnIdMulWithOverflow, "mulWithOverflow", 4);
@@ -4913,6 +4914,7 @@ static void define_builtin_fns(CodeGen *g) {
49134914
create_builtin_fn(g, BuiltinFnIdAlignCast, "alignCast", 2);
49144915
create_builtin_fn(g, BuiltinFnIdOpaqueType, "OpaqueType", 0);
49154916
create_builtin_fn(g, BuiltinFnIdSetAlignStack, "setAlignStack", 1);
4917+
create_builtin_fn(g, BuiltinFnIdArgType, "ArgType", 2);
49164918
}
49174919

49184920
static const char *bool_to_str(bool b) {

‎src/ir.cpp

+80
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSetAlignStack *)
567567
return IrInstructionIdSetAlignStack;
568568
}
569569

570+
static constexpr IrInstructionId ir_instruction_id(IrInstructionArgType *) {
571+
return IrInstructionIdArgType;
572+
}
573+
570574
template<typename T>
571575
static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
572576
T *special_instruction = allocate<T>(1);
@@ -2263,6 +2267,19 @@ static IrInstruction *ir_build_set_align_stack(IrBuilder *irb, Scope *scope, Ast
22632267
return &instruction->base;
22642268
}
22652269

2270+
static IrInstruction *ir_build_arg_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
2271+
IrInstruction *fn_type, IrInstruction *arg_index)
2272+
{
2273+
IrInstructionArgType *instruction = ir_build_instruction<IrInstructionArgType>(irb, scope, source_node);
2274+
instruction->fn_type = fn_type;
2275+
instruction->arg_index = arg_index;
2276+
2277+
ir_ref_instruction(fn_type, irb->current_basic_block);
2278+
ir_ref_instruction(arg_index, irb->current_basic_block);
2279+
2280+
return &instruction->base;
2281+
}
2282+
22662283
static IrInstruction *ir_instruction_br_get_dep(IrInstructionBr *instruction, size_t index) {
22672284
return nullptr;
22682285
}
@@ -2992,6 +3009,14 @@ static IrInstruction *ir_instruction_setalignstack_get_dep(IrInstructionSetAlign
29923009
}
29933010
}
29943011

3012+
static IrInstruction *ir_instruction_argtype_get_dep(IrInstructionArgType *instruction, size_t index) {
3013+
switch (index) {
3014+
case 0: return instruction->fn_type;
3015+
case 1: return instruction->arg_index;
3016+
default: return nullptr;
3017+
}
3018+
}
3019+
29953020
static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t index) {
29963021
switch (instruction->id) {
29973022
case IrInstructionIdInvalid:
@@ -3194,6 +3219,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
31943219
return ir_instruction_opaquetype_get_dep((IrInstructionOpaqueType *) instruction, index);
31953220
case IrInstructionIdSetAlignStack:
31963221
return ir_instruction_setalignstack_get_dep((IrInstructionSetAlignStack *) instruction, index);
3222+
case IrInstructionIdArgType:
3223+
return ir_instruction_argtype_get_dep((IrInstructionArgType *) instruction, index);
31973224
}
31983225
zig_unreachable();
31993226
}
@@ -4629,6 +4656,20 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
46294656

46304657
return ir_build_set_align_stack(irb, scope, node, arg0_value);
46314658
}
4659+
case BuiltinFnIdArgType:
4660+
{
4661+
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4662+
IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4663+
if (arg0_value == irb->codegen->invalid_instruction)
4664+
return arg0_value;
4665+
4666+
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
4667+
IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
4668+
if (arg1_value == irb->codegen->invalid_instruction)
4669+
return arg1_value;
4670+
4671+
return ir_build_arg_type(irb, scope, node, arg0_value, arg1_value);
4672+
}
46324673
}
46334674
zig_unreachable();
46344675
}
@@ -11686,6 +11727,13 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
1168611727
create_const_bool(ira->codegen, child_type->data.fn.fn_type_id.is_var_args),
1168711728
ira->codegen->builtin_types.entry_bool,
1168811729
ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
11730+
} else if (buf_eql_str(field_name, "arg_count")) {
11731+
bool ptr_is_const = true;
11732+
bool ptr_is_volatile = false;
11733+
return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
11734+
create_const_usize(ira->codegen, child_type->data.fn.fn_type_id.param_count),
11735+
ira->codegen->builtin_types.entry_usize,
11736+
ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
1168911737
} else {
1169011738
ir_add_error(ira, &field_ptr_instruction->base,
1169111739
buf_sprintf("type '%s' has no member called '%s'",
@@ -15395,6 +15443,35 @@ static TypeTableEntry *ir_analyze_instruction_set_align_stack(IrAnalyze *ira, Ir
1539515443
return ira->codegen->builtin_types.entry_void;
1539615444
}
1539715445

15446+
static TypeTableEntry *ir_analyze_instruction_arg_type(IrAnalyze *ira, IrInstructionArgType *instruction) {
15447+
IrInstruction *fn_type_inst = instruction->fn_type->other;
15448+
TypeTableEntry *fn_type = ir_resolve_type(ira, fn_type_inst);
15449+
if (type_is_invalid(fn_type))
15450+
return ira->codegen->builtin_types.entry_invalid;
15451+
15452+
IrInstruction *arg_index_inst = instruction->arg_index->other;
15453+
uint64_t arg_index;
15454+
if (!ir_resolve_usize(ira, arg_index_inst, &arg_index))
15455+
return ira->codegen->builtin_types.entry_invalid;
15456+
15457+
if (fn_type->id != TypeTableEntryIdFn) {
15458+
ir_add_error(ira, fn_type_inst, buf_sprintf("expected function, found '%s'", buf_ptr(&fn_type->name)));
15459+
return ira->codegen->builtin_types.entry_invalid;
15460+
}
15461+
15462+
FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
15463+
if (arg_index >= fn_type_id->param_count) {
15464+
ir_add_error(ira, arg_index_inst,
15465+
buf_sprintf("arg index %" ZIG_PRI_usize " out of bounds; '%s' has %" ZIG_PRI_usize " arguments",
15466+
arg_index, buf_ptr(&fn_type->name), fn_type_id->param_count));
15467+
return ira->codegen->builtin_types.entry_invalid;
15468+
}
15469+
15470+
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
15471+
out_val->data.x_type = fn_type_id->param_info[arg_index].type;
15472+
return ira->codegen->builtin_types.entry_type;
15473+
}
15474+
1539815475
static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
1539915476
switch (instruction->id) {
1540015477
case IrInstructionIdInvalid:
@@ -15585,6 +15662,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1558515662
return ir_analyze_instruction_opaque_type(ira, (IrInstructionOpaqueType *)instruction);
1558615663
case IrInstructionIdSetAlignStack:
1558715664
return ir_analyze_instruction_set_align_stack(ira, (IrInstructionSetAlignStack *)instruction);
15665+
case IrInstructionIdArgType:
15666+
return ir_analyze_instruction_arg_type(ira, (IrInstructionArgType *)instruction);
1558815667
}
1558915668
zig_unreachable();
1559015669
}
@@ -15765,6 +15844,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1576515844
case IrInstructionIdTypeId:
1576615845
case IrInstructionIdAlignCast:
1576715846
case IrInstructionIdOpaqueType:
15847+
case IrInstructionIdArgType:
1576815848
return false;
1576915849
case IrInstructionIdAsm:
1577015850
{

‎src/ir_print.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -954,6 +954,15 @@ static void ir_print_set_align_stack(IrPrint *irp, IrInstructionSetAlignStack *i
954954
fprintf(irp->f, ")");
955955
}
956956

957+
static void ir_print_arg_type(IrPrint *irp, IrInstructionArgType *instruction) {
958+
fprintf(irp->f, "@ArgType(");
959+
ir_print_other_instruction(irp, instruction->fn_type);
960+
fprintf(irp->f, ",");
961+
ir_print_other_instruction(irp, instruction->arg_index);
962+
fprintf(irp->f, ")");
963+
}
964+
965+
957966
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
958967
ir_print_prefix(irp, instruction);
959968
switch (instruction->id) {
@@ -1256,6 +1265,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
12561265
case IrInstructionIdSetAlignStack:
12571266
ir_print_set_align_stack(irp, (IrInstructionSetAlignStack *)instruction);
12581267
break;
1268+
case IrInstructionIdArgType:
1269+
ir_print_arg_type(irp, (IrInstructionArgType *)instruction);
1270+
break;
12591271
}
12601272
fprintf(irp->f, "\n");
12611273
}

‎test/cases/reflection.zig

+7-2
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,18 @@ test "reflection: array, pointer, nullable, error union type child" {
1010
}
1111
}
1212

13-
test "reflection: function return type and var args" {
13+
test "reflection: function return type, var args, and param types" {
1414
comptime {
1515
assert(@typeOf(dummy).ReturnType == i32);
1616
assert(!@typeOf(dummy).is_var_args);
1717
assert(@typeOf(dummy_varargs).is_var_args);
18+
assert(@typeOf(dummy).arg_count == 3);
19+
assert(@ArgType(@typeOf(dummy), 0) == bool);
20+
assert(@ArgType(@typeOf(dummy), 1) == i32);
21+
assert(@ArgType(@typeOf(dummy), 2) == f32);
1822
}
1923
}
2024

21-
fn dummy() -> i32 { 1234 }
25+
fn dummy(a: bool, b: i32, c: f32) -> i32 { 1234 }
2226
fn dummy_varargs(args: ...) {}
27+

‎test/compile_errors.zig

+14
Original file line numberDiff line numberDiff line change
@@ -2275,4 +2275,18 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
22752275
,
22762276
".tmp_source.zig:2:1: error: invalid character: '\\t'");
22772277

2278+
cases.add("@ArgType given non function parameter",
2279+
\\comptime {
2280+
\\ _ = @ArgType(i32, 3);
2281+
\\}
2282+
,
2283+
".tmp_source.zig:2:18: error: expected function, found 'i32'");
2284+
2285+
cases.add("@ArgType arg index out of bounds",
2286+
\\comptime {
2287+
\\ _ = @ArgType(@typeOf(add), 2);
2288+
\\}
2289+
\\fn add(a: i32, b: i32) -> i32 { return a + b; }
2290+
,
2291+
".tmp_source.zig:2:32: error: arg index 2 out of bounds; 'fn(i32, i32) -> i32' has 2 arguments");
22782292
}

0 commit comments

Comments
 (0)
Please sign in to comment.