diff --git a/lib/std/zig/AstGen.zig b/lib/std/zig/AstGen.zig index aeb4b7a311c7..d6207d16a8c8 100644 --- a/lib/std/zig/AstGen.zig +++ b/lib/std/zig/AstGen.zig @@ -107,6 +107,8 @@ fn setExtra(astgen: *AstGen, index: usize, extra: anytype) void { Zir.Inst.SwitchBlock.Bits, Zir.Inst.SwitchBlockErrUnion.Bits, Zir.Inst.FuncFancy.Bits, + Zir.Inst.Param.Type, + Zir.Inst.Func.RetTy, => @bitCast(@field(extra, field.name)), else => @compileError("bad field type"), @@ -1384,7 +1386,7 @@ fn fnProtoExprInner( const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param; // We pass `prev_param_insts` as `&.{}` here because a function prototype can't refer to previous // arguments (we haven't set up scopes here). - const param_inst = try block_scope.addParam(¶m_gz, &.{}, tag, name_token, param_name); + const param_inst = try block_scope.addParam(¶m_gz, &.{}, false, tag, name_token, param_name); assert(param_inst_expected == param_inst); } } @@ -1416,6 +1418,7 @@ fn fnProtoExprInner( .ret_param_refs = &.{}, .param_insts = &.{}, + .ret_ty_is_generic = false, .param_block = block_inst, .body_gz = null, @@ -4336,6 +4339,9 @@ fn fnDeclInner( // Note that the capacity here may not be sufficient, as this does not include `anytype` parameters. var param_insts: std.ArrayListUnmanaged(Zir.Inst.Index) = try .initCapacity(astgen.arena, fn_proto.ast.params.len); + // We use this as `is_used_or_discarded` to figure out if parameters / return types are generic. + var any_param_used = false; + var noalias_bits: u32 = 0; var params_scope = scope; const is_var_args = is_var_args: { @@ -4409,16 +4415,18 @@ fn fnDeclInner( } else param: { const param_type_node = param.type_expr; assert(param_type_node != 0); + any_param_used = false; // we will check this later var param_gz = decl_gz.makeSubBlock(scope); defer param_gz.unstack(); const param_type = try fullBodyExpr(¶m_gz, params_scope, coerced_type_ri, param_type_node, .normal); const param_inst_expected: Zir.Inst.Index = @enumFromInt(astgen.instructions.len + 1); _ = try param_gz.addBreakWithSrcNode(.break_inline, param_inst_expected, param_type, param_type_node); + const param_type_is_generic = any_param_used; const main_tokens = tree.nodes.items(.main_token); const name_token = param.name_token orelse main_tokens[param_type_node]; const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param; - const param_inst = try decl_gz.addParam(¶m_gz, param_insts.items, tag, name_token, param_name); + const param_inst = try decl_gz.addParam(¶m_gz, param_insts.items, param_type_is_generic, tag, name_token, param_name); assert(param_inst_expected == param_inst); break :param param_inst.toRef(); }; @@ -4433,6 +4441,7 @@ fn fnDeclInner( .inst = param_inst, .token_src = param.name_token.?, .id_cat = .@"function parameter", + .is_used_or_discarded = &any_param_used, }; params_scope = &sub_scope.base; try param_insts.append(astgen.arena, param_inst.toIndex().?); @@ -4446,6 +4455,7 @@ fn fnDeclInner( var ret_gz = decl_gz.makeSubBlock(params_scope); defer ret_gz.unstack(); + any_param_used = false; // we will check this later const ret_ref: Zir.Inst.Ref = inst: { // Parameters are in scope for the return type, so we use `params_scope` here. // The calling convention will not have parameters in scope, so we'll just use `scope`. @@ -4459,6 +4469,7 @@ fn fnDeclInner( break :inst inst; }; const ret_body_param_refs = try astgen.fetchRemoveRefEntries(param_insts.items); + const ret_ty_is_generic = any_param_used; // We're jumping back in source, so restore the cursor. astgen.restoreSourceCursor(saved_cursor); @@ -4556,6 +4567,7 @@ fn fnDeclInner( .ret_ref = ret_ref, .ret_gz = &ret_gz, .ret_param_refs = ret_body_param_refs, + .ret_ty_is_generic = ret_ty_is_generic, .lbrace_line = lbrace_line, .lbrace_column = lbrace_column, .param_block = decl_inst, @@ -5028,6 +5040,7 @@ fn testDecl( .ret_param_refs = &.{}, .param_insts = &.{}, + .ret_ty_is_generic = false, .lbrace_line = lbrace_line, .lbrace_column = lbrace_column, @@ -8546,6 +8559,8 @@ fn localVarRef( local_val.used = ident_token; } + if (local_val.is_used_or_discarded) |ptr| ptr.* = true; + const value_inst = if (num_namespaces_out != 0) try tunnelThroughClosure( gz, ident, @@ -11876,6 +11891,7 @@ const Scope = struct { /// Track the identifier where it is discarded, like this `_ = foo;`. /// 0 means never discarded. discarded: Ast.TokenIndex = 0, + is_used_or_discarded: ?*bool = null, /// String table index. name: Zir.NullTerminatedString, id_cat: IdCat, @@ -12223,6 +12239,7 @@ const GenZir = struct { ret_param_refs: []Zir.Inst.Index, param_insts: []Zir.Inst.Index, // refs to params in `body_gz` should still be in `astgen.ref_table` + ret_ty_is_generic: bool, cc_ref: Zir.Inst.Ref, ret_ref: Zir.Inst.Ref, @@ -12322,6 +12339,8 @@ const GenZir = struct { .has_cc_body = cc_body.len != 0, .has_ret_ty_body = ret_body.len != 0, + + .ret_ty_is_generic = args.ret_ty_is_generic, }, }); @@ -12372,7 +12391,10 @@ const GenZir = struct { const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.Func{ .param_block = args.param_block, - .ret_body_len = ret_body_len, + .ret_ty = .{ + .body_len = @intCast(ret_body_len), + .is_generic = args.ret_ty_is_generic, + }, .body_len = body_len, }); const zir_datas = astgen.instructions.items(.data); @@ -12535,6 +12557,7 @@ const GenZir = struct { /// Previous parameters, which might be referenced in `param_gz` (the new parameter type). /// `ref`s of these instructions will be put into this param's type body, and removed from `AstGen.ref_table`. prev_param_insts: []const Zir.Inst.Index, + ty_is_generic: bool, tag: Zir.Inst.Tag, /// Absolute token index. This function does the conversion to Decl offset. abs_tok_index: Ast.TokenIndex, @@ -12548,7 +12571,10 @@ const GenZir = struct { const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Param{ .name = name, - .body_len = @intCast(body_len), + .type = .{ + .body_len = @intCast(body_len), + .is_generic = ty_is_generic, + }, }); gz.astgen.appendBodyWithFixupsExtraRefsArrayList(&gz.astgen.extra, param_body, prev_param_insts); param_gz.unstack(); diff --git a/lib/std/zig/Zir.zig b/lib/std/zig/Zir.zig index 4e7e00708e43..7edb99ee03a1 100644 --- a/lib/std/zig/Zir.zig +++ b/lib/std/zig/Zir.zig @@ -89,6 +89,8 @@ pub fn extraData(code: Zir, comptime T: type, index: usize) ExtraData(T) { Inst.SwitchBlockErrUnion.Bits, Inst.FuncFancy.Bits, Inst.Declaration.Flags, + Inst.Param.Type, + Inst.Func.RetTy, => @bitCast(code.extra[i]), else => @compileError("bad field type"), @@ -2126,7 +2128,7 @@ pub const Inst = struct { ref_start_index = static_len, _, - pub const static_len = 71; + pub const static_len = 70; pub fn toRef(i: Index) Inst.Ref { return @enumFromInt(@intFromEnum(Index.ref_start_index) + @intFromEnum(i)); @@ -2229,7 +2231,6 @@ pub const Inst = struct { bool_true, bool_false, empty_tuple, - generic_poison, /// This Ref does not correspond to any ZIR instruction or constant /// value and may instead be used as a sentinel to indicate null. @@ -2472,24 +2473,31 @@ pub const Inst = struct { }; /// Trailing: - /// if (ret_body_len == 1) { + /// if (ret_ty.body_len == 1) { /// 0. return_type: Ref /// } - /// if (ret_body_len > 1) { - /// 1. return_type: Index // for each ret_body_len + /// if (ret_ty.body_len > 1) { + /// 1. return_type: Index // for each ret_ty.body_len /// } /// 2. body: Index // for each body_len /// 3. src_locs: SrcLocs // if body_len != 0 /// 4. proto_hash: std.zig.SrcHash // if body_len != 0; hash of function prototype pub const Func = struct { - /// If this is 0 it means a void return type. - /// If this is 1 it means return_type is a simple Ref - ret_body_len: u32, + ret_ty: RetTy, /// Points to the block that contains the param instructions for this function. /// If this is a `declaration`, it refers to the declaration's value body. param_block: Index, body_len: u32, + pub const RetTy = packed struct(u32) { + /// 0 means `void`. + /// 1 means the type is a simple `Ref`. + /// Otherwise, the length of a trailing body. + body_len: u31, + /// Whether the return type is generic, i.e. refers to one or more previous parameters. + is_generic: bool, + }; + pub const SrcLocs = struct { /// Line index in the source file relative to the parent decl. lbrace_line: u32, @@ -2539,7 +2547,8 @@ pub const Inst = struct { has_ret_ty_ref: bool, has_ret_ty_body: bool, has_any_noalias: bool, - _: u24 = undefined, + ret_ty_is_generic: bool, + _: u23 = undefined, }; }; @@ -3708,8 +3717,14 @@ pub const Inst = struct { pub const Param = struct { /// Null-terminated string index. name: NullTerminatedString, - /// The body contains the type of the parameter. - body_len: u32, + type: Type, + + pub const Type = packed struct(u32) { + /// The body contains the type of the parameter. + body_len: u31, + /// Whether the type is generic, i.e. refers to one or more previous parameters. + is_generic: bool, + }; }; /// Trailing: @@ -4492,7 +4507,7 @@ fn findTrackableInner( if (extra.data.body_len == 0) { // This is just a prototype. No need to track. - assert(extra.data.ret_body_len < 2); + assert(extra.data.ret_ty.body_len < 2); return; } @@ -4500,11 +4515,11 @@ fn findTrackableInner( contents.func_decl = inst; var extra_index: usize = extra.end; - switch (extra.data.ret_body_len) { + switch (extra.data.ret_ty.body_len) { 0 => {}, 1 => extra_index += 1, else => { - const body = zir.bodySlice(extra_index, extra.data.ret_body_len); + const body = zir.bodySlice(extra_index, extra.data.ret_ty.body_len); extra_index += body.len; try zir.findTrackableBody(gpa, contents, defers, body); }, @@ -4595,7 +4610,7 @@ fn findTrackableInner( .param, .param_comptime => { const inst_data = datas[@intFromEnum(inst)].pl_tok; const extra = zir.extraData(Inst.Param, inst_data.payload_index); - const body = zir.bodySlice(extra.end, extra.data.body_len); + const body = zir.bodySlice(extra.end, extra.data.type.body_len); try zir.findTrackableBody(gpa, contents, defers, body); }, @@ -4738,6 +4753,7 @@ pub const FnInfo = struct { ret_ty_body: []const Inst.Index, body: []const Inst.Index, ret_ty_ref: Zir.Inst.Ref, + ret_ty_is_generic: bool, total_params_len: u32, inferred_error_set: bool, }; @@ -4779,6 +4795,7 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo { body: []const Inst.Index, ret_ty_ref: Inst.Ref, ret_ty_body: []const Inst.Index, + ret_ty_is_generic: bool, ies: bool, } = switch (tags[@intFromEnum(fn_inst)]) { .func, .func_inferred => |tag| blk: { @@ -4789,7 +4806,7 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo { var ret_ty_ref: Inst.Ref = .none; var ret_ty_body: []const Inst.Index = &.{}; - switch (extra.data.ret_body_len) { + switch (extra.data.ret_ty.body_len) { 0 => { ret_ty_ref = .void_type; }, @@ -4798,7 +4815,7 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo { extra_index += 1; }, else => { - ret_ty_body = zir.bodySlice(extra_index, extra.data.ret_body_len); + ret_ty_body = zir.bodySlice(extra_index, extra.data.ret_ty.body_len); extra_index += ret_ty_body.len; }, } @@ -4811,6 +4828,7 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo { .ret_ty_ref = ret_ty_ref, .ret_ty_body = ret_ty_body, .body = body, + .ret_ty_is_generic = extra.data.ret_ty.is_generic, .ies = tag == .func_inferred, }; }, @@ -4848,6 +4866,7 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo { .ret_ty_ref = ret_ty_ref, .ret_ty_body = ret_ty_body, .body = body, + .ret_ty_is_generic = extra.data.bits.ret_ty_is_generic, .ies = extra.data.bits.is_inferred_error, }; }, @@ -4870,6 +4889,7 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo { .ret_ty_ref = info.ret_ty_ref, .body = info.body, .total_params_len = total_params_len, + .ret_ty_is_generic = info.ret_ty_is_generic, .inferred_error_set = info.ies, }; } @@ -4967,7 +4987,7 @@ pub fn getAssociatedSrcHash(zir: Zir, inst: Zir.Inst.Index) ?std.zig.SrcHash { return null; } const extra_index = extra.end + - extra.data.ret_body_len + + extra.data.ret_ty.body_len + extra.data.body_len + @typeInfo(Inst.Func.SrcLocs).@"struct".fields.len; return @bitCast([4]u32{ diff --git a/src/Air.zig b/src/Air.zig index 81fb7af85eec..3bd658befdda 100644 --- a/src/Air.zig +++ b/src/Air.zig @@ -1004,7 +1004,6 @@ pub const Inst = struct { bool_true = @intFromEnum(InternPool.Index.bool_true), bool_false = @intFromEnum(InternPool.Index.bool_false), empty_tuple = @intFromEnum(InternPool.Index.empty_tuple), - generic_poison = @intFromEnum(InternPool.Index.generic_poison), /// This Ref does not correspond to any AIR instruction or constant /// value and may instead be used as a sentinel to indicate null. diff --git a/src/Air/types_resolved.zig b/src/Air/types_resolved.zig index cc866184e475..b627ad388b55 100644 --- a/src/Air/types_resolved.zig +++ b/src/Air/types_resolved.zig @@ -455,9 +455,8 @@ pub fn checkVal(val: Value, zcu: *Zcu) bool { pub fn checkType(ty: Type, zcu: *Zcu) bool { const ip = &zcu.intern_pool; - return switch (ty.zigTypeTagOrPoison(zcu) catch |err| switch (err) { - error.GenericPoison => return true, - }) { + if (ty.isGenericPoison()) return true; + return switch (ty.zigTypeTag(zcu)) { .type, .void, .bool, diff --git a/src/InternPool.zig b/src/InternPool.zig index 36ddfda857d3..17ede067257e 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -620,11 +620,11 @@ pub const Nav = struct { return switch (nav.status) { .unresolved => unreachable, .type_resolved => |r| { - const tag = ip.zigTypeTagOrPoison(r.type) catch unreachable; + const tag = ip.zigTypeTag(r.type); return tag == .@"fn"; }, .fully_resolved => |r| { - const tag = ip.zigTypeTagOrPoison(ip.typeOf(r.val)) catch unreachable; + const tag = ip.zigTypeTag(ip.typeOf(r.val)); return tag == .@"fn"; }, }; @@ -639,13 +639,13 @@ pub const Nav = struct { .unresolved => unreachable, .type_resolved => |r| { if (r.is_extern_decl) return true; - const tag = ip.zigTypeTagOrPoison(r.type) catch unreachable; + const tag = ip.zigTypeTag(r.type); if (tag == .@"fn") return true; return false; }, .fully_resolved => |r| { if (ip.indexToKey(r.val) == .@"extern") return true; - const tag = ip.zigTypeTagOrPoison(ip.typeOf(r.val)) catch unreachable; + const tag = ip.zigTypeTag(ip.typeOf(r.val)); if (tag == .@"fn") return true; return false; }, @@ -3216,7 +3216,6 @@ pub const Key = union(enum) { .false, .true => .bool_type, .empty_tuple => .empty_tuple_type, .@"unreachable" => .noreturn_type, - .generic_poison => .generic_poison_type, }, .memoized_call => unreachable, @@ -4581,6 +4580,10 @@ pub const Index = enum(u32) { anyerror_void_error_union_type, /// Used for the inferred error set of inline/comptime function calls. adhoc_inferred_error_set_type, + /// Represents a type which is unknown. + /// This is used in functions to represent generic parameter/return types, and + /// during semantic analysis to represent unknown result types (i.e. where AstGen + /// thought we would have a result type, but we do not). generic_poison_type, /// `@TypeOf(.{})`; a tuple with zero elements. /// This is not the same as `struct {}`, since that is a struct rather than a tuple. @@ -4617,10 +4620,6 @@ pub const Index = enum(u32) { /// `.{}` empty_tuple, - /// Used for generic parameters where the type and value - /// is not known until generic function instantiation. - generic_poison, - /// Used by Air/Sema only. none = std.math.maxInt(u32), @@ -5136,7 +5135,6 @@ pub const static_keys = [_]Key{ .{ .simple_value = .true }, .{ .simple_value = .false }, .{ .simple_value = .empty_tuple }, - .{ .simple_value = .generic_poison }, }; /// How many items in the InternPool are statically known. @@ -6054,8 +6052,6 @@ pub const SimpleValue = enum(u32) { true = @intFromEnum(Index.bool_true), false = @intFromEnum(Index.bool_false), @"unreachable" = @intFromEnum(Index.unreachable_value), - - generic_poison = @intFromEnum(Index.generic_poison), }; /// Stored as a power-of-two, with one special value to indicate none. @@ -11712,7 +11708,6 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index { .null_value => .null_type, .bool_true, .bool_false => .bool_type, .empty_tuple => .empty_tuple_type, - .generic_poison => .generic_poison_type, // This optimization on tags is needed so that indexToKey can call // typeOf without being recursive. @@ -11954,7 +11949,8 @@ pub fn getBackingAddrTag(ip: *const InternPool, val: Index) ?Key.Ptr.BaseAddr.Ta /// This is a particularly hot function, so we operate directly on encodings /// rather than the more straightforward implementation of calling `indexToKey`. -pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPoison}!std.builtin.TypeId { +/// Asserts `index` is not `.generic_poison_type`. +pub fn zigTypeTag(ip: *const InternPool, index: Index) std.builtin.TypeId { return switch (index) { .u0_type, .i0_type, @@ -12017,7 +12013,7 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois .anyerror_void_error_union_type => .error_union, .empty_tuple_type => .@"struct", - .generic_poison_type => return error.GenericPoison, + .generic_poison_type => unreachable, // values, not types .undef => unreachable, @@ -12035,7 +12031,6 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois .bool_true => unreachable, .bool_false => unreachable, .empty_tuple => unreachable, - .generic_poison => unreachable, _ => switch (index.unwrap(ip).getTag(ip)) { .removed => unreachable, diff --git a/src/Sema.zig b/src/Sema.zig index e19110bbfb64..978396e371dc 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -53,9 +53,6 @@ comptime_break_inst: Zir.Inst.Index = undefined, post_hoc_blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, *LabeledBlock) = .empty, /// Populated with the last compile error created. err: ?*Zcu.ErrorMsg = null, -/// Set to true when analyzing a func type instruction so that nested generic -/// function types will emit generic poison instead of a partial type. -no_partial_func_ty: bool = false, /// The temporary arena is used for the memory of the `InferredAlloc` values /// here so the values can be dropped without any cleanup. @@ -1935,9 +1932,7 @@ pub fn resolveInstAllowNone(sema: *Sema, zir_ref: Zir.Inst.Ref) !Air.Inst.Ref { pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) !Air.Inst.Ref { assert(zir_ref != .none); if (zir_ref.toIndex()) |i| { - const inst = sema.inst_map.get(i).?; - if (inst == .generic_poison) return error.GenericPoison; - return inst; + return sema.inst_map.get(i).?; } // First section of indexes correspond to a set number of constant values. // We intentionally map the same indexes to the same values between ZIR and AIR. @@ -1997,13 +1992,17 @@ pub fn resolveConstStringIntern( return sema.sliceToIpString(block, src, val, reason); } -pub fn resolveType(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) !Type { +fn resolveTypeOrPoison(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) !?Type { const air_inst = try sema.resolveInst(zir_ref); const ty = try sema.analyzeAsType(block, src, air_inst); - if (ty.isGenericPoison()) return error.GenericPoison; + if (ty.isGenericPoison()) return null; return ty; } +pub fn resolveType(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) !Type { + return (try sema.resolveTypeOrPoison(block, src, zir_ref)).?; +} + fn resolveDestType( sema: *Sema, block: *Block, @@ -2023,24 +2022,21 @@ fn resolveDestType( .remove_eu => false, }; - const raw_ty = sema.resolveType(block, src, zir_ref) catch |err| switch (err) { - error.GenericPoison => { - // Cast builtins use their result type as the destination type, but - // it could be an anytype argument, which we can't catch in AstGen. - const msg = msg: { - const msg = try sema.errMsg(src, "{s} must have a known result type", .{builtin_name}); - errdefer msg.destroy(sema.gpa); - switch (sema.genericPoisonReason(block, zir_ref)) { - .anytype_param => |call_src| try sema.errNote(call_src, msg, "result type is unknown due to anytype parameter", .{}), - .anyopaque_ptr => |ptr_src| try sema.errNote(ptr_src, msg, "result type is unknown due to opaque pointer type", .{}), - .unknown => {}, - } - try sema.errNote(src, msg, "use @as to provide explicit result type", .{}); - break :msg msg; - }; - return sema.failWithOwnedErrorMsg(block, msg); - }, - else => |e| return e, + const raw_ty = try sema.resolveTypeOrPoison(block, src, zir_ref) orelse { + // Cast builtins use their result type as the destination type, but + // it could be an anytype argument, which we can't catch in AstGen. + const msg = msg: { + const msg = try sema.errMsg(src, "{s} must have a known result type", .{builtin_name}); + errdefer msg.destroy(sema.gpa); + switch (sema.genericPoisonReason(block, zir_ref)) { + .anytype_param => |call_src| try sema.errNote(call_src, msg, "result type is unknown due to anytype parameter", .{}), + .anyopaque_ptr => |ptr_src| try sema.errNote(ptr_src, msg, "result type is unknown due to opaque pointer type", .{}), + .unknown => {}, + } + try sema.errNote(src, msg, "use @as to provide explicit result type", .{}); + break :msg msg; + }; + return sema.failWithOwnedErrorMsg(block, msg); }; if (remove_eu and raw_ty.zigTypeTag(zcu) == .error_union) { @@ -2086,9 +2082,7 @@ fn genericPoisonReason(sema: *Sema, block: *Block, ref: Zir.Inst.Ref) GenericPoi // Either the input type was itself poison, or it was a slice, which we cannot translate // to an overall result type. const un_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; - const operand_ref = sema.resolveInst(un_node.operand) catch |err| switch (err) { - error.GenericPoison => unreachable, // this is a type, not a value - }; + const operand_ref = try sema.resolveInst(un_node.operand); if (operand_ref == .generic_poison_type) { // The input was poison -- keep looking. cur = un_node.operand; @@ -2107,9 +2101,7 @@ fn genericPoisonReason(sema: *Sema, block: *Block, ref: Zir.Inst.Ref) GenericPoi // There are two cases here: the pointer type may already have been // generic poison, or it may have been an anyopaque pointer. const un_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; - const operand_ref = sema.resolveInst(un_node.operand) catch |err| switch (err) { - error.GenericPoison => unreachable, // this is a type, not a value - }; + const operand_ref = try sema.resolveInst(un_node.operand); const operand_val = operand_ref.toInterned() orelse return .unknown; if (operand_val == .generic_poison_type) { // The pointer was generic poison - keep looking. @@ -2187,7 +2179,6 @@ pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize) } /// Return the Value corresponding to a given AIR ref, or `null` if it refers to a runtime value. -/// Generic poison causes `error.GenericPoison` to be returned. fn resolveValue(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value { const zcu = sema.pt.zcu; assert(inst != .none); @@ -2201,7 +2192,6 @@ fn resolveValue(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value { assert(val.getVariable(zcu) == null); if (val.isPtrRuntimeValue(zcu)) return null; - if (val.isGenericPoison()) return error.GenericPoison; return val; } else { @@ -2761,8 +2751,7 @@ fn zirTupleDecl( .elem_index = @intCast(field_index), } }); - const uncoerced_field_ty = try sema.resolveInst(zir_field_ty); - const field_type = try sema.analyzeAsType(block, type_src, uncoerced_field_ty); + const field_type = try sema.resolveType(block, type_src, zir_field_ty); try sema.validateTupleFieldType(block, field_type, type_src); field_ty.* = field_type.toIntern(); @@ -4555,10 +4544,7 @@ fn zirCoercePtrElemTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE const src = block.nodeOffset(pl_node.src_node); const extra = sema.code.extraData(Zir.Inst.Bin, pl_node.payload_index).data; const uncoerced_val = try sema.resolveInst(extra.rhs); - const maybe_wrapped_ptr_ty = sema.resolveType(block, LazySrcLoc.unneeded, extra.lhs) catch |err| switch (err) { - error.GenericPoison => return uncoerced_val, - else => |e| return e, - }; + const maybe_wrapped_ptr_ty = try sema.resolveTypeOrPoison(block, LazySrcLoc.unneeded, extra.lhs) orelse return uncoerced_val; const ptr_ty = maybe_wrapped_ptr_ty.optEuBaseType(zcu); assert(ptr_ty.zigTypeTag(zcu) == .pointer); // validated by a previous instruction const elem_ty = ptr_ty.childType(zcu); @@ -4606,10 +4592,7 @@ fn zirTryOperandTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is_ref: boo const un_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; const src = block.nodeOffset(un_node.src_node); - const operand_ty = sema.resolveType(block, src, un_node.operand) catch |err| switch (err) { - error.GenericPoison => return .generic_poison_type, - else => |e| return e, - }; + const operand_ty = try sema.resolveTypeOrPoison(block, src, un_node.operand) orelse return .generic_poison_type; const payload_ty = if (is_ref) ty: { if (!operand_ty.isSinglePointer(zcu)) { @@ -4656,15 +4639,7 @@ fn zirValidateRefTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr const src = block.tokenOffset(un_tok.src_tok); // In case of GenericPoison, we don't actually have a type, so this will be // treated as an untyped address-of operator. - const operand_air_inst = sema.resolveInst(un_tok.operand) catch |err| switch (err) { - error.GenericPoison => return, - else => |e| return e, - }; - const ty_operand = sema.analyzeAsType(block, src, operand_air_inst) catch |err| switch (err) { - error.GenericPoison => return, - else => |e| return e, - }; - if (ty_operand.isGenericPoison()) return; + const ty_operand = try sema.resolveTypeOrPoison(block, src, un_tok.operand) orelse return; if (ty_operand.optEuBaseType(zcu).zigTypeTag(zcu) != .pointer) { return sema.failWithOwnedErrorMsg(block, msg: { const msg = try sema.errMsg(src, "expected type '{}', found pointer", .{ty_operand.fmt(pt)}); @@ -4696,10 +4671,7 @@ fn zirValidateArrayInitRefTy( const pl_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; const src = block.nodeOffset(pl_node.src_node); const extra = sema.code.extraData(Zir.Inst.ArrayInitRefTy, pl_node.payload_index).data; - const maybe_wrapped_ptr_ty = sema.resolveType(block, LazySrcLoc.unneeded, extra.ptr_ty) catch |err| switch (err) { - error.GenericPoison => return .generic_poison_type, - else => |e| return e, - }; + const maybe_wrapped_ptr_ty = try sema.resolveTypeOrPoison(block, LazySrcLoc.unneeded, extra.ptr_ty) orelse return .generic_poison_type; const ptr_ty = maybe_wrapped_ptr_ty.optEuBaseType(zcu); assert(ptr_ty.zigTypeTag(zcu) == .pointer); // validated by a previous instruction switch (zcu.intern_pool.indexToKey(ptr_ty.toIntern())) { @@ -4740,11 +4712,8 @@ fn zirValidateArrayInitTy( const src = block.nodeOffset(inst_data.src_node); const ty_src: LazySrcLoc = if (is_result_ty) src else block.src(.{ .node_offset_init_ty = inst_data.src_node }); const extra = sema.code.extraData(Zir.Inst.ArrayInit, inst_data.payload_index).data; - const ty = sema.resolveType(block, ty_src, extra.ty) catch |err| switch (err) { - // It's okay for the type to be unknown: this will result in an anonymous array init. - error.GenericPoison => return, - else => |e| return e, - }; + // It's okay for the type to be poison: this will result in an anonymous array init. + const ty = try sema.resolveTypeOrPoison(block, ty_src, extra.ty) orelse return; const arr_ty = if (is_result_ty) ty.optEuBaseType(zcu) else ty; return sema.validateArrayInitTy(block, src, ty_src, extra.init_count, arr_ty); } @@ -4803,11 +4772,8 @@ fn zirValidateStructInitTy( const zcu = pt.zcu; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; const src = block.nodeOffset(inst_data.src_node); - const ty = sema.resolveType(block, src, inst_data.operand) catch |err| switch (err) { - // It's okay for the type to be unknown: this will result in an anonymous struct init. - error.GenericPoison => return, - else => |e| return e, - }; + // It's okay for the type to be poison: this will result in an anonymous struct init. + const ty = try sema.resolveTypeOrPoison(block, src, inst_data.operand) orelse return; const struct_ty = if (is_result_ty) ty.optEuBaseType(zcu) else ty; switch (struct_ty.zigTypeTag(zcu)) { @@ -7043,7 +7009,7 @@ pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref const field_name = try zcu.intern_pool.getOrPutString(gpa, pt.tid, "index", .no_embedded_nulls); const field_index = sema.structFieldIndex(block, stack_trace_ty, field_name, LazySrcLoc.unneeded) catch |err| switch (err) { error.AnalysisFail => @panic("std.builtin.StackTrace is corrupt"), - error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable, + error.ComptimeReturn, error.ComptimeBreak => unreachable, error.OutOfMemory => |e| return e, }; @@ -7668,6 +7634,11 @@ fn analyzeCall( } } + // This is whether we already know this to be an inline call. + // If so, then comptime-known arguments are propagated when evaluating generic parameter/return types. + // We might still learn that this call is inline *after* evaluating the generic return type. + const early_known_inline = inline_requested or block.isComptime(); + // These values are undefined if `func_val == null`. const fn_nav: InternPool.Nav, const fn_zir: Zir, const fn_tracked_inst: InternPool.TrackedInst.Index, const fn_zir_inst: Zir.Inst.Index, const fn_zir_info: Zir.FnInfo = if (func_val) |f| b: { const info = ip.indexToKey(f.toIntern()).func; @@ -7746,7 +7717,7 @@ fn analyzeCall( const extra = sema.code.extraData(Zir.Inst.Param, param_inst.data.pl_tok.payload_index); const param_src = generic_block.tokenOffset(param_inst.data.pl_tok.src_tok); - const body = sema.code.bodySlice(extra.end, extra.data.body_len); + const body = sema.code.bodySlice(extra.end, extra.data.type.body_len); generic_block.comptime_reason = .{ .reason = .{ .r = .{ .simple = .function_parameters }, @@ -7777,8 +7748,10 @@ fn analyzeCall( const param_inst_idx = fn_zir_info.param_body[arg_idx]; const declared_comptime = if (std.math.cast(u5, arg_idx)) |i| func_ty_info.paramIsComptime(i) else false; const param_is_comptime = declared_comptime or try arg_ty.comptimeOnlySema(pt); - if (param_is_comptime) { - if (!try sema.isComptimeKnown(arg.*)) { + // We allow comptime-known arguments to propagate to generic types not only for comptime + // parameters, but if the call is known to be inline. + if (param_is_comptime or early_known_inline) { + if (param_is_comptime and !try sema.isComptimeKnown(arg.*)) { assert(!declared_comptime); // `analyzeArg` handles this const arg_src = args_info.argSrc(block, arg_idx); const param_ty_src: LazySrcLoc = .{ @@ -8313,14 +8286,7 @@ fn zirArrayInitElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil const pt = sema.pt; const zcu = pt.zcu; const bin = sema.code.instructions.items(.data)[@intFromEnum(inst)].bin; - const maybe_wrapped_indexable_ty = sema.resolveType(block, LazySrcLoc.unneeded, bin.lhs) catch |err| switch (err) { - // Since this is a ZIR instruction that returns a type, encountering - // generic poison should not result in a failed compilation, but the - // generic poison type. This prevents unnecessary failures when - // constructing types at compile-time. - error.GenericPoison => return .generic_poison_type, - else => |e| return e, - }; + const maybe_wrapped_indexable_ty = try sema.resolveTypeOrPoison(block, LazySrcLoc.unneeded, bin.lhs) orelse return .generic_poison_type; const indexable_ty = maybe_wrapped_indexable_ty.optEuBaseType(zcu); try indexable_ty.resolveFields(pt); assert(indexable_ty.isIndexable(zcu)); // validated by a previous instruction @@ -8337,10 +8303,7 @@ fn zirElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const pt = sema.pt; const zcu = pt.zcu; const un_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; - const maybe_wrapped_ptr_ty = sema.resolveType(block, LazySrcLoc.unneeded, un_node.operand) catch |err| switch (err) { - error.GenericPoison => return .generic_poison_type, - else => |e| return e, - }; + const maybe_wrapped_ptr_ty = try sema.resolveTypeOrPoison(block, LazySrcLoc.unneeded, un_node.operand) orelse return .generic_poison_type; const ptr_ty = maybe_wrapped_ptr_ty.optEuBaseType(zcu); assert(ptr_ty.zigTypeTag(zcu) == .pointer); // validated by a previous instruction const elem_ty = ptr_ty.childType(zcu); @@ -8357,10 +8320,7 @@ fn zirIndexablePtrElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com const zcu = pt.zcu; const un_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; const src = block.nodeOffset(un_node.src_node); - const ptr_ty = sema.resolveType(block, src, un_node.operand) catch |err| switch (err) { - error.GenericPoison => return .generic_poison_type, - else => |e| return e, - }; + const ptr_ty = try sema.resolveTypeOrPoison(block, src, un_node.operand) orelse return .generic_poison_type; try sema.checkMemOperand(block, src, ptr_ty); const elem_ty = switch (ptr_ty.ptrSize(zcu)) { .slice, .many, .c => ptr_ty.childType(zcu), @@ -8373,14 +8333,7 @@ fn zirVecArrElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr const pt = sema.pt; const zcu = pt.zcu; const un_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; - const vec_ty = sema.resolveType(block, LazySrcLoc.unneeded, un_node.operand) catch |err| switch (err) { - // Since this is a ZIR instruction that returns a type, encountering - // generic poison should not result in a failed compilation, but the - // generic poison type. This prevents unnecessary failures when - // constructing types at compile-time. - error.GenericPoison => return .generic_poison_type, - else => |e| return e, - }; + const vec_ty = try sema.resolveTypeOrPoison(block, LazySrcLoc.unneeded, un_node.operand) orelse return .generic_poison_type; switch (vec_ty.zigTypeTag(zcu)) { .array, .vector => {}, else => return sema.fail(block, block.nodeOffset(un_node.src_node), "expected array or vector type, found '{}'", .{vec_ty.fmt(pt)}), @@ -8702,10 +8655,7 @@ fn zirDeclLiteral(sema: *Sema, block: *Block, inst: Zir.Inst.Index, do_coerce: b .no_embedded_nulls, ); - const orig_ty = sema.resolveType(block, src, extra.lhs) catch |err| switch (err) { - error.GenericPoison => Type.generic_poison, - else => |e| return e, - }; + const orig_ty: Type = try sema.resolveTypeOrPoison(block, src, extra.lhs) orelse .generic_poison; const uncoerced_result = res: { if (orig_ty.toIntern() == .generic_poison_type) { @@ -9232,22 +9182,17 @@ fn zirFunc( var extra_index = extra.end; - const ret_ty: Type = switch (extra.data.ret_body_len) { + const ret_ty: Type = if (extra.data.ret_ty.is_generic) + .generic_poison + else switch (extra.data.ret_ty.body_len) { 0 => Type.void, 1 => blk: { const ret_ty_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]); extra_index += 1; - if (sema.resolveType(block, ret_ty_src, ret_ty_ref)) |ret_ty| { - break :blk ret_ty; - } else |err| switch (err) { - error.GenericPoison => { - break :blk Type.generic_poison; - }, - else => |e| return e, - } + break :blk try sema.resolveType(block, ret_ty_src, ret_ty_ref); }, else => blk: { - const ret_ty_body = sema.code.bodySlice(extra_index, extra.data.ret_body_len); + const ret_ty_body = sema.code.bodySlice(extra_index, extra.data.ret_ty.body_len); extra_index += ret_ty_body.len; const ret_ty_val = try sema.resolveGenericBody(block, ret_ty_src, ret_ty_body, inst, Type.type, .{ .simple = .function_ret_ty }); @@ -9319,32 +9264,16 @@ fn resolveGenericBody( ) !Value { assert(body.len != 0); - const err = err: { - // Make sure any nested param instructions don't clobber our work. - const prev_params = block.params; - const prev_no_partial_func_type = sema.no_partial_func_ty; - block.params = .{}; - sema.no_partial_func_ty = true; - defer { - block.params = prev_params; - sema.no_partial_func_ty = prev_no_partial_func_type; - } - - const uncasted = sema.resolveInlineBody(block, body, func_inst) catch |err| break :err err; - const result = sema.coerce(block, dest_ty, uncasted, src) catch |err| break :err err; - const val = sema.resolveConstDefinedValue(block, src, result, reason) catch |err| break :err err; - return val; - }; - switch (err) { - error.GenericPoison => { - if (dest_ty.toIntern() == .type_type) { - return Value.generic_poison_type; - } else { - return Value.generic_poison; - } - }, - else => |e| return e, + // Make sure any nested param instructions don't clobber our work. + const prev_params = block.params; + block.params = .{}; + defer { + block.params = prev_params; } + + const uncasted = try sema.resolveInlineBody(block, body, func_inst); + const result = try sema.coerce(block, dest_ty, uncasted, src); + return sema.resolveConstDefinedValue(block, src, result, reason); } /// Given a library name, examines if the library name should end up in @@ -9593,8 +9522,6 @@ fn funcCommon( const cc_src = block.src(.{ .node_offset_fn_type_cc = src_node_offset }); const func_src = block.nodeOffset(src_node_offset); - if (bare_return_type.isGenericPoison() and sema.no_partial_func_ty) return error.GenericPoison; - const ret_ty_requires_comptime = try bare_return_type.comptimeOnlySema(pt); var is_generic = bare_return_type.isGenericPoison() or ret_ty_requires_comptime; @@ -9611,9 +9538,6 @@ fn funcCommon( } }); const param_ty_comptime = try param_ty.comptimeOnlySema(pt); const param_ty_generic = param_ty.isGenericPoison(); - if (param_ty_generic and sema.no_partial_func_ty) { - return error.GenericPoison; - } if (param_is_comptime or param_ty_comptime or param_ty_generic) { is_generic = true; } @@ -9962,64 +9886,25 @@ fn zirParam( const src = block.tokenOffset(inst_data.src_tok); const extra = sema.code.extraData(Zir.Inst.Param, inst_data.payload_index); const param_name: Zir.NullTerminatedString = extra.data.name; - const body = sema.code.bodySlice(extra.end, extra.data.body_len); + const body = sema.code.bodySlice(extra.end, extra.data.type.body_len); - const param_ty = param_ty: { - const err = err: { - // Make sure any nested param instructions don't clobber our work. - const prev_params = block.params; - const prev_no_partial_func_type = sema.no_partial_func_ty; - block.params = .{}; - sema.no_partial_func_ty = true; - defer { - block.params = prev_params; - sema.no_partial_func_ty = prev_no_partial_func_type; - } - - if (sema.resolveInlineBody(block, body, inst)) |param_ty_inst| { - if (sema.analyzeAsType(block, src, param_ty_inst)) |param_ty| { - break :param_ty param_ty; - } else |err| break :err err; - } else |err| break :err err; - }; - switch (err) { - error.GenericPoison => { - // The type is not available until the generic instantiation. - // We result the param instruction with a poison value and - // insert an anytype parameter. - try block.params.append(sema.arena, .{ - .ty = .generic_poison_type, - .is_comptime = comptime_syntax, - .name = param_name, - }); - sema.inst_map.putAssumeCapacity(inst, .generic_poison); - return; - }, - else => |e| return e, + const param_ty: Type = if (extra.data.type.is_generic) .generic_poison else ty: { + // Make sure any nested param instructions don't clobber our work. + const prev_params = block.params; + block.params = .{}; + defer { + block.params = prev_params; } - }; - const is_comptime = try param_ty.comptimeOnlySema(sema.pt) or comptime_syntax; + const param_ty_inst = try sema.resolveInlineBody(block, body, inst); + break :ty try sema.analyzeAsType(block, src, param_ty_inst); + }; try block.params.append(sema.arena, .{ .ty = param_ty.toIntern(), .is_comptime = comptime_syntax, .name = param_name, }); - - if (is_comptime) { - // If this is a comptime parameter we can add a constant generic_poison - // since this is also a generic parameter. - sema.inst_map.putAssumeCapacity(inst, .generic_poison); - } else { - // Otherwise we need a dummy runtime instruction. - const result_index: Air.Inst.Index = @enumFromInt(sema.air_instructions.len); - try sema.air_instructions.append(sema.gpa, .{ - .tag = .alloc, - .data = .{ .ty = param_ty }, - }); - sema.inst_map.putAssumeCapacity(inst, result_index.toRef()); - } } fn zirParamAnytype( @@ -10031,14 +9916,11 @@ fn zirParamAnytype( const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].str_tok; const param_name: Zir.NullTerminatedString = inst_data.start; - // We are evaluating a generic function without any comptime args provided. - try block.params.append(sema.arena, .{ .ty = .generic_poison_type, .is_comptime = comptime_syntax, .name = param_name, }); - sema.inst_map.putAssumeCapacity(inst, .generic_poison); } fn zirAsNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -10072,24 +9954,11 @@ fn analyzeAs( const pt = sema.pt; const zcu = pt.zcu; const operand = try sema.resolveInst(zir_operand); - const operand_air_inst = sema.resolveInst(zir_dest_type) catch |err| switch (err) { - error.GenericPoison => return operand, - else => |e| return e, - }; - const dest_ty = sema.analyzeAsType(block, src, operand_air_inst) catch |err| switch (err) { - error.GenericPoison => return operand, - else => |e| return e, - }; - const dest_ty_tag = dest_ty.zigTypeTagOrPoison(zcu) catch |err| switch (err) { - error.GenericPoison => return operand, - }; - - if (dest_ty_tag == .@"opaque") { - return sema.fail(block, src, "cannot cast to opaque type '{}'", .{dest_ty.fmt(pt)}); - } - - if (dest_ty_tag == .noreturn) { - return sema.fail(block, src, "cannot cast to noreturn", .{}); + const dest_ty = try sema.resolveTypeOrPoison(block, src, zir_dest_type) orelse return operand; + switch (dest_ty.zigTypeTag(zcu)) { + .@"opaque" => return sema.fail(block, src, "cannot cast to opaque type '{}'", .{dest_ty.fmt(pt)}), + .noreturn => return sema.fail(block, src, "cannot cast to noreturn", .{}), + else => {}, } const is_ret = if (zir_dest_type.toIndex()) |ptr_index| @@ -15071,9 +14940,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai // and have a tuple, coerce the tuple immediately. no_coerce: { if (extra.res_ty == .none) break :no_coerce; - const res_ty_inst = try sema.resolveInst(extra.res_ty); - const res_ty = try sema.analyzeAsType(block, src, res_ty_inst); - if (res_ty.isGenericPoison()) break :no_coerce; + const res_ty = try sema.resolveTypeOrPoison(block, src, extra.res_ty) orelse break :no_coerce; if (!uncoerced_lhs_ty.isTuple(zcu)) break :no_coerce; const lhs_len = uncoerced_lhs_ty.structFieldCount(zcu); const lhs_dest_ty = switch (res_ty.zigTypeTag(zcu)) { @@ -15313,8 +15180,8 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins const rhs = try sema.resolveInst(extra.rhs); const lhs_ty = sema.typeOf(lhs); const rhs_ty = sema.typeOf(rhs); - const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(zcu); - const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(zcu); + const lhs_zig_ty_tag = lhs_ty.zigTypeTag(zcu); + const rhs_zig_ty_tag = rhs_ty.zigTypeTag(zcu); try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); try sema.checkInvalidPtrIntArithmetic(block, src, lhs_ty); @@ -15479,8 +15346,8 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const rhs = try sema.resolveInst(extra.rhs); const lhs_ty = sema.typeOf(lhs); const rhs_ty = sema.typeOf(rhs); - const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(zcu); - const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(zcu); + const lhs_zig_ty_tag = lhs_ty.zigTypeTag(zcu); + const rhs_zig_ty_tag = rhs_ty.zigTypeTag(zcu); try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); try sema.checkInvalidPtrIntArithmetic(block, src, lhs_ty); @@ -15645,8 +15512,8 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const rhs = try sema.resolveInst(extra.rhs); const lhs_ty = sema.typeOf(lhs); const rhs_ty = sema.typeOf(rhs); - const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(zcu); - const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(zcu); + const lhs_zig_ty_tag = lhs_ty.zigTypeTag(zcu); + const rhs_zig_ty_tag = rhs_ty.zigTypeTag(zcu); try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); try sema.checkInvalidPtrIntArithmetic(block, src, lhs_ty); @@ -15756,8 +15623,8 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const rhs = try sema.resolveInst(extra.rhs); const lhs_ty = sema.typeOf(lhs); const rhs_ty = sema.typeOf(rhs); - const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(zcu); - const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(zcu); + const lhs_zig_ty_tag = lhs_ty.zigTypeTag(zcu); + const rhs_zig_ty_tag = rhs_ty.zigTypeTag(zcu); try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); try sema.checkInvalidPtrIntArithmetic(block, src, lhs_ty); @@ -16000,8 +15867,8 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. const rhs = try sema.resolveInst(extra.rhs); const lhs_ty = sema.typeOf(lhs); const rhs_ty = sema.typeOf(rhs); - const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(zcu); - const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(zcu); + const lhs_zig_ty_tag = lhs_ty.zigTypeTag(zcu); + const rhs_zig_ty_tag = rhs_ty.zigTypeTag(zcu); try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); try sema.checkInvalidPtrIntArithmetic(block, src, lhs_ty); @@ -16186,8 +16053,8 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins const rhs = try sema.resolveInst(extra.rhs); const lhs_ty = sema.typeOf(lhs); const rhs_ty = sema.typeOf(rhs); - const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(zcu); - const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(zcu); + const lhs_zig_ty_tag = lhs_ty.zigTypeTag(zcu); + const rhs_zig_ty_tag = rhs_ty.zigTypeTag(zcu); try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); try sema.checkInvalidPtrIntArithmetic(block, src, lhs_ty); @@ -16282,8 +16149,8 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins const rhs = try sema.resolveInst(extra.rhs); const lhs_ty = sema.typeOf(lhs); const rhs_ty = sema.typeOf(rhs); - const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(zcu); - const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(zcu); + const lhs_zig_ty_tag = lhs_ty.zigTypeTag(zcu); + const rhs_zig_ty_tag = rhs_ty.zigTypeTag(zcu); try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); try sema.checkInvalidPtrIntArithmetic(block, src, lhs_ty); @@ -16623,8 +16490,8 @@ fn analyzeArithmetic( const zcu = pt.zcu; const lhs_ty = sema.typeOf(lhs); const rhs_ty = sema.typeOf(rhs); - const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(zcu); - const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(zcu); + const lhs_zig_ty_tag = lhs_ty.zigTypeTag(zcu); + const rhs_zig_ty_tag = rhs_ty.zigTypeTag(zcu); try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); if (lhs_zig_ty_tag == .pointer) { @@ -19028,9 +18895,7 @@ fn zirTypeofBuiltin(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr defer child_block.instructions.deinit(sema.gpa); const operand = try sema.resolveInlineBody(&child_block, body, inst); - const operand_ty = sema.typeOf(operand); - if (operand_ty.isGenericPoison()) return error.GenericPoison; - return Air.internedToRef(operand_ty.toIntern()); + return Air.internedToRef(sema.typeOf(operand).toIntern()); } fn zirTypeofLog2IntType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -20100,7 +19965,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air } return err; }; - if (ty.isGenericPoison()) return error.GenericPoison; + assert(!ty.isGenericPoison()); break :blk ty; }; @@ -20252,11 +20117,8 @@ fn zirStructInitEmptyResult(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is const zcu = pt.zcu; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; const src = block.nodeOffset(inst_data.src_node); - const ty_operand = sema.resolveType(block, src, inst_data.operand) catch |err| switch (err) { - // Generic poison means this is an untyped anonymous empty struct/array init - error.GenericPoison => return .empty_tuple, - else => |e| return e, - }; + // Generic poison means this is an untyped anonymous empty struct/array init + const ty_operand = try sema.resolveTypeOrPoison(block, src, inst_data.operand) orelse return .empty_tuple; const init_ty = if (is_byref) ty: { const ptr_ty = ty_operand.optEuBaseType(zcu); assert(ptr_ty.zigTypeTag(zcu) == .pointer); // validated by a previous instruction @@ -20410,12 +20272,9 @@ fn zirStructInit( const first_item = sema.code.extraData(Zir.Inst.StructInit.Item, extra.end).data; const first_field_type_data = zir_datas[@intFromEnum(first_item.field_type)].pl_node; const first_field_type_extra = sema.code.extraData(Zir.Inst.FieldType, first_field_type_data.payload_index).data; - const result_ty = sema.resolveType(block, src, first_field_type_extra.container_type) catch |err| switch (err) { - error.GenericPoison => { - // The type wasn't actually known, so treat this as an anon struct init. - return sema.structInitAnon(block, src, inst, .typed_init, extra.data, extra.end, is_ref); - }, - else => |e| return e, + const result_ty = try sema.resolveTypeOrPoison(block, src, first_field_type_extra.container_type) orelse { + // The type wasn't actually known, so treat this as an anon struct init. + return sema.structInitAnon(block, src, inst, .typed_init, extra.data, extra.end, is_ref); }; const resolved_ty = result_ty.optEuBaseType(zcu); try resolved_ty.resolveLayout(pt); @@ -20932,12 +20791,9 @@ fn zirArrayInit( const args = sema.code.refSlice(extra.end, extra.data.operands_len); assert(args.len >= 2); // array_ty + at least one element - const result_ty = sema.resolveType(block, src, args[0]) catch |err| switch (err) { - error.GenericPoison => { - // The type wasn't actually known, so treat this as an anon array init. - return sema.arrayInitAnon(block, src, args[1..], is_ref); - }, - else => |e| return e, + const result_ty = try sema.resolveTypeOrPoison(block, src, args[0]) orelse { + // The type wasn't actually known, so treat this as an anon array init. + return sema.arrayInitAnon(block, src, args[1..], is_ref); }; const array_ty = result_ty.optEuBaseType(zcu); const is_tuple = array_ty.zigTypeTag(zcu) == .@"struct"; @@ -21185,14 +21041,7 @@ fn zirStructInitFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp const extra = sema.code.extraData(Zir.Inst.FieldType, inst_data.payload_index).data; const ty_src = block.nodeOffset(inst_data.src_node); const field_name_src = block.src(.{ .node_offset_field_name_init = inst_data.src_node }); - const wrapped_aggregate_ty = sema.resolveType(block, ty_src, extra.container_type) catch |err| switch (err) { - // Since this is a ZIR instruction that returns a type, encountering - // generic poison should not result in a failed compilation, but the - // generic poison type. This prevents unnecessary failures when - // constructing types at compile-time. - error.GenericPoison => return .generic_poison_type, - else => |e| return e, - }; + const wrapped_aggregate_ty = try sema.resolveTypeOrPoison(block, ty_src, extra.container_type) orelse return .generic_poison_type; const aggregate_ty = wrapped_aggregate_ty.optEuBaseType(zcu); const zir_field_name = sema.code.nullTerminatedString(extra.name_start); const field_name = try ip.getOrPutString(sema.gpa, pt.tid, zir_field_name, .no_embedded_nulls); @@ -24068,7 +23917,7 @@ fn checkNamespaceType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) Com fn checkIntType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool { const pt = sema.pt; const zcu = pt.zcu; - switch (try ty.zigTypeTagOrPoison(zcu)) { + switch (ty.zigTypeTag(zcu)) { .comptime_int => return true, .int => return false, else => return sema.fail(block, src, "expected integer type, found '{}'", .{ty.fmt(pt)}), @@ -24083,7 +23932,7 @@ fn checkInvalidPtrIntArithmetic( ) CompileError!void { const pt = sema.pt; const zcu = pt.zcu; - switch (try ty.zigTypeTagOrPoison(zcu)) { + switch (ty.zigTypeTag(zcu)) { .pointer => switch (ty.ptrSize(zcu)) { .one, .slice => return, .many, .c => return sema.failWithInvalidPtrArithmetic(block, src, "pointer-integer", "addition and subtraction"), @@ -24266,7 +24115,7 @@ fn checkAtomicPtrOperand( }; const ptr_ty = sema.typeOf(ptr); - const ptr_data = switch (try ptr_ty.zigTypeTagOrPoison(zcu)) { + const ptr_data = switch (ptr_ty.zigTypeTag(zcu)) { .pointer => ptr_ty.ptrInfo(zcu), else => { const wanted_ptr_ty = try pt.ptrTypeSema(wanted_ptr_data); @@ -24307,11 +24156,11 @@ fn checkIntOrVector( const pt = sema.pt; const zcu = pt.zcu; const operand_ty = sema.typeOf(operand); - switch (try operand_ty.zigTypeTagOrPoison(zcu)) { + switch (operand_ty.zigTypeTag(zcu)) { .int => return operand_ty, .vector => { const elem_ty = operand_ty.childType(zcu); - switch (try elem_ty.zigTypeTagOrPoison(zcu)) { + switch (elem_ty.zigTypeTag(zcu)) { .int => return elem_ty, else => return sema.fail(block, operand_src, "expected vector of integers; found vector of '{}'", .{ elem_ty.fmt(pt), @@ -24332,11 +24181,11 @@ fn checkIntOrVectorAllowComptime( ) CompileError!Type { const pt = sema.pt; const zcu = pt.zcu; - switch (try operand_ty.zigTypeTagOrPoison(zcu)) { + switch (operand_ty.zigTypeTag(zcu)) { .int, .comptime_int => return operand_ty, .vector => { const elem_ty = operand_ty.childType(zcu); - switch (try elem_ty.zigTypeTagOrPoison(zcu)) { + switch (elem_ty.zigTypeTag(zcu)) { .int, .comptime_int => return elem_ty, else => return sema.fail(block, operand_src, "expected vector of integers; found vector of '{}'", .{ elem_ty.fmt(pt), @@ -24406,8 +24255,8 @@ fn checkVectorizableBinaryOperands( ) CompileError!void { const pt = sema.pt; const zcu = pt.zcu; - const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(zcu); - const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(zcu); + const lhs_zig_ty_tag = lhs_ty.zigTypeTag(zcu); + const rhs_zig_ty_tag = rhs_ty.zigTypeTag(zcu); if (lhs_zig_ty_tag != .vector and rhs_zig_ty_tag != .vector) return; const lhs_is_vector = switch (lhs_zig_ty_tag) { @@ -24987,7 +24836,7 @@ fn zirSelect(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C const pred_uncoerced = try sema.resolveInst(extra.pred); const pred_ty = sema.typeOf(pred_uncoerced); - const vec_len_u64 = switch (try pred_ty.zigTypeTagOrPoison(zcu)) { + const vec_len_u64 = switch (pred_ty.zigTypeTag(zcu)) { .vector, .array => pred_ty.arrayLen(zcu), else => return sema.fail(block, pred_src, "expected vector or array, found '{}'", .{pred_ty.fmt(pt)}), }; @@ -26306,7 +26155,9 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A break :cc .auto; }; - const ret_ty: Type = if (extra.data.bits.has_ret_ty_body) blk: { + const ret_ty: Type = if (extra.data.bits.ret_ty_is_generic) + .generic_poison + else if (extra.data.bits.has_ret_ty_body) blk: { const body_len = sema.code.extra[extra_index]; extra_index += 1; const body = sema.code.bodySlice(extra_index, body_len); @@ -26318,14 +26169,8 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A } else if (extra.data.bits.has_ret_ty_ref) blk: { const ret_ty_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]); extra_index += 1; - const ret_ty_air_ref = sema.resolveInst(ret_ty_ref) catch |err| switch (err) { - error.GenericPoison => break :blk Type.generic_poison, - else => |e| return e, - }; - const ret_ty_val = sema.resolveConstDefinedValue(block, ret_src, ret_ty_air_ref, .{ .simple = .function_ret_ty }) catch |err| switch (err) { - error.GenericPoison => break :blk Type.generic_poison, - else => |e| return e, - }; + const ret_ty_air_ref = try sema.resolveInst(ret_ty_ref); + const ret_ty_val = try sema.resolveConstDefinedValue(block, ret_src, ret_ty_air_ref, .{ .simple = .function_ret_ty }); break :blk ret_ty_val.toType(); } else Type.void; @@ -27625,7 +27470,7 @@ fn fieldVal( const val = (try sema.resolveDefinedValue(block, object_src, dereffed_type)).?; const child_type = val.toType(); - switch (try child_type.zigTypeTagOrPoison(zcu)) { + switch (child_type.zigTypeTag(zcu)) { .error_set => { switch (ip.indexToKey(child_type.toIntern())) { .error_set_type => |error_set_type| blk: { @@ -35180,7 +35025,7 @@ pub fn resolveStructLayout(sema: *Sema, ty: Type) SemaError!void { if (struct_type.layout == .@"packed") { sema.backingIntType(struct_type) catch |err| switch (err) { error.OutOfMemory, error.AnalysisFail => |e| return e, - error.ComptimeBreak, error.ComptimeReturn, error.GenericPoison => unreachable, + error.ComptimeBreak, error.ComptimeReturn => unreachable, }; return; } @@ -35688,7 +35533,7 @@ pub fn resolveStructFieldTypes( sema.structFields(struct_type) catch |err| switch (err) { error.AnalysisFail, error.OutOfMemory => |e| return e, - error.ComptimeBreak, error.ComptimeReturn, error.GenericPoison => unreachable, + error.ComptimeBreak, error.ComptimeReturn => unreachable, }; } @@ -35717,7 +35562,7 @@ pub fn resolveStructFieldInits(sema: *Sema, ty: Type) SemaError!void { sema.structFieldInits(struct_type) catch |err| switch (err) { error.AnalysisFail, error.OutOfMemory => |e| return e, - error.ComptimeBreak, error.ComptimeReturn, error.GenericPoison => unreachable, + error.ComptimeBreak, error.ComptimeReturn => unreachable, }; struct_type.setHaveFieldInits(ip); } @@ -35751,7 +35596,7 @@ pub fn resolveUnionFieldTypes(sema: *Sema, ty: Type, union_type: InternPool.Load errdefer union_type.setStatus(ip, .none); sema.unionFields(ty.toIntern(), union_type) catch |err| switch (err) { error.AnalysisFail, error.OutOfMemory => |e| return e, - error.ComptimeBreak, error.ComptimeReturn, error.GenericPoison => unreachable, + error.ComptimeBreak, error.ComptimeReturn => unreachable, }; union_type.setStatus(ip, .have_field_types); } @@ -36078,9 +35923,6 @@ fn structFields( const ty_ref = try sema.resolveInlineBody(&block_scope, body, zir_index); break :ty try sema.analyzeAsType(&block_scope, ty_src, ty_ref); }; - if (field_ty.isGenericPoison()) { - return error.GenericPoison; - } struct_type.field_types.get(ip)[field_i] = field_ty.toIntern(); @@ -36523,10 +36365,6 @@ fn unionFields( else try sema.resolveType(&block_scope, type_src, field_type_ref); - if (field_ty.isGenericPoison()) { - return error.GenericPoison; - } - if (explicit_tags_seen.len > 0) { const tag_ty = union_type.tagTypeUnordered(ip); const tag_info = ip.loadEnumType(tag_ty); @@ -36779,7 +36617,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { .null_type => Value.null, .undefined_type => Value.undef, .optional_noreturn_type => try pt.nullValue(ty), - .generic_poison_type => error.GenericPoison, + .generic_poison_type => unreachable, .empty_tuple_type => Value.empty_tuple, // values, not types .undef, @@ -36797,7 +36635,6 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { .bool_true, .bool_false, .empty_tuple, - .generic_poison, // invalid .none, => unreachable, @@ -38095,7 +37932,6 @@ fn notePathToComptimeAllocPtr(sema: *Sema, msg: *Zcu.ErrorMsg, src: LazySrcLoc, ) catch |err| switch (err) { error.OutOfMemory => |e| return e, error.AnalysisFail => unreachable, - error.GenericPoison => unreachable, error.ComptimeReturn => unreachable, error.ComptimeBreak => unreachable, }; @@ -38410,7 +38246,6 @@ pub fn resolveDeclaredEnum( zir, body_end, ) catch |err| switch (err) { - error.GenericPoison => unreachable, error.ComptimeBreak => unreachable, error.ComptimeReturn => unreachable, error.OutOfMemory => |e| return e, diff --git a/src/Type.zig b/src/Type.zig index b628e0c60e4d..0e6ccfa58550 100644 --- a/src/Type.zig +++ b/src/Type.zig @@ -22,11 +22,7 @@ const SemaError = Zcu.SemaError; ip_index: InternPool.Index, pub fn zigTypeTag(ty: Type, zcu: *const Zcu) std.builtin.TypeId { - return ty.zigTypeTagOrPoison(zcu) catch unreachable; -} - -pub fn zigTypeTagOrPoison(ty: Type, zcu: *const Zcu) error{GenericPoison}!std.builtin.TypeId { - return zcu.intern_pool.zigTypeTagOrPoison(ty.toIntern()); + return zcu.intern_pool.zigTypeTag(ty.toIntern()); } pub fn baseZigTypeTag(self: Type, mod: *Zcu) std.builtin.TypeId { @@ -2503,14 +2499,16 @@ pub fn fnCallingConvention(ty: Type, zcu: *const Zcu) std.builtin.CallingConvent } pub fn isValidParamType(self: Type, zcu: *const Zcu) bool { - return switch (self.zigTypeTagOrPoison(zcu) catch return true) { + if (self.toIntern() == .generic_poison_type) return true; + return switch (self.zigTypeTag(zcu)) { .@"opaque", .noreturn => false, else => true, }; } pub fn isValidReturnType(self: Type, zcu: *const Zcu) bool { - return switch (self.zigTypeTagOrPoison(zcu) catch return true) { + if (self.toIntern() == .generic_poison_type) return true; + return switch (self.zigTypeTag(zcu)) { .@"opaque" => false, else => true, }; @@ -3784,7 +3782,6 @@ pub fn resolveFields(ty: Type, pt: Zcu.PerThread) SemaError!void { .bool_true => unreachable, .bool_false => unreachable, .empty_tuple => unreachable, - .generic_poison => unreachable, else => switch (ty_ip.unwrap(ip).getTag(ip)) { .type_struct, diff --git a/src/Value.zig b/src/Value.zig index 828ad051c828..c8ae997d9823 100644 --- a/src/Value.zig +++ b/src/Value.zig @@ -3673,10 +3673,6 @@ pub fn hasRepeatedByteRepr(val: Value, pt: Zcu.PerThread) !?u8 { return first_byte; } -pub fn isGenericPoison(val: Value) bool { - return val.toIntern() == .generic_poison; -} - pub fn typeOf(val: Value, zcu: *const Zcu) Type { return Type.fromInterned(zcu.intern_pool.typeOf(val.toIntern())); } @@ -3709,7 +3705,6 @@ pub const @"false": Value = .{ .ip_index = .bool_false }; pub const @"true": Value = .{ .ip_index = .bool_true }; pub const @"unreachable": Value = .{ .ip_index = .unreachable_value }; -pub const generic_poison: Value = .{ .ip_index = .generic_poison }; pub const generic_poison_type: Value = .{ .ip_index = .generic_poison_type }; pub const empty_tuple: Value = .{ .ip_index = .empty_tuple }; diff --git a/src/Zcu.zig b/src/Zcu.zig index 54f4349a6eaa..8f3525350998 100644 --- a/src/Zcu.zig +++ b/src/Zcu.zig @@ -2404,10 +2404,6 @@ pub const CompileError = error{ OutOfMemory, /// When this is returned, the compile error for the failure has already been recorded. AnalysisFail, - /// A Type or Value was needed to be used during semantic analysis, but it was not available - /// because the function is generic. This is only seen when analyzing the body of a param - /// instruction. - GenericPoison, /// In a comptime scope, a return instruction was encountered. This error is only seen when /// doing a comptime function call. ComptimeReturn, diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig index 6231ca29fd80..d7ec7ccea84a 100644 --- a/src/Zcu/PerThread.zig +++ b/src/Zcu/PerThread.zig @@ -627,7 +627,6 @@ pub fn ensureMemoizedStateUpToDate(pt: Zcu.PerThread, stage: InternPool.Memoized // TODO: same as for `ensureComptimeUnitUpToDate` etc return error.OutOfMemory; }, - error.GenericPoison => unreachable, error.ComptimeReturn => unreachable, error.ComptimeBreak => unreachable, }; @@ -781,7 +780,6 @@ pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeU // for reporting OOM errors without allocating. return error.OutOfMemory; }, - error.GenericPoison => unreachable, error.ComptimeReturn => unreachable, error.ComptimeBreak => unreachable, }; @@ -967,7 +965,6 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu // for reporting OOM errors without allocating. return error.OutOfMemory; }, - error.GenericPoison => unreachable, error.ComptimeReturn => unreachable, error.ComptimeBreak => unreachable, }; @@ -1168,7 +1165,6 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr }; switch (nav_val.toIntern()) { - .generic_poison => unreachable, // assertion failure .unreachable_value => unreachable, // assertion failure else => {}, } @@ -1347,7 +1343,6 @@ pub fn ensureNavTypeUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zc // for reporting OOM errors without allocating. return error.OutOfMemory; }, - error.GenericPoison => unreachable, error.ComptimeReturn => unreachable, error.ComptimeBreak => unreachable, }; @@ -2665,7 +2660,6 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE runtime_param_index += 1; const opt_opv = sema.typeHasOnePossibleValue(Type.fromInterned(param_ty)) catch |err| switch (err) { - error.GenericPoison => unreachable, error.ComptimeReturn => unreachable, error.ComptimeBreak => unreachable, else => |e| return e, @@ -2698,7 +2692,6 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE inner_block.error_return_trace_index = error_return_trace_index; sema.analyzeFnBody(&inner_block, fn_info.body) catch |err| switch (err) { - error.GenericPoison => unreachable, error.ComptimeReturn => unreachable, else => |e| return e, }; @@ -2720,7 +2713,6 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE !sema.fn_ret_ty.isError(zcu)) { sema.setupErrorReturnTrace(&inner_block, last_arg_index) catch |err| switch (err) { - error.GenericPoison => unreachable, error.ComptimeReturn => unreachable, error.ComptimeBreak => unreachable, else => |e| return e, @@ -2744,7 +2736,6 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE .base_node_inst = inner_block.src_base_inst, .offset = Zcu.LazySrcLoc.Offset.nodeOffset(0), }, ies) catch |err| switch (err) { - error.GenericPoison => unreachable, error.ComptimeReturn => unreachable, error.ComptimeBreak => unreachable, else => |e| return e, @@ -2763,7 +2754,6 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE // TODO: this can go away once we fix backends having to resolve `StackTrace`. // The codegen timing guarantees that the parameter types will be populated. sema.resolveFnTypes(fn_ty, inner_block.nodeOffset(0)) catch |err| switch (err) { - error.GenericPoison => unreachable, error.ComptimeReturn => unreachable, error.ComptimeBreak => unreachable, else => |e| return e, diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 8b32fe1d7ab3..14bc0b2e88b7 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -3170,7 +3170,6 @@ fn lowerConstant(cg: *CodeGen, val: Value, ty: Type) InnerError!WValue { .null, .empty_tuple, .@"unreachable", - .generic_poison, => unreachable, // non-runtime values .false, .true => return .{ .imm32 = switch (simple_value) { .false => 0, diff --git a/src/codegen.zig b/src/codegen.zig index dd3b874bc0d9..6d054f6b012a 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -229,7 +229,6 @@ pub fn generateSymbol( .void => unreachable, // non-runtime value .null => unreachable, // non-runtime value .@"unreachable" => unreachable, // non-runtime value - .generic_poison => unreachable, // non-runtime value .empty_tuple => return, .false, .true => try code.append(gpa, switch (simple_value) { .false => 0, diff --git a/src/codegen/c.zig b/src/codegen/c.zig index bbb06ae06fb4..5364b0432dd1 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -968,7 +968,6 @@ pub const DeclGen = struct { .null => unreachable, .empty_tuple => unreachable, .@"unreachable" => unreachable, - .generic_poison => unreachable, .false => try writer.writeAll("false"), .true => try writer.writeAll("true"), diff --git a/src/codegen/c/Type.zig b/src/codegen/c/Type.zig index 20ba8fe6c0c0..2673576b90f6 100644 --- a/src/codegen/c/Type.zig +++ b/src/codegen/c/Type.zig @@ -1451,7 +1451,6 @@ pub const Pool = struct { .bool_true, .bool_false, .empty_tuple, - .generic_poison, .none, => unreachable, diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 43558a9f1d77..89595f0f5c03 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -3372,7 +3372,6 @@ pub const Object = struct { .bool_true, .bool_false, .empty_tuple, - .generic_poison, .none, => unreachable, else => switch (ip.indexToKey(t.toIntern())) { @@ -3923,7 +3922,6 @@ pub const Object = struct { .null => unreachable, // non-runtime value .empty_tuple => unreachable, // non-runtime value .@"unreachable" => unreachable, // non-runtime value - .generic_poison => unreachable, // non-runtime value .false => .false, .true => .true, diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index ceb9c46b1ba3..e9322a9d7095 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -941,7 +941,6 @@ const NavGen = struct { .null, .empty_tuple, .@"unreachable", - .generic_poison, => unreachable, // non-runtime values .false, .true => break :cache try self.constBool(val.toBool(), repr), diff --git a/src/print_value.zig b/src/print_value.zig index bb84880745a5..0bd5bcee231f 100644 --- a/src/print_value.zig +++ b/src/print_value.zig @@ -84,7 +84,6 @@ pub fn print( .simple_value => |simple_value| switch (simple_value) { .void => try writer.writeAll("{}"), .empty_tuple => try writer.writeAll(".{}"), - .generic_poison => try writer.writeAll("(generic poison)"), else => try writer.writeAll(@tagName(simple_value)), }, .variable => try writer.writeAll("(variable)"), diff --git a/src/print_zir.zig b/src/print_zir.zig index 9fe3f563ca94..afa94f40ed3a 100644 --- a/src/print_zir.zig +++ b/src/print_zir.zig @@ -948,11 +948,13 @@ const Writer = struct { fn writeParam(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_tok; const extra = self.code.extraData(Zir.Inst.Param, inst_data.payload_index); - const body = self.code.bodySlice(extra.end, extra.data.body_len); + const body = self.code.bodySlice(extra.end, extra.data.type.body_len); try stream.print("\"{}\", ", .{ std.zig.fmtEscapes(self.code.nullTerminatedString(extra.data.name)), }); + if (extra.data.type.is_generic) try stream.writeAll("[generic] "); + try self.writeBracedBody(stream, body); try stream.writeAll(") "); try self.writeSrcTok(stream, inst_data.src_tok); @@ -2283,7 +2285,7 @@ const Writer = struct { var ret_ty_ref: Zir.Inst.Ref = .none; var ret_ty_body: []const Zir.Inst.Index = &.{}; - switch (extra.data.ret_body_len) { + switch (extra.data.ret_ty.body_len) { 0 => { ret_ty_ref = .void_type; }, @@ -2292,7 +2294,7 @@ const Writer = struct { extra_index += 1; }, else => { - ret_ty_body = self.code.bodySlice(extra_index, extra.data.ret_body_len); + ret_ty_body = self.code.bodySlice(extra_index, extra.data.ret_ty.body_len); extra_index += ret_ty_body.len; }, } @@ -2314,6 +2316,7 @@ const Writer = struct { &.{}, ret_ty_ref, ret_ty_body, + extra.data.ret_ty.is_generic, body, inst_data.src_node, @@ -2373,6 +2376,7 @@ const Writer = struct { cc_body, ret_ty_ref, ret_ty_body, + extra.data.bits.ret_ty_is_generic, body, inst_data.src_node, src_locs, @@ -2532,12 +2536,14 @@ const Writer = struct { cc_body: []const Zir.Inst.Index, ret_ty_ref: Zir.Inst.Ref, ret_ty_body: []const Zir.Inst.Index, + ret_ty_is_generic: bool, body: []const Zir.Inst.Index, src_node: i32, src_locs: Zir.Inst.Func.SrcLocs, noalias_bits: u32, ) !void { try self.writeOptionalInstRefOrBody(stream, "cc=", cc_ref, cc_body); + if (ret_ty_is_generic) try stream.writeAll("[generic] "); try self.writeOptionalInstRefOrBody(stream, "ret_ty=", ret_ty_ref, ret_ty_body); try self.writeFlag(stream, "vargs, ", var_args); try self.writeFlag(stream, "inferror, ", inferred_error_set); diff --git a/test/behavior/fn.zig b/test/behavior/fn.zig index 975b0e9baa3e..6cf0f1579500 100644 --- a/test/behavior/fn.zig +++ b/test/behavior/fn.zig @@ -672,3 +672,42 @@ test "function parameter self equality" { try expect(!S.greaterThan(42)); try expect(S.greaterThanOrEqual(42)); } + +test "inline call propagates comptime-known argument to generic parameter and return types" { + const S = struct { + inline fn f(x: bool, y: if (x) u8 else u16) if (x) bool else u32 { + if (x) { + comptime assert(@TypeOf(y) == u8); + return y == 0; + } else { + comptime assert(@TypeOf(y) == u16); + return y * 10; + } + } + fn g(x: bool, y: if (x) u8 else u16) if (x) bool else u32 { + if (x) { + comptime assert(@TypeOf(y) == u8); + return y == 0; + } else { + comptime assert(@TypeOf(y) == u16); + return y * 10; + } + } + }; + + const a0 = S.f(true, 200); // false + const a1 = S.f(false, 1234); // 12340 + + const b0 = @call(.always_inline, S.g, .{ true, 200 }); // false + const b1 = @call(.always_inline, S.g, .{ false, 1234 }); // 12340 + + comptime assert(@TypeOf(a0) == bool); + comptime assert(@TypeOf(b0) == bool); + try expect(a0 == false); + try expect(b0 == false); + + comptime assert(@TypeOf(a1) == u32); + comptime assert(@TypeOf(b1) == u32); + try expect(a1 == 12340); + try expect(b1 == 12340); +} diff --git a/test/cases/compile_errors/anytype_param_requires_comptime.zig b/test/cases/compile_errors/anytype_param_requires_comptime.zig index 94a08ac1194b..6ddfafc91616 100644 --- a/test/cases/compile_errors/anytype_param_requires_comptime.zig +++ b/test/cases/compile_errors/anytype_param_requires_comptime.zig @@ -15,6 +15,6 @@ pub export fn entry() void { // error // // :7:25: error: unable to resolve comptime value -// :7:25: note: initializer of comptime-only struct 'tmp.S.foo__anon_166.C' must be comptime-known +// :7:25: note: initializer of comptime-only struct 'tmp.S.foo__anon_165.C' must be comptime-known // :4:16: note: struct requires comptime because of this field // :4:16: note: types are not available at runtime diff --git a/test/cases/compile_errors/bogus_method_call_on_slice.zig b/test/cases/compile_errors/bogus_method_call_on_slice.zig index b796f6dd363e..089573b11c8d 100644 --- a/test/cases/compile_errors/bogus_method_call_on_slice.zig +++ b/test/cases/compile_errors/bogus_method_call_on_slice.zig @@ -13,10 +13,8 @@ pub export fn entry2() void { } // error -// backend=stage2 -// target=native // // :3:6: error: no field or member function named 'copy' in '[]const u8' // :9:8: error: no field or member function named 'bar' in '@TypeOf(.{})' -// :12:18: error: no field or member function named 'bar' in 'tmp.entry2__struct_170' +// :12:18: error: no field or member function named 'bar' in 'tmp.entry2__struct_169' // :12:6: note: struct declared here diff --git a/test/cases/compile_errors/coerce_anon_struct.zig b/test/cases/compile_errors/coerce_anon_struct.zig index 84e3c732c802..f56591932d84 100644 --- a/test/cases/compile_errors/coerce_anon_struct.zig +++ b/test/cases/compile_errors/coerce_anon_struct.zig @@ -6,6 +6,6 @@ export fn foo() void { // error // -// :4:16: error: expected type 'tmp.T', found 'tmp.foo__struct_159' +// :4:16: error: expected type 'tmp.T', found 'tmp.foo__struct_158' // :3:16: note: struct declared here // :1:11: note: struct declared here diff --git a/test/cases/compile_errors/non-comptime-parameter-used-as-array-size.zig b/test/cases/compile_errors/non-comptime-parameter-used-as-array-size.zig index f5eba9ee62a0..65b2886d076e 100644 --- a/test/cases/compile_errors/non-comptime-parameter-used-as-array-size.zig +++ b/test/cases/compile_errors/non-comptime-parameter-used-as-array-size.zig @@ -8,7 +8,7 @@ export fn entry() void { fn makeLlamas(count: usize) [count]u8 {} // error -// target=native // // :8:30: error: unable to resolve comptime value // :8:30: note: array length must be comptime-known +// :2:31: note: called from here