Commit 0ec6b2dd88
Changed files (23)
lib
std
src
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();
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{
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,
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,
src/codegen/c/Type.zig
@@ -1451,7 +1451,6 @@ pub const Pool = struct {
.bool_true,
.bool_false,
.empty_tuple,
- .generic_poison,
.none,
=> unreachable,
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"),
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,
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),
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,
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.
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,
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,
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)"),
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);
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,
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,
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 };
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,
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);
+}
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
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
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
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