| author | |
| committer | |
| log | 1472dc3ddb6fd7932ff530e7a2fd3f0185c7353f |
| tree | 77c6cae8dbc822e9fc5ec069b9d61d6e769694f8 |
| parent | b465037a65dd6a31c5865086ec4392a1d3a372bc |
ZIR encoding for functions is changed in preparation for generic
function support. As an example:
```zig
const std = @import("std");
const expect = std.testing.expect;
test "example" {
var x: usize = 0;
x += checkSize(i32, 1);
x += checkSize(bool, true);
try expect(x == 5);
}
fn checkSize(comptime T: type, x: T) usize {
_ = x;
return @sizeOf(T);
}
```
Previous ZIR for the `checkSize` function:
```zir
[165] checkSize line(10) hash(0226f62e189fd0b1c5fca02cf4617562): %55 = block_inline({
%56 = decl_val("T") token_offset:11:35
%57 = as_node(@Ref.type_type, %56) node_offset:11:35
%69 = extended(func([comptime @Ref.type_type, %57], @Ref.usize_type, {
%58 = arg("T") token_offset:11:23
%59 = as_node(@Ref.type_type, %58) node_offset:11:35
%60 = arg("x") token_offset:11:32
%61 = dbg_stmt(11, 4)
```
ZIR for the `checkSize` function after this commit:
```zir
[157] checkSize line(10) hash(0226f62e189fd0b1c5fca02cf4617562): %55 = block_inline({
%56 = param_comptime("T", @Ref.type_type) token_offset:11:23
%57 = as_node(@Ref.type_type, %56) node_offset:11:35
%58 = param("x", %57) token_offset:11:32
%67 = func(@Ref.usize_type, {
%59 = dbg_stmt(11, 4)
```
Noted differences:
* Previously the type expression was redundantly repeated.
* Previously the parameter names were redundantly stored in the ZIR
extra array.
* Instead of `arg` ZIR instructions as the first instructions within a
function body, they are now outside the function body, in the same
block as the `func` instruction. There are variants:
- param
- param_comptime
- param_anytype
- param_anytype_comptime
* The param instructions additionally encode the type.
* Because of the param instructions, the `func` instruction no longer
encodes the list of parameter types or the comptime bits.
It's implied that Sema will collect the parameters so that when a `func`
instruction is encountered, they will be implicitly used to construct
the function's type. This is so that we can satisfy all 3 ways of
performing semantic analysis on a function:
1. runtime: Sema will insert AIR arg instructions for each parameter,
and insert into the Sema inst_map ZIR param => AIR arg.
2. comptime/inline: Sema will insert into the inst_map ZIR param =>
callsite arguments.
3. generic: Sema will map *only the comptime* ZIR param instructions to
the AIR instructions for the comptime arguments at the callsite, and
then re-run Sema for the function's Decl. This will produce a new
function which is the monomorphized function.
Additionally:
* AstGen: Update usage of deprecated `ensureCapacity` to
`ensureUnusedCapacity` or `ensureTotalCapacity`.
* Introduce `Type.fnInfo` for getting a bunch of data about a function
type at once, and use it in `analyzeCall`.
This commit starts a branch to implement generic functions in stage2.
Test regressions have not been addressed yet.6 files changed, 431 insertions(+), 378 deletions(-)
BRANCH_TODO created+9| ... | ... | @@ -0,0 +1,9 @@ |
| 1 | * update arg instructions: | |
| 2 | - runtime function call inserts AIR arg instructions and Sema map items for them | |
| 3 | - comptime/inline function call inserts Sema map items for the args | |
| 4 | - generic instantiation inserts Sema map items for the comptime args only, re-runs the | |
| 5 | Decl ZIR to get the new Fn. | |
| 6 | * generic function call where it makes a new function | |
| 7 | * memoize the instantiation in a table | |
| 8 | * anytype with next parameter expression using it | |
| 9 | * comptime anytype |
src/AstGen.zig+182-242| ... | ... | @@ -42,7 +42,7 @@ const InnerError = error{ OutOfMemory, AnalysisFail }; |
| 42 | 42 | |
| 43 | 43 | fn addExtra(astgen: *AstGen, extra: anytype) Allocator.Error!u32 { |
| 44 | 44 | const fields = std.meta.fields(@TypeOf(extra)); |
| 45 | try astgen.extra.ensureCapacity(astgen.gpa, astgen.extra.items.len + fields.len); | |
| 45 | try astgen.extra.ensureUnusedCapacity(astgen.gpa, fields.len); | |
| 46 | 46 | return addExtraAssumeCapacity(astgen, extra); |
| 47 | 47 | } |
| 48 | 48 | |
| ... | ... | @@ -259,6 +259,7 @@ pub const ResultLoc = union(enum) { |
| 259 | 259 | |
| 260 | 260 | pub const align_rl: ResultLoc = .{ .ty = .u16_type }; |
| 261 | 261 | pub const bool_rl: ResultLoc = .{ .ty = .bool_type }; |
| 262 | pub const type_rl: ResultLoc = .{ .ty = .type_type }; | |
| 262 | 263 | |
| 263 | 264 | fn typeExpr(gz: *GenZir, scope: *Scope, type_node: ast.Node.Index) InnerError!Zir.Inst.Ref { |
| 264 | 265 | const prev_force_comptime = gz.force_comptime; |
| ... | ... | @@ -1036,7 +1037,6 @@ fn fnProtoExpr( |
| 1036 | 1037 | fn_proto: ast.full.FnProto, |
| 1037 | 1038 | ) InnerError!Zir.Inst.Ref { |
| 1038 | 1039 | const astgen = gz.astgen; |
| 1039 | const gpa = astgen.gpa; | |
| 1040 | 1040 | const tree = astgen.tree; |
| 1041 | 1041 | const token_tags = tree.tokens.items(.tag); |
| 1042 | 1042 | |
| ... | ... | @@ -1046,71 +1046,53 @@ fn fnProtoExpr( |
| 1046 | 1046 | }; |
| 1047 | 1047 | assert(!is_extern); |
| 1048 | 1048 | |
| 1049 | // The AST params array does not contain anytype and ... parameters. | |
| 1050 | // We must iterate to count how many param types to allocate. | |
| 1051 | const param_count = blk: { | |
| 1052 | var count: usize = 0; | |
| 1053 | var it = fn_proto.iterate(tree.*); | |
| 1054 | while (it.next()) |param| { | |
| 1055 | if (param.anytype_ellipsis3) |token| switch (token_tags[token]) { | |
| 1056 | .ellipsis3 => break, | |
| 1057 | .keyword_anytype => {}, | |
| 1058 | else => unreachable, | |
| 1059 | }; | |
| 1060 | count += 1; | |
| 1061 | } | |
| 1062 | break :blk count; | |
| 1063 | }; | |
| 1064 | const param_types = try gpa.alloc(Zir.Inst.Ref, param_count); | |
| 1065 | defer gpa.free(param_types); | |
| 1066 | ||
| 1067 | const bits_per_param = 1; | |
| 1068 | const params_per_u32 = 32 / bits_per_param; | |
| 1069 | // We only need this if there are greater than params_per_u32 fields. | |
| 1070 | var bit_bag = ArrayListUnmanaged(u32){}; | |
| 1071 | defer bit_bag.deinit(gpa); | |
| 1072 | var cur_bit_bag: u32 = 0; | |
| 1073 | var is_var_args = false; | |
| 1074 | { | |
| 1049 | const is_var_args = is_var_args: { | |
| 1075 | 1050 | var param_type_i: usize = 0; |
| 1076 | 1051 | var it = fn_proto.iterate(tree.*); |
| 1077 | 1052 | while (it.next()) |param| : (param_type_i += 1) { |
| 1078 | if (param_type_i % params_per_u32 == 0 and param_type_i != 0) { | |
| 1079 | try bit_bag.append(gpa, cur_bit_bag); | |
| 1080 | cur_bit_bag = 0; | |
| 1081 | } | |
| 1082 | 1053 | const is_comptime = if (param.comptime_noalias) |token| |
| 1083 | 1054 | token_tags[token] == .keyword_comptime |
| 1084 | 1055 | else |
| 1085 | 1056 | false; |
| 1086 | cur_bit_bag = (cur_bit_bag >> bits_per_param) | | |
| 1087 | (@as(u32, @boolToInt(is_comptime)) << 31); | |
| 1088 | 1057 | |
| 1089 | if (param.anytype_ellipsis3) |token| { | |
| 1058 | const is_anytype = if (param.anytype_ellipsis3) |token| blk: { | |
| 1090 | 1059 | switch (token_tags[token]) { |
| 1091 | .keyword_anytype => { | |
| 1092 | param_types[param_type_i] = .none; | |
| 1093 | continue; | |
| 1094 | }, | |
| 1095 | .ellipsis3 => { | |
| 1096 | is_var_args = true; | |
| 1097 | break; | |
| 1098 | }, | |
| 1060 | .keyword_anytype => break :blk true, | |
| 1061 | .ellipsis3 => break :is_var_args true, | |
| 1099 | 1062 | else => unreachable, |
| 1100 | 1063 | } |
| 1101 | } | |
| 1102 | const param_type_node = param.type_expr; | |
| 1103 | assert(param_type_node != 0); | |
| 1104 | param_types[param_type_i] = | |
| 1105 | try expr(gz, scope, .{ .ty = .type_type }, param_type_node); | |
| 1106 | } | |
| 1107 | assert(param_type_i == param_count); | |
| 1064 | } else false; | |
| 1065 | ||
| 1066 | const param_name: u32 = if (param.name_token) |name_token| blk: { | |
| 1067 | if (mem.eql(u8, "_", tree.tokenSlice(name_token))) | |
| 1068 | break :blk 0; | |
| 1069 | ||
| 1070 | break :blk try astgen.identAsString(name_token); | |
| 1071 | } else 0; | |
| 1108 | 1072 | |
| 1109 | const empty_slot_count = params_per_u32 - (param_type_i % params_per_u32); | |
| 1110 | if (empty_slot_count < params_per_u32) { | |
| 1111 | cur_bit_bag >>= @intCast(u5, empty_slot_count * bits_per_param); | |
| 1073 | if (is_anytype) { | |
| 1074 | const name_token = param.name_token orelse param.anytype_ellipsis3.?; | |
| 1075 | ||
| 1076 | const tag: Zir.Inst.Tag = if (is_comptime) | |
| 1077 | .param_anytype_comptime | |
| 1078 | else | |
| 1079 | .param_anytype; | |
| 1080 | _ = try gz.addStrTok(tag, param_name, name_token); | |
| 1081 | } else { | |
| 1082 | const param_type_node = param.type_expr; | |
| 1083 | assert(param_type_node != 0); | |
| 1084 | const param_type = try expr(gz, scope, type_rl, param_type_node); | |
| 1085 | const main_tokens = tree.nodes.items(.main_token); | |
| 1086 | const name_token = param.name_token orelse main_tokens[param_type_node]; | |
| 1087 | const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param; | |
| 1088 | _ = try gz.addPlTok(tag, name_token, Zir.Inst.Param{ | |
| 1089 | .name = param_name, | |
| 1090 | .ty = param_type, | |
| 1091 | }); | |
| 1092 | } | |
| 1112 | 1093 | } |
| 1113 | } | |
| 1094 | break :is_var_args false; | |
| 1095 | }; | |
| 1114 | 1096 | |
| 1115 | 1097 | const align_inst: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: { |
| 1116 | 1098 | break :inst try expr(gz, scope, align_rl, fn_proto.ast.align_expr); |
| ... | ... | @@ -1144,7 +1126,6 @@ fn fnProtoExpr( |
| 1144 | 1126 | const result = try gz.addFunc(.{ |
| 1145 | 1127 | .src_node = fn_proto.ast.proto_node, |
| 1146 | 1128 | .ret_ty = return_type_inst, |
| 1147 | .param_types = param_types, | |
| 1148 | 1129 | .body = &[0]Zir.Inst.Index{}, |
| 1149 | 1130 | .cc = cc, |
| 1150 | 1131 | .align_inst = align_inst, |
| ... | ... | @@ -1153,8 +1134,6 @@ fn fnProtoExpr( |
| 1153 | 1134 | .is_inferred_error = false, |
| 1154 | 1135 | .is_test = false, |
| 1155 | 1136 | .is_extern = false, |
| 1156 | .cur_bit_bag = cur_bit_bag, | |
| 1157 | .bit_bag = bit_bag.items, | |
| 1158 | 1137 | }); |
| 1159 | 1138 | return rvalue(gz, rl, result, fn_proto.ast.proto_node); |
| 1160 | 1139 | } |
| ... | ... | @@ -1447,8 +1426,8 @@ fn structInitExprRlNone( |
| 1447 | 1426 | const init_inst = try gz.addPlNode(tag, node, Zir.Inst.StructInitAnon{ |
| 1448 | 1427 | .fields_len = @intCast(u32, fields_list.len), |
| 1449 | 1428 | }); |
| 1450 | try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len + | |
| 1451 | fields_list.len * @typeInfo(Zir.Inst.StructInitAnon.Item).Struct.fields.len); | |
| 1429 | try astgen.extra.ensureUnusedCapacity(gpa, fields_list.len * | |
| 1430 | @typeInfo(Zir.Inst.StructInitAnon.Item).Struct.fields.len); | |
| 1452 | 1431 | for (fields_list) |field| { |
| 1453 | 1432 | _ = gz.astgen.addExtraAssumeCapacity(field); |
| 1454 | 1433 | } |
| ... | ... | @@ -1520,8 +1499,8 @@ fn structInitExprRlTy( |
| 1520 | 1499 | const init_inst = try gz.addPlNode(tag, node, Zir.Inst.StructInit{ |
| 1521 | 1500 | .fields_len = @intCast(u32, fields_list.len), |
| 1522 | 1501 | }); |
| 1523 | try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len + | |
| 1524 | fields_list.len * @typeInfo(Zir.Inst.StructInit.Item).Struct.fields.len); | |
| 1502 | try astgen.extra.ensureUnusedCapacity(gpa, fields_list.len * | |
| 1503 | @typeInfo(Zir.Inst.StructInit.Item).Struct.fields.len); | |
| 1525 | 1504 | for (fields_list) |field| { |
| 1526 | 1505 | _ = gz.astgen.addExtraAssumeCapacity(field); |
| 1527 | 1506 | } |
| ... | ... | @@ -1918,7 +1897,10 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner |
| 1918 | 1897 | // ZIR instructions that might be a type other than `noreturn` or `void`. |
| 1919 | 1898 | .add, |
| 1920 | 1899 | .addwrap, |
| 1921 | .arg, | |
| 1900 | .param, | |
| 1901 | .param_comptime, | |
| 1902 | .param_anytype, | |
| 1903 | .param_anytype_comptime, | |
| 1922 | 1904 | .alloc, |
| 1923 | 1905 | .alloc_mut, |
| 1924 | 1906 | .alloc_comptime, |
| ... | ... | @@ -2488,7 +2470,7 @@ fn varDecl( |
| 2488 | 2470 | // Move the init_scope instructions into the parent scope, swapping |
| 2489 | 2471 | // store_to_block_ptr for store_to_inferred_ptr. |
| 2490 | 2472 | const expected_len = parent_zir.items.len + init_scope.instructions.items.len; |
| 2491 | try parent_zir.ensureCapacity(gpa, expected_len); | |
| 2473 | try parent_zir.ensureTotalCapacity(gpa, expected_len); | |
| 2492 | 2474 | for (init_scope.instructions.items) |src_inst| { |
| 2493 | 2475 | if (zir_tags[src_inst] == .store_to_block_ptr) { |
| 2494 | 2476 | if (zir_datas[src_inst].bin.lhs == init_scope.rl_ptr) { |
| ... | ... | @@ -2750,10 +2732,10 @@ fn ptrType( |
| 2750 | 2732 | } |
| 2751 | 2733 | |
| 2752 | 2734 | const gpa = gz.astgen.gpa; |
| 2753 | try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); | |
| 2754 | try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1); | |
| 2755 | try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len + | |
| 2756 | @typeInfo(Zir.Inst.PtrType).Struct.fields.len + trailing_count); | |
| 2735 | try gz.instructions.ensureUnusedCapacity(gpa, 1); | |
| 2736 | try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); | |
| 2737 | try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.PtrType).Struct.fields.len + | |
| 2738 | trailing_count); | |
| 2757 | 2739 | |
| 2758 | 2740 | const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.PtrType{ .elem_type = elem_type }); |
| 2759 | 2741 | if (sentinel_ref != .none) { |
| ... | ... | @@ -2899,6 +2881,16 @@ fn fnDecl( |
| 2899 | 2881 | }; |
| 2900 | 2882 | defer decl_gz.instructions.deinit(gpa); |
| 2901 | 2883 | |
| 2884 | var fn_gz: GenZir = .{ | |
| 2885 | .force_comptime = false, | |
| 2886 | .in_defer = false, | |
| 2887 | .decl_node_index = fn_proto.ast.proto_node, | |
| 2888 | .decl_line = decl_gz.decl_line, | |
| 2889 | .parent = &decl_gz.base, | |
| 2890 | .astgen = astgen, | |
| 2891 | }; | |
| 2892 | defer fn_gz.instructions.deinit(gpa); | |
| 2893 | ||
| 2902 | 2894 | // TODO: support noinline |
| 2903 | 2895 | const is_pub = fn_proto.visib_token != null; |
| 2904 | 2896 | const is_export = blk: { |
| ... | ... | @@ -2922,71 +2914,76 @@ fn fnDecl( |
| 2922 | 2914 | |
| 2923 | 2915 | try wip_decls.next(gpa, is_pub, is_export, align_inst != .none, section_inst != .none); |
| 2924 | 2916 | |
| 2925 | // The AST params array does not contain anytype and ... parameters. | |
| 2926 | // We must iterate to count how many param types to allocate. | |
| 2927 | const param_count = blk: { | |
| 2928 | var count: usize = 0; | |
| 2929 | var it = fn_proto.iterate(tree.*); | |
| 2930 | while (it.next()) |param| { | |
| 2931 | if (param.anytype_ellipsis3) |token| switch (token_tags[token]) { | |
| 2932 | .ellipsis3 => break, | |
| 2933 | .keyword_anytype => {}, | |
| 2934 | else => unreachable, | |
| 2935 | }; | |
| 2936 | count += 1; | |
| 2937 | } | |
| 2938 | break :blk count; | |
| 2939 | }; | |
| 2940 | const param_types = try gpa.alloc(Zir.Inst.Ref, param_count); | |
| 2941 | defer gpa.free(param_types); | |
| 2942 | ||
| 2943 | const bits_per_param = 1; | |
| 2944 | const params_per_u32 = 32 / bits_per_param; | |
| 2945 | // We only need this if there are greater than params_per_u32 fields. | |
| 2946 | var bit_bag = ArrayListUnmanaged(u32){}; | |
| 2947 | defer bit_bag.deinit(gpa); | |
| 2948 | var cur_bit_bag: u32 = 0; | |
| 2949 | var is_var_args = false; | |
| 2950 | { | |
| 2917 | var params_scope = &fn_gz.base; | |
| 2918 | const is_var_args = is_var_args: { | |
| 2951 | 2919 | var param_type_i: usize = 0; |
| 2952 | 2920 | var it = fn_proto.iterate(tree.*); |
| 2953 | 2921 | while (it.next()) |param| : (param_type_i += 1) { |
| 2954 | if (param_type_i % params_per_u32 == 0 and param_type_i != 0) { | |
| 2955 | try bit_bag.append(gpa, cur_bit_bag); | |
| 2956 | cur_bit_bag = 0; | |
| 2957 | } | |
| 2958 | 2922 | const is_comptime = if (param.comptime_noalias) |token| |
| 2959 | 2923 | token_tags[token] == .keyword_comptime |
| 2960 | 2924 | else |
| 2961 | 2925 | false; |
| 2962 | cur_bit_bag = (cur_bit_bag >> bits_per_param) | | |
| 2963 | (@as(u32, @boolToInt(is_comptime)) << 31); | |
| 2964 | 2926 | |
| 2965 | if (param.anytype_ellipsis3) |token| { | |
| 2927 | const is_anytype = if (param.anytype_ellipsis3) |token| blk: { | |
| 2966 | 2928 | switch (token_tags[token]) { |
| 2967 | .keyword_anytype => { | |
| 2968 | param_types[param_type_i] = .none; | |
| 2969 | continue; | |
| 2970 | }, | |
| 2971 | .ellipsis3 => { | |
| 2972 | is_var_args = true; | |
| 2973 | break; | |
| 2974 | }, | |
| 2929 | .keyword_anytype => break :blk true, | |
| 2930 | .ellipsis3 => break :is_var_args true, | |
| 2975 | 2931 | else => unreachable, |
| 2976 | 2932 | } |
| 2977 | } | |
| 2978 | const param_type_node = param.type_expr; | |
| 2979 | assert(param_type_node != 0); | |
| 2980 | param_types[param_type_i] = | |
| 2981 | try expr(&decl_gz, &decl_gz.base, .{ .ty = .type_type }, param_type_node); | |
| 2982 | } | |
| 2983 | assert(param_type_i == param_count); | |
| 2933 | } else false; | |
| 2934 | ||
| 2935 | const param_name: u32 = if (param.name_token) |name_token| blk: { | |
| 2936 | if (mem.eql(u8, "_", tree.tokenSlice(name_token))) | |
| 2937 | break :blk 0; | |
| 2938 | ||
| 2939 | const param_name = try astgen.identAsString(name_token); | |
| 2940 | if (!is_extern) { | |
| 2941 | try astgen.detectLocalShadowing(params_scope, param_name, name_token); | |
| 2942 | } | |
| 2943 | break :blk param_name; | |
| 2944 | } else if (!is_extern) { | |
| 2945 | if (param.anytype_ellipsis3) |tok| { | |
| 2946 | return astgen.failTok(tok, "missing parameter name", .{}); | |
| 2947 | } else { | |
| 2948 | return astgen.failNode(param.type_expr, "missing parameter name", .{}); | |
| 2949 | } | |
| 2950 | } else 0; | |
| 2951 | ||
| 2952 | const param_inst = if (is_anytype) param: { | |
| 2953 | const name_token = param.name_token orelse param.anytype_ellipsis3.?; | |
| 2954 | const tag: Zir.Inst.Tag = if (is_comptime) | |
| 2955 | .param_anytype_comptime | |
| 2956 | else | |
| 2957 | .param_anytype; | |
| 2958 | break :param try decl_gz.addStrTok(tag, param_name, name_token); | |
| 2959 | } else param: { | |
| 2960 | const param_type_node = param.type_expr; | |
| 2961 | assert(param_type_node != 0); | |
| 2962 | const param_type = try expr(&decl_gz, params_scope, type_rl, param_type_node); | |
| 2963 | const main_tokens = tree.nodes.items(.main_token); | |
| 2964 | const name_token = param.name_token orelse main_tokens[param_type_node]; | |
| 2965 | const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param; | |
| 2966 | break :param try decl_gz.addPlTok(tag, name_token, Zir.Inst.Param{ | |
| 2967 | .name = param_name, | |
| 2968 | .ty = param_type, | |
| 2969 | }); | |
| 2970 | }; | |
| 2971 | ||
| 2972 | if (param_name == 0) continue; | |
| 2984 | 2973 | |
| 2985 | const empty_slot_count = params_per_u32 - (param_type_i % params_per_u32); | |
| 2986 | if (empty_slot_count < params_per_u32) { | |
| 2987 | cur_bit_bag >>= @intCast(u5, empty_slot_count * bits_per_param); | |
| 2974 | const sub_scope = try astgen.arena.create(Scope.LocalVal); | |
| 2975 | sub_scope.* = .{ | |
| 2976 | .parent = params_scope, | |
| 2977 | .gen_zir = &decl_gz, | |
| 2978 | .name = param_name, | |
| 2979 | .inst = param_inst, | |
| 2980 | .token_src = param.name_token.?, | |
| 2981 | .id_cat = .@"function parameter", | |
| 2982 | }; | |
| 2983 | params_scope = &sub_scope.base; | |
| 2988 | 2984 | } |
| 2989 | } | |
| 2985 | break :is_var_args false; | |
| 2986 | }; | |
| 2990 | 2987 | |
| 2991 | 2988 | const lib_name: u32 = if (fn_proto.lib_name) |lib_name_token| blk: { |
| 2992 | 2989 | const lib_name_str = try astgen.strLitAsString(lib_name_token); |
| ... | ... | @@ -2998,7 +2995,7 @@ fn fnDecl( |
| 2998 | 2995 | |
| 2999 | 2996 | const return_type_inst = try AstGen.expr( |
| 3000 | 2997 | &decl_gz, |
| 3001 | &decl_gz.base, | |
| 2998 | params_scope, | |
| 3002 | 2999 | .{ .ty = .type_type }, |
| 3003 | 3000 | fn_proto.ast.return_type, |
| 3004 | 3001 | ); |
| ... | ... | @@ -3014,7 +3011,7 @@ fn fnDecl( |
| 3014 | 3011 | } |
| 3015 | 3012 | break :blk try AstGen.expr( |
| 3016 | 3013 | &decl_gz, |
| 3017 | &decl_gz.base, | |
| 3014 | params_scope, | |
| 3018 | 3015 | .{ .ty = .calling_convention_type }, |
| 3019 | 3016 | fn_proto.ast.callconv_expr, |
| 3020 | 3017 | ); |
| ... | ... | @@ -3038,7 +3035,6 @@ fn fnDecl( |
| 3038 | 3035 | break :func try decl_gz.addFunc(.{ |
| 3039 | 3036 | .src_node = decl_node, |
| 3040 | 3037 | .ret_ty = return_type_inst, |
| 3041 | .param_types = param_types, | |
| 3042 | 3038 | .body = &[0]Zir.Inst.Index{}, |
| 3043 | 3039 | .cc = cc, |
| 3044 | 3040 | .align_inst = .none, // passed in the per-decl data |
| ... | ... | @@ -3047,75 +3043,18 @@ fn fnDecl( |
| 3047 | 3043 | .is_inferred_error = false, |
| 3048 | 3044 | .is_test = false, |
| 3049 | 3045 | .is_extern = true, |
| 3050 | .cur_bit_bag = cur_bit_bag, | |
| 3051 | .bit_bag = bit_bag.items, | |
| 3052 | 3046 | }); |
| 3053 | 3047 | } else func: { |
| 3054 | 3048 | if (is_var_args) { |
| 3055 | 3049 | return astgen.failTok(fn_proto.ast.fn_token, "non-extern function is variadic", .{}); |
| 3056 | 3050 | } |
| 3057 | 3051 | |
| 3058 | var fn_gz: GenZir = .{ | |
| 3059 | .force_comptime = false, | |
| 3060 | .in_defer = false, | |
| 3061 | .decl_node_index = fn_proto.ast.proto_node, | |
| 3062 | .decl_line = decl_gz.decl_line, | |
| 3063 | .parent = &decl_gz.base, | |
| 3064 | .astgen = astgen, | |
| 3065 | }; | |
| 3066 | defer fn_gz.instructions.deinit(gpa); | |
| 3067 | ||
| 3068 | 3052 | const prev_fn_block = astgen.fn_block; |
| 3069 | 3053 | astgen.fn_block = &fn_gz; |
| 3070 | 3054 | defer astgen.fn_block = prev_fn_block; |
| 3071 | 3055 | |
| 3072 | // Iterate over the parameters. We put the param names as the first N | |
| 3073 | // items inside `extra` so that debug info later can refer to the parameter names | |
| 3074 | // even while the respective source code is unloaded. | |
| 3075 | try astgen.extra.ensureUnusedCapacity(gpa, param_count); | |
| 3076 | ||
| 3077 | { | |
| 3078 | var params_scope = &fn_gz.base; | |
| 3079 | var i: usize = 0; | |
| 3080 | var it = fn_proto.iterate(tree.*); | |
| 3081 | while (it.next()) |param| : (i += 1) { | |
| 3082 | const name_token = param.name_token orelse { | |
| 3083 | if (param.anytype_ellipsis3) |tok| { | |
| 3084 | return astgen.failTok(tok, "missing parameter name", .{}); | |
| 3085 | } else { | |
| 3086 | return astgen.failNode(param.type_expr, "missing parameter name", .{}); | |
| 3087 | } | |
| 3088 | }; | |
| 3089 | if (param.type_expr != 0) | |
| 3090 | _ = try typeExpr(&fn_gz, params_scope, param.type_expr); | |
| 3091 | if (mem.eql(u8, "_", tree.tokenSlice(name_token))) | |
| 3092 | continue; | |
| 3093 | const param_name = try astgen.identAsString(name_token); | |
| 3094 | // Create an arg instruction. This is needed to emit a semantic analysis | |
| 3095 | // error for shadowing decls. | |
| 3096 | try astgen.detectLocalShadowing(params_scope, param_name, name_token); | |
| 3097 | const arg_inst = try fn_gz.addStrTok(.arg, param_name, name_token); | |
| 3098 | const sub_scope = try astgen.arena.create(Scope.LocalVal); | |
| 3099 | sub_scope.* = .{ | |
| 3100 | .parent = params_scope, | |
| 3101 | .gen_zir = &fn_gz, | |
| 3102 | .name = param_name, | |
| 3103 | .inst = arg_inst, | |
| 3104 | .token_src = name_token, | |
| 3105 | .id_cat = .@"function parameter", | |
| 3106 | }; | |
| 3107 | params_scope = &sub_scope.base; | |
| 3108 | ||
| 3109 | // Additionally put the param name into `string_bytes` and reference it with | |
| 3110 | // `extra` so that we have access to the data in codegen, for debug info. | |
| 3111 | const str_index = try astgen.identAsString(name_token); | |
| 3112 | try astgen.extra.append(astgen.gpa, str_index); | |
| 3113 | } | |
| 3114 | _ = try typeExpr(&fn_gz, params_scope, fn_proto.ast.return_type); | |
| 3115 | ||
| 3116 | _ = try expr(&fn_gz, params_scope, .none, body_node); | |
| 3117 | try checkUsed(gz, &fn_gz.base, params_scope); | |
| 3118 | } | |
| 3056 | _ = try expr(&fn_gz, params_scope, .none, body_node); | |
| 3057 | try checkUsed(gz, &fn_gz.base, params_scope); | |
| 3119 | 3058 | |
| 3120 | 3059 | const need_implicit_ret = blk: { |
| 3121 | 3060 | if (fn_gz.instructions.items.len == 0) |
| ... | ... | @@ -3133,7 +3072,6 @@ fn fnDecl( |
| 3133 | 3072 | break :func try decl_gz.addFunc(.{ |
| 3134 | 3073 | .src_node = decl_node, |
| 3135 | 3074 | .ret_ty = return_type_inst, |
| 3136 | .param_types = param_types, | |
| 3137 | 3075 | .body = fn_gz.instructions.items, |
| 3138 | 3076 | .cc = cc, |
| 3139 | 3077 | .align_inst = .none, // passed in the per-decl data |
| ... | ... | @@ -3142,8 +3080,6 @@ fn fnDecl( |
| 3142 | 3080 | .is_inferred_error = is_inferred_error, |
| 3143 | 3081 | .is_test = false, |
| 3144 | 3082 | .is_extern = false, |
| 3145 | .cur_bit_bag = cur_bit_bag, | |
| 3146 | .bit_bag = bit_bag.items, | |
| 3147 | 3083 | }); |
| 3148 | 3084 | }; |
| 3149 | 3085 | |
| ... | ... | @@ -3480,7 +3416,6 @@ fn testDecl( |
| 3480 | 3416 | const func_inst = try decl_block.addFunc(.{ |
| 3481 | 3417 | .src_node = node, |
| 3482 | 3418 | .ret_ty = .void_type, |
| 3483 | .param_types = &[0]Zir.Inst.Ref{}, | |
| 3484 | 3419 | .body = fn_block.instructions.items, |
| 3485 | 3420 | .cc = .none, |
| 3486 | 3421 | .align_inst = .none, |
| ... | ... | @@ -3489,8 +3424,6 @@ fn testDecl( |
| 3489 | 3424 | .is_inferred_error = true, |
| 3490 | 3425 | .is_test = true, |
| 3491 | 3426 | .is_extern = false, |
| 3492 | .cur_bit_bag = 0, | |
| 3493 | .bit_bag = &.{}, | |
| 3494 | 3427 | }); |
| 3495 | 3428 | |
| 3496 | 3429 | _ = try decl_block.addBreak(.break_inline, block_inst, func_inst); |
| ... | ... | @@ -4238,7 +4171,7 @@ fn containerDecl( |
| 4238 | 4171 | var fields_data = ArrayListUnmanaged(u32){}; |
| 4239 | 4172 | defer fields_data.deinit(gpa); |
| 4240 | 4173 | |
| 4241 | try fields_data.ensureCapacity(gpa, counts.total_fields + counts.values); | |
| 4174 | try fields_data.ensureTotalCapacity(gpa, counts.total_fields + counts.values); | |
| 4242 | 4175 | |
| 4243 | 4176 | // We only need this if there are greater than 32 fields. |
| 4244 | 4177 | var bit_bag = ArrayListUnmanaged(u32){}; |
| ... | ... | @@ -5184,8 +5117,7 @@ fn setCondBrPayload( |
| 5184 | 5117 | ) !void { |
| 5185 | 5118 | const astgen = then_scope.astgen; |
| 5186 | 5119 | |
| 5187 | try astgen.extra.ensureCapacity(astgen.gpa, astgen.extra.items.len + | |
| 5188 | @typeInfo(Zir.Inst.CondBr).Struct.fields.len + | |
| 5120 | try astgen.extra.ensureUnusedCapacity(astgen.gpa, @typeInfo(Zir.Inst.CondBr).Struct.fields.len + | |
| 5189 | 5121 | then_scope.instructions.items.len + else_scope.instructions.items.len); |
| 5190 | 5122 | |
| 5191 | 5123 | const zir_datas = astgen.instructions.items(.data); |
| ... | ... | @@ -5839,10 +5771,9 @@ fn switchExpr( |
| 5839 | 5771 | _ = try case_scope.addBreak(.@"break", switch_block, case_result); |
| 5840 | 5772 | } |
| 5841 | 5773 | // Documentation for this: `Zir.Inst.SwitchBlock` and `Zir.Inst.SwitchBlockMulti`. |
| 5842 | try scalar_cases_payload.ensureCapacity(gpa, scalar_cases_payload.items.len + | |
| 5774 | try scalar_cases_payload.ensureUnusedCapacity(gpa, case_scope.instructions.items.len + | |
| 5843 | 5775 | 3 + // operand, scalar_cases_len, else body len |
| 5844 | @boolToInt(multi_cases_len != 0) + | |
| 5845 | case_scope.instructions.items.len); | |
| 5776 | @boolToInt(multi_cases_len != 0)); | |
| 5846 | 5777 | scalar_cases_payload.appendAssumeCapacity(@enumToInt(operand)); |
| 5847 | 5778 | scalar_cases_payload.appendAssumeCapacity(scalar_cases_len); |
| 5848 | 5779 | if (multi_cases_len != 0) { |
| ... | ... | @@ -5852,9 +5783,11 @@ fn switchExpr( |
| 5852 | 5783 | scalar_cases_payload.appendSliceAssumeCapacity(case_scope.instructions.items); |
| 5853 | 5784 | } else { |
| 5854 | 5785 | // Documentation for this: `Zir.Inst.SwitchBlock` and `Zir.Inst.SwitchBlockMulti`. |
| 5855 | try scalar_cases_payload.ensureCapacity(gpa, scalar_cases_payload.items.len + | |
| 5856 | 2 + // operand, scalar_cases_len | |
| 5857 | @boolToInt(multi_cases_len != 0)); | |
| 5786 | try scalar_cases_payload.ensureUnusedCapacity( | |
| 5787 | gpa, | |
| 5788 | @as(usize, 2) + // operand, scalar_cases_len | |
| 5789 | @boolToInt(multi_cases_len != 0), | |
| 5790 | ); | |
| 5858 | 5791 | scalar_cases_payload.appendAssumeCapacity(@enumToInt(operand)); |
| 5859 | 5792 | scalar_cases_payload.appendAssumeCapacity(scalar_cases_len); |
| 5860 | 5793 | if (multi_cases_len != 0) { |
| ... | ... | @@ -5975,8 +5908,8 @@ fn switchExpr( |
| 5975 | 5908 | block_scope.break_count += 1; |
| 5976 | 5909 | _ = try case_scope.addBreak(.@"break", switch_block, case_result); |
| 5977 | 5910 | } |
| 5978 | try scalar_cases_payload.ensureCapacity(gpa, scalar_cases_payload.items.len + | |
| 5979 | 2 + case_scope.instructions.items.len); | |
| 5911 | try scalar_cases_payload.ensureUnusedCapacity(gpa, 2 + | |
| 5912 | case_scope.instructions.items.len); | |
| 5980 | 5913 | scalar_cases_payload.appendAssumeCapacity(@enumToInt(item_inst)); |
| 5981 | 5914 | scalar_cases_payload.appendAssumeCapacity(@intCast(u32, case_scope.instructions.items.len)); |
| 5982 | 5915 | scalar_cases_payload.appendSliceAssumeCapacity(case_scope.instructions.items); |
| ... | ... | @@ -6012,8 +5945,8 @@ fn switchExpr( |
| 6012 | 5945 | const payload_index = astgen.extra.items.len; |
| 6013 | 5946 | const zir_datas = astgen.instructions.items(.data); |
| 6014 | 5947 | zir_datas[switch_block].pl_node.payload_index = @intCast(u32, payload_index); |
| 6015 | try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len + | |
| 6016 | scalar_cases_payload.items.len + multi_cases_payload.items.len); | |
| 5948 | try astgen.extra.ensureUnusedCapacity(gpa, scalar_cases_payload.items.len + | |
| 5949 | multi_cases_payload.items.len); | |
| 6017 | 5950 | const strat = rl.strategy(&block_scope); |
| 6018 | 5951 | switch (strat.tag) { |
| 6019 | 5952 | .break_operand => { |
| ... | ... | @@ -8659,7 +8592,7 @@ fn failNodeNotes( |
| 8659 | 8592 | } |
| 8660 | 8593 | const notes_index: u32 = if (notes.len != 0) blk: { |
| 8661 | 8594 | const notes_start = astgen.extra.items.len; |
| 8662 | try astgen.extra.ensureCapacity(astgen.gpa, notes_start + 1 + notes.len); | |
| 8595 | try astgen.extra.ensureTotalCapacity(astgen.gpa, notes_start + 1 + notes.len); | |
| 8663 | 8596 | astgen.extra.appendAssumeCapacity(@intCast(u32, notes.len)); |
| 8664 | 8597 | astgen.extra.appendSliceAssumeCapacity(notes); |
| 8665 | 8598 | break :blk @intCast(u32, notes_start); |
| ... | ... | @@ -8700,7 +8633,7 @@ fn failTokNotes( |
| 8700 | 8633 | } |
| 8701 | 8634 | const notes_index: u32 = if (notes.len != 0) blk: { |
| 8702 | 8635 | const notes_start = astgen.extra.items.len; |
| 8703 | try astgen.extra.ensureCapacity(astgen.gpa, notes_start + 1 + notes.len); | |
| 8636 | try astgen.extra.ensureTotalCapacity(astgen.gpa, notes_start + 1 + notes.len); | |
| 8704 | 8637 | astgen.extra.appendAssumeCapacity(@intCast(u32, notes.len)); |
| 8705 | 8638 | astgen.extra.appendSliceAssumeCapacity(notes); |
| 8706 | 8639 | break :blk @intCast(u32, notes_start); |
| ... | ... | @@ -8864,7 +8797,7 @@ fn strLitNodeAsString(astgen: *AstGen, node: ast.Node.Index) !IndexSlice { |
| 8864 | 8797 | while (tok_i <= end) : (tok_i += 1) { |
| 8865 | 8798 | const slice = tree.tokenSlice(tok_i); |
| 8866 | 8799 | const line_bytes = slice[2 .. slice.len - 1]; |
| 8867 | try string_bytes.ensureCapacity(gpa, string_bytes.items.len + line_bytes.len + 1); | |
| 8800 | try string_bytes.ensureUnusedCapacity(gpa, line_bytes.len + 1); | |
| 8868 | 8801 | string_bytes.appendAssumeCapacity('\n'); |
| 8869 | 8802 | string_bytes.appendSliceAssumeCapacity(line_bytes); |
| 8870 | 8803 | } |
| ... | ... | @@ -9131,8 +9064,8 @@ const GenZir = struct { |
| 9131 | 9064 | |
| 9132 | 9065 | fn setBoolBrBody(gz: GenZir, inst: Zir.Inst.Index) !void { |
| 9133 | 9066 | const gpa = gz.astgen.gpa; |
| 9134 | try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len + | |
| 9135 | @typeInfo(Zir.Inst.Block).Struct.fields.len + gz.instructions.items.len); | |
| 9067 | try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Block).Struct.fields.len + | |
| 9068 | gz.instructions.items.len); | |
| 9136 | 9069 | const zir_datas = gz.astgen.instructions.items(.data); |
| 9137 | 9070 | zir_datas[inst].bool_br.payload_index = gz.astgen.addExtraAssumeCapacity( |
| 9138 | 9071 | Zir.Inst.Block{ .body_len = @intCast(u32, gz.instructions.items.len) }, |
| ... | ... | @@ -9142,8 +9075,8 @@ const GenZir = struct { |
| 9142 | 9075 | |
| 9143 | 9076 | fn setBlockBody(gz: GenZir, inst: Zir.Inst.Index) !void { |
| 9144 | 9077 | const gpa = gz.astgen.gpa; |
| 9145 | try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len + | |
| 9146 | @typeInfo(Zir.Inst.Block).Struct.fields.len + gz.instructions.items.len); | |
| 9078 | try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Block).Struct.fields.len + | |
| 9079 | gz.instructions.items.len); | |
| 9147 | 9080 | const zir_datas = gz.astgen.instructions.items(.data); |
| 9148 | 9081 | zir_datas[inst].pl_node.payload_index = gz.astgen.addExtraAssumeCapacity( |
| 9149 | 9082 | Zir.Inst.Block{ .body_len = @intCast(u32, gz.instructions.items.len) }, |
| ... | ... | @@ -9155,8 +9088,8 @@ const GenZir = struct { |
| 9155 | 9088 | /// `store_to_block_ptr` instructions with lhs set to .none. |
| 9156 | 9089 | fn setBlockBodyEliding(gz: GenZir, inst: Zir.Inst.Index) !void { |
| 9157 | 9090 | const gpa = gz.astgen.gpa; |
| 9158 | try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len + | |
| 9159 | @typeInfo(Zir.Inst.Block).Struct.fields.len + gz.instructions.items.len); | |
| 9091 | try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Block).Struct.fields.len + | |
| 9092 | gz.instructions.items.len); | |
| 9160 | 9093 | const zir_datas = gz.astgen.instructions.items(.data); |
| 9161 | 9094 | const zir_tags = gz.astgen.instructions.items(.tag); |
| 9162 | 9095 | const block_pl_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Block{ |
| ... | ... | @@ -9177,7 +9110,6 @@ const GenZir = struct { |
| 9177 | 9110 | |
| 9178 | 9111 | fn addFunc(gz: *GenZir, args: struct { |
| 9179 | 9112 | src_node: ast.Node.Index, |
| 9180 | param_types: []const Zir.Inst.Ref, | |
| 9181 | 9113 | body: []const Zir.Inst.Index, |
| 9182 | 9114 | ret_ty: Zir.Inst.Ref, |
| 9183 | 9115 | cc: Zir.Inst.Ref, |
| ... | ... | @@ -9187,8 +9119,6 @@ const GenZir = struct { |
| 9187 | 9119 | is_inferred_error: bool, |
| 9188 | 9120 | is_test: bool, |
| 9189 | 9121 | is_extern: bool, |
| 9190 | cur_bit_bag: u32, | |
| 9191 | bit_bag: []const u32, | |
| 9192 | 9122 | }) !Zir.Inst.Ref { |
| 9193 | 9123 | assert(args.src_node != 0); |
| 9194 | 9124 | assert(args.ret_ty != .none); |
| ... | ... | @@ -9226,19 +9156,14 @@ const GenZir = struct { |
| 9226 | 9156 | src_locs = &src_locs_buffer; |
| 9227 | 9157 | } |
| 9228 | 9158 | |
| 9229 | const any_are_comptime = args.cur_bit_bag != 0 or for (args.bit_bag) |x| { | |
| 9230 | if (x != 0) break true; | |
| 9231 | } else false; | |
| 9232 | ||
| 9233 | 9159 | if (args.cc != .none or args.lib_name != 0 or |
| 9234 | 9160 | args.is_var_args or args.is_test or args.align_inst != .none or |
| 9235 | args.is_extern or any_are_comptime) | |
| 9161 | args.is_extern) | |
| 9236 | 9162 | { |
| 9237 | 9163 | try astgen.extra.ensureUnusedCapacity( |
| 9238 | 9164 | gpa, |
| 9239 | 9165 | @typeInfo(Zir.Inst.ExtendedFunc).Struct.fields.len + |
| 9240 | @boolToInt(any_are_comptime) + args.bit_bag.len + | |
| 9241 | args.param_types.len + args.body.len + src_locs.len + | |
| 9166 | args.body.len + src_locs.len + | |
| 9242 | 9167 | @boolToInt(args.lib_name != 0) + |
| 9243 | 9168 | @boolToInt(args.align_inst != .none) + |
| 9244 | 9169 | @boolToInt(args.cc != .none), |
| ... | ... | @@ -9246,7 +9171,6 @@ const GenZir = struct { |
| 9246 | 9171 | const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedFunc{ |
| 9247 | 9172 | .src_node = gz.nodeIndexToRelative(args.src_node), |
| 9248 | 9173 | .return_type = args.ret_ty, |
| 9249 | .param_types_len = @intCast(u32, args.param_types.len), | |
| 9250 | 9174 | .body_len = @intCast(u32, args.body.len), |
| 9251 | 9175 | }); |
| 9252 | 9176 | if (args.lib_name != 0) { |
| ... | ... | @@ -9258,11 +9182,6 @@ const GenZir = struct { |
| 9258 | 9182 | if (args.align_inst != .none) { |
| 9259 | 9183 | astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst)); |
| 9260 | 9184 | } |
| 9261 | if (any_are_comptime) { | |
| 9262 | astgen.extra.appendSliceAssumeCapacity(args.bit_bag); // Likely empty. | |
| 9263 | astgen.extra.appendAssumeCapacity(args.cur_bit_bag); | |
| 9264 | } | |
| 9265 | astgen.appendRefsAssumeCapacity(args.param_types); | |
| 9266 | 9185 | astgen.extra.appendSliceAssumeCapacity(args.body); |
| 9267 | 9186 | astgen.extra.appendSliceAssumeCapacity(src_locs); |
| 9268 | 9187 | |
| ... | ... | @@ -9279,7 +9198,6 @@ const GenZir = struct { |
| 9279 | 9198 | .has_align = args.align_inst != .none, |
| 9280 | 9199 | .is_test = args.is_test, |
| 9281 | 9200 | .is_extern = args.is_extern, |
| 9282 | .has_comptime_bits = any_are_comptime, | |
| 9283 | 9201 | }), |
| 9284 | 9202 | .operand = payload_index, |
| 9285 | 9203 | } }, |
| ... | ... | @@ -9290,15 +9208,13 @@ const GenZir = struct { |
| 9290 | 9208 | try gz.astgen.extra.ensureUnusedCapacity( |
| 9291 | 9209 | gpa, |
| 9292 | 9210 | @typeInfo(Zir.Inst.Func).Struct.fields.len + |
| 9293 | args.param_types.len + args.body.len + src_locs.len, | |
| 9211 | args.body.len + src_locs.len, | |
| 9294 | 9212 | ); |
| 9295 | 9213 | |
| 9296 | 9214 | const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Func{ |
| 9297 | 9215 | .return_type = args.ret_ty, |
| 9298 | .param_types_len = @intCast(u32, args.param_types.len), | |
| 9299 | 9216 | .body_len = @intCast(u32, args.body.len), |
| 9300 | 9217 | }); |
| 9301 | gz.astgen.appendRefsAssumeCapacity(args.param_types); | |
| 9302 | 9218 | gz.astgen.extra.appendSliceAssumeCapacity(args.body); |
| 9303 | 9219 | gz.astgen.extra.appendSliceAssumeCapacity(src_locs); |
| 9304 | 9220 | |
| ... | ... | @@ -9380,10 +9296,10 @@ const GenZir = struct { |
| 9380 | 9296 | assert(callee != .none); |
| 9381 | 9297 | assert(src_node != 0); |
| 9382 | 9298 | const gpa = gz.astgen.gpa; |
| 9383 | try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); | |
| 9384 | try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1); | |
| 9385 | try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len + | |
| 9386 | @typeInfo(Zir.Inst.Call).Struct.fields.len + args.len); | |
| 9299 | try gz.instructions.ensureUnusedCapacity(gpa, 1); | |
| 9300 | try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); | |
| 9301 | try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Call).Struct.fields.len + | |
| 9302 | args.len); | |
| 9387 | 9303 | |
| 9388 | 9304 | const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Call{ |
| 9389 | 9305 | .callee = callee, |
| ... | ... | @@ -9412,8 +9328,8 @@ const GenZir = struct { |
| 9412 | 9328 | ) !Zir.Inst.Index { |
| 9413 | 9329 | assert(lhs != .none); |
| 9414 | 9330 | const gpa = gz.astgen.gpa; |
| 9415 | try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); | |
| 9416 | try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1); | |
| 9331 | try gz.instructions.ensureUnusedCapacity(gpa, 1); | |
| 9332 | try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); | |
| 9417 | 9333 | |
| 9418 | 9334 | const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); |
| 9419 | 9335 | gz.astgen.instructions.appendAssumeCapacity(.{ |
| ... | ... | @@ -9486,8 +9402,8 @@ const GenZir = struct { |
| 9486 | 9402 | extra: anytype, |
| 9487 | 9403 | ) !Zir.Inst.Ref { |
| 9488 | 9404 | const gpa = gz.astgen.gpa; |
| 9489 | try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); | |
| 9490 | try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1); | |
| 9405 | try gz.instructions.ensureUnusedCapacity(gpa, 1); | |
| 9406 | try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); | |
| 9491 | 9407 | |
| 9492 | 9408 | const payload_index = try gz.astgen.addExtra(extra); |
| 9493 | 9409 | const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); |
| ... | ... | @@ -9502,6 +9418,30 @@ const GenZir = struct { |
| 9502 | 9418 | return indexToRef(new_index); |
| 9503 | 9419 | } |
| 9504 | 9420 | |
| 9421 | fn addPlTok( | |
| 9422 | gz: *GenZir, | |
| 9423 | tag: Zir.Inst.Tag, | |
| 9424 | /// Absolute token index. This function does the conversion to Decl offset. | |
| 9425 | abs_tok_index: ast.TokenIndex, | |
| 9426 | extra: anytype, | |
| 9427 | ) !Zir.Inst.Ref { | |
| 9428 | const gpa = gz.astgen.gpa; | |
| 9429 | try gz.instructions.ensureUnusedCapacity(gpa, 1); | |
| 9430 | try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); | |
| 9431 | ||
| 9432 | const payload_index = try gz.astgen.addExtra(extra); | |
| 9433 | const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); | |
| 9434 | gz.astgen.instructions.appendAssumeCapacity(.{ | |
| 9435 | .tag = tag, | |
| 9436 | .data = .{ .pl_tok = .{ | |
| 9437 | .src_tok = gz.tokenIndexToRelative(abs_tok_index), | |
| 9438 | .payload_index = payload_index, | |
| 9439 | } }, | |
| 9440 | }); | |
| 9441 | gz.instructions.appendAssumeCapacity(new_index); | |
| 9442 | return indexToRef(new_index); | |
| 9443 | } | |
| 9444 | ||
| 9505 | 9445 | fn addExtendedPayload( |
| 9506 | 9446 | gz: *GenZir, |
| 9507 | 9447 | opcode: Zir.Inst.Extended, |
| ... | ... | @@ -9509,8 +9449,8 @@ const GenZir = struct { |
| 9509 | 9449 | ) !Zir.Inst.Ref { |
| 9510 | 9450 | const gpa = gz.astgen.gpa; |
| 9511 | 9451 | |
| 9512 | try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); | |
| 9513 | try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1); | |
| 9452 | try gz.instructions.ensureUnusedCapacity(gpa, 1); | |
| 9453 | try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); | |
| 9514 | 9454 | |
| 9515 | 9455 | const payload_index = try gz.astgen.addExtra(extra); |
| 9516 | 9456 | const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); |
| ... | ... | @@ -9566,8 +9506,8 @@ const GenZir = struct { |
| 9566 | 9506 | elem_type: Zir.Inst.Ref, |
| 9567 | 9507 | ) !Zir.Inst.Ref { |
| 9568 | 9508 | const gpa = gz.astgen.gpa; |
| 9569 | try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); | |
| 9570 | try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1); | |
| 9509 | try gz.instructions.ensureUnusedCapacity(gpa, 1); | |
| 9510 | try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); | |
| 9571 | 9511 | |
| 9572 | 9512 | const payload_index = try gz.astgen.addExtra(Zir.Inst.ArrayTypeSentinel{ |
| 9573 | 9513 | .sentinel = sentinel, |
| ... | ... | @@ -9822,7 +9762,7 @@ const GenZir = struct { |
| 9822 | 9762 | /// Leaves the `payload_index` field undefined. |
| 9823 | 9763 | fn addCondBr(gz: *GenZir, tag: Zir.Inst.Tag, node: ast.Node.Index) !Zir.Inst.Index { |
| 9824 | 9764 | const gpa = gz.astgen.gpa; |
| 9825 | try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1); | |
| 9765 | try gz.instructions.ensureUnusedCapacity(gpa, 1); | |
| 9826 | 9766 | const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); |
| 9827 | 9767 | try gz.astgen.instructions.append(gpa, .{ |
| 9828 | 9768 | .tag = tag, |
src/Module.zig+1-1| ... | ... | @@ -3714,7 +3714,7 @@ fn markOutdatedDecl(mod: *Module, decl: *Decl) !void { |
| 3714 | 3714 | decl.analysis = .outdated; |
| 3715 | 3715 | } |
| 3716 | 3716 | |
| 3717 | fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: ast.Node.Index) !*Decl { | |
| 3717 | pub fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: ast.Node.Index) !*Decl { | |
| 3718 | 3718 | // If we have emit-h then we must allocate a bigger structure to store the emit-h state. |
| 3719 | 3719 | const new_decl: *Decl = if (mod.emit_h != null) blk: { |
| 3720 | 3720 | const parent_struct = try mod.gpa.create(DeclPlusEmitH); |
src/Sema.zig+124-69| ... | ... | @@ -44,6 +44,7 @@ branch_count: u32 = 0, |
| 44 | 44 | /// contain a mapped source location. |
| 45 | 45 | src: LazySrcLoc = .{ .token_offset = 0 }, |
| 46 | 46 | next_arg_index: usize = 0, |
| 47 | params: std.ArrayListUnmanaged(Param) = .{}, | |
| 47 | 48 | decl_val_table: std.AutoHashMapUnmanaged(*Decl, Air.Inst.Ref) = .{}, |
| 48 | 49 | |
| 49 | 50 | const std = @import("std"); |
| ... | ... | @@ -68,6 +69,13 @@ const LazySrcLoc = Module.LazySrcLoc; |
| 68 | 69 | const RangeSet = @import("RangeSet.zig"); |
| 69 | 70 | const target_util = @import("target.zig"); |
| 70 | 71 | |
| 72 | const Param = struct { | |
| 73 | name: [:0]const u8, | |
| 74 | /// `none` means `anytype`. | |
| 75 | ty: Air.Inst.Ref, | |
| 76 | is_comptime: bool, | |
| 77 | }; | |
| 78 | ||
| 71 | 79 | pub const InstMap = std.AutoHashMapUnmanaged(Zir.Inst.Index, Air.Inst.Ref); |
| 72 | 80 | |
| 73 | 81 | pub fn deinit(sema: *Sema) void { |
| ... | ... | @@ -91,8 +99,7 @@ pub fn analyzeFnBody( |
| 91 | 99 | .func, .func_inferred => blk: { |
| 92 | 100 | const inst_data = datas[fn_body_inst].pl_node; |
| 93 | 101 | const extra = sema.code.extraData(Zir.Inst.Func, inst_data.payload_index); |
| 94 | const param_types_len = extra.data.param_types_len; | |
| 95 | const body = sema.code.extra[extra.end + param_types_len ..][0..extra.data.body_len]; | |
| 102 | const body = sema.code.extra[extra.end..][0..extra.data.body_len]; | |
| 96 | 103 | break :blk body; |
| 97 | 104 | }, |
| 98 | 105 | .extended => blk: { |
| ... | ... | @@ -104,10 +111,6 @@ pub fn analyzeFnBody( |
| 104 | 111 | extra_index += @boolToInt(small.has_lib_name); |
| 105 | 112 | extra_index += @boolToInt(small.has_cc); |
| 106 | 113 | extra_index += @boolToInt(small.has_align); |
| 107 | if (small.has_comptime_bits) { | |
| 108 | extra_index += (extra.data.param_types_len + 31) / 32; | |
| 109 | } | |
| 110 | extra_index += extra.data.param_types_len; | |
| 111 | 114 | const body = sema.code.extra[extra_index..][0..extra.data.body_len]; |
| 112 | 115 | break :blk body; |
| 113 | 116 | }, |
| ... | ... | @@ -162,7 +165,6 @@ pub fn analyzeBody( |
| 162 | 165 | const inst = body[i]; |
| 163 | 166 | const air_inst: Air.Inst.Ref = switch (tags[inst]) { |
| 164 | 167 | // zig fmt: off |
| 165 | .arg => try sema.zirArg(block, inst), | |
| 166 | 168 | .alloc => try sema.zirAlloc(block, inst), |
| 167 | 169 | .alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)), |
| 168 | 170 | .alloc_inferred_mut => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)), |
| ... | ... | @@ -404,6 +406,26 @@ pub fn analyzeBody( |
| 404 | 406 | // continue the loop. |
| 405 | 407 | // We also know that they cannot be referenced later, so we avoid |
| 406 | 408 | // putting them into the map. |
| 409 | .param => { | |
| 410 | try sema.zirParam(inst, false); | |
| 411 | i += 1; | |
| 412 | continue; | |
| 413 | }, | |
| 414 | .param_comptime => { | |
| 415 | try sema.zirParam(inst, true); | |
| 416 | i += 1; | |
| 417 | continue; | |
| 418 | }, | |
| 419 | .param_anytype => { | |
| 420 | try sema.zirParamAnytype(inst, false); | |
| 421 | i += 1; | |
| 422 | continue; | |
| 423 | }, | |
| 424 | .param_anytype_comptime => { | |
| 425 | try sema.zirParamAnytype(inst, true); | |
| 426 | i += 1; | |
| 427 | continue; | |
| 428 | }, | |
| 407 | 429 | .breakpoint => { |
| 408 | 430 | try sema.zirBreakpoint(block, inst); |
| 409 | 431 | i += 1; |
| ... | ... | @@ -1358,23 +1380,34 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Co |
| 1358 | 1380 | return sema.analyzeLoad(block, src, result_ptr, result_ptr_src); |
| 1359 | 1381 | } |
| 1360 | 1382 | |
| 1361 | fn zirArg(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 1362 | const inst_data = sema.code.instructions.items(.data)[inst].str_tok; | |
| 1363 | const arg_name = inst_data.get(sema.code); | |
| 1364 | const arg_index = sema.next_arg_index; | |
| 1365 | sema.next_arg_index += 1; | |
| 1383 | fn zirParam(sema: *Sema, inst: Zir.Inst.Index, is_comptime: bool) CompileError!void { | |
| 1384 | const inst_data = sema.code.instructions.items(.data)[inst].pl_tok; | |
| 1385 | const extra = sema.code.extraData(Zir.Inst.Param, inst_data.payload_index).data; | |
| 1386 | const param_name = sema.code.nullTerminatedString(extra.name); | |
| 1366 | 1387 | |
| 1367 | // TODO check if arg_name shadows a Decl | |
| 1368 | _ = arg_name; | |
| 1388 | // TODO check if param_name shadows a Decl. This only needs to be done if | |
| 1389 | // usingnamespace is implemented. | |
| 1369 | 1390 | |
| 1370 | if (block.inlining) |_| { | |
| 1371 | return sema.param_inst_list[arg_index]; | |
| 1372 | } | |
| 1391 | const param_ty = sema.resolveInst(extra.ty); | |
| 1392 | try sema.params.append(sema.gpa, .{ | |
| 1393 | .name = param_name, | |
| 1394 | .ty = param_ty, | |
| 1395 | .is_comptime = is_comptime, | |
| 1396 | }); | |
| 1397 | } | |
| 1398 | ||
| 1399 | fn zirParamAnytype(sema: *Sema, inst: Zir.Inst.Index, is_comptime: bool) CompileError!void { | |
| 1400 | const inst_data = sema.code.instructions.items(.data)[inst].str_tok; | |
| 1401 | const param_name = inst_data.get(sema.code); | |
| 1373 | 1402 | |
| 1374 | // Set the name of the Air.Arg instruction for use by codegen debug info. | |
| 1375 | const air_arg = sema.param_inst_list[arg_index]; | |
| 1376 | sema.air_instructions.items(.data)[Air.refToIndex(air_arg).?].ty_str.str = inst_data.start; | |
| 1377 | return air_arg; | |
| 1403 | // TODO check if param_name shadows a Decl. This only needs to be done if | |
| 1404 | // usingnamespace is implemented. | |
| 1405 | ||
| 1406 | try sema.params.append(sema.gpa, .{ | |
| 1407 | .name = param_name, | |
| 1408 | .ty = .none, | |
| 1409 | .is_comptime = is_comptime, | |
| 1410 | }); | |
| 1378 | 1411 | } |
| 1379 | 1412 | |
| 1380 | 1413 | fn zirAllocExtended( |
| ... | ... | @@ -2395,26 +2428,29 @@ fn analyzeCall( |
| 2395 | 2428 | ensure_result_used: bool, |
| 2396 | 2429 | args: []const Air.Inst.Ref, |
| 2397 | 2430 | ) CompileError!Air.Inst.Ref { |
| 2431 | const mod = sema.mod; | |
| 2432 | ||
| 2398 | 2433 | const func_ty = sema.typeOf(func); |
| 2399 | 2434 | if (func_ty.zigTypeTag() != .Fn) |
| 2400 | return sema.mod.fail(&block.base, func_src, "type '{}' not a function", .{func_ty}); | |
| 2435 | return mod.fail(&block.base, func_src, "type '{}' not a function", .{func_ty}); | |
| 2401 | 2436 | |
| 2402 | const cc = func_ty.fnCallingConvention(); | |
| 2437 | const func_ty_info = func_ty.fnInfo(); | |
| 2438 | const cc = func_ty_info.cc; | |
| 2403 | 2439 | if (cc == .Naked) { |
| 2404 | 2440 | // TODO add error note: declared here |
| 2405 | return sema.mod.fail( | |
| 2441 | return mod.fail( | |
| 2406 | 2442 | &block.base, |
| 2407 | 2443 | func_src, |
| 2408 | 2444 | "unable to call function with naked calling convention", |
| 2409 | 2445 | .{}, |
| 2410 | 2446 | ); |
| 2411 | 2447 | } |
| 2412 | const fn_params_len = func_ty.fnParamLen(); | |
| 2413 | if (func_ty.fnIsVarArgs()) { | |
| 2448 | const fn_params_len = func_ty_info.param_types.len; | |
| 2449 | if (func_ty_info.is_var_args) { | |
| 2414 | 2450 | assert(cc == .C); |
| 2415 | 2451 | if (args.len < fn_params_len) { |
| 2416 | 2452 | // TODO add error note: declared here |
| 2417 | return sema.mod.fail( | |
| 2453 | return mod.fail( | |
| 2418 | 2454 | &block.base, |
| 2419 | 2455 | func_src, |
| 2420 | 2456 | "expected at least {d} argument(s), found {d}", |
| ... | ... | @@ -2423,7 +2459,7 @@ fn analyzeCall( |
| 2423 | 2459 | } |
| 2424 | 2460 | } else if (fn_params_len != args.len) { |
| 2425 | 2461 | // TODO add error note: declared here |
| 2426 | return sema.mod.fail( | |
| 2462 | return mod.fail( | |
| 2427 | 2463 | &block.base, |
| 2428 | 2464 | func_src, |
| 2429 | 2465 | "expected {d} argument(s), found {d}", |
| ... | ... | @@ -2442,7 +2478,7 @@ fn analyzeCall( |
| 2442 | 2478 | .never_inline, |
| 2443 | 2479 | .no_async, |
| 2444 | 2480 | .always_tail, |
| 2445 | => return sema.mod.fail(&block.base, call_src, "TODO implement call with modifier {}", .{ | |
| 2481 | => return mod.fail(&block.base, call_src, "TODO implement call with modifier {}", .{ | |
| 2446 | 2482 | modifier, |
| 2447 | 2483 | }), |
| 2448 | 2484 | } |
| ... | ... | @@ -2451,12 +2487,12 @@ fn analyzeCall( |
| 2451 | 2487 | |
| 2452 | 2488 | const is_comptime_call = block.is_comptime or modifier == .compile_time; |
| 2453 | 2489 | const is_inline_call = is_comptime_call or modifier == .always_inline or |
| 2454 | func_ty.fnCallingConvention() == .Inline; | |
| 2490 | func_ty_info.cc == .Inline; | |
| 2455 | 2491 | const result: Air.Inst.Ref = if (is_inline_call) res: { |
| 2456 | 2492 | const func_val = try sema.resolveConstValue(block, func_src, func); |
| 2457 | 2493 | const module_fn = switch (func_val.tag()) { |
| 2458 | 2494 | .function => func_val.castTag(.function).?.data, |
| 2459 | .extern_fn => return sema.mod.fail(&block.base, call_src, "{s} call of extern function", .{ | |
| 2495 | .extern_fn => return mod.fail(&block.base, call_src, "{s} call of extern function", .{ | |
| 2460 | 2496 | @as([]const u8, if (is_comptime_call) "comptime" else "inline"), |
| 2461 | 2497 | }), |
| 2462 | 2498 | else => unreachable, |
| ... | ... | @@ -2535,10 +2571,46 @@ fn analyzeCall( |
| 2535 | 2571 | const result = try sema.analyzeBlockBody(block, call_src, &child_block, merges); |
| 2536 | 2572 | |
| 2537 | 2573 | break :res result; |
| 2574 | } else if (func_ty_info.is_generic) { | |
| 2575 | const func_val = try sema.resolveConstValue(block, func_src, func); | |
| 2576 | const module_fn = func_val.castTag(.function).?.data; | |
| 2577 | // Check the Module's generic function map with an adapted context, so that we | |
| 2578 | // can match against `args` rather than doing the work below to create a generic Scope | |
| 2579 | // only to junk it if it matches an existing instantiation. | |
| 2580 | // TODO | |
| 2581 | ||
| 2582 | // Create a Decl for the new function. | |
| 2583 | const generic_namespace = try sema.arena.create(Module.Scope.Namespace); | |
| 2584 | generic_namespace.* = .{ | |
| 2585 | .parent = block.src_decl.namespace, | |
| 2586 | .file_scope = block.src_decl.namespace.file_scope, | |
| 2587 | .ty = func_ty, | |
| 2588 | }; | |
| 2589 | const new_decl = try mod.allocateNewDecl(generic_namespace, module_fn.owner_decl.src_node); | |
| 2590 | _ = new_decl; | |
| 2591 | ||
| 2592 | // Iterate over the parameters that are comptime, evaluating their type expressions | |
| 2593 | // inside a Scope which contains the previous parameters. | |
| 2594 | //for (args) |arg, arg_i| { | |
| 2595 | //} | |
| 2596 | ||
| 2597 | // Create a new Fn with only the runtime-known parameters. | |
| 2598 | // TODO | |
| 2599 | ||
| 2600 | // Populate the Decl ty/val with the function and its type. | |
| 2601 | // TODO | |
| 2602 | ||
| 2603 | // Queue up a `codegen_func` work item for the new Fn, making sure it will have | |
| 2604 | // `analyzeFnBody` called with the Scope which contains the comptime parameters. | |
| 2605 | // TODO | |
| 2606 | ||
| 2607 | // Save it into the Module's generic function map. | |
| 2608 | // TODO | |
| 2609 | ||
| 2610 | // Call it the same as a runtime function. | |
| 2611 | // TODO | |
| 2612 | return mod.fail(&block.base, func_src, "TODO implement generic fn call", .{}); | |
| 2538 | 2613 | } else res: { |
| 2539 | if (func_ty.fnIsGeneric()) { | |
| 2540 | return sema.mod.fail(&block.base, func_src, "TODO implement generic fn call", .{}); | |
| 2541 | } | |
| 2542 | 2614 | try sema.requireRuntimeBlock(block, call_src); |
| 2543 | 2615 | try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len + |
| 2544 | 2616 | args.len); |
| ... | ... | @@ -3186,13 +3258,12 @@ fn zirFunc( |
| 3186 | 3258 | |
| 3187 | 3259 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 3188 | 3260 | const extra = sema.code.extraData(Zir.Inst.Func, inst_data.payload_index); |
| 3189 | const param_types = sema.code.refSlice(extra.end, extra.data.param_types_len); | |
| 3190 | 3261 | |
| 3191 | 3262 | var body_inst: Zir.Inst.Index = 0; |
| 3192 | 3263 | var src_locs: Zir.Inst.Func.SrcLocs = undefined; |
| 3193 | 3264 | if (extra.data.body_len != 0) { |
| 3194 | 3265 | body_inst = inst; |
| 3195 | const extra_index = extra.end + extra.data.param_types_len + extra.data.body_len; | |
| 3266 | const extra_index = extra.end + extra.data.body_len; | |
| 3196 | 3267 | src_locs = sema.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data; |
| 3197 | 3268 | } |
| 3198 | 3269 | |
| ... | ... | @@ -3204,7 +3275,6 @@ fn zirFunc( |
| 3204 | 3275 | return sema.funcCommon( |
| 3205 | 3276 | block, |
| 3206 | 3277 | inst_data.src_node, |
| 3207 | param_types, | |
| 3208 | 3278 | body_inst, |
| 3209 | 3279 | extra.data.return_type, |
| 3210 | 3280 | cc, |
| ... | ... | @@ -3214,7 +3284,6 @@ fn zirFunc( |
| 3214 | 3284 | false, |
| 3215 | 3285 | src_locs, |
| 3216 | 3286 | null, |
| 3217 | &.{}, | |
| 3218 | 3287 | ); |
| 3219 | 3288 | } |
| 3220 | 3289 | |
| ... | ... | @@ -3222,7 +3291,6 @@ fn funcCommon( |
| 3222 | 3291 | sema: *Sema, |
| 3223 | 3292 | block: *Scope.Block, |
| 3224 | 3293 | src_node_offset: i32, |
| 3225 | zir_param_types: []const Zir.Inst.Ref, | |
| 3226 | 3294 | body_inst: Zir.Inst.Index, |
| 3227 | 3295 | zir_return_type: Zir.Inst.Ref, |
| 3228 | 3296 | cc: std.builtin.CallingConvention, |
| ... | ... | @@ -3232,7 +3300,6 @@ fn funcCommon( |
| 3232 | 3300 | is_extern: bool, |
| 3233 | 3301 | src_locs: Zir.Inst.Func.SrcLocs, |
| 3234 | 3302 | opt_lib_name: ?[]const u8, |
| 3235 | comptime_bits: []const u32, | |
| 3236 | 3303 | ) CompileError!Air.Inst.Ref { |
| 3237 | 3304 | const src: LazySrcLoc = .{ .node_offset = src_node_offset }; |
| 3238 | 3305 | const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset }; |
| ... | ... | @@ -3245,7 +3312,7 @@ fn funcCommon( |
| 3245 | 3312 | |
| 3246 | 3313 | const fn_ty: Type = fn_ty: { |
| 3247 | 3314 | // Hot path for some common function types. |
| 3248 | if (zir_param_types.len == 0 and !var_args and align_val.tag() == .null_value and | |
| 3315 | if (sema.params.items.len == 0 and !var_args and align_val.tag() == .null_value and | |
| 3249 | 3316 | !inferred_error_set) |
| 3250 | 3317 | { |
| 3251 | 3318 | if (bare_return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) { |
| ... | ... | @@ -3266,22 +3333,21 @@ fn funcCommon( |
| 3266 | 3333 | } |
| 3267 | 3334 | |
| 3268 | 3335 | var any_are_comptime = false; |
| 3269 | const param_types = try sema.arena.alloc(Type, zir_param_types.len); | |
| 3270 | for (zir_param_types) |param_type, i| { | |
| 3271 | // TODO make a compile error from `resolveType` report the source location | |
| 3272 | // of the specific parameter. Will need to take a similar strategy as | |
| 3273 | // `resolveSwitchItemVal` to avoid resolving the source location unless | |
| 3274 | // we actually need to report an error. | |
| 3275 | const param_src = src; | |
| 3276 | param_types[i] = try sema.resolveType(block, param_src, param_type); | |
| 3277 | ||
| 3278 | any_are_comptime = any_are_comptime or blk: { | |
| 3279 | if (comptime_bits.len == 0) | |
| 3280 | break :blk false; | |
| 3281 | const bag = comptime_bits[i / 32]; | |
| 3282 | const is_comptime = @truncate(u1, bag >> @intCast(u5, i % 32)) != 0; | |
| 3283 | break :blk is_comptime; | |
| 3284 | }; | |
| 3336 | const param_types = try sema.arena.alloc(Type, sema.params.items.len); | |
| 3337 | const comptime_params = try sema.arena.alloc(bool, sema.params.items.len); | |
| 3338 | for (sema.params.items) |param, i| { | |
| 3339 | if (param.ty == .none) { | |
| 3340 | param_types[i] = Type.initTag(.noreturn); // indicates anytype | |
| 3341 | } else { | |
| 3342 | // TODO make a compile error from `resolveType` report the source location | |
| 3343 | // of the specific parameter. Will need to take a similar strategy as | |
| 3344 | // `resolveSwitchItemVal` to avoid resolving the source location unless | |
| 3345 | // we actually need to report an error. | |
| 3346 | const param_src = src; | |
| 3347 | param_types[i] = try sema.resolveType(block, param_src, param.ty); | |
| 3348 | } | |
| 3349 | comptime_params[i] = param.is_comptime; | |
| 3350 | any_are_comptime = any_are_comptime or param.is_comptime; | |
| 3285 | 3351 | } |
| 3286 | 3352 | |
| 3287 | 3353 | if (align_val.tag() != .null_value) { |
| ... | ... | @@ -3301,6 +3367,7 @@ fn funcCommon( |
| 3301 | 3367 | |
| 3302 | 3368 | break :fn_ty try Type.Tag.function.create(sema.arena, .{ |
| 3303 | 3369 | .param_types = param_types, |
| 3370 | .comptime_params = comptime_params.ptr, | |
| 3304 | 3371 | .return_type = return_type, |
| 3305 | 3372 | .cc = cc, |
| 3306 | 3373 | .is_var_args = var_args, |
| ... | ... | @@ -6545,16 +6612,6 @@ fn zirFuncExtended( |
| 6545 | 6612 | break :blk align_tv.val; |
| 6546 | 6613 | } else Value.initTag(.null_value); |
| 6547 | 6614 | |
| 6548 | const comptime_bits: []const u32 = if (!small.has_comptime_bits) &.{} else blk: { | |
| 6549 | const amt = (extra.data.param_types_len + 31) / 32; | |
| 6550 | const bit_bags = sema.code.extra[extra_index..][0..amt]; | |
| 6551 | extra_index += amt; | |
| 6552 | break :blk bit_bags; | |
| 6553 | }; | |
| 6554 | ||
| 6555 | const param_types = sema.code.refSlice(extra_index, extra.data.param_types_len); | |
| 6556 | extra_index += param_types.len; | |
| 6557 | ||
| 6558 | 6615 | var body_inst: Zir.Inst.Index = 0; |
| 6559 | 6616 | var src_locs: Zir.Inst.Func.SrcLocs = undefined; |
| 6560 | 6617 | if (extra.data.body_len != 0) { |
| ... | ... | @@ -6570,7 +6627,6 @@ fn zirFuncExtended( |
| 6570 | 6627 | return sema.funcCommon( |
| 6571 | 6628 | block, |
| 6572 | 6629 | extra.data.src_node, |
| 6573 | param_types, | |
| 6574 | 6630 | body_inst, |
| 6575 | 6631 | extra.data.return_type, |
| 6576 | 6632 | cc, |
| ... | ... | @@ -6580,7 +6636,6 @@ fn zirFuncExtended( |
| 6580 | 6636 | is_extern, |
| 6581 | 6637 | src_locs, |
| 6582 | 6638 | lib_name, |
| 6583 | comptime_bits, | |
| 6584 | 6639 | ); |
| 6585 | 6640 | } |
| 6586 | 6641 |
src/Zir.zig+65-56| ... | ... | @@ -173,11 +173,22 @@ pub const Inst = struct { |
| 173 | 173 | /// Twos complement wrapping integer addition. |
| 174 | 174 | /// Uses the `pl_node` union field. Payload is `Bin`. |
| 175 | 175 | addwrap, |
| 176 | /// Declares a parameter of the current function. Used for debug info and | |
| 177 | /// for checking shadowing against declarations in the current namespace. | |
| 178 | /// Uses the `str_tok` field. Token is the parameter name, string is the | |
| 179 | /// parameter name. | |
| 180 | arg, | |
| 176 | /// Declares a parameter of the current function. Used for: | |
| 177 | /// * debug info | |
| 178 | /// * checking shadowing against declarations in the current namespace | |
| 179 | /// * parameter type expressions referencing other parameters | |
| 180 | /// These occur in the block outside a function body (the same block as | |
| 181 | /// contains the func instruction). | |
| 182 | /// Uses the `pl_tok` field. Token is the parameter name, payload is a `Param`. | |
| 183 | param, | |
| 184 | /// Same as `param` except the parameter is marked comptime. | |
| 185 | param_comptime, | |
| 186 | /// Same as `param` except the parameter is marked anytype. | |
| 187 | /// Uses the `str_tok` field. Token is the parameter name. String is the parameter name. | |
| 188 | param_anytype, | |
| 189 | /// Same as `param` except the parameter is marked both comptime and anytype. | |
| 190 | /// Uses the `str_tok` field. Token is the parameter name. String is the parameter name. | |
| 191 | param_anytype_comptime, | |
| 181 | 192 | /// Array concatenation. `a ++ b` |
| 182 | 193 | /// Uses the `pl_node` union field. Payload is `Bin`. |
| 183 | 194 | array_cat, |
| ... | ... | @@ -971,7 +982,10 @@ pub const Inst = struct { |
| 971 | 982 | /// Function calls do not count. |
| 972 | 983 | pub fn isNoReturn(tag: Tag) bool { |
| 973 | 984 | return switch (tag) { |
| 974 | .arg, | |
| 985 | .param, | |
| 986 | .param_comptime, | |
| 987 | .param_anytype, | |
| 988 | .param_anytype_comptime, | |
| 975 | 989 | .add, |
| 976 | 990 | .addwrap, |
| 977 | 991 | .alloc, |
| ... | ... | @@ -1233,7 +1247,10 @@ pub const Inst = struct { |
| 1233 | 1247 | break :list std.enums.directEnumArray(Tag, Data.FieldEnum, 0, .{ |
| 1234 | 1248 | .add = .pl_node, |
| 1235 | 1249 | .addwrap = .pl_node, |
| 1236 | .arg = .str_tok, | |
| 1250 | .param = .pl_tok, | |
| 1251 | .param_comptime = .pl_tok, | |
| 1252 | .param_anytype = .str_tok, | |
| 1253 | .param_anytype_comptime = .str_tok, | |
| 1237 | 1254 | .array_cat = .pl_node, |
| 1238 | 1255 | .array_mul = .pl_node, |
| 1239 | 1256 | .array_type = .bin, |
| ... | ... | @@ -2047,6 +2064,17 @@ pub const Inst = struct { |
| 2047 | 2064 | return .{ .node_offset = self.src_node }; |
| 2048 | 2065 | } |
| 2049 | 2066 | }, |
| 2067 | pl_tok: struct { | |
| 2068 | /// Offset from Decl AST token index. | |
| 2069 | src_tok: ast.TokenIndex, | |
| 2070 | /// index into extra. | |
| 2071 | /// `Tag` determines what lives there. | |
| 2072 | payload_index: u32, | |
| 2073 | ||
| 2074 | pub fn src(self: @This()) LazySrcLoc { | |
| 2075 | return .{ .token_offset = self.src_tok }; | |
| 2076 | } | |
| 2077 | }, | |
| 2050 | 2078 | bin: Bin, |
| 2051 | 2079 | /// For strings which may contain null bytes. |
| 2052 | 2080 | str: struct { |
| ... | ... | @@ -2170,6 +2198,7 @@ pub const Inst = struct { |
| 2170 | 2198 | un_node, |
| 2171 | 2199 | un_tok, |
| 2172 | 2200 | pl_node, |
| 2201 | pl_tok, | |
| 2173 | 2202 | bin, |
| 2174 | 2203 | str, |
| 2175 | 2204 | str_tok, |
| ... | ... | @@ -2226,17 +2255,11 @@ pub const Inst = struct { |
| 2226 | 2255 | /// 0. lib_name: u32, // null terminated string index, if has_lib_name is set |
| 2227 | 2256 | /// 1. cc: Ref, // if has_cc is set |
| 2228 | 2257 | /// 2. align: Ref, // if has_align is set |
| 2229 | /// 3. comptime_bits: u32 // for every 32 parameters, if has_comptime_bits is set | |
| 2230 | /// - sets of 1 bit: | |
| 2231 | /// 0bX: whether corresponding parameter is comptime | |
| 2232 | /// 4. param_type: Ref // for each param_types_len | |
| 2233 | /// - `none` indicates that the param type is `anytype`. | |
| 2234 | /// 5. body: Index // for each body_len | |
| 2235 | /// 6. src_locs: Func.SrcLocs // if body_len != 0 | |
| 2258 | /// 3. body: Index // for each body_len | |
| 2259 | /// 4. src_locs: Func.SrcLocs // if body_len != 0 | |
| 2236 | 2260 | pub const ExtendedFunc = struct { |
| 2237 | 2261 | src_node: i32, |
| 2238 | 2262 | return_type: Ref, |
| 2239 | param_types_len: u32, | |
| 2240 | 2263 | body_len: u32, |
| 2241 | 2264 | |
| 2242 | 2265 | pub const Small = packed struct { |
| ... | ... | @@ -2247,8 +2270,7 @@ pub const Inst = struct { |
| 2247 | 2270 | has_align: bool, |
| 2248 | 2271 | is_test: bool, |
| 2249 | 2272 | is_extern: bool, |
| 2250 | has_comptime_bits: bool, | |
| 2251 | _: u8 = undefined, | |
| 2273 | _: u9 = undefined, | |
| 2252 | 2274 | }; |
| 2253 | 2275 | }; |
| 2254 | 2276 | |
| ... | ... | @@ -2271,13 +2293,10 @@ pub const Inst = struct { |
| 2271 | 2293 | }; |
| 2272 | 2294 | |
| 2273 | 2295 | /// Trailing: |
| 2274 | /// 0. param_type: Ref // for each param_types_len | |
| 2275 | /// - `none` indicates that the param type is `anytype`. | |
| 2276 | /// 1. body: Index // for each body_len | |
| 2277 | /// 2. src_locs: SrcLocs // if body_len != 0 | |
| 2296 | /// 0. body: Index // for each body_len | |
| 2297 | /// 1. src_locs: SrcLocs // if body_len != 0 | |
| 2278 | 2298 | pub const Func = struct { |
| 2279 | 2299 | return_type: Ref, |
| 2280 | param_types_len: u32, | |
| 2281 | 2300 | body_len: u32, |
| 2282 | 2301 | |
| 2283 | 2302 | pub const SrcLocs = struct { |
| ... | ... | @@ -2764,6 +2783,12 @@ pub const Inst = struct { |
| 2764 | 2783 | args: Ref, |
| 2765 | 2784 | }; |
| 2766 | 2785 | |
| 2786 | pub const Param = struct { | |
| 2787 | /// Null-terminated string index. | |
| 2788 | name: u32, | |
| 2789 | ty: Ref, | |
| 2790 | }; | |
| 2791 | ||
| 2767 | 2792 | /// Trailing: |
| 2768 | 2793 | /// 0. type_inst: Ref, // if small 0b000X is set |
| 2769 | 2794 | /// 1. align_inst: Ref, // if small 0b00X0 is set |
| ... | ... | @@ -3108,11 +3133,14 @@ const Writer = struct { |
| 3108 | 3133 | .decl_ref, |
| 3109 | 3134 | .decl_val, |
| 3110 | 3135 | .import, |
| 3111 | .arg, | |
| 3112 | 3136 | .ret_err_value, |
| 3113 | 3137 | .ret_err_value_code, |
| 3138 | .param_anytype, | |
| 3139 | .param_anytype_comptime, | |
| 3114 | 3140 | => try self.writeStrTok(stream, inst), |
| 3115 | 3141 | |
| 3142 | .param, .param_comptime => try self.writeParam(stream, inst), | |
| 3143 | ||
| 3116 | 3144 | .func => try self.writeFunc(stream, inst, false), |
| 3117 | 3145 | .func_inferred => try self.writeFunc(stream, inst, true), |
| 3118 | 3146 | |
| ... | ... | @@ -3314,6 +3342,17 @@ const Writer = struct { |
| 3314 | 3342 | try self.writeSrc(stream, inst_data.src()); |
| 3315 | 3343 | } |
| 3316 | 3344 | |
| 3345 | fn writeParam(self: *Writer, stream: anytype, inst: Inst.Index) !void { | |
| 3346 | const inst_data = self.code.instructions.items(.data)[inst].pl_tok; | |
| 3347 | const extra = self.code.extraData(Inst.Param, inst_data.payload_index).data; | |
| 3348 | try stream.print("\"{}\", ", .{ | |
| 3349 | std.zig.fmtEscapes(self.code.nullTerminatedString(extra.name)), | |
| 3350 | }); | |
| 3351 | try self.writeInstRef(stream, extra.ty); | |
| 3352 | try stream.writeAll(") "); | |
| 3353 | try self.writeSrc(stream, inst_data.src()); | |
| 3354 | } | |
| 3355 | ||
| 3317 | 3356 | fn writePlNodeBin(self: *Writer, stream: anytype, inst: Inst.Index) !void { |
| 3318 | 3357 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; |
| 3319 | 3358 | const extra = self.code.extraData(Inst.Bin, inst_data.payload_index).data; |
| ... | ... | @@ -4277,16 +4316,14 @@ const Writer = struct { |
| 4277 | 4316 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; |
| 4278 | 4317 | const src = inst_data.src(); |
| 4279 | 4318 | const extra = self.code.extraData(Inst.Func, inst_data.payload_index); |
| 4280 | const param_types = self.code.refSlice(extra.end, extra.data.param_types_len); | |
| 4281 | const body = self.code.extra[extra.end + param_types.len ..][0..extra.data.body_len]; | |
| 4319 | const body = self.code.extra[extra.end..][0..extra.data.body_len]; | |
| 4282 | 4320 | var src_locs: Zir.Inst.Func.SrcLocs = undefined; |
| 4283 | 4321 | if (body.len != 0) { |
| 4284 | const extra_index = extra.end + param_types.len + body.len; | |
| 4322 | const extra_index = extra.end + body.len; | |
| 4285 | 4323 | src_locs = self.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data; |
| 4286 | 4324 | } |
| 4287 | 4325 | return self.writeFuncCommon( |
| 4288 | 4326 | stream, |
| 4289 | param_types, | |
| 4290 | 4327 | extra.data.return_type, |
| 4291 | 4328 | inferred_error_set, |
| 4292 | 4329 | false, |
| ... | ... | @@ -4296,7 +4333,6 @@ const Writer = struct { |
| 4296 | 4333 | body, |
| 4297 | 4334 | src, |
| 4298 | 4335 | src_locs, |
| 4299 | &.{}, | |
| 4300 | 4336 | ); |
| 4301 | 4337 | } |
| 4302 | 4338 | |
| ... | ... | @@ -4323,16 +4359,6 @@ const Writer = struct { |
| 4323 | 4359 | break :blk align_inst; |
| 4324 | 4360 | }; |
| 4325 | 4361 | |
| 4326 | const comptime_bits: []const u32 = if (!small.has_comptime_bits) &.{} else blk: { | |
| 4327 | const amt = (extra.data.param_types_len + 31) / 32; | |
| 4328 | const bit_bags = self.code.extra[extra_index..][0..amt]; | |
| 4329 | extra_index += amt; | |
| 4330 | break :blk bit_bags; | |
| 4331 | }; | |
| 4332 | ||
| 4333 | const param_types = self.code.refSlice(extra_index, extra.data.param_types_len); | |
| 4334 | extra_index += param_types.len; | |
| 4335 | ||
| 4336 | 4362 | const body = self.code.extra[extra_index..][0..extra.data.body_len]; |
| 4337 | 4363 | extra_index += body.len; |
| 4338 | 4364 | |
| ... | ... | @@ -4342,7 +4368,6 @@ const Writer = struct { |
| 4342 | 4368 | } |
| 4343 | 4369 | return self.writeFuncCommon( |
| 4344 | 4370 | stream, |
| 4345 | param_types, | |
| 4346 | 4371 | extra.data.return_type, |
| 4347 | 4372 | small.is_inferred_error, |
| 4348 | 4373 | small.is_var_args, |
| ... | ... | @@ -4352,7 +4377,6 @@ const Writer = struct { |
| 4352 | 4377 | body, |
| 4353 | 4378 | src, |
| 4354 | 4379 | src_locs, |
| 4355 | comptime_bits, | |
| 4356 | 4380 | ); |
| 4357 | 4381 | } |
| 4358 | 4382 | |
| ... | ... | @@ -4426,7 +4450,6 @@ const Writer = struct { |
| 4426 | 4450 | fn writeFuncCommon( |
| 4427 | 4451 | self: *Writer, |
| 4428 | 4452 | stream: anytype, |
| 4429 | param_types: []const Inst.Ref, | |
| 4430 | 4453 | ret_ty: Inst.Ref, |
| 4431 | 4454 | inferred_error_set: bool, |
| 4432 | 4455 | var_args: bool, |
| ... | ... | @@ -4436,19 +4459,7 @@ const Writer = struct { |
| 4436 | 4459 | body: []const Inst.Index, |
| 4437 | 4460 | src: LazySrcLoc, |
| 4438 | 4461 | src_locs: Zir.Inst.Func.SrcLocs, |
| 4439 | comptime_bits: []const u32, | |
| 4440 | 4462 | ) !void { |
| 4441 | try stream.writeAll("["); | |
| 4442 | for (param_types) |param_type, i| { | |
| 4443 | if (i != 0) try stream.writeAll(", "); | |
| 4444 | if (comptime_bits.len != 0) { | |
| 4445 | const bag = comptime_bits[i / 32]; | |
| 4446 | const is_comptime = @truncate(u1, bag >> @intCast(u5, i % 32)) != 0; | |
| 4447 | try self.writeFlag(stream, "comptime ", is_comptime); | |
| 4448 | } | |
| 4449 | try self.writeInstRef(stream, param_type); | |
| 4450 | } | |
| 4451 | try stream.writeAll("], "); | |
| 4452 | 4463 | try self.writeInstRef(stream, ret_ty); |
| 4453 | 4464 | try self.writeOptionalInstRef(stream, ", cc=", cc); |
| 4454 | 4465 | try self.writeOptionalInstRef(stream, ", align=", align_inst); |
| ... | ... | @@ -4714,8 +4725,7 @@ fn findDeclsInner( |
| 4714 | 4725 | |
| 4715 | 4726 | const inst_data = datas[inst].pl_node; |
| 4716 | 4727 | const extra = zir.extraData(Inst.Func, inst_data.payload_index); |
| 4717 | const param_types_len = extra.data.param_types_len; | |
| 4718 | const body = zir.extra[extra.end + param_types_len ..][0..extra.data.body_len]; | |
| 4728 | const body = zir.extra[extra.end..][0..extra.data.body_len]; | |
| 4719 | 4729 | return zir.findDeclsBody(list, body); |
| 4720 | 4730 | }, |
| 4721 | 4731 | .extended => { |
| ... | ... | @@ -4730,7 +4740,6 @@ fn findDeclsInner( |
| 4730 | 4740 | extra_index += @boolToInt(small.has_lib_name); |
| 4731 | 4741 | extra_index += @boolToInt(small.has_cc); |
| 4732 | 4742 | extra_index += @boolToInt(small.has_align); |
| 4733 | extra_index += extra.data.param_types_len; | |
| 4734 | 4743 | const body = zir.extra[extra_index..][0..extra.data.body_len]; |
| 4735 | 4744 | return zir.findDeclsBody(list, body); |
| 4736 | 4745 | }, |
src/type.zig+50-10| ... | ... | @@ -759,12 +759,15 @@ pub const Type = extern union { |
| 759 | 759 | for (payload.param_types) |param_type, i| { |
| 760 | 760 | param_types[i] = try param_type.copy(allocator); |
| 761 | 761 | } |
| 762 | const other_comptime_params = payload.comptime_params[0..payload.param_types.len]; | |
| 763 | const comptime_params = try allocator.dupe(bool, other_comptime_params); | |
| 762 | 764 | return Tag.function.create(allocator, .{ |
| 763 | 765 | .return_type = try payload.return_type.copy(allocator), |
| 764 | 766 | .param_types = param_types, |
| 765 | 767 | .cc = payload.cc, |
| 766 | 768 | .is_var_args = payload.is_var_args, |
| 767 | 769 | .is_generic = payload.is_generic, |
| 770 | .comptime_params = comptime_params.ptr, | |
| 768 | 771 | }); |
| 769 | 772 | }, |
| 770 | 773 | .pointer => { |
| ... | ... | @@ -2408,14 +2411,41 @@ pub const Type = extern union { |
| 2408 | 2411 | }; |
| 2409 | 2412 | } |
| 2410 | 2413 | |
| 2411 | /// Asserts the type is a function. | |
| 2412 | pub fn fnIsGeneric(self: Type) bool { | |
| 2413 | return switch (self.tag()) { | |
| 2414 | .fn_noreturn_no_args => false, | |
| 2415 | .fn_void_no_args => false, | |
| 2416 | .fn_naked_noreturn_no_args => false, | |
| 2417 | .fn_ccc_void_no_args => false, | |
| 2418 | .function => self.castTag(.function).?.data.is_generic, | |
| 2414 | pub fn fnInfo(ty: Type) Payload.Function.Data { | |
| 2415 | return switch (ty.tag()) { | |
| 2416 | .fn_noreturn_no_args => .{ | |
| 2417 | .param_types = &.{}, | |
| 2418 | .comptime_params = undefined, | |
| 2419 | .return_type = initTag(.noreturn), | |
| 2420 | .cc = .Unspecified, | |
| 2421 | .is_var_args = false, | |
| 2422 | .is_generic = false, | |
| 2423 | }, | |
| 2424 | .fn_void_no_args => .{ | |
| 2425 | .param_types = &.{}, | |
| 2426 | .comptime_params = undefined, | |
| 2427 | .return_type = initTag(.void), | |
| 2428 | .cc = .Unspecified, | |
| 2429 | .is_var_args = false, | |
| 2430 | .is_generic = false, | |
| 2431 | }, | |
| 2432 | .fn_naked_noreturn_no_args => .{ | |
| 2433 | .param_types = &.{}, | |
| 2434 | .comptime_params = undefined, | |
| 2435 | .return_type = initTag(.noreturn), | |
| 2436 | .cc = .Naked, | |
| 2437 | .is_var_args = false, | |
| 2438 | .is_generic = false, | |
| 2439 | }, | |
| 2440 | .fn_ccc_void_no_args => .{ | |
| 2441 | .param_types = &.{}, | |
| 2442 | .comptime_params = undefined, | |
| 2443 | .return_type = initTag(.void), | |
| 2444 | .cc = .C, | |
| 2445 | .is_var_args = false, | |
| 2446 | .is_generic = false, | |
| 2447 | }, | |
| 2448 | .function => ty.castTag(.function).?.data, | |
| 2419 | 2449 | |
| 2420 | 2450 | else => unreachable, |
| 2421 | 2451 | }; |
| ... | ... | @@ -3223,13 +3253,23 @@ pub const Type = extern union { |
| 3223 | 3253 | pub const base_tag = Tag.function; |
| 3224 | 3254 | |
| 3225 | 3255 | base: Payload = Payload{ .tag = base_tag }, |
| 3226 | data: struct { | |
| 3256 | data: Data, | |
| 3257 | ||
| 3258 | // TODO look into optimizing this memory to take fewer bytes | |
| 3259 | const Data = struct { | |
| 3227 | 3260 | param_types: []Type, |
| 3261 | comptime_params: [*]bool, | |
| 3228 | 3262 | return_type: Type, |
| 3229 | 3263 | cc: std.builtin.CallingConvention, |
| 3230 | 3264 | is_var_args: bool, |
| 3231 | 3265 | is_generic: bool, |
| 3232 | }, | |
| 3266 | ||
| 3267 | fn paramIsComptime(self: @This(), i: usize) bool { | |
| 3268 | if (!self.is_generic) return false; | |
| 3269 | assert(i < self.param_types.len); | |
| 3270 | return self.comptime_params[i]; | |
| 3271 | } | |
| 3272 | }; | |
| 3233 | 3273 | }; |
| 3234 | 3274 | |
| 3235 | 3275 | pub const ErrorSet = struct { |