This commit is contained in:
Boxy
2025-04-14 13:41:18 +01:00
parent 4316259729
commit cc10370fc8
4 changed files with 32 additions and 25 deletions

View File

@@ -108,8 +108,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let deferred_repeat_expr_checks = deferred_repeat_expr_checks
.drain(..)
.flat_map(|(element, element_ty, count)| {
// Actual constants as the repeat element get inserted repeatedly instead of getting copied via Copy
// so we don't need to attempt to structurally resolve the repeat count which may unnecessarily error.
// Actual constants as the repeat element are inserted repeatedly instead
// of being copied via `Copy`, so we don't need to attempt to structurally
// resolve the repeat count which may unnecessarily error.
match &element.kind {
hir::ExprKind::ConstBlock(..) => return None,
hir::ExprKind::Path(qpath) => {
@@ -121,23 +122,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
_ => {}
}
// We want to emit an error if the const is not structurally resolveable as otherwise
// we can find up conservatively proving `Copy` which may infer the repeat expr count
// to something that never required `Copy` in the first place.
// We want to emit an error if the const is not structurally resolveable
// as otherwise we can wind up conservatively proving `Copy` which may
// infer the repeat expr count to something that never required `Copy` in
// the first place.
let count = self
.structurally_resolve_const(element.span, self.normalize(element.span, count));
// Avoid run on "`NotCopy: Copy` is not implemented" errors when the repeat expr count
// is erroneous/unknown. The user might wind up specifying a repeat count of 0/1.
// Avoid run on "`NotCopy: Copy` is not implemented" errors when the
// repeat expr count is erroneous/unknown. The user might wind up
// specifying a repeat count of 0/1.
if count.references_error() {
return None;
}
Some((element, element_ty, count))
})
// We collect to force the side effects of structurally resolving the repeat count to happen in one
// go, to avoid side effects from proving `Copy` affecting whether repeat counts are known or not.
// If we did not do this we would get results that depend on the order that we evaluate each repeat
// We collect to force the side effects of structurally resolving the repeat
// count to happen in one go, to avoid side effects from proving `Copy`
// affecting whether repeat counts are known or not. If we did not do this we
// would get results that depend on the order that we evaluate each repeat
// expr's `Copy` check.
.collect::<Vec<_>>();
@@ -171,14 +175,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
for (element, element_ty, count) in deferred_repeat_expr_checks {
match count.kind() {
ty::ConstKind::Value(val)
if val.try_to_target_usize(self.tcx).is_none_or(|count| count > 1) =>
{
enforce_copy_bound(element, element_ty)
ty::ConstKind::Value(val) => {
if val.try_to_target_usize(self.tcx).is_none_or(|count| count > 1) {
enforce_copy_bound(element, element_ty)
} else {
// If the length is 0 or 1 we don't actually copy the element, we either don't create it
// or we just use the one value.
}
}
// If the length is 0 or 1 we don't actually copy the element, we either don't create it
// or we just use the one value.
ty::ConstKind::Value(_) => (),
// If the length is a generic parameter or some rigid alias then conservatively
// require `element_ty: Copy` as it may wind up being `>1` after monomorphization.

View File

@@ -195,13 +195,16 @@ fn typeck_with_inspect<'tcx>(
fcx.write_ty(id, expected_type);
};
// Whether to check repeat exprs before/after inference fallback is somewhat arbitrary of a decision
// as neither option is strictly more permissive than the other. However, we opt to check repeat exprs
// first as errors from not having inferred array lengths yet seem less confusing than errors from inference
// fallback arbitrarily inferring something incompatible with `Copy` inference side effects.
// Whether to check repeat exprs before/after inference fallback is somewhat
// arbitrary of a decision as neither option is strictly more permissive than
// the other. However, we opt to check repeat exprs first as errors from not
// having inferred array lengths yet seem less confusing than errors from inference
// fallback arbitrarily inferring something incompatible with `Copy` inference
// side effects.
//
// This should also be forwards compatible with moving repeat expr checks to a custom goal kind or using
// marker traits in the future.
// FIXME(#140855): This should also be forwards compatible with moving
// repeat expr checks to a custom goal kind or using marker traits in
// the future.
fcx.check_repeat_exprs();
fcx.type_inference_fallback();

View File

@@ -5,7 +5,7 @@
// checked before integer fallback occurs. We accomplish this by having the repeat
// expr check allow inference progress on an ambiguous goal, where the ambiguous goal
// would fail if the inference variable was fallen back to `i32`. This test will
// pass if wecheck repeat exprs before integer fallback.
// pass if we check repeat exprs before integer fallback.
use std::marker::PhantomData;
struct Foo<T>(PhantomData<T>);

View File

@@ -12,7 +12,7 @@ impl Copy for Foo<1> {}
fn unify<const N: usize>(_: &[Foo<N>; 2], _: &[String; N]) {}
fn works_if_inference_side_effects() {
// This will only pass if inference side effectrs from proving `Foo<?x>: Copy` are
// This will only pass if inference side effects from proving `Foo<?x>: Copy` are
// able to be relied upon by other repeat expressions.
let a /* : [Foo<?x>; 2] */ = [Foo::<_>; 2];
//~^ ERROR: type annotations needed for `[Foo<_>; 2]`