authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-04-14 06:10:41-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-04-24 11:08:01-04:00
log20e7929f6db4404ee343d993aa3d483e9a7ac71f
tree0a039f8fce654f9de05b100c3d37d445d73ce0a7
parent453df509b889c9b855cd0eeccc53a0363092403f

Sema: get restricted function pointers working


3 files changed, 51 insertions(+), 39 deletions(-)

src/InternPool.zig+23-17
...@@ -11913,23 +11913,29 @@ pub fn aggregateTypeLenIncludingSentinel(ip: *const InternPool, ty: Index) u64 {...@@ -11913,23 +11913,29 @@ pub fn aggregateTypeLenIncludingSentinel(ip: *const InternPool, ty: Index) u64 {
11913}11913}
1191411914
11915pub fn funcTypeReturnType(ip: *const InternPool, ty: Index) Index {11915pub fn funcTypeReturnType(ip: *const InternPool, ty: Index) Index {
11916 const unwrapped_ty = ty.unwrap(ip);11916 var ty_item, var ty_extra = unwrapped: {
11917 const ty_extra = unwrapped_ty.getExtra(ip);11917 const unwrapped_ty = ty.unwrap(ip);
11918 const ty_item = unwrapped_ty.getItem(ip);11918 break :unwrapped .{ unwrapped_ty.getItem(ip), unwrapped_ty.getExtra(ip) };
11919 const child_extra, const child_item = switch (ty_item.tag) {11919 };
11920 .type_pointer => child: {11920 if (ty_item.tag == .type_restricted) {
11921 const child_index: Index = @enumFromInt(ty_extra.view().items(.@"0")[11921 const unrestricted_ty: Index = @enumFromInt(ty_extra.view().items(.@"0")[
11922 ty_item.data + std.meta.fieldIndex(Tag.TypePointer, "child").?11922 ty_item.data + std.meta.fieldIndex(Tag.TypeRestricted, "unrestricted_type").?
11923 ]);11923 ]);
11924 const unwrapped_child = child_index.unwrap(ip);11924 const unwrapped_ty = unrestricted_ty.unwrap(ip);
11925 break :child .{ unwrapped_child.getExtra(ip), unwrapped_child.getItem(ip) };11925 ty_item = unwrapped_ty.getItem(ip);
11926 },11926 ty_extra = unwrapped_ty.getExtra(ip);
11927 .type_function => .{ ty_extra, ty_item },11927 }
11928 else => unreachable,11928 if (ty_item.tag == .type_pointer) {
11929 };11929 const child_ty: Index = @enumFromInt(ty_extra.view().items(.@"0")[
11930 assert(child_item.tag == .type_function);11930 ty_item.data + std.meta.fieldIndex(Tag.TypePointer, "child").?
11931 return @enumFromInt(child_extra.view().items(.@"0")[11931 ]);
11932 child_item.data + std.meta.fieldIndex(Tag.TypeFunction, "return_type").?11932 const unwrapped_ty = child_ty.unwrap(ip);
11933 ty_item = unwrapped_ty.getItem(ip);
11934 ty_extra = unwrapped_ty.getExtra(ip);
11935 }
11936 assert(ty_item.tag == .type_function);
11937 return @enumFromInt(ty_extra.view().items(.@"0")[
11938 ty_item.data + std.meta.fieldIndex(Tag.TypeFunction, "return_type").?
11933 ]);11939 ]);
11934}11940}
1193511941
src/Sema.zig+27-21
...@@ -6274,16 +6274,17 @@ fn checkCallArgumentCount(...@@ -6274,16 +6274,17 @@ fn checkCallArgumentCount(
6274 const pt = sema.pt;6274 const pt = sema.pt;
6275 const zcu = pt.zcu;6275 const zcu = pt.zcu;
6276 const func_ty: Type = func_ty: {6276 const func_ty: Type = func_ty: {
6277 switch (callee_ty.zigTypeTag(zcu)) {6277 const unrestricted_callee_ty = callee_ty.unrestrictedType(zcu) orelse callee_ty;
6278 .@"fn" => break :func_ty callee_ty,6278 switch (unrestricted_callee_ty.zigTypeTag(zcu)) {
6279 .@"fn" => break :func_ty unrestricted_callee_ty,
6279 .pointer => {6280 .pointer => {
6280 const ptr_info = callee_ty.ptrInfo(zcu);6281 const ptr_info = unrestricted_callee_ty.ptrInfo(zcu);
6281 if (ptr_info.flags.size == .one and Type.fromInterned(ptr_info.child).zigTypeTag(zcu) == .@"fn") {6282 if (ptr_info.flags.size == .one and Type.fromInterned(ptr_info.child).zigTypeTag(zcu) == .@"fn") {
6282 break :func_ty .fromInterned(ptr_info.child);6283 break :func_ty .fromInterned(ptr_info.child);
6283 }6284 }
6284 },6285 },
6285 .optional => {6286 .optional => {
6286 const opt_child = callee_ty.optionalChild(zcu);6287 const opt_child = unrestricted_callee_ty.optionalChild(zcu);
6287 if (opt_child.zigTypeTag(zcu) == .@"fn" or (opt_child.isSinglePointer(zcu) and6288 if (opt_child.zigTypeTag(zcu) == .@"fn" or (opt_child.isSinglePointer(zcu) and
6288 opt_child.childType(zcu).zigTypeTag(zcu) == .@"fn"))6289 opt_child.childType(zcu).zigTypeTag(zcu) == .@"fn"))
6289 {6290 {
...@@ -7012,13 +7013,21 @@ fn analyzeCall(...@@ -7012,13 +7013,21 @@ fn analyzeCall(
7012 break :func .{ Air.internedToRef(func_instance), runtime_args.items };7013 break :func .{ Air.internedToRef(func_instance), runtime_args.items };
7013 };7014 };
70147015
7015 ref_func: {7016 const unrestricted_runtime_func: Air.Inst.Ref = if (sema.resolveValue(runtime_func)) |runtime_func_val| unrestricted_runtime_func: {
7016 const runtime_func_val = sema.resolveValue(runtime_func) orelse break :ref_func;7017 const unrestricted_runtime_func_val = switch (ip.indexToKey(runtime_func_val.toIntern())) {
7017 if (!ip.isFuncBody(runtime_func_val.toIntern())) break :ref_func;7018 else => runtime_func_val.toIntern(),
7018 const orig_fn_index = ip.unwrapCoercedFunc(runtime_func_val.toIntern());7019 .restricted_value => |restricted_value| restricted_value.unrestricted_value,
7019 try sema.addReferenceEntry(block, call_src, .wrap(.{ .func = orig_fn_index }));7020 };
7020 try zcu.ensureFuncBodyAnalysisQueued(orig_fn_index);7021 if (ip.isFuncBody(unrestricted_runtime_func_val)) {
7021 }7022 const orig_fn_index = ip.unwrapCoercedFunc(unrestricted_runtime_func_val);
7023 try sema.addReferenceEntry(block, call_src, .wrap(.{ .func = orig_fn_index }));
7024 try zcu.ensureFuncBodyAnalysisQueued(orig_fn_index);
7025 }
7026 break :unrestricted_runtime_func .fromIntern(unrestricted_runtime_func_val);
7027 } else if (sema.typeOf(runtime_func).unrestrictedType(zcu)) |unrestricted_ty|
7028 try sema.unwrapRestricted(block, unrestricted_ty, runtime_func, func_src)
7029 else
7030 runtime_func;
70227031
7023 const call_tag: Air.Inst.Tag = switch (modifier) {7032 const call_tag: Air.Inst.Tag = switch (modifier) {
7024 .auto, .no_suspend => .call,7033 .auto, .no_suspend => .call,
...@@ -7035,7 +7044,7 @@ fn analyzeCall(...@@ -7035,7 +7044,7 @@ fn analyzeCall(
7035 const call_ref = try block.addInst(.{7044 const call_ref = try block.addInst(.{
7036 .tag = call_tag,7045 .tag = call_tag,
7037 .data = .{ .pl_op = .{7046 .data = .{ .pl_op = .{
7038 .operand = runtime_func,7047 .operand = unrestricted_runtime_func,
7039 .payload = sema.addExtraAssumeCapacity(Air.Call{7048 .payload = sema.addExtraAssumeCapacity(Air.Call{
7040 .args_len = @intCast(runtime_args.len),7049 .args_len = @intCast(runtime_args.len),
7041 }),7050 }),
...@@ -7050,10 +7059,10 @@ fn analyzeCall(...@@ -7050,10 +7059,10 @@ fn analyzeCall(
7050 }7059 }
70517060
7052 if (call_tag == .call_always_tail) {7061 if (call_tag == .call_always_tail) {
7053 const func_or_ptr_ty = sema.typeOf(runtime_func);7062 const unrestricted_runtime_func_ty = sema.typeOf(unrestricted_runtime_func);
7054 const runtime_func_ty = switch (func_or_ptr_ty.zigTypeTag(zcu)) {7063 const runtime_func_ty = switch (unrestricted_runtime_func_ty.zigTypeTag(zcu)) {
7055 .@"fn" => func_or_ptr_ty,7064 .@"fn" => unrestricted_runtime_func_ty,
7056 .pointer => func_or_ptr_ty.childType(zcu),7065 .pointer => unrestricted_runtime_func_ty.childType(zcu),
7057 else => unreachable,7066 else => unreachable,
7058 };7067 };
7059 const result = sema.coerceExtra(block, sema.fn_ret_ty, call_ref, call_src, .{ .is_ret = true }) catch |err| switch (err) {7068 const result = sema.coerceExtra(block, sema.fn_ret_ty, call_ref, call_src, .{ .is_ret = true }) catch |err| switch (err) {
...@@ -9129,11 +9138,8 @@ fn analyzeAs(...@@ -9129,11 +9138,8 @@ fn analyzeAs(
9129 const zcu = pt.zcu;9138 const zcu = pt.zcu;
9130 const operand = sema.resolveInst(zir_operand);9139 const operand = sema.resolveInst(zir_operand);
9131 const dest_ty = try sema.resolveTypeOrPoison(block, src, zir_dest_type) orelse return operand;9140 const dest_ty = try sema.resolveTypeOrPoison(block, src, zir_dest_type) orelse return operand;
9132 switch (dest_ty.zigTypeTag(zcu)) {9141 if (dest_ty.toIntern() == .noreturn_type) return sema.fail(block, src, "cannot cast to noreturn", .{});
9133 .@"opaque" => return sema.fail(block, src, "cannot cast to opaque type '{f}'", .{dest_ty.fmt(pt)}),9142 if (zcu.intern_pool.isOpaqueType(dest_ty.toIntern())) return sema.fail(block, src, "cannot cast to opaque type '{f}'", .{dest_ty.fmt(pt)});
9134 .noreturn => return sema.fail(block, src, "cannot cast to noreturn", .{}),
9135 else => {},
9136 }
91379143
9138 const is_ret = if (zir_dest_type.toIndex()) |ptr_index|9144 const is_ret = if (zir_dest_type.toIndex()) |ptr_index|
9139 sema.code.instructions.items(.tag)[@intFromEnum(ptr_index)] == .ret_type9145 sema.code.instructions.items(.tag)[@intFromEnum(ptr_index)] == .ret_type
src/Sema/type_resolution.zig+1-1
...@@ -289,7 +289,7 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {...@@ -289,7 +289,7 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {
289 assert(!field_ty.isGenericPoison());289 assert(!field_ty.isGenericPoison());
290 const field_ty_src = block.src(.{ .container_field_type = @intCast(field_index) });290 const field_ty_src = block.src(.{ .container_field_type = @intCast(field_index) });
291 try sema.ensureLayoutResolved(field_ty, field_ty_src, .field);291 try sema.ensureLayoutResolved(field_ty, field_ty_src, .field);
292 if (field_ty.zigTypeTag(zcu) == .@"opaque") {292 if (ip.isOpaqueType(field_ty.toIntern())) {
293 return sema.failWithOwnedErrorMsg(&block, msg: {293 return sema.failWithOwnedErrorMsg(&block, msg: {
294 const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in struct", .{field_ty.fmt(pt)});294 const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in struct", .{field_ty.fmt(pt)});
295 errdefer msg.destroy(gpa);295 errdefer msg.destroy(gpa);