compiler: start using destructure syntax

This commit is contained in:
mlugg 2023-09-15 00:00:11 +01:00 committed by Andrew Kelley
parent ded628e4fa
commit f366d9f879
2 changed files with 74 additions and 108 deletions

View File

@ -1392,14 +1392,8 @@ fn arrayInitExpr(
assert(array_init.ast.elements.len != 0); // Otherwise it would be struct init.
const types: struct {
array: Zir.Inst.Ref,
elem: Zir.Inst.Ref,
} = inst: {
if (array_init.ast.type_expr == 0) break :inst .{
.array = .none,
.elem = .none,
};
const array_ty: Zir.Inst.Ref, const elem_ty: Zir.Inst.Ref = inst: {
if (array_init.ast.type_expr == 0) break :inst .{ .none, .none };
infer: {
const array_type: Ast.full.ArrayType = tree.fullArrayType(array_init.ast.type_expr) orelse break :infer;
@ -1414,10 +1408,7 @@ fn arrayInitExpr(
.lhs = len_inst,
.rhs = elem_type,
});
break :inst .{
.array = array_type_inst,
.elem = elem_type,
};
break :inst .{ array_type_inst, elem_type };
} else {
const sentinel = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = elem_type } }, array_type.ast.sentinel);
const array_type_inst = try gz.addPlNode(
@ -1429,10 +1420,7 @@ fn arrayInitExpr(
.sentinel = sentinel,
},
);
break :inst .{
.array = array_type_inst,
.elem = elem_type,
};
break :inst .{ array_type_inst, elem_type };
}
}
}
@ -1441,29 +1429,26 @@ fn arrayInitExpr(
.ty = array_type_inst,
.init_count = @intCast(array_init.ast.elements.len),
});
break :inst .{
.array = array_type_inst,
.elem = .none,
};
break :inst .{ array_type_inst, .none };
};
switch (ri.rl) {
.discard => {
if (types.elem != .none) {
const elem_ri: ResultInfo = .{ .rl = .{ .ty = types.elem } };
if (elem_ty != .none) {
const elem_ri: ResultInfo = .{ .rl = .{ .ty = elem_ty } };
for (array_init.ast.elements) |elem_init| {
_ = try expr(gz, scope, elem_ri, elem_init);
}
} else if (types.array != .none) {
} else if (array_ty != .none) {
for (array_init.ast.elements, 0..) |elem_init, i| {
const elem_ty = try gz.add(.{
const this_elem_ty = try gz.add(.{
.tag = .elem_type_index,
.data = .{ .bin = .{
.lhs = types.array,
.lhs = array_ty,
.rhs = @enumFromInt(i),
} },
});
_ = try expr(gz, scope, .{ .rl = .{ .ty = elem_ty } }, elem_init);
_ = try expr(gz, scope, .{ .rl = .{ .ty = this_elem_ty } }, elem_init);
}
} else {
for (array_init.ast.elements) |elem_init| {
@ -1473,15 +1458,15 @@ fn arrayInitExpr(
return Zir.Inst.Ref.void_value;
},
.ref => {
const tag: Zir.Inst.Tag = if (types.array != .none) .array_init_ref else .array_init_anon_ref;
return arrayInitExprInner(gz, scope, node, array_init.ast.elements, types.array, types.elem, tag);
const tag: Zir.Inst.Tag = if (array_ty != .none) .array_init_ref else .array_init_anon_ref;
return arrayInitExprInner(gz, scope, node, array_init.ast.elements, array_ty, elem_ty, tag);
},
.none => {
const tag: Zir.Inst.Tag = if (types.array != .none) .array_init else .array_init_anon;
return arrayInitExprInner(gz, scope, node, array_init.ast.elements, types.array, types.elem, tag);
const tag: Zir.Inst.Tag = if (array_ty != .none) .array_init else .array_init_anon;
return arrayInitExprInner(gz, scope, node, array_init.ast.elements, array_ty, elem_ty, tag);
},
.ty, .coerced_ty => |ty_inst| {
const arr_ty = if (types.array != .none) types.array else blk: {
const arr_ty = if (array_ty != .none) array_ty else blk: {
const arr_ty = try gz.addUnNode(.opt_eu_base_ty, ty_inst, node);
_ = try gz.addPlNode(.validate_array_init_ty, node, Zir.Inst.ArrayInit{
.ty = arr_ty,
@ -1489,29 +1474,29 @@ fn arrayInitExpr(
});
break :blk arr_ty;
};
const result = try arrayInitExprInner(gz, scope, node, array_init.ast.elements, arr_ty, types.elem, .array_init);
const result = try arrayInitExprInner(gz, scope, node, array_init.ast.elements, arr_ty, elem_ty, .array_init);
return rvalue(gz, ri, result, node);
},
.ptr => |ptr_res| {
return arrayInitExprRlPtr(gz, scope, node, ptr_res.inst, array_init.ast.elements, types.array);
return arrayInitExprRlPtr(gz, scope, node, ptr_res.inst, array_init.ast.elements, array_ty);
},
.inferred_ptr => |ptr_inst| {
if (types.array == .none) {
if (array_ty == .none) {
// We treat this case differently so that we don't get a crash when
// analyzing array_base_ptr against an alloc_inferred_mut.
// See corresponding logic in structInitExpr.
const result = try arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon);
return rvalue(gz, ri, result, node);
} else {
return arrayInitExprRlPtr(gz, scope, node, ptr_inst, array_init.ast.elements, types.array);
return arrayInitExprRlPtr(gz, scope, node, ptr_inst, array_init.ast.elements, array_ty);
}
},
.destructure => |destructure| {
if (types.array != .none) {
if (array_ty != .none) {
// We have a specific type, so there may be things like default
// field values messing with us. Do this as a standard typed
// init followed by an rvalue destructure.
const result = try arrayInitExprInner(gz, scope, node, array_init.ast.elements, types.array, types.elem, .array_init);
const result = try arrayInitExprInner(gz, scope, node, array_init.ast.elements, array_ty, elem_ty, .array_init);
return rvalue(gz, ri, result, node);
}
// Untyped init - destructure directly into result pointers
@ -3177,10 +3162,7 @@ fn varDecl(
.keyword_var => {
const is_comptime = var_decl.comptime_token != null or gz.is_comptime;
var resolve_inferred_alloc: Zir.Inst.Ref = .none;
const var_data: struct {
result_info: ResultInfo,
alloc: Zir.Inst.Ref,
} = if (var_decl.ast.type_node != 0) a: {
const alloc: Zir.Inst.Ref, const result_info: ResultInfo = if (var_decl.ast.type_node != 0) a: {
const type_inst = try typeExpr(gz, scope, var_decl.ast.type_node);
const alloc = alloc: {
if (align_inst == .none) {
@ -3199,7 +3181,7 @@ fn varDecl(
});
}
};
break :a .{ .alloc = alloc, .result_info = .{ .rl = .{ .ptr = .{ .inst = alloc } } } };
break :a .{ alloc, .{ .rl = .{ .ptr = .{ .inst = alloc } } } };
} else a: {
const alloc = alloc: {
if (align_inst == .none) {
@ -3219,24 +3201,24 @@ fn varDecl(
}
};
resolve_inferred_alloc = alloc;
break :a .{ .alloc = alloc, .result_info = .{ .rl = .{ .inferred_ptr = alloc } } };
break :a .{ alloc, .{ .rl = .{ .inferred_ptr = alloc } } };
};
const prev_anon_name_strategy = gz.anon_name_strategy;
gz.anon_name_strategy = .dbg_var;
_ = try reachableExprComptime(gz, scope, var_data.result_info, var_decl.ast.init_node, node, is_comptime);
_ = try reachableExprComptime(gz, scope, result_info, var_decl.ast.init_node, node, is_comptime);
gz.anon_name_strategy = prev_anon_name_strategy;
if (resolve_inferred_alloc != .none) {
_ = try gz.addUnNode(.resolve_inferred_alloc, resolve_inferred_alloc, node);
}
try gz.addDbgVar(.dbg_var_ptr, ident_name, var_data.alloc);
try gz.addDbgVar(.dbg_var_ptr, ident_name, alloc);
const sub_scope = try block_arena.create(Scope.LocalPtr);
sub_scope.* = .{
.parent = scope,
.gen_zir = gz,
.name = ident_name,
.ptr = var_data.alloc,
.ptr = alloc,
.token_src = name_token,
.maybe_comptime = is_comptime,
.id_cat = .@"local variable",

View File

@ -11092,17 +11092,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
const special_prong_src: LazySrcLoc = .{ .node_offset_switch_special_prong = src_node_offset };
const extra = sema.code.extraData(Zir.Inst.SwitchBlock, inst_data.payload_index);
const raw_operand: struct { val: Air.Inst.Ref, ptr: Air.Inst.Ref } = blk: {
const raw_operand_val: Air.Inst.Ref, const raw_operand_ptr: Air.Inst.Ref = blk: {
const maybe_ptr = try sema.resolveInst(extra.data.operand);
if (operand_is_ref) {
const val = try sema.analyzeLoad(block, src, maybe_ptr, operand_src);
break :blk .{ .val = val, .ptr = maybe_ptr };
break :blk .{ val, maybe_ptr };
} else {
break :blk .{ .val = maybe_ptr, .ptr = undefined };
break :blk .{ maybe_ptr, undefined };
}
};
const operand = try sema.switchCond(block, operand_src, raw_operand.val);
const operand = try sema.switchCond(block, operand_src, raw_operand_val);
// AstGen guarantees that the instruction immediately preceding
// switch_block(_ref) is a dbg_stmt
@ -11160,7 +11160,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
},
};
const maybe_union_ty = sema.typeOf(raw_operand.val);
const maybe_union_ty = sema.typeOf(raw_operand_val);
const union_originally = maybe_union_ty.zigTypeTag(mod) == .Union;
// Duplicate checking variables later also used for `inline else`.
@ -11711,8 +11711,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
const spa: SwitchProngAnalysis = .{
.sema = sema,
.parent_block = block,
.operand = raw_operand.val,
.operand_ptr = raw_operand.ptr,
.operand = raw_operand_val,
.operand_ptr = raw_operand_ptr,
.cond = operand,
.else_error_ty = else_error_ty,
.switch_block_inst = inst,
@ -15500,11 +15500,7 @@ fn analyzeArithmetic(
const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs);
const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs);
const rs: struct {
src: LazySrcLoc,
air_tag: Air.Inst.Tag,
air_tag_safe: Air.Inst.Tag,
} = rs: {
const runtime_src: LazySrcLoc, const air_tag: Air.Inst.Tag, const air_tag_safe: Air.Inst.Tag = rs: {
switch (zir_tag) {
.add, .add_unsafe => {
// For integers:intAddSat
@ -15551,8 +15547,8 @@ fn analyzeArithmetic(
} else {
return Air.internedToRef((try Value.floatAdd(lhs_val, rhs_val, resolved_type, sema.arena, mod)).toIntern());
}
} else break :rs .{ .src = rhs_src, .air_tag = air_tag, .air_tag_safe = .add_safe };
} else break :rs .{ .src = lhs_src, .air_tag = air_tag, .air_tag_safe = .add_safe };
} else break :rs .{ rhs_src, air_tag, .add_safe };
} else break :rs .{ lhs_src, air_tag, .add_safe };
},
.addwrap => {
// Integers only; floats are checked above.
@ -15572,8 +15568,8 @@ fn analyzeArithmetic(
}
if (maybe_lhs_val) |lhs_val| {
return Air.internedToRef((try sema.numberAddWrapScalar(lhs_val, rhs_val, resolved_type)).toIntern());
} else break :rs .{ .src = lhs_src, .air_tag = .add_wrap, .air_tag_safe = .add_wrap };
} else break :rs .{ .src = rhs_src, .air_tag = .add_wrap, .air_tag_safe = .add_wrap };
} else break :rs .{ lhs_src, .add_wrap, .add_wrap };
} else break :rs .{ rhs_src, .add_wrap, .add_wrap };
},
.add_sat => {
// Integers only; floats are checked above.
@ -15599,14 +15595,14 @@ fn analyzeArithmetic(
return Air.internedToRef(val.toIntern());
} else break :rs .{
.src = lhs_src,
.air_tag = .add_sat,
.air_tag_safe = .add_sat,
lhs_src,
.add_sat,
.add_sat,
};
} else break :rs .{
.src = rhs_src,
.air_tag = .add_sat,
.air_tag_safe = .add_sat,
rhs_src,
.add_sat,
.add_sat,
};
},
.sub => {
@ -15649,8 +15645,8 @@ fn analyzeArithmetic(
} else {
return Air.internedToRef((try Value.floatSub(lhs_val, rhs_val, resolved_type, sema.arena, mod)).toIntern());
}
} else break :rs .{ .src = rhs_src, .air_tag = air_tag, .air_tag_safe = .sub_safe };
} else break :rs .{ .src = lhs_src, .air_tag = air_tag, .air_tag_safe = .sub_safe };
} else break :rs .{ rhs_src, air_tag, .sub_safe };
} else break :rs .{ lhs_src, air_tag, .sub_safe };
},
.subwrap => {
// Integers only; floats are checked above.
@ -15670,8 +15666,8 @@ fn analyzeArithmetic(
}
if (maybe_rhs_val) |rhs_val| {
return Air.internedToRef((try sema.numberSubWrapScalar(lhs_val, rhs_val, resolved_type)).toIntern());
} else break :rs .{ .src = rhs_src, .air_tag = .sub_wrap, .air_tag_safe = .sub_wrap };
} else break :rs .{ .src = lhs_src, .air_tag = .sub_wrap, .air_tag_safe = .sub_wrap };
} else break :rs .{ rhs_src, .sub_wrap, .sub_wrap };
} else break :rs .{ lhs_src, .sub_wrap, .sub_wrap };
},
.sub_sat => {
// Integers only; floats are checked above.
@ -15696,8 +15692,8 @@ fn analyzeArithmetic(
try lhs_val.intSubSat(rhs_val, resolved_type, sema.arena, mod);
return Air.internedToRef(val.toIntern());
} else break :rs .{ .src = rhs_src, .air_tag = .sub_sat, .air_tag_safe = .sub_sat };
} else break :rs .{ .src = lhs_src, .air_tag = .sub_sat, .air_tag_safe = .sub_sat };
} else break :rs .{ rhs_src, .sub_sat, .sub_sat };
} else break :rs .{ lhs_src, .sub_sat, .sub_sat };
},
.mul => {
// For integers:
@ -15789,8 +15785,8 @@ fn analyzeArithmetic(
} else {
return Air.internedToRef((try lhs_val.floatMul(rhs_val, resolved_type, sema.arena, mod)).toIntern());
}
} else break :rs .{ .src = lhs_src, .air_tag = air_tag, .air_tag_safe = .mul_safe };
} else break :rs .{ .src = rhs_src, .air_tag = air_tag, .air_tag_safe = .mul_safe };
} else break :rs .{ lhs_src, air_tag, .mul_safe };
} else break :rs .{ rhs_src, air_tag, .mul_safe };
},
.mulwrap => {
// Integers only; floats are handled above.
@ -15834,8 +15830,8 @@ fn analyzeArithmetic(
return mod.undefRef(resolved_type);
}
return Air.internedToRef((try lhs_val.numberMulWrap(rhs_val, resolved_type, sema.arena, mod)).toIntern());
} else break :rs .{ .src = lhs_src, .air_tag = .mul_wrap, .air_tag_safe = .mul_wrap };
} else break :rs .{ .src = rhs_src, .air_tag = .mul_wrap, .air_tag_safe = .mul_wrap };
} else break :rs .{ lhs_src, .mul_wrap, .mul_wrap };
} else break :rs .{ rhs_src, .mul_wrap, .mul_wrap };
},
.mul_sat => {
// Integers only; floats are checked above.
@ -15885,20 +15881,20 @@ fn analyzeArithmetic(
try lhs_val.intMulSat(rhs_val, resolved_type, sema.arena, mod);
return Air.internedToRef(val.toIntern());
} else break :rs .{ .src = lhs_src, .air_tag = .mul_sat, .air_tag_safe = .mul_sat };
} else break :rs .{ .src = rhs_src, .air_tag = .mul_sat, .air_tag_safe = .mul_sat };
} else break :rs .{ lhs_src, .mul_sat, .mul_sat };
} else break :rs .{ rhs_src, .mul_sat, .mul_sat };
},
else => unreachable,
}
};
try sema.requireRuntimeBlock(block, src, rs.src);
try sema.requireRuntimeBlock(block, src, runtime_src);
if (block.wantSafety() and want_safety and scalar_tag == .Int) {
if (mod.backendSupportsFeature(.safety_checked_instructions)) {
_ = try sema.preparePanicId(block, .integer_overflow);
return block.addBinOp(rs.air_tag_safe, casted_lhs, casted_rhs);
return block.addBinOp(air_tag_safe, casted_lhs, casted_rhs);
} else {
const maybe_op_ov: ?Air.Inst.Tag = switch (rs.air_tag) {
const maybe_op_ov: ?Air.Inst.Tag = switch (air_tag) {
.add => .add_with_overflow,
.sub => .sub_with_overflow,
.mul => .mul_with_overflow,
@ -15935,7 +15931,7 @@ fn analyzeArithmetic(
}
}
}
return block.addBinOp(rs.air_tag, casted_lhs, casted_rhs);
return block.addBinOp(air_tag, casted_lhs, casted_rhs);
}
fn analyzePtrArithmetic(
@ -32345,16 +32341,10 @@ fn compareIntsOnlyPossibleResult(
// For any other comparison, we need to know if the LHS value is
// equal to the maximum or minimum possible value of the RHS type.
const edge: struct { min: bool, max: bool } = edge: {
if (is_zero and rhs_info.signedness == .unsigned) break :edge .{
.min = true,
.max = false,
};
const is_min, const is_max = edge: {
if (is_zero and rhs_info.signedness == .unsigned) break :edge .{ true, false };
if (req_bits != rhs_info.bits) break :edge .{
.min = false,
.max = false,
};
if (req_bits != rhs_info.bits) break :edge .{ false, false };
const ty = try mod.intType(
if (is_negative) .signed else .unsigned,
@ -32363,24 +32353,18 @@ fn compareIntsOnlyPossibleResult(
const pop_count = lhs_val.popCount(ty, mod);
if (is_negative) {
break :edge .{
.min = pop_count == 1,
.max = false,
};
break :edge .{ pop_count == 1, false };
} else {
break :edge .{
.min = false,
.max = pop_count == req_bits - sign_adj,
};
break :edge .{ false, pop_count == req_bits - sign_adj };
}
};
assert(fits);
return switch (op) {
.lt => if (edge.max) false else null,
.lte => if (edge.min) true else null,
.gt => if (edge.min) false else null,
.gte => if (edge.max) true else null,
.lt => if (is_max) false else null,
.lte => if (is_min) true else null,
.gt => if (is_min) false else null,
.gte => if (is_max) true else null,
.eq, .neq => unreachable,
};
}
@ -32617,7 +32601,7 @@ const PeerResolveStrategy = enum {
either,
};
const res: struct { ReasonMethod, PeerResolveStrategy } = switch (s0) {
const reason_method: ReasonMethod, const strat: PeerResolveStrategy = switch (s0) {
.unknown => .{ .all_s1, s1 },
.error_set => switch (s1) {
.error_set => .{ .either, .error_set },
@ -32685,7 +32669,7 @@ const PeerResolveStrategy = enum {
.exact => .{ .all_s0, .exact },
};
switch (res[0]) {
switch (reason_method) {
.all_s0 => {
if (!s0_is_a) {
reason_peer.* = b_peer_idx;
@ -32702,7 +32686,7 @@ const PeerResolveStrategy = enum {
},
}
return res[1];
return strat;
}
fn select(ty: Type, mod: *Module) PeerResolveStrategy {