diff --git a/lib/std/rand.zig b/lib/std/rand.zig index 53b536f9ff..cfac15a1fb 100644 --- a/lib/std/rand.zig +++ b/lib/std/rand.zig @@ -7,6 +7,7 @@ //! TODO(tiehuis): Benchmark these against other reference implementations. const std = @import("std.zig"); +const builtin = @import("builtin"); const assert = std.debug.assert; const expect = std.testing.expect; const expectEqual = std.testing.expectEqual; @@ -30,7 +31,10 @@ pub const Sfc64 = @import("rand/Sfc64.zig"); pub const Random = struct { ptr: *anyopaque, - fillFn: fn (ptr: *anyopaque, buf: []u8) void, + fillFn: if (builtin.zig_backend == .stage1) + fn (ptr: *anyopaque, buf: []u8) void + else + *const fn (ptr: *anyopaque, buf: []u8) void, pub fn init(pointer: anytype, comptime fillFn: fn (ptr: @TypeOf(pointer), buf: []u8) void) Random { const Ptr = @TypeOf(pointer); diff --git a/src/Sema.zig b/src/Sema.zig index 2a3236e8ad..619d9a0664 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -5923,6 +5923,10 @@ fn funcCommon( break :ret_ty ret_ty; } else |err| break :err err; } else |err| break :err err; + // Check for generic params. + for (block.params.items) |param| { + if (param.ty.tag() == .generic_poison) is_generic = true; + } }; switch (err) { error.GenericPoison => { @@ -6111,6 +6115,13 @@ fn zirParam( if (sema.resolveBody(block, body, inst)) |param_ty_inst| { if (sema.analyzeAsType(block, src, param_ty_inst)) |param_ty| { + if (param_ty.zigTypeTag() == .Fn and param_ty.fnInfo().is_generic) { + // zirFunc will not emit error.GenericPoison to build a + // partial type for generic functions but we still need to + // detect if a function parameter is a generic function + // to force the parent function to also be generic. + break :err error.GenericPoison; + } break :param_ty param_ty; } else |err| break :err err; } else |err| break :err err; @@ -10965,6 +10976,7 @@ fn zirTypeofBuiltin(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr const operand = try sema.resolveBody(&child_block, body, inst); const operand_ty = sema.typeOf(operand); + if (operand_ty.tag() == .generic_poison) return error.GenericPoison; return sema.addType(operand_ty); } @@ -11044,6 +11056,7 @@ fn zirTypeofPeer( for (args) |arg_ref, i| { inst_list[i] = sema.resolveInst(arg_ref); + if (sema.typeOf(inst_list[i]).tag() == .generic_poison) return error.GenericPoison; } const result_type = try sema.resolvePeerTypes(block, src, inst_list, .{ .typeof_builtin_call_node_offset = extra.data.src_node }); diff --git a/test/behavior/generics.zig b/test/behavior/generics.zig index 412d87befd..656acb61eb 100644 --- a/test/behavior/generics.zig +++ b/test/behavior/generics.zig @@ -230,3 +230,16 @@ fn GenNode(comptime T: type) type { } }; } + +test "function parameter is generic" { + const S = struct { + pub fn init(pointer: anytype, comptime fillFn: fn (ptr: *@TypeOf(pointer)) void) void { + _ = fillFn; + } + pub fn fill(self: *u32) void { + _ = self; + } + }; + var rng: u32 = 2; + S.init(rng, S.fill); +}