Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
189 changes: 104 additions & 85 deletions src/Sema.zig
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ gpa: Allocator,
arena: Allocator,
code: Zir,
air_instructions: std.MultiArrayList(Air.Inst) = .{},
air_extra: std.ArrayListUnmanaged(u32) = .empty,
air_extra: std.ArrayList(u32) = .empty,
/// Maps ZIR to AIR.
inst_map: InstMap = .{},
/// The "owner" of a `Sema` represents the root "thing" that is being analyzed.
Expand Down Expand Up @@ -111,11 +111,11 @@ maybe_comptime_allocs: std.AutoHashMapUnmanaged(Air.Inst.Index, MaybeComptimeAll
/// stored as elements of this array.
/// Pointers to such memory are represented via an index into this array.
/// Backed by gpa.
comptime_allocs: std.ArrayListUnmanaged(ComptimeAlloc) = .empty,
comptime_allocs: std.ArrayList(ComptimeAlloc) = .empty,

/// A list of exports performed by this analysis. After this `Sema` terminates,
/// these are flushed to `Zcu.single_exports` or `Zcu.multi_exports`.
exports: std.ArrayListUnmanaged(Zcu.Export) = .empty,
exports: std.ArrayList(Zcu.Export) = .empty,

/// All references registered so far by this `Sema`. This is a temporary duplicate
/// of data stored in `Zcu.all_references`. It exists to avoid adding references to
Expand Down Expand Up @@ -343,7 +343,7 @@ pub const Block = struct {
/// The namespace to use for lookups from this source block
namespace: InternPool.NamespaceIndex,
/// The AIR instructions generated for this block.
instructions: std.ArrayListUnmanaged(Air.Inst.Index),
instructions: std.ArrayList(Air.Inst.Index),
// `param` instructions are collected here to be used by the `func` instruction.
/// When doing a generic function instantiation, this array collects a type
/// for each *runtime-known* parameter. This array corresponds to the instance
Expand Down Expand Up @@ -475,23 +475,23 @@ pub const Block = struct {
block_inst: Air.Inst.Index,
/// Separate array list from break_inst_list so that it can be passed directly
/// to resolvePeerTypes.
results: std.ArrayListUnmanaged(Air.Inst.Ref),
results: std.ArrayList(Air.Inst.Ref),
/// Keeps track of the break instructions so that the operand can be replaced
/// if we need to add type coercion at the end of block analysis.
/// Same indexes, capacity, length as `results`.
br_list: std.ArrayListUnmanaged(Air.Inst.Index),
br_list: std.ArrayList(Air.Inst.Index),
/// Keeps the source location of the rhs operand of the break instruction,
/// to enable more precise compile errors.
/// Same indexes, capacity, length as `results`.
src_locs: std.ArrayListUnmanaged(?LazySrcLoc),
src_locs: std.ArrayList(?LazySrcLoc),
/// Most blocks do not utilize this field. When it is used, its use is
/// contextual. The possible uses are as follows:
/// * for a `switch_block[_ref]`, this refers to dummy `br` instructions
/// which correspond to `switch_continue` ZIR. The switch logic will
/// rewrite these to appropriate AIR switch dispatches.
extra_insts: std.ArrayListUnmanaged(Air.Inst.Index) = .empty,
extra_insts: std.ArrayList(Air.Inst.Index) = .empty,
/// Same indexes, capacity, length as `extra_insts`.
extra_src_locs: std.ArrayListUnmanaged(LazySrcLoc) = .empty,
extra_src_locs: std.ArrayList(LazySrcLoc) = .empty,

pub fn deinit(merges: *@This(), allocator: Allocator) void {
merges.results.deinit(allocator);
Expand Down Expand Up @@ -985,7 +985,7 @@ const InferredAlloc = struct {
/// is known. These should be rewritten to perform any required coercions
/// when the type is resolved.
/// Allocated from `sema.arena`.
prongs: std.ArrayListUnmanaged(Air.Inst.Index) = .empty,
prongs: std.ArrayList(Air.Inst.Index) = .empty,
};

pub fn deinit(sema: *Sema) void {
Expand Down Expand Up @@ -7502,8 +7502,8 @@ fn analyzeCall(

// This may be an overestimate, but it's definitely sufficient.
const max_runtime_args = args_info.count() - @popCount(func_ty_info.comptime_bits);
var runtime_args: std.ArrayListUnmanaged(Air.Inst.Ref) = try .initCapacity(arena, max_runtime_args);
var runtime_param_tys: std.ArrayListUnmanaged(InternPool.Index) = try .initCapacity(arena, max_runtime_args);
var runtime_args: std.ArrayList(Air.Inst.Ref) = try .initCapacity(arena, max_runtime_args);
var runtime_param_tys: std.ArrayList(InternPool.Index) = try .initCapacity(arena, max_runtime_args);

const comptime_args = try arena.alloc(InternPool.Index, args_info.count());

Expand Down Expand Up @@ -11000,22 +11000,41 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp
break :blk err_capture_inst;
} else undefined;

var case_vals = try std.ArrayListUnmanaged(Air.Inst.Ref).initCapacity(gpa, scalar_cases_len + 2 * multi_cases_len);
var case_vals: std.ArrayList(Air.Inst.Ref) = try .initCapacity(gpa, scalar_cases_len + 2 * multi_cases_len);
defer case_vals.deinit(gpa);

const operand_ty = sema.typeOf(raw_operand_val);
const operand_err_union_ty = if (extra.data.bits.payload_is_ref)
operand_ty.childType(zcu)
else
operand_ty;

if (operand_err_union_ty.zigTypeTag(zcu) != .error_union) {
return sema.fail(block, switch_src, "expected error union type, found '{f}'", .{
operand_ty.fmt(pt),
});
}

const operand_err_set_ty = operand_err_union_ty.errorUnionSet(zcu);
const operand_payload_ty = operand_err_union_ty.errorUnionPayload(zcu);

const NonError = struct {
body: []const Zir.Inst.Index,
end: usize,
capture: Zir.Inst.SwitchBlock.ProngInfo.Capture,
};

const non_error_case: NonError = non_error: {
const non_error_case: ?NonError, const non_err_case_end: usize = non_error: {
const info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(sema.code.extra[header_extra_index]);
const extra_body_start = header_extra_index + 1;
const non_err_case_end = extra_body_start + info.body_len;
break :non_error .{
.body = sema.code.bodySlice(extra_body_start, info.body_len),
.end = extra_body_start + info.body_len,
.capture = info.capture,
if (operand_payload_ty.isNoReturn(zcu)) null else .{
.body = sema.code.bodySlice(extra_body_start, info.body_len),
.end = non_err_case_end,
.capture = info.capture,
},
non_err_case_end,
};
};

Expand All @@ -11028,12 +11047,12 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp

const else_case: Else = if (!extra.data.bits.has_else) .{
.body = &.{},
.end = non_error_case.end,
.end = non_err_case_end,
.is_inline = false,
.has_capture = false,
} else special: {
const info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(sema.code.extra[non_error_case.end]);
const extra_body_start = non_error_case.end + 1;
const info: Zir.Inst.SwitchBlock.ProngInfo = @bitCast(sema.code.extra[non_err_case_end]);
const extra_body_start = non_err_case_end + 1;
assert(info.capture != .by_ref);
assert(!info.has_tag_capture);
break :special .{
Expand All @@ -11047,20 +11066,6 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp
var seen_errors = SwitchErrorSet.init(gpa);
defer seen_errors.deinit();

const operand_ty = sema.typeOf(raw_operand_val);
const operand_err_set = if (extra.data.bits.payload_is_ref)
operand_ty.childType(zcu)
else
operand_ty;

if (operand_err_set.zigTypeTag(zcu) != .error_union) {
return sema.fail(block, switch_src, "expected error union type, found '{f}'", .{
operand_ty.fmt(pt),
});
}

const operand_err_set_ty = operand_err_set.errorUnionSet(zcu);

const block_inst: Air.Inst.Index = @enumFromInt(sema.air_instructions.len);
try sema.air_instructions.append(gpa, .{
.tag = .block,
Expand Down Expand Up @@ -11100,7 +11105,12 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp

const resolved_err_set = try sema.resolveInferredErrorSetTy(block, main_src, operand_err_set_ty.toIntern());
if (Type.fromInterned(resolved_err_set).errorSetIsEmpty(zcu)) {
return sema.resolveBlockBody(block, main_operand_src, &child_block, non_error_case.body, inst, merges);
return if (non_error_case) |nec|
sema.resolveBlockBody(block, main_operand_src, &child_block, nec.body, inst, merges)
else unreach: {
try sema.analyzeUnreachable(block, main_operand_src, false);
break :unreach .unreachable_value;
};
}

const else_error_ty: ?Type = try validateErrSetSwitch(
Expand Down Expand Up @@ -11138,7 +11148,7 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp
ov;

if (operand_val.errorUnionIsPayload(zcu)) {
return sema.resolveBlockBody(block, main_operand_src, &child_block, non_error_case.body, inst, merges);
return sema.resolveBlockBody(block, main_operand_src, &child_block, non_error_case.?.body, inst, merges);
} else {
const err_val = Value.fromInterned(try pt.intern(.{
.err = .{
Expand Down Expand Up @@ -11184,7 +11194,12 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp

if (scalar_cases_len + multi_cases_len == 0) {
if (else_error_ty) |ty| if (ty.errorSetIsEmpty(zcu)) {
return sema.resolveBlockBody(block, main_operand_src, &child_block, non_error_case.body, inst, merges);
return if (non_error_case) |nec|
sema.resolveBlockBody(block, main_operand_src, &child_block, nec.body, inst, merges)
else unreach: {
try sema.analyzeUnreachable(block, main_operand_src, false);
break :unreach .unreachable_value;
};
};
}

Expand All @@ -11193,26 +11208,13 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp
unreachable;
}

const cond = if (extra.data.bits.payload_is_ref) blk: {
try sema.checkErrorType(block, main_src, sema.typeOf(raw_operand_val).elemType2(zcu));
const loaded = try sema.analyzeLoad(block, main_src, raw_operand_val, main_src);
break :blk try sema.analyzeIsNonErr(block, main_src, loaded);
} else blk: {
try sema.checkErrorType(block, main_src, sema.typeOf(raw_operand_val));
break :blk try sema.analyzeIsNonErr(block, main_src, raw_operand_val);
};

var sub_block = child_block.makeSubBlock();
sub_block.runtime_loop = null;
sub_block.runtime_cond = main_operand_src;
sub_block.runtime_index.increment();
sub_block.need_debug_scope = null; // this body is emitted regardless
defer sub_block.instructions.deinit(gpa);

const non_error_hint = try sema.analyzeBodyRuntimeBreak(&sub_block, non_error_case.body);
const true_instructions = try sub_block.instructions.toOwnedSlice(gpa);
defer gpa.free(true_instructions);

spa.operand.simple.by_val = if (extra.data.bits.payload_is_ref)
try sema.analyzeErrUnionCodePtr(&sub_block, switch_operand_src, raw_operand_val)
else
Expand Down Expand Up @@ -11257,31 +11259,48 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp
&.{},
&.{},
);
const err_switch_instructions = try sub_block.instructions.toOwnedSlice(gpa);
defer gpa.free(err_switch_instructions);

if (non_error_case) |nec| {
const cond = if (extra.data.bits.payload_is_ref) blk: {
try sema.checkErrorType(block, main_src, sema.typeOf(raw_operand_val).elemType2(zcu));
const loaded = try sema.analyzeLoad(block, main_src, raw_operand_val, main_src);
break :blk try sema.analyzeIsNonErr(block, main_src, loaded);
} else blk: {
try sema.checkErrorType(block, main_src, sema.typeOf(raw_operand_val));
break :blk try sema.analyzeIsNonErr(block, main_src, raw_operand_val);
};

try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).@"struct".fields.len +
true_instructions.len + sub_block.instructions.items.len);
const non_error_hint = try sema.analyzeBodyRuntimeBreak(&sub_block, nec.body);

_ = try child_block.addInst(.{
.tag = .cond_br,
.data = .{
.pl_op = .{
.operand = cond,
.payload = sema.addExtraAssumeCapacity(Air.CondBr{
.then_body_len = @intCast(true_instructions.len),
.else_body_len = @intCast(sub_block.instructions.items.len),
.branch_hints = .{
.true = non_error_hint,
.false = .none,
// Code coverage is desired for error handling.
.then_cov = .poi,
.else_cov = .poi,
},
}),
try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).@"struct".fields.len +
err_switch_instructions.len + sub_block.instructions.items.len);

_ = try child_block.addInst(.{
.tag = .cond_br,
.data = .{
.pl_op = .{
.operand = cond,
.payload = sema.addExtraAssumeCapacity(Air.CondBr{
.then_body_len = @intCast(sub_block.instructions.items.len),
.else_body_len = @intCast(err_switch_instructions.len),
.branch_hints = .{
.true = non_error_hint,
.false = .none,
// Code coverage is desired for error handling.
.then_cov = .poi,
.else_cov = .poi,
},
}),
},
},
},
});
sema.air_extra.appendSliceAssumeCapacity(@ptrCast(true_instructions));
sema.air_extra.appendSliceAssumeCapacity(@ptrCast(sub_block.instructions.items));
});
sema.air_extra.appendSliceAssumeCapacity(@ptrCast(sub_block.instructions.items));
sema.air_extra.appendSliceAssumeCapacity(@ptrCast(err_switch_instructions));
} else {
try child_block.instructions.appendSlice(gpa, err_switch_instructions);
}

return sema.resolveAnalyzedBlock(block, main_src, &child_block, merges, false);
}
Expand Down Expand Up @@ -11383,7 +11402,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
break :blk tag_capture_inst;
} else undefined;

var case_vals = try std.ArrayListUnmanaged(Air.Inst.Ref).initCapacity(gpa, scalar_cases_len + 2 * multi_cases_len);
var case_vals: std.ArrayList(Air.Inst.Ref) = try .initCapacity(gpa, scalar_cases_len + 2 * multi_cases_len);
defer case_vals.deinit(gpa);

var single_absorbed_item: Zir.Inst.Ref = .none;
Expand Down Expand Up @@ -12037,8 +12056,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
}

var extra_case_vals: struct {
items: std.ArrayListUnmanaged(Air.Inst.Ref),
ranges: std.ArrayListUnmanaged([2]Air.Inst.Ref),
items: std.ArrayList(Air.Inst.Ref),
ranges: std.ArrayList([2]Air.Inst.Ref),
} = .{ .items = .empty, .ranges = .empty };
defer {
extra_case_vals.items.deinit(gpa);
Expand Down Expand Up @@ -12230,7 +12249,7 @@ fn analyzeSwitchRuntimeBlock(
operand: Air.Inst.Ref,
operand_ty: Type,
operand_src: LazySrcLoc,
case_vals: std.ArrayListUnmanaged(Air.Inst.Ref),
case_vals: std.ArrayList(Air.Inst.Ref),
else_prong: SpecialProng,
scalar_cases_len: usize,
multi_cases_len: usize,
Expand Down Expand Up @@ -12262,10 +12281,10 @@ fn analyzeSwitchRuntimeBlock(

const estimated_cases_extra = (scalar_cases_len + multi_cases_len) *
@typeInfo(Air.SwitchBr.Case).@"struct".fields.len + 2;
var cases_extra = try std.ArrayListUnmanaged(u32).initCapacity(gpa, estimated_cases_extra);
var cases_extra: std.ArrayList(u32) = try .initCapacity(gpa, estimated_cases_extra);
defer cases_extra.deinit(gpa);

var branch_hints = try std.ArrayListUnmanaged(std.builtin.BranchHint).initCapacity(gpa, scalar_cases_len);
var branch_hints: std.ArrayList(std.builtin.BranchHint) = try .initCapacity(gpa, scalar_cases_len);
defer branch_hints.deinit(gpa);

var case_block = child_block.makeSubBlock();
Expand Down Expand Up @@ -12915,7 +12934,7 @@ fn resolveSwitchComptimeLoop(
special_members_only: ?SpecialProng,
special_generic: SpecialProng,
special_generic_is_under: bool,
case_vals: std.ArrayListUnmanaged(Air.Inst.Ref),
case_vals: std.ArrayList(Air.Inst.Ref),
scalar_cases_len: u32,
multi_cases_len: u32,
err_set: bool,
Expand Down Expand Up @@ -12987,7 +13006,7 @@ fn resolveSwitchComptime(
special_members_only: ?SpecialProng,
special_generic: SpecialProng,
special_generic_is_under: bool,
case_vals: std.ArrayListUnmanaged(Air.Inst.Ref),
case_vals: std.ArrayList(Air.Inst.Ref),
scalar_cases_len: u32,
multi_cases_len: u32,
err_set: bool,
Expand Down Expand Up @@ -13243,7 +13262,7 @@ fn validateErrSetSwitch(
sema: *Sema,
block: *Block,
seen_errors: *SwitchErrorSet,
case_vals: *std.ArrayListUnmanaged(Air.Inst.Ref),
case_vals: *std.ArrayList(Air.Inst.Ref),
operand_ty: Type,
inst_data: @FieldType(Zir.Inst.Data, "pl_node"),
scalar_cases_len: u32,
Expand Down Expand Up @@ -35563,8 +35582,8 @@ fn unionFields(
enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len);
}

var field_types: std.ArrayListUnmanaged(InternPool.Index) = .empty;
var field_aligns: std.ArrayListUnmanaged(InternPool.Alignment) = .empty;
var field_types: std.ArrayList(InternPool.Index) = .empty;
var field_aligns: std.ArrayList(InternPool.Alignment) = .empty;

try field_types.ensureTotalCapacityPrecise(sema.arena, fields_len);
if (small.any_aligned_fields)
Expand Down Expand Up @@ -36923,7 +36942,7 @@ fn notePathToComptimeAllocPtr(
const zcu = pt.zcu;
const ip = &zcu.intern_pool;

var first_path: std.ArrayListUnmanaged(u8) = .empty;
var first_path: std.ArrayList(u8) = .empty;
if (intermediate_value_count == 0) {
try first_path.print(arena, "{f}", .{start_value_name.fmt(ip)});
} else {
Expand Down Expand Up @@ -36994,7 +37013,7 @@ fn notePathToComptimeAllocPtr(
}
}

fn notePathToComptimeAllocPtrInner(sema: *Sema, val: Value, path: *std.ArrayListUnmanaged(u8)) Allocator.Error!Value {
fn notePathToComptimeAllocPtrInner(sema: *Sema, val: Value, path: *std.ArrayList(u8)) Allocator.Error!Value {
const pt = sema.pt;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
Expand Down
Loading
Loading