mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-15 05:26:47 +00:00
Check for element being const
before resolving repeat count
This commit is contained in:
parent
9a2856837c
commit
be564703b0
@ -115,6 +115,23 @@ 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.
|
||||
match &element.kind {
|
||||
hir::ExprKind::ConstBlock(..) => return None,
|
||||
hir::ExprKind::Path(qpath) => {
|
||||
let res = self.typeck_results.borrow().qpath_res(qpath, element.hir_id);
|
||||
if let Res::Def(
|
||||
DefKind::Const | DefKind::AssocConst | DefKind::AnonConst,
|
||||
_,
|
||||
) = res
|
||||
{
|
||||
return None;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// 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.
|
||||
@ -135,12 +152,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// expr's `Copy` check.
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let enforce_copy_bound = |element: &hir::Expr<'_>, element_ty| {
|
||||
// If someone calls a const fn or constructs a const value, they can extract that
|
||||
// out into a separate constant (or a const block in the future), so we check that
|
||||
// to tell them that in the diagnostic. Does not affect typeck.
|
||||
let is_constable = match element.kind {
|
||||
hir::ExprKind::Call(func, _args) => match *self.node_ty(func.hir_id).kind() {
|
||||
ty::FnDef(def_id, _) if self.tcx.is_stable_const_fn(def_id) => {
|
||||
traits::IsConstable::Fn
|
||||
}
|
||||
_ => traits::IsConstable::No,
|
||||
},
|
||||
hir::ExprKind::Path(qpath) => {
|
||||
match self.typeck_results.borrow().qpath_res(&qpath, element.hir_id) {
|
||||
Res::Def(DefKind::Ctor(_, CtorKind::Const), _) => traits::IsConstable::Ctor,
|
||||
_ => traits::IsConstable::No,
|
||||
}
|
||||
}
|
||||
_ => traits::IsConstable::No,
|
||||
};
|
||||
|
||||
let lang_item = self.tcx.require_lang_item(LangItem::Copy, None);
|
||||
let code = traits::ObligationCauseCode::RepeatElementCopy {
|
||||
is_constable,
|
||||
elt_span: element.span,
|
||||
};
|
||||
self.require_type_meets(element_ty, element.span, code, lang_item);
|
||||
};
|
||||
|
||||
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) =>
|
||||
{
|
||||
self.enforce_repeat_element_needs_copy_bound(element, element_ty)
|
||||
enforce_copy_bound(element, element_ty)
|
||||
}
|
||||
// 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.
|
||||
@ -151,9 +196,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
ty::ConstKind::Param(_)
|
||||
| ty::ConstKind::Expr(_)
|
||||
| ty::ConstKind::Placeholder(_)
|
||||
| ty::ConstKind::Unevaluated(_) => {
|
||||
self.enforce_repeat_element_needs_copy_bound(element, element_ty)
|
||||
}
|
||||
| ty::ConstKind::Unevaluated(_) => enforce_copy_bound(element, element_ty),
|
||||
|
||||
ty::ConstKind::Bound(_, _) | ty::ConstKind::Infer(_) | ty::ConstKind::Error(_) => {
|
||||
unreachable!()
|
||||
@ -162,50 +205,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Requires that `element_ty` is `Copy` (unless it's a const expression itself).
|
||||
pub(super) fn enforce_repeat_element_needs_copy_bound(
|
||||
&self,
|
||||
element: &hir::Expr<'_>,
|
||||
element_ty: Ty<'tcx>,
|
||||
) {
|
||||
// Actual constants as the repeat element get inserted repeatedly instead of getting copied via Copy.
|
||||
match &element.kind {
|
||||
hir::ExprKind::ConstBlock(..) => return,
|
||||
hir::ExprKind::Path(qpath) => {
|
||||
let res = self.typeck_results.borrow().qpath_res(qpath, element.hir_id);
|
||||
if let Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::AnonConst, _) = res
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// If someone calls a const fn or constructs a const value, they can extract that
|
||||
// out into a separate constant (or a const block in the future), so we check that
|
||||
// to tell them that in the diagnostic. Does not affect typeck.
|
||||
let is_constable = match element.kind {
|
||||
hir::ExprKind::Call(func, _args) => match *self.node_ty(func.hir_id).kind() {
|
||||
ty::FnDef(def_id, _) if self.tcx.is_stable_const_fn(def_id) => {
|
||||
traits::IsConstable::Fn
|
||||
}
|
||||
_ => traits::IsConstable::No,
|
||||
},
|
||||
hir::ExprKind::Path(qpath) => {
|
||||
match self.typeck_results.borrow().qpath_res(&qpath, element.hir_id) {
|
||||
Res::Def(DefKind::Ctor(_, CtorKind::Const), _) => traits::IsConstable::Ctor,
|
||||
_ => traits::IsConstable::No,
|
||||
}
|
||||
}
|
||||
_ => traits::IsConstable::No,
|
||||
};
|
||||
|
||||
let lang_item = self.tcx.require_lang_item(LangItem::Copy, None);
|
||||
let code =
|
||||
traits::ObligationCauseCode::RepeatElementCopy { is_constable, elt_span: element.span };
|
||||
self.require_type_meets(element_ty, element.span, code, lang_item);
|
||||
}
|
||||
|
||||
pub(in super::super) fn check_method_argument_types(
|
||||
&self,
|
||||
sp: Span,
|
||||
|
@ -20,7 +20,6 @@ fn tie_and_make_goal<const N: usize, T: Trait<N>>(_: &T, _: &[String; N]) {}
|
||||
fn const_block() {
|
||||
// Deferred repeat expr `String; ?n`
|
||||
let a = [const { String::new() }; _];
|
||||
//~^ ERROR: type annotations needed for `[String; _]`
|
||||
|
||||
// `?int: Trait<?n>` goal
|
||||
tie_and_make_goal(&1, &a);
|
||||
@ -36,7 +35,6 @@ fn const_item() {
|
||||
|
||||
// Deferred repeat expr `String; ?n`
|
||||
let a = [MY_CONST; _];
|
||||
//~^ ERROR: type annotations needed for `[String; _]`
|
||||
|
||||
// `?int: Trait<?n>` goal
|
||||
tie_and_make_goal(&1, &a);
|
||||
@ -54,7 +52,6 @@ fn assoc_const() {
|
||||
|
||||
// Deferred repeat expr `String; ?n`
|
||||
let a = [<() as Dummy>::ASSOC; _];
|
||||
//~^ ERROR: type annotations needed for `[String; _]`
|
||||
|
||||
// `?int: Trait<?n>` goal
|
||||
tie_and_make_goal(&1, &a);
|
||||
@ -62,4 +59,14 @@ fn assoc_const() {
|
||||
// ... same as `const_block`
|
||||
}
|
||||
|
||||
fn const_block_but_uninferred() {
|
||||
// Deferred repeat expr `String; ?n`
|
||||
let a = [const { String::new() }; _];
|
||||
//~^ ERROR: type annotations needed for `[String; _]`
|
||||
|
||||
// Even if we don't structurally resolve the repeat count as part of repeat expr
|
||||
// checks, we still error on the repeat count being uninferred as we require all
|
||||
// types/consts to be inferred by the end of type checking.
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,36 +1,15 @@
|
||||
error[E0282]: type annotations needed for `[String; _]`
|
||||
--> $DIR/copy-check-const-element-uninferred-count.rs:22:9
|
||||
error[E0284]: type annotations needed for `[String; _]`
|
||||
--> $DIR/copy-check-const-element-uninferred-count.rs:64:9
|
||||
|
|
||||
LL | let a = [const { String::new() }; _];
|
||||
| ^ ----------------------- type must be known at this point
|
||||
| ^ ---------------------------- type must be known at this point
|
||||
|
|
||||
help: consider giving `a` an explicit type, where the value of const parameter `N` is specified
|
||||
= note: the length of array `[String; _]` must be type `usize`
|
||||
help: consider giving `a` an explicit type, where the placeholders `_` are specified
|
||||
|
|
||||
LL | let a: [_; N] = [const { String::new() }; _];
|
||||
LL | let a: [_; _] = [const { String::new() }; _];
|
||||
| ++++++++
|
||||
|
||||
error[E0282]: type annotations needed for `[String; _]`
|
||||
--> $DIR/copy-check-const-element-uninferred-count.rs:38:9
|
||||
|
|
||||
LL | let a = [MY_CONST; _];
|
||||
| ^ -------- type must be known at this point
|
||||
|
|
||||
help: consider giving `a` an explicit type, where the value of const parameter `N` is specified
|
||||
|
|
||||
LL | let a: [_; N] = [MY_CONST; _];
|
||||
| ++++++++
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
error[E0282]: type annotations needed for `[String; _]`
|
||||
--> $DIR/copy-check-const-element-uninferred-count.rs:56:9
|
||||
|
|
||||
LL | let a = [<() as Dummy>::ASSOC; _];
|
||||
| ^ -------------------- type must be known at this point
|
||||
|
|
||||
help: consider giving `a` an explicit type, where the value of const parameter `N` is specified
|
||||
|
|
||||
LL | let a: [_; N] = [<() as Dummy>::ASSOC; _];
|
||||
| ++++++++
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0282`.
|
||||
For more information about this error, try `rustc --explain E0284`.
|
||||
|
Loading…
Reference in New Issue
Block a user