diff options
| -rw-r--r-- | src/AstGen.zig | 66 | ||||
| -rw-r--r-- | src/Sema.zig | 29 | ||||
| -rw-r--r-- | src/Zir.zig | 28 | ||||
| -rw-r--r-- | src/type.zig | 15 |
4 files changed, 132 insertions, 6 deletions
diff --git a/src/AstGen.zig b/src/AstGen.zig index b5e5d60b2c..20480ab33b 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -1064,11 +1064,28 @@ fn fnProtoExpr( const param_types = try gpa.alloc(Zir.Inst.Ref, param_count); defer gpa.free(param_types); + const bits_per_param = 1; + const params_per_u32 = 32 / bits_per_param; + // We only need this if there are greater than params_per_u32 fields. + var bit_bag = ArrayListUnmanaged(u32){}; + defer bit_bag.deinit(gpa); + var cur_bit_bag: u32 = 0; var is_var_args = false; { var param_type_i: usize = 0; var it = fn_proto.iterate(tree.*); while (it.next()) |param| : (param_type_i += 1) { + if (param_type_i % params_per_u32 == 0 and param_type_i != 0) { + try bit_bag.append(gpa, cur_bit_bag); + cur_bit_bag = 0; + } + const is_comptime = if (param.comptime_noalias) |token| + token_tags[token] == .keyword_comptime + else + false; + cur_bit_bag = (cur_bit_bag >> bits_per_param) | + (@as(u32, @boolToInt(is_comptime)) << 31); + if (param.anytype_ellipsis3) |token| { switch (token_tags[token]) { .keyword_anytype => { @@ -1088,6 +1105,11 @@ fn fnProtoExpr( try expr(gz, scope, .{ .ty = .type_type }, param_type_node); } assert(param_type_i == param_count); + + const empty_slot_count = params_per_u32 - (param_type_i % params_per_u32); + if (empty_slot_count < params_per_u32) { + cur_bit_bag >>= @intCast(u5, empty_slot_count * bits_per_param); + } } const align_inst: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: { @@ -1131,6 +1153,8 @@ fn fnProtoExpr( .is_inferred_error = false, .is_test = false, .is_extern = false, + .cur_bit_bag = cur_bit_bag, + .bit_bag = bit_bag.items, }); return rvalue(gz, rl, result, fn_proto.ast.proto_node); } @@ -2916,11 +2940,28 @@ fn fnDecl( const param_types = try gpa.alloc(Zir.Inst.Ref, param_count); defer gpa.free(param_types); + const bits_per_param = 1; + const params_per_u32 = 32 / bits_per_param; + // We only need this if there are greater than params_per_u32 fields. + var bit_bag = ArrayListUnmanaged(u32){}; + defer bit_bag.deinit(gpa); + var cur_bit_bag: u32 = 0; var is_var_args = false; { var param_type_i: usize = 0; var it = fn_proto.iterate(tree.*); while (it.next()) |param| : (param_type_i += 1) { + if (param_type_i % params_per_u32 == 0 and param_type_i != 0) { + try bit_bag.append(gpa, cur_bit_bag); + cur_bit_bag = 0; + } + const is_comptime = if (param.comptime_noalias) |token| + token_tags[token] == .keyword_comptime + else + false; + cur_bit_bag = (cur_bit_bag >> bits_per_param) | + (@as(u32, @boolToInt(is_comptime)) << 31); + if (param.anytype_ellipsis3) |token| { switch (token_tags[token]) { .keyword_anytype => { @@ -2940,6 +2981,11 @@ fn fnDecl( try expr(&decl_gz, &decl_gz.base, .{ .ty = .type_type }, param_type_node); } assert(param_type_i == param_count); + + const empty_slot_count = params_per_u32 - (param_type_i % params_per_u32); + if (empty_slot_count < params_per_u32) { + cur_bit_bag >>= @intCast(u5, empty_slot_count * bits_per_param); + } } const lib_name: u32 = if (fn_proto.lib_name) |lib_name_token| blk: { @@ -3001,6 +3047,8 @@ fn fnDecl( .is_inferred_error = false, .is_test = false, .is_extern = true, + .cur_bit_bag = cur_bit_bag, + .bit_bag = bit_bag.items, }); } else func: { if (is_var_args) { @@ -3094,6 +3142,8 @@ fn fnDecl( .is_inferred_error = is_inferred_error, .is_test = false, .is_extern = false, + .cur_bit_bag = cur_bit_bag, + .bit_bag = bit_bag.items, }); }; @@ -3439,6 +3489,8 @@ fn testDecl( .is_inferred_error = true, .is_test = true, .is_extern = false, + .cur_bit_bag = 0, + .bit_bag = &.{}, }); _ = try decl_block.addBreak(.break_inline, block_inst, func_inst); @@ -9135,6 +9187,8 @@ const GenZir = struct { is_inferred_error: bool, is_test: bool, is_extern: bool, + cur_bit_bag: u32, + bit_bag: []const u32, }) !Zir.Inst.Ref { assert(args.src_node != 0); assert(args.ret_ty != .none); @@ -9172,13 +9226,18 @@ const GenZir = struct { src_locs = &src_locs_buffer; } + const any_are_comptime = args.cur_bit_bag != 0 or for (args.bit_bag) |x| { + if (x != 0) break true; + } else false; + if (args.cc != .none or args.lib_name != 0 or args.is_var_args or args.is_test or args.align_inst != .none or - args.is_extern) + args.is_extern or any_are_comptime) { try astgen.extra.ensureUnusedCapacity( gpa, @typeInfo(Zir.Inst.ExtendedFunc).Struct.fields.len + + @boolToInt(any_are_comptime) + args.bit_bag.len + args.param_types.len + args.body.len + src_locs.len + @boolToInt(args.lib_name != 0) + @boolToInt(args.align_inst != .none) + @@ -9199,6 +9258,10 @@ const GenZir = struct { if (args.align_inst != .none) { astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst)); } + if (any_are_comptime) { + astgen.extra.appendSliceAssumeCapacity(args.bit_bag); // Likely empty. + astgen.extra.appendAssumeCapacity(args.cur_bit_bag); + } astgen.appendRefsAssumeCapacity(args.param_types); astgen.extra.appendSliceAssumeCapacity(args.body); astgen.extra.appendSliceAssumeCapacity(src_locs); @@ -9216,6 +9279,7 @@ const GenZir = struct { .has_align = args.align_inst != .none, .is_test = args.is_test, .is_extern = args.is_extern, + .has_comptime_bits = any_are_comptime, }), .operand = payload_index, } }, diff --git a/src/Sema.zig b/src/Sema.zig index 6b281f8569..753ef8fb9c 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -104,6 +104,9 @@ pub fn analyzeFnBody( extra_index += @boolToInt(small.has_lib_name); extra_index += @boolToInt(small.has_cc); extra_index += @boolToInt(small.has_align); + if (small.has_comptime_bits) { + extra_index += (extra.data.param_types_len + 31) / 32; + } extra_index += extra.data.param_types_len; const body = sema.code.extra[extra_index..][0..extra.data.body_len]; break :blk body; @@ -2533,6 +2536,9 @@ fn analyzeCall( break :res result; } else res: { + if (func_ty.fnIsGeneric()) { + return sema.mod.fail(&block.base, func_src, "TODO implement generic fn call", .{}); + } try sema.requireRuntimeBlock(block, call_src); try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len + args.len); @@ -3208,6 +3214,7 @@ fn zirFunc( false, src_locs, null, + &.{}, ); } @@ -3225,6 +3232,7 @@ fn funcCommon( is_extern: bool, src_locs: Zir.Inst.Func.SrcLocs, opt_lib_name: ?[]const u8, + comptime_bits: []const u32, ) CompileError!Air.Inst.Ref { const src: LazySrcLoc = .{ .node_offset = src_node_offset }; const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset }; @@ -3257,13 +3265,23 @@ fn funcCommon( } } + var any_are_comptime = false; const param_types = try sema.arena.alloc(Type, zir_param_types.len); for (zir_param_types) |param_type, i| { // TODO make a compile error from `resolveType` report the source location // of the specific parameter. Will need to take a similar strategy as // `resolveSwitchItemVal` to avoid resolving the source location unless // we actually need to report an error. - param_types[i] = try sema.resolveType(block, src, param_type); + const param_src = src; + param_types[i] = try sema.resolveType(block, param_src, param_type); + + any_are_comptime = any_are_comptime or blk: { + if (comptime_bits.len == 0) + break :blk false; + const bag = comptime_bits[i / 32]; + const is_comptime = @truncate(u1, bag >> @intCast(u5, i % 32)) != 0; + break :blk is_comptime; + }; } if (align_val.tag() != .null_value) { @@ -3286,6 +3304,7 @@ fn funcCommon( .return_type = return_type, .cc = cc, .is_var_args = var_args, + .is_generic = any_are_comptime, }); }; @@ -6526,6 +6545,13 @@ fn zirFuncExtended( break :blk align_tv.val; } else Value.initTag(.null_value); + const comptime_bits: []const u32 = if (!small.has_comptime_bits) &.{} else blk: { + const amt = (extra.data.param_types_len + 31) / 32; + const bit_bags = sema.code.extra[extra_index..][0..amt]; + extra_index += amt; + break :blk bit_bags; + }; + const param_types = sema.code.refSlice(extra_index, extra.data.param_types_len); extra_index += param_types.len; @@ -6554,6 +6580,7 @@ fn zirFuncExtended( is_extern, src_locs, lib_name, + comptime_bits, ); } diff --git a/src/Zir.zig b/src/Zir.zig index a8320b65d4..109ae3b186 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -2226,9 +2226,13 @@ pub const Inst = struct { /// 0. lib_name: u32, // null terminated string index, if has_lib_name is set /// 1. cc: Ref, // if has_cc is set /// 2. align: Ref, // if has_align is set - /// 3. param_type: Ref // for each param_types_len - /// 4. body: Index // for each body_len - /// 5. src_locs: Func.SrcLocs // if body_len != 0 + /// 3. comptime_bits: u32 // for every 32 parameters, if has_comptime_bits is set + /// - sets of 1 bit: + /// 0bX: whether corresponding parameter is comptime + /// 4. param_type: Ref // for each param_types_len + /// - `none` indicates that the param type is `anytype`. + /// 5. body: Index // for each body_len + /// 6. src_locs: Func.SrcLocs // if body_len != 0 pub const ExtendedFunc = struct { src_node: i32, return_type: Ref, @@ -2243,7 +2247,8 @@ pub const Inst = struct { has_align: bool, is_test: bool, is_extern: bool, - _: u9 = undefined, + has_comptime_bits: bool, + _: u8 = undefined, }; }; @@ -4291,6 +4296,7 @@ const Writer = struct { body, src, src_locs, + &.{}, ); } @@ -4317,6 +4323,13 @@ const Writer = struct { break :blk align_inst; }; + const comptime_bits: []const u32 = if (!small.has_comptime_bits) &.{} else blk: { + const amt = (extra.data.param_types_len + 31) / 32; + const bit_bags = self.code.extra[extra_index..][0..amt]; + extra_index += amt; + break :blk bit_bags; + }; + const param_types = self.code.refSlice(extra_index, extra.data.param_types_len); extra_index += param_types.len; @@ -4339,6 +4352,7 @@ const Writer = struct { body, src, src_locs, + comptime_bits, ); } @@ -4422,10 +4436,16 @@ const Writer = struct { body: []const Inst.Index, src: LazySrcLoc, src_locs: Zir.Inst.Func.SrcLocs, + comptime_bits: []const u32, ) !void { try stream.writeAll("["); for (param_types) |param_type, i| { if (i != 0) try stream.writeAll(", "); + if (comptime_bits.len != 0) { + const bag = comptime_bits[i / 32]; + const is_comptime = @truncate(u1, bag >> @intCast(u5, i % 32)) != 0; + try self.writeFlag(stream, "comptime ", is_comptime); + } try self.writeInstRef(stream, param_type); } try stream.writeAll("], "); diff --git a/src/type.zig b/src/type.zig index 82c28ef398..a8c3d77bbb 100644 --- a/src/type.zig +++ b/src/type.zig @@ -764,6 +764,7 @@ pub const Type = extern union { .param_types = param_types, .cc = payload.cc, .is_var_args = payload.is_var_args, + .is_generic = payload.is_generic, }); }, .pointer => { @@ -2407,6 +2408,19 @@ pub const Type = extern union { }; } + /// Asserts the type is a function. + pub fn fnIsGeneric(self: Type) bool { + return switch (self.tag()) { + .fn_noreturn_no_args => false, + .fn_void_no_args => false, + .fn_naked_noreturn_no_args => false, + .fn_ccc_void_no_args => false, + .function => self.castTag(.function).?.data.is_generic, + + else => unreachable, + }; + } + pub fn isNumeric(self: Type) bool { return switch (self.tag()) { .f16, @@ -3214,6 +3228,7 @@ pub const Type = extern union { return_type: Type, cc: std.builtin.CallingConvention, is_var_args: bool, + is_generic: bool, }, }; |
