about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_feature/src/unstable.rs2
-rw-r--r--compiler/rustc_hir/src/hir.rs13
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs66
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs27
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/intrinsicck.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs15
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/matches/match_pair.rs7
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs4
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc.rs11
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs59
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs39
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/structural_normalize.rs40
16 files changed, 186 insertions, 112 deletions
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 408da6d5d86..0b09e9fbb85 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -578,7 +578,7 @@ declare_features! (
     /// be used to describe E or vise-versa.
     (unstable, result_ffi_guarantees, "1.80.0", Some(110503)),
     /// Allows bounding the return type of AFIT/RPITIT.
-    (incomplete, return_type_notation, "1.70.0", Some(109417)),
+    (unstable, return_type_notation, "1.70.0", Some(109417)),
     /// Allows `extern "rust-cold"`.
     (unstable, rust_cold_cc, "1.63.0", Some(97544)),
     /// Allows use of x86 SHA512, SM3 and SM4 target-features and intrinsics
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 17273f1f8fc..71216023ecc 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1668,10 +1668,17 @@ pub enum ArrayLen<'hir> {
 }
 
 impl ArrayLen<'_> {
-    pub fn hir_id(&self) -> HirId {
+    pub fn span(self) -> Span {
+        match self {
+            ArrayLen::Infer(arg) => arg.span,
+            ArrayLen::Body(body) => body.span(),
+        }
+    }
+
+    pub fn hir_id(self) -> HirId {
         match self {
-            ArrayLen::Infer(InferArg { hir_id, .. }) | ArrayLen::Body(ConstArg { hir_id, .. }) => {
-                *hir_id
+            ArrayLen::Infer(InferArg { hir_id, .. }) | ArrayLen::Body(&ConstArg { hir_id, .. }) => {
+                hir_id
             }
         }
     }
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index e7efa32bdb0..015a7283250 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -1491,8 +1491,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expr: &'tcx hir::Expr<'tcx>,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
-        let count = self.lower_array_length(count);
-        if let Some(count) = count.try_eval_target_usize(tcx, self.param_env) {
+        let count_span = count.span();
+        let count = self.try_structurally_resolve_const(count_span, self.lower_array_length(count));
+
+        if let Some(count) = count.try_to_target_usize(tcx) {
             self.suggest_array_len(expr, count);
         }
 
@@ -1520,19 +1522,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return Ty::new_error(tcx, guar);
         }
 
-        self.check_repeat_element_needs_copy_bound(element, count, element_ty);
+        // If the length is 0, we don't create any elements, so we don't copy any.
+        // If the length is 1, we don't copy that one element, we move it. Only check
+        // for `Copy` if the length is larger, or unevaluated.
+        // FIXME(min_const_generic_exprs): We could perhaps defer this check so that
+        // we don't require `<?0t as Tr>::CONST` doesn't unnecessarily require `Copy`.
+        if count.try_to_target_usize(tcx).is_none_or(|x| x > 1) {
+            self.enforce_repeat_element_needs_copy_bound(element, element_ty);
+        }
 
         let ty = Ty::new_array_with_const_len(tcx, t, count);
-
         self.register_wf_obligation(ty.into(), expr.span, ObligationCauseCode::WellFormed(None));
-
         ty
     }
 
-    fn check_repeat_element_needs_copy_bound(
+    /// Requires that `element_ty` is `Copy` (unless it's a const expression itself).
+    fn enforce_repeat_element_needs_copy_bound(
         &self,
         element: &hir::Expr<'_>,
-        count: ty::Const<'tcx>,
         element_ty: Ty<'tcx>,
     ) {
         let tcx = self.tcx;
@@ -1565,27 +1572,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             _ => traits::IsConstable::No,
         };
 
-        // If the length is 0, we don't create any elements, so we don't copy any. If the length is 1, we
-        // don't copy that one element, we move it. Only check for Copy if the length is larger.
-        if count.try_eval_target_usize(tcx, self.param_env).is_none_or(|len| len > 1) {
-            let lang_item = self.tcx.require_lang_item(LangItem::Copy, None);
-            let code = traits::ObligationCauseCode::RepeatElementCopy {
-                is_constable,
-                elt_type: element_ty,
-                elt_span: element.span,
-                elt_stmt_span: self
-                    .tcx
-                    .hir()
-                    .parent_iter(element.hir_id)
-                    .find_map(|(_, node)| match node {
-                        hir::Node::Item(it) => Some(it.span),
-                        hir::Node::Stmt(stmt) => Some(stmt.span),
-                        _ => None,
-                    })
-                    .expect("array repeat expressions must be inside an item or statement"),
-            };
-            self.require_type_meets(element_ty, element.span, code, lang_item);
-        }
+        let lang_item = self.tcx.require_lang_item(LangItem::Copy, None);
+        let code = traits::ObligationCauseCode::RepeatElementCopy {
+            is_constable,
+            elt_type: element_ty,
+            elt_span: element.span,
+            elt_stmt_span: self
+                .tcx
+                .hir()
+                .parent_iter(element.hir_id)
+                .find_map(|(_, node)| match node {
+                    hir::Node::Item(it) => Some(it.span),
+                    hir::Node::Stmt(stmt) => Some(stmt.span),
+                    _ => None,
+                })
+                .expect("array repeat expressions must be inside an item or statement"),
+        };
+        self.require_type_meets(element_ty, element.span, code, lang_item);
     }
 
     fn check_expr_tuple(
@@ -2800,9 +2803,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         len: ty::Const<'tcx>,
     ) {
         err.span_label(field.span, "unknown field");
-        if let (Some(len), Ok(user_index)) =
-            (len.try_eval_target_usize(self.tcx, self.param_env), field.as_str().parse::<u64>())
-        {
+        if let (Some(len), Ok(user_index)) = (
+            self.try_structurally_resolve_const(base.span, len).try_to_target_usize(self.tcx),
+            field.as_str().parse::<u64>(),
+        ) {
             let help = "instead of using tuple indexing, use array indexing";
             let applicability = if len < user_index {
                 Applicability::MachineApplicable
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 7cae6e08f81..2c469c0d52c 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -1470,6 +1470,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
+    #[instrument(level = "debug", skip(self, sp), ret)]
+    pub fn try_structurally_resolve_const(&self, sp: Span, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+        // FIXME(min_const_generic_exprs): We could process obligations here if `ct` is a var.
+
+        if self.next_trait_solver()
+            && let ty::ConstKind::Unevaluated(..) = ct.kind()
+        {
+            // We need to use a separate variable here as otherwise the temporary for
+            // `self.fulfillment_cx.borrow_mut()` is alive in the `Err` branch, resulting
+            // in a reentrant borrow, causing an ICE.
+            let result = self
+                .at(&self.misc(sp), self.param_env)
+                .structurally_normalize_const(ct, &mut **self.fulfillment_cx.borrow_mut());
+            match result {
+                Ok(normalized_ct) => normalized_ct,
+                Err(errors) => {
+                    let guar = self.err_ctxt().report_fulfillment_errors(errors);
+                    return ty::Const::new_error(self.tcx, guar);
+                }
+            }
+        } else if self.tcx.features().generic_const_exprs {
+            ct.normalize(self.tcx, self.param_env)
+        } else {
+            ct
+        }
+    }
+
     /// Resolves `ty` by a single level if `ty` is a type variable.
     ///
     /// When the new solver is enabled, this will also attempt to normalize
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index b09bd476576..5f89f7dedc2 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -1502,7 +1502,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // Create an dummy type `&[_]` so that both &[] and `&Vec<T>` can coerce to it.
         let dummy_ty = if let ty::Array(elem_ty, size) = peeled.kind()
             && let ty::Infer(_) = elem_ty.kind()
-            && size.try_eval_target_usize(self.tcx, self.param_env) == Some(0)
+            && self
+                .try_structurally_resolve_const(provided_expr.span, *size)
+                .try_to_target_usize(self.tcx)
+                == Some(0)
         {
             let slice = Ty::new_slice(self.tcx, *elem_ty);
             Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, slice)
diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs
index 81d940a3f9b..a4121adf628 100644
--- a/compiler/rustc_hir_typeck/src/intrinsicck.rs
+++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs
@@ -101,7 +101,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
             }
             Ok(SizeSkeleton::Generic(size)) => {
-                if let Some(size) = size.try_eval_target_usize(tcx, self.param_env) {
+                if let Some(size) =
+                    self.try_structurally_resolve_const(span, size).try_to_target_usize(tcx)
+                {
                     format!("{size} bytes")
                 } else {
                     format!("generic size {size}")
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 805fb39480c..feb47209f5e 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -1721,20 +1721,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
         }
 
-        if item_name.name == sym::as_str && rcvr_ty.peel_refs().is_str() {
-            let msg = "remove this method call";
-            let mut fallback_span = true;
-            if let SelfSource::MethodCall(expr) = source {
-                let call_expr = self.tcx.hir().expect_expr(self.tcx.parent_hir_id(expr.hir_id));
-                if let Some(span) = call_expr.span.trim_start(expr.span) {
-                    err.span_suggestion(span, msg, "", Applicability::MachineApplicable);
-                    fallback_span = false;
-                }
-            }
-            if fallback_span {
-                err.span_label(span, msg);
-            }
-        } else if let Some(similar_candidate) = similar_candidate {
+        if let Some(similar_candidate) = similar_candidate {
             // Don't emit a suggestion if we found an actual method
             // that had unsatisfied trait bounds
             if unsatisfied_predicates.is_empty()
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 51964b8e753..49c5a7d8a65 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -2412,7 +2412,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         len: ty::Const<'tcx>,
         min_len: u64,
     ) -> (Option<Ty<'tcx>>, Ty<'tcx>) {
-        let len = len.try_eval_target_usize(self.tcx, self.param_env);
+        let len = self.try_structurally_resolve_const(span, len).try_to_target_usize(self.tcx);
 
         let guar = if let Some(len) = len {
             // Now we know the length...
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
index 5c92791a029..ffedee8a1e8 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -57,7 +57,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 this.in_scope(region_scope, lint_level, |this| this.as_rvalue(block, scope, value))
             }
             ExprKind::Repeat { value, count } => {
-                if Some(0) == count.try_eval_target_usize(this.tcx, this.param_env) {
+                if Some(0) == count.try_to_target_usize(this.tcx) {
                     this.build_zero_repeat(block, value, scope, source_info)
                 } else {
                     let value_operand = unpack!(
diff --git a/compiler/rustc_mir_build/src/build/matches/match_pair.rs b/compiler/rustc_mir_build/src/build/matches/match_pair.rs
index 25151f78c57..6df50057ee8 100644
--- a/compiler/rustc_mir_build/src/build/matches/match_pair.rs
+++ b/compiler/rustc_mir_build/src/build/matches/match_pair.rs
@@ -42,7 +42,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         let tcx = self.tcx;
         let (min_length, exact_size) = if let Some(place_resolved) = place.try_to_place(self) {
             match place_resolved.ty(&self.local_decls, tcx).ty.kind() {
-                ty::Array(_, length) => (length.eval_target_usize(tcx, self.param_env), true),
+                ty::Array(_, length) => (
+                    length
+                        .try_to_target_usize(tcx)
+                        .expect("expected len of array pat to be definite"),
+                    true,
+                ),
                 _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
             }
         } else {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index d78e1f5da09..04e921ecc2e 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -441,7 +441,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             ty::Slice(..) => PatKind::Slice { prefix, slice, suffix },
             // Fixed-length array, `[T; len]`.
             ty::Array(_, len) => {
-                let len = len.eval_target_usize(self.tcx, self.param_env);
+                let len = len
+                    .try_to_target_usize(self.tcx)
+                    .expect("expected len of array pat to be definite");
                 assert!(len >= prefix.len() as u64 + suffix.len() as u64);
                 PatKind::Array { prefix, slice, suffix }
             }
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index d164b8ab832..72737fb98cb 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -352,7 +352,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
             ty::Array(sub_ty, len) => {
                 // We treat arrays of a constant but unknown length like slices.
                 ConstructorSet::Slice {
-                    array_len: len.try_eval_target_usize(cx.tcx, cx.param_env).map(|l| l as usize),
+                    array_len: len.try_to_target_usize(cx.tcx).map(|l| l as usize),
                     subtype_is_empty: cx.is_uninhabited(*sub_ty),
                 }
             }
@@ -685,9 +685,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
             }
             PatKind::Array { prefix, slice, suffix } | PatKind::Slice { prefix, slice, suffix } => {
                 let array_len = match ty.kind() {
-                    ty::Array(_, length) => {
-                        Some(length.eval_target_usize(cx.tcx, cx.param_env) as usize)
-                    }
+                    ty::Array(_, length) => Some(
+                        length
+                            .try_to_target_usize(cx.tcx)
+                            .expect("expected len of array pat to be definite")
+                            as usize,
+                    ),
                     ty::Slice(_) => None,
                     _ => span_bug!(pat.span, "bad ty {} for slice pattern", ty.inner()),
                 };
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 79de9bbb351..f3da7ff1ca7 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -607,45 +607,40 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
                 let _ = write!(self.out, "{bits:x}_");
             }
 
+            // Handle `str` as partial support for unsized constants
+            ty::Str => {
+                let tcx = self.tcx();
+                // HACK(jaic1): hide the `str` type behind a reference
+                // for the following transformation from valtree to raw bytes
+                let ref_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, ct_ty);
+                let slice = valtree.try_to_raw_bytes(tcx, ref_ty).unwrap_or_else(|| {
+                    bug!("expected to get raw bytes from valtree {:?} for type {:}", valtree, ct_ty)
+                });
+                let s = std::str::from_utf8(slice).expect("non utf8 str from MIR interpreter");
+
+                // "e" for str as a basic type
+                self.push("e");
+
+                // FIXME(eddyb) use a specialized hex-encoding loop.
+                for byte in s.bytes() {
+                    let _ = write!(self.out, "{byte:02x}");
+                }
+
+                self.push("_");
+            }
+
             // FIXME(valtrees): Remove the special case for `str`
             // here and fully support unsized constants.
-            ty::Ref(_, inner_ty, mutbl) => {
+            ty::Ref(_, _, mutbl) => {
                 self.push(match mutbl {
                     hir::Mutability::Not => "R",
                     hir::Mutability::Mut => "Q",
                 });
 
-                match inner_ty.kind() {
-                    ty::Str if mutbl.is_not() => {
-                        let slice =
-                            valtree.try_to_raw_bytes(self.tcx(), ct_ty).unwrap_or_else(|| {
-                                bug!(
-                                    "expected to get raw bytes from valtree {:?} for type {:}",
-                                    valtree,
-                                    ct_ty
-                                )
-                            });
-                        let s =
-                            std::str::from_utf8(slice).expect("non utf8 str from MIR interpreter");
-
-                        self.push("e");
-
-                        // FIXME(eddyb) use a specialized hex-encoding loop.
-                        for byte in s.bytes() {
-                            let _ = write!(self.out, "{byte:02x}");
-                        }
-
-                        self.push("_");
-                    }
-                    _ => {
-                        let pointee_ty = ct_ty
-                            .builtin_deref(true)
-                            .expect("tried to dereference on non-ptr type");
-                        let dereferenced_const =
-                            ty::Const::new_value(self.tcx, valtree, pointee_ty);
-                        dereferenced_const.print(self)?;
-                    }
-                }
+                let pointee_ty =
+                    ct_ty.builtin_deref(true).expect("tried to dereference on non-ptr type");
+                let dereferenced_const = ty::Const::new_value(self.tcx, valtree, pointee_ty);
+                dereferenced_const.print(self)?;
             }
 
             ty::Array(..) | ty::Tuple(..) | ty::Adt(..) | ty::Slice(_) => {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index f9aab33d532..19e2679ae4d 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -17,7 +17,7 @@ use rustc_middle::traits::SignatureMismatchData;
 use rustc_middle::traits::select::OverflowError;
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::fold::{BottomUpFolder, TypeFolder, TypeSuperFoldable};
+use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::print::{
     FmtPrinter, Print, PrintTraitPredicateExt as _, PrintTraitRefExt as _,
     with_forced_trimmed_paths,
@@ -1788,22 +1788,18 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         return false;
                     }
 
-                    let cand = self.resolve_vars_if_possible(impl_trait_ref).fold_with(
-                        &mut BottomUpFolder {
-                            tcx: self.tcx,
-                            ty_op: |ty| ty,
-                            lt_op: |lt| lt,
-                            ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()),
-                        },
-                    );
-                    if cand.references_error() {
+                    let impl_trait_ref = self.resolve_vars_if_possible(impl_trait_ref);
+                    if impl_trait_ref.references_error() {
                         return false;
                     }
                     err.highlighted_help(vec![
-                        StringPart::normal(format!("the trait `{}` ", cand.print_trait_sugared())),
+                        StringPart::normal(format!(
+                            "the trait `{}` ",
+                            impl_trait_ref.print_trait_sugared()
+                        )),
                         StringPart::highlighted("is"),
                         StringPart::normal(" implemented for `"),
-                        StringPart::highlighted(cand.self_ty().to_string()),
+                        StringPart::highlighted(impl_trait_ref.self_ty().to_string()),
                         StringPart::normal("`"),
                     ]);
 
@@ -1915,15 +1911,18 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         let mut impl_candidates: Vec<_> = impl_candidates
             .iter()
             .cloned()
+            .filter(|cand| !cand.trait_ref.references_error())
             .map(|mut cand| {
-                // Fold the consts so that they shows up as, e.g., `10`
-                // instead of `core::::array::{impl#30}::{constant#0}`.
-                cand.trait_ref = cand.trait_ref.fold_with(&mut BottomUpFolder {
-                    tcx: self.tcx,
-                    ty_op: |ty| ty,
-                    lt_op: |lt| lt,
-                    ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()),
-                });
+                // Normalize the trait ref in its *own* param-env so
+                // that consts are folded and any trivial projections
+                // are normalized.
+                cand.trait_ref = self
+                    .tcx
+                    .try_normalize_erasing_regions(
+                        self.tcx.param_env(cand.impl_def_id),
+                        cand.trait_ref,
+                    )
+                    .unwrap_or(cand.trait_ref);
                 cand
             })
             .collect();
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index 9639d9d319c..6df7fac949c 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -4620,7 +4620,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     format!("&{}{ty}", mutability.prefix_str())
                 }
             }
-            ty::Array(ty, len) if let Some(len) = len.try_eval_target_usize(tcx, param_env) => {
+            ty::Array(ty, len) if let Some(len) = len.try_to_target_usize(tcx) => {
                 if len == 0 {
                     "[]".to_string()
                 } else if self.type_is_copy_modulo_regions(param_env, ty) || len == 1 {
diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
index 9d657ade86b..3814f8112e9 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
@@ -46,4 +46,44 @@ impl<'tcx> At<'_, 'tcx> {
             Ok(self.normalize(ty).into_value_registering_obligations(self.infcx, fulfill_cx))
         }
     }
+
+    fn structurally_normalize_const<E: 'tcx>(
+        &self,
+        ct: ty::Const<'tcx>,
+        fulfill_cx: &mut dyn TraitEngine<'tcx, E>,
+    ) -> Result<ty::Const<'tcx>, Vec<E>> {
+        assert!(!ct.is_ct_infer(), "should have resolved vars before calling");
+
+        if self.infcx.next_trait_solver() {
+            let ty::ConstKind::Unevaluated(..) = ct.kind() else {
+                return Ok(ct);
+            };
+
+            let new_infer_ct = self.infcx.next_const_var(self.cause.span);
+
+            // We simply emit an `alias-eq` goal here, since that will take care of
+            // normalizing the LHS of the projection until it is a rigid projection
+            // (or a not-yet-defined opaque in scope).
+            let obligation = Obligation::new(
+                self.infcx.tcx,
+                self.cause.clone(),
+                self.param_env,
+                ty::PredicateKind::AliasRelate(
+                    ct.into(),
+                    new_infer_ct.into(),
+                    ty::AliasRelationDirection::Equate,
+                ),
+            );
+
+            fulfill_cx.register_predicate_obligation(self.infcx, obligation);
+            let errors = fulfill_cx.select_where_possible(self.infcx);
+            if !errors.is_empty() {
+                return Err(errors);
+            }
+
+            Ok(self.infcx.resolve_vars_if_possible(new_infer_ct))
+        } else {
+            Ok(self.normalize(ct).into_value_registering_obligations(self.infcx, fulfill_cx))
+        }
+    }
 }