@@ -24626,6 +24626,7 @@ fn checkSimdBinOp(
24626
24626
sema: *Sema,
24627
24627
block: *Block,
24628
24628
src: LazySrcLoc,
24629
+ comptime air_tag: Air.Inst.Tag,
24629
24630
uncasted_lhs: Air.Inst.Ref,
24630
24631
uncasted_rhs: Air.Inst.Ref,
24631
24632
lhs_src: LazySrcLoc,
@@ -24638,11 +24639,11 @@ fn checkSimdBinOp(
24638
24639
24639
24640
try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
24640
24641
const vec_len: ?usize = if (lhs_ty.zigTypeTag(zcu) == .vector) lhs_ty.vectorLen(zcu) else null;
24641
- const result_ty = try sema.resolvePeerTypes (block, src, &.{ uncasted_lhs, uncasted_rhs }, .{
24642
+ const result_ty = try sema.resolvePeerTypesWithOp (block, src, air_tag , &.{ uncasted_lhs, uncasted_rhs }, .{
24642
24643
.override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
24643
24644
});
24644
- const lhs = try sema.coerce (block, result_ty, uncasted_lhs, lhs_src);
24645
- const rhs = try sema.coerce (block, result_ty, uncasted_rhs, rhs_src);
24645
+ const lhs = try sema.coerceWithOp (block, result_ty, uncasted_lhs, lhs_src, air_tag );
24646
+ const rhs = try sema.coerceWithOp (block, result_ty, uncasted_rhs, rhs_src, air_tag );
24646
24647
24647
24648
return SimdBinOp{
24648
24649
.len = vec_len,
@@ -25993,7 +25994,7 @@ fn analyzeMinMax(
25993
25994
continue;
25994
25995
};
25995
25996
25996
- const simd_op = try sema.checkSimdBinOp(block, src, cur, operand, cur_minmax_src, operand_src);
25997
+ const simd_op = try sema.checkSimdBinOp(block, src, air_tag, cur, operand, cur_minmax_src, operand_src);
25997
25998
const cur_val = try sema.resolveLazyValue(simd_op.lhs_val.?); // cur_minmax is comptime-known
25998
25999
const operand_val = try sema.resolveLazyValue(simd_op.rhs_val.?); // we checked the operand was resolvable above
25999
26000
@@ -26085,7 +26086,7 @@ fn analyzeMinMax(
26085
26086
const lhs_src = cur_minmax_src;
26086
26087
const rhs = operands[idx];
26087
26088
const rhs_src = operand_srcs[idx];
26088
- const simd_op = try sema.checkSimdBinOp(block, src, lhs, rhs, lhs_src, rhs_src);
26089
+ const simd_op = try sema.checkSimdBinOp(block, src, air_tag, lhs, rhs, lhs_src, rhs_src);
26089
26090
if (known_undef) {
26090
26091
cur_minmax = try pt.undefRef(simd_op.result_ty);
26091
26092
} else {
@@ -29455,6 +29456,20 @@ pub fn coerce(
29455
29456
};
29456
29457
}
29457
29458
29459
+ pub fn coerceWithOp(
29460
+ sema: *Sema,
29461
+ block: *Block,
29462
+ dest_ty_unresolved: Type,
29463
+ inst: Air.Inst.Ref,
29464
+ inst_src: LazySrcLoc,
29465
+ op_tag: Air.Inst.Tag,
29466
+ ) CompileError!Air.Inst.Ref {
29467
+ return sema.coerceExtra(block, dest_ty_unresolved, inst, inst_src, .{ .opt_op_tag = op_tag }) catch |err| switch (err) {
29468
+ error.NotCoercible => unreachable,
29469
+ else => |e| return e,
29470
+ };
29471
+ }
29472
+
29458
29473
const CoersionError = CompileError || error{
29459
29474
/// When coerce is called recursively, this error should be returned instead of using `fail`
29460
29475
/// to ensure correct types in compile errors.
@@ -29468,6 +29483,8 @@ const CoerceOpts = struct {
29468
29483
is_ret: bool = false,
29469
29484
/// Should coercion to comptime_int emit an error message.
29470
29485
no_cast_to_comptime_int: bool = false,
29486
+ /// The tag of operator in which the coerce is called
29487
+ opt_op_tag: ?Air.Inst.Tag = null,
29471
29488
29472
29489
param_src: struct {
29473
29490
func_inst: Air.Inst.Ref = .none,
@@ -29854,6 +29871,13 @@ fn coerceExtra(
29854
29871
if (maybe_inst_val) |val| {
29855
29872
// comptime-known integer to other number
29856
29873
if (!(try sema.intFitsInType(val, dest_ty, null))) {
29874
+ if (opts.opt_op_tag) |op_tag| {
29875
+ switch (op_tag) {
29876
+ .min => return Air.internedToRef((try dest_ty.maxInt(pt, dest_ty)).toIntern()),
29877
+ .max => return pt.intRef(dest_ty, 0),
29878
+ else => {},
29879
+ }
29880
+ }
29857
29881
if (!opts.report_err) return error.NotCoercible;
29858
29882
return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(pt), val.fmtValueSema(pt, sema) });
29859
29883
}
@@ -29881,6 +29905,30 @@ fn coerceExtra(
29881
29905
try sema.requireRuntimeBlock(block, inst_src, null);
29882
29906
return block.addTyOp(.intcast, dest_ty, inst);
29883
29907
}
29908
+
29909
+ if (opts.opt_op_tag) |op_tag| {
29910
+ switch (op_tag) {
29911
+ .min => {
29912
+ if (src_info.signedness != dst_info.signedness and dst_info.signedness == .signed) {
29913
+ std.debug.assert(dst_info.bits <= src_info.bits);
29914
+ try sema.requireRuntimeBlock(block, inst_src, null);
29915
+ const max_int_inst = Air.internedToRef((try dest_ty.maxInt(pt, inst_ty)).toIntern());
29916
+ const min_inst = try block.addBinOp(.min, inst, max_int_inst);
29917
+ return block.addTyOp(.intcast, dest_ty, min_inst);
29918
+ }
29919
+ },
29920
+ .max => {
29921
+ if (src_info.signedness != dst_info.signedness and dst_info.signedness == .unsigned) {
29922
+ std.debug.assert(dst_info.bits >= src_info.bits);
29923
+ try sema.requireRuntimeBlock(block, inst_src, null);
29924
+ const zero_inst = try pt.intRef(inst_ty, 0);
29925
+ const max_inst = try block.addBinOp(.max, inst, zero_inst);
29926
+ return block.addTyOp(.intcast, dest_ty, max_inst);
29927
+ }
29928
+ },
29929
+ else => {},
29930
+ }
29931
+ }
29884
29932
},
29885
29933
else => {},
29886
29934
},
@@ -30033,9 +30081,9 @@ fn coerceExtra(
30033
30081
}
30034
30082
}
30035
30083
30036
- return sema.coerceArrayLike(block, dest_ty, dest_ty_src, inst, inst_src);
30084
+ return sema.coerceArrayLike(block, dest_ty, dest_ty_src, inst, inst_src, opts.opt_op_tag );
30037
30085
},
30038
- .vector => return sema.coerceArrayLike(block, dest_ty, dest_ty_src, inst, inst_src),
30086
+ .vector => return sema.coerceArrayLike(block, dest_ty, dest_ty_src, inst, inst_src, opts.opt_op_tag ),
30039
30087
.@"struct" => {
30040
30088
if (inst_ty.isTuple(zcu)) {
30041
30089
return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src);
@@ -30044,7 +30092,7 @@ fn coerceExtra(
30044
30092
else => {},
30045
30093
},
30046
30094
.vector => switch (inst_ty.zigTypeTag(zcu)) {
30047
- .array, .vector => return sema.coerceArrayLike(block, dest_ty, dest_ty_src, inst, inst_src),
30095
+ .array, .vector => return sema.coerceArrayLike(block, dest_ty, dest_ty_src, inst, inst_src, opts.opt_op_tag ),
30048
30096
.@"struct" => {
30049
30097
if (inst_ty.isTuple(zcu)) {
30050
30098
return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src);
@@ -31927,6 +31975,7 @@ fn coerceArrayLike(
31927
31975
dest_ty_src: LazySrcLoc,
31928
31976
inst: Air.Inst.Ref,
31929
31977
inst_src: LazySrcLoc,
31978
+ opt_op_tag: ?Air.Inst.Tag,
31930
31979
) !Air.Inst.Ref {
31931
31980
const pt = sema.pt;
31932
31981
const zcu = pt.zcu;
@@ -31975,6 +32024,31 @@ fn coerceArrayLike(
31975
32024
try sema.requireRuntimeBlock(block, inst_src, null);
31976
32025
return block.addTyOp(.intcast, dest_ty, inst);
31977
32026
}
32027
+
32028
+ if (opt_op_tag) |op_tag| {
32029
+ switch (op_tag) {
32030
+ .min => {
32031
+ if (src_info.signedness != dst_info.signedness and dst_info.signedness == .signed) {
32032
+ std.debug.assert(dst_info.bits <= src_info.bits);
32033
+ try sema.requireRuntimeBlock(block, inst_src, null);
32034
+ const max_int_inst = Air.internedToRef((try dest_ty.maxInt(pt, inst_ty)).toIntern());
32035
+ const min_inst = try block.addBinOp(.min, inst, max_int_inst);
32036
+ return block.addTyOp(.intcast, dest_ty, min_inst);
32037
+ }
32038
+ },
32039
+ .max => {
32040
+ if (src_info.signedness != dst_info.signedness and dst_info.signedness == .unsigned) {
32041
+ std.debug.assert(dst_info.bits >= src_info.bits);
32042
+ try sema.requireRuntimeBlock(block, inst_src, null);
32043
+ const zeros = try sema.splat(inst_ty, try pt.intValue(inst_elem_ty, 0));
32044
+ const zero_inst = Air.internedToRef(zeros.toIntern());
32045
+ const max_inst = try block.addBinOp(.max, inst, zero_inst);
32046
+ return block.addTyOp(.intcast, dest_ty, max_inst);
32047
+ }
32048
+ },
32049
+ else => {},
32050
+ }
32051
+ }
31978
32052
},
31979
32053
.float => if (inst_elem_ty.isRuntimeFloat()) {
31980
32054
// float widening
@@ -31998,7 +32072,10 @@ fn coerceArrayLike(
31998
32072
const src = inst_src; // TODO better source location
31999
32073
const elem_src = inst_src; // TODO better source location
32000
32074
const elem_ref = try sema.elemValArray(block, src, inst_src, inst, elem_src, index_ref, true);
32001
- const coerced = try sema.coerce(block, dest_elem_ty, elem_ref, elem_src);
32075
+ const coerced = if (opt_op_tag) |op_tag|
32076
+ try sema.coerceWithOp(block, dest_elem_ty, elem_ref, elem_src, op_tag)
32077
+ else
32078
+ try sema.coerce(block, dest_elem_ty, elem_ref, elem_src);
32002
32079
ref.* = coerced;
32003
32080
if (runtime_src == null) {
32004
32081
if (try sema.resolveValue(coerced)) |elem_val| {
@@ -34073,6 +34150,17 @@ fn resolvePeerTypes(
34073
34150
src: LazySrcLoc,
34074
34151
instructions: []const Air.Inst.Ref,
34075
34152
candidate_srcs: PeerTypeCandidateSrc,
34153
+ ) !Type {
34154
+ return resolvePeerTypesWithOp(sema, block, src, null, instructions, candidate_srcs);
34155
+ }
34156
+
34157
+ fn resolvePeerTypesWithOp(
34158
+ sema: *Sema,
34159
+ block: *Block,
34160
+ src: LazySrcLoc,
34161
+ comptime opt_op_tag: ?Air.Inst.Tag,
34162
+ instructions: []const Air.Inst.Ref,
34163
+ candidate_srcs: PeerTypeCandidateSrc,
34076
34164
) !Type {
34077
34165
switch (instructions.len) {
34078
34166
0 => return Type.noreturn,
@@ -34099,7 +34187,7 @@ fn resolvePeerTypes(
34099
34187
val.* = try sema.resolveValue(inst);
34100
34188
}
34101
34189
34102
- switch (try sema.resolvePeerTypesInner(block, src, peer_tys, peer_vals)) {
34190
+ switch (try sema.resolvePeerTypesInner(block, src, opt_op_tag, peer_tys, peer_vals)) {
34103
34191
.success => |ty| return ty,
34104
34192
else => |result| {
34105
34193
const msg = try result.report(sema, block, src, instructions, candidate_srcs);
@@ -34112,6 +34200,7 @@ fn resolvePeerTypesInner(
34112
34200
sema: *Sema,
34113
34201
block: *Block,
34114
34202
src: LazySrcLoc,
34203
+ comptime opt_op_tag: ?Air.Inst.Tag,
34115
34204
peer_tys: []?Type,
34116
34205
peer_vals: []?Value,
34117
34206
) !PeerResolveResult {
@@ -34197,6 +34286,7 @@ fn resolvePeerTypesInner(
34197
34286
const final_payload = switch (try sema.resolvePeerTypesInner(
34198
34287
block,
34199
34288
src,
34289
+ opt_op_tag,
34200
34290
peer_tys,
34201
34291
peer_vals,
34202
34292
)) {
@@ -34235,6 +34325,7 @@ fn resolvePeerTypesInner(
34235
34325
const child_ty = switch (try sema.resolvePeerTypesInner(
34236
34326
block,
34237
34327
src,
34328
+ opt_op_tag,
34238
34329
peer_tys,
34239
34330
peer_vals,
34240
34331
)) {
@@ -34384,6 +34475,7 @@ fn resolvePeerTypesInner(
34384
34475
const child_ty = switch (try sema.resolvePeerTypesInner(
34385
34476
block,
34386
34477
src,
34478
+ opt_op_tag,
34387
34479
peer_tys,
34388
34480
peer_vals,
34389
34481
)) {
@@ -34989,6 +35081,14 @@ fn resolvePeerTypesInner(
34989
35081
return .{ .success = peer_tys[idx_signed.?].? };
34990
35082
}
34991
35083
35084
+ if (opt_op_tag) |op_tag| {
35085
+ switch (op_tag) {
35086
+ .min => return .{ .success = peer_tys[idx_signed.?].? },
35087
+ .max => return .{ .success = peer_tys[idx_unsigned.?].? },
35088
+ else => {},
35089
+ }
35090
+ }
35091
+
34992
35092
// TODO: this is for compatibility with legacy behavior. Before this version of PTR was
34993
35093
// implemented, the algorithm very often returned false positives, with the expectation
34994
35094
// that you'd just hit a coercion error later. One of these was that for integers, the
@@ -35107,7 +35207,7 @@ fn resolvePeerTypesInner(
35107
35207
}
35108
35208
35109
35209
// Resolve field type recursively
35110
- field_ty.* = switch (try sema.resolvePeerTypesInner(block, src, sub_peer_tys, sub_peer_vals)) {
35210
+ field_ty.* = switch (try sema.resolvePeerTypesInner(block, src, opt_op_tag, sub_peer_tys, sub_peer_vals)) {
35111
35211
.success => |ty| ty.toIntern(),
35112
35212
else => |result| {
35113
35213
const result_buf = try sema.arena.create(PeerResolveResult);
0 commit comments