about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-06-14 02:44:01 +0000
committerbors <bors@rust-lang.org>2024-06-14 02:44:01 +0000
commitbfa098eae0b5667a8cb5bbbe990a2d7e8445571f (patch)
treeccf475d10d0968adfa323ac7f2c610ca92a51966
parent0ef0dd24510b52da980889546fcd15254dc56a23 (diff)
parent3494ea18186482b9753a00cc7d163151704aa220 (diff)
downloadrust-bfa098eae0b5667a8cb5bbbe990a2d7e8445571f.tar.gz
rust-bfa098eae0b5667a8cb5bbbe990a2d7e8445571f.zip
Auto merge of #126439 - matthiaskrgr:rollup-856xt18, r=matthiaskrgr
Rollup of 10 pull requests

Successful merges:

 - #123726 (Clarify `Command::new` behavior for programs with arguments)
 - #126088 ([1/2] clean-up / general improvements)
 - #126238 (Fix Miri sysroot for `x run`)
 - #126315 (Add pub struct with allow(dead_code) into worklist)
 - #126360 (Uplift `structural_traits.rs` into the new trait solver)
 - #126371 (Tweak output of import suggestions)
 - #126388 (const-eval: make lint scope computation consistent)
 - #126390 (Fix wording in {checked_}next_power_of_two)
 - #126392 (Small style improvement in `gvn.rs`)
 - #126402 (Fix wrong `assert_unsafe_precondition` message for `core::ptr::copy`)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_const_eval/src/const_eval/error.rs16
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs24
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs26
-rw-r--r--compiler/rustc_const_eval/src/const_eval/valtrees.rs16
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs27
-rw-r--r--compiler/rustc_const_eval/src/interpret/intern.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/util.rs6
-rw-r--r--compiler/rustc_const_eval/src/util/caller_location.rs4
-rw-r--r--compiler/rustc_const_eval/src/util/check_validity_requirement.rs4
-rw-r--r--compiler/rustc_hir/src/lang_items.rs4
-rw-r--r--compiler/rustc_infer/src/infer/at.rs81
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs20
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs101
-rw-r--r--compiler/rustc_middle/src/ty/adt.rs17
-rw-r--r--compiler/rustc_middle/src/ty/context.rs84
-rw-r--r--compiler/rustc_middle/src/ty/generic_args.rs2
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/predicate.rs13
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs4
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs3
-rw-r--r--compiler/rustc_passes/src/dead.rs2
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs46
-rw-r--r--compiler/rustc_span/src/symbol.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs260
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs296
-rw-r--r--compiler/rustc_trait_selection/src/solve/inspect/build.rs7
-rw-r--r--compiler/rustc_trait_selection/src/solve/mod.rs11
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs13
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs9
-rw-r--r--compiler/rustc_type_ir/src/infcx.rs74
-rw-r--r--compiler/rustc_type_ir/src/inherent.rs134
-rw-r--r--compiler/rustc_type_ir/src/interner.rs61
-rw-r--r--compiler/rustc_type_ir/src/lang_items.rs8
-rw-r--r--compiler/rustc_type_ir/src/lib.rs1
-rw-r--r--library/core/src/intrinsics.rs3
-rw-r--r--library/core/src/num/nonzero.rs2
-rw-r--r--library/core/src/num/uint_macros.rs4
-rw-r--r--library/core/src/ops/coroutine.rs2
-rw-r--r--library/std/src/process.rs19
-rw-r--r--src/bootstrap/src/core/build_steps/format.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/run.rs8
-rw-r--r--src/tools/build-manifest/src/main.rs2
-rw-r--r--src/tools/build_helper/src/git.rs26
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-6252.stderr4
-rw-r--r--src/tools/compiletest/src/common.rs2
-rw-r--r--src/tools/compiletest/src/header.rs24
-rw-r--r--src/tools/compiletest/src/header/cfg.rs2
-rw-r--r--src/tools/compiletest/src/lib.rs2
-rw-r--r--src/tools/compiletest/src/read2.rs5
-rw-r--r--src/tools/compiletest/src/read2/tests.rs6
-rw-r--r--src/tools/compiletest/src/runtest.rs54
-rw-r--r--src/tools/compiletest/src/runtest/debugger.rs2
-rw-r--r--src/tools/compiletest/src/tests.rs10
-rw-r--r--src/tools/jsondoclint/src/validator.rs12
-rw-r--r--src/tools/lint-docs/src/groups.rs8
-rw-r--r--src/tools/lint-docs/src/lib.rs12
-rw-r--r--src/tools/opt-dist/src/training.rs8
-rw-r--r--src/tools/remote-test-client/src/main.rs10
-rw-r--r--src/tools/remote-test-server/src/main.rs2
-rw-r--r--src/tools/tidy/src/alphabetical.rs2
-rw-r--r--src/tools/tidy/src/bins.rs6
-rw-r--r--src/tools/tidy/src/deps.rs8
-rw-r--r--src/tools/tidy/src/error_codes.rs8
-rw-r--r--src/tools/tidy/src/ext_tool_checks.rs9
-rw-r--r--src/tools/tidy/src/style.rs57
-rw-r--r--src/tools/tidy/src/walk.rs18
-rw-r--r--src/tools/tidy/src/x_version.rs2
-rw-r--r--tests/ui/const-generics/issues/issue-82956.stderr2
-rw-r--r--tests/ui/consts/const_refs_to_static-ice-121413.rs4
-rw-r--r--tests/ui/consts/const_refs_to_static-ice-121413.stderr8
-rw-r--r--tests/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr2
-rw-r--r--tests/ui/hygiene/extern-prelude-from-opaque-fail-2018.stderr7
-rw-r--r--tests/ui/imports/cycle-import-in-std-1.stderr3
-rw-r--r--tests/ui/imports/cycle-import-in-std-2.stderr3
-rw-r--r--tests/ui/imports/import-alias-issue-121168.edition2018.stderr2
-rw-r--r--tests/ui/imports/import-alias-issue-121168.edition2021.stderr2
-rw-r--r--tests/ui/imports/issue-56125.stderr10
-rw-r--r--tests/ui/lint/dead-code/allow-unconstructed-pub-struct.rs33
-rw-r--r--tests/ui/lint/use_suggestion_json.stderr4
-rw-r--r--tests/ui/namespace/namespace-mix.stderr8
-rw-r--r--tests/ui/resolve/issue-16058.stderr2
-rw-r--r--tests/ui/resolve/issue-21221-1.stderr12
-rw-r--r--tests/ui/resolve/issue-21221-2.stderr2
-rw-r--r--tests/ui/resolve/issue-50599.stderr2
-rw-r--r--tests/ui/resolve/issue-73427.stderr2
-rw-r--r--tests/ui/resolve/privacy-enum-ctor.stderr4
-rw-r--r--tests/ui/rfcs/rfc-2126-extern-absolute-paths/not-allowed.stderr4
-rw-r--r--tests/ui/rust-2018/issue-52202-use-suggestions.stderr2
-rw-r--r--tests/ui/suggestions/core-std-import-order-issue-83564.no_std.fixed22
-rw-r--r--tests/ui/suggestions/core-std-import-order-issue-83564.no_std.stderr (renamed from tests/ui/suggestions/core-std-import-order-issue-83564.stderr)6
-rw-r--r--tests/ui/suggestions/core-std-import-order-issue-83564.rs12
-rw-r--r--tests/ui/suggestions/core-std-import-order-issue-83564.std.fixed22
-rw-r--r--tests/ui/suggestions/core-std-import-order-issue-83564.std.stderr14
-rw-r--r--tests/ui/suggestions/crate-or-module-typo.stderr4
-rw-r--r--tests/ui/suggestions/suggest-tryinto-edition-change.rs5
-rw-r--r--tests/ui/suggestions/suggest-tryinto-edition-change.stderr19
96 files changed, 1245 insertions, 698 deletions
diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs
index 923b9ddf9af..b17dc7f3ddd 100644
--- a/compiler/rustc_const_eval/src/const_eval/error.rs
+++ b/compiler/rustc_const_eval/src/const_eval/error.rs
@@ -1,7 +1,6 @@
 use std::mem;
 
 use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage, Diagnostic, IntoDiagArg};
-use rustc_hir::CRATE_HIR_ID;
 use rustc_middle::mir::interpret::{Provenance, ReportedErrorInfo};
 use rustc_middle::mir::AssertKind;
 use rustc_middle::query::TyCtxtAt;
@@ -9,7 +8,7 @@ use rustc_middle::ty::TyCtxt;
 use rustc_middle::ty::{layout::LayoutError, ConstInt};
 use rustc_span::{Span, Symbol};
 
-use super::CompileTimeInterpreter;
+use super::CompileTimeMachine;
 use crate::errors::{self, FrameNote, ReportErrorExt};
 use crate::interpret::{err_inval, err_machine_stop};
 use crate::interpret::{ErrorHandled, Frame, InterpError, InterpErrorInfo, MachineStopType};
@@ -156,11 +155,11 @@ where
     }
 }
 
-/// Emit a lint from a const-eval situation.
+/// Emit a lint from a const-eval situation, with a backtrace.
 // Even if this is unused, please don't remove it -- chances are we will need to emit a lint during const-eval again in the future!
 pub(super) fn lint<'tcx, L>(
     tcx: TyCtxtAt<'tcx>,
-    machine: &CompileTimeInterpreter<'tcx>,
+    machine: &CompileTimeMachine<'tcx>,
     lint: &'static rustc_session::lint::Lint,
     decorator: impl FnOnce(Vec<errors::FrameNote>) -> L,
 ) where
@@ -168,12 +167,5 @@ pub(super) fn lint<'tcx, L>(
 {
     let (span, frames) = get_span_and_frames(tcx, &machine.stack);
 
-    tcx.emit_node_span_lint(
-        lint,
-        // We use the root frame for this so the crate that defines the const defines whether the
-        // lint is emitted.
-        machine.stack.first().and_then(|frame| frame.lint_root()).unwrap_or(CRATE_HIR_ID),
-        span,
-        decorator(frames),
-    );
+    tcx.emit_node_span_lint(lint, machine.best_lint_scope(*tcx), span, decorator(frames));
 }
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index 36f468d3308..4b8145eb485 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -17,7 +17,7 @@ use rustc_span::def_id::LocalDefId;
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::{self, Abi};
 
-use super::{CanAccessMutGlobal, CompileTimeEvalContext, CompileTimeInterpreter};
+use super::{CanAccessMutGlobal, CompileTimeInterpCx, CompileTimeMachine};
 use crate::const_eval::CheckAlignment;
 use crate::errors::ConstEvalError;
 use crate::errors::{self, DanglingPtrInFinal};
@@ -32,7 +32,7 @@ use crate::CTRL_C_RECEIVED;
 // Returns a pointer to where the result lives
 #[instrument(level = "trace", skip(ecx, body))]
 fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
-    ecx: &mut CompileTimeEvalContext<'tcx>,
+    ecx: &mut CompileTimeInterpCx<'tcx>,
     cid: GlobalId<'tcx>,
     body: &'tcx mir::Body<'tcx>,
 ) -> InterpResult<'tcx, R> {
@@ -114,7 +114,7 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
             let err_diag = errors::MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind };
             ecx.tcx.emit_node_span_lint(
                 lint::builtin::CONST_EVAL_MUTABLE_PTR_IN_FINAL_VALUE,
-                ecx.best_lint_scope(),
+                ecx.machine.best_lint_scope(*ecx.tcx),
                 err_diag.span,
                 err_diag,
             )
@@ -139,13 +139,13 @@ pub(crate) fn mk_eval_cx_to_read_const_val<'tcx>(
     root_span: Span,
     param_env: ty::ParamEnv<'tcx>,
     can_access_mut_global: CanAccessMutGlobal,
-) -> CompileTimeEvalContext<'tcx> {
+) -> CompileTimeInterpCx<'tcx> {
     debug!("mk_eval_cx: {:?}", param_env);
     InterpCx::new(
         tcx,
         root_span,
         param_env,
-        CompileTimeInterpreter::new(can_access_mut_global, CheckAlignment::No),
+        CompileTimeMachine::new(can_access_mut_global, CheckAlignment::No),
     )
 }
 
@@ -156,7 +156,7 @@ pub fn mk_eval_cx_for_const_val<'tcx>(
     param_env: ty::ParamEnv<'tcx>,
     val: mir::ConstValue<'tcx>,
     ty: Ty<'tcx>,
-) -> Option<(CompileTimeEvalContext<'tcx>, OpTy<'tcx>)> {
+) -> Option<(CompileTimeInterpCx<'tcx>, OpTy<'tcx>)> {
     let ecx = mk_eval_cx_to_read_const_val(tcx.tcx, tcx.span, param_env, CanAccessMutGlobal::No);
     let op = ecx.const_val_to_op(val, ty, None).ok()?;
     Some((ecx, op))
@@ -170,7 +170,7 @@ pub fn mk_eval_cx_for_const_val<'tcx>(
 /// encounter an `Indirect` they cannot handle.
 #[instrument(skip(ecx), level = "debug")]
 pub(super) fn op_to_const<'tcx>(
-    ecx: &CompileTimeEvalContext<'tcx>,
+    ecx: &CompileTimeInterpCx<'tcx>,
     op: &OpTy<'tcx>,
     for_diagnostics: bool,
 ) -> ConstValue<'tcx> {
@@ -328,14 +328,14 @@ pub trait InterpretationResult<'tcx> {
     /// evaluation query.
     fn make_result(
         mplace: MPlaceTy<'tcx>,
-        ecx: &mut InterpCx<'tcx, CompileTimeInterpreter<'tcx>>,
+        ecx: &mut InterpCx<'tcx, CompileTimeMachine<'tcx>>,
     ) -> Self;
 }
 
 impl<'tcx> InterpretationResult<'tcx> for ConstAlloc<'tcx> {
     fn make_result(
         mplace: MPlaceTy<'tcx>,
-        _ecx: &mut InterpCx<'tcx, CompileTimeInterpreter<'tcx>>,
+        _ecx: &mut InterpCx<'tcx, CompileTimeMachine<'tcx>>,
     ) -> Self {
         ConstAlloc { alloc_id: mplace.ptr().provenance.unwrap().alloc_id(), ty: mplace.layout.ty }
     }
@@ -383,7 +383,7 @@ fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>(
         // they do not have to behave "as if" they were evaluated at runtime.
         // For consts however we want to ensure they behave "as if" they were evaluated at runtime,
         // so we have to reject reading mutable global memory.
-        CompileTimeInterpreter::new(CanAccessMutGlobal::from(is_static), CheckAlignment::Error),
+        CompileTimeMachine::new(CanAccessMutGlobal::from(is_static), CheckAlignment::Error),
     );
     let res = ecx.load_mir(cid.instance.def, cid.promoted);
     res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, body)).map_err(|error| {
@@ -417,7 +417,7 @@ fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>(
 
 #[inline(always)]
 fn const_validate_mplace<'tcx>(
-    ecx: &InterpCx<'tcx, CompileTimeInterpreter<'tcx>>,
+    ecx: &InterpCx<'tcx, CompileTimeMachine<'tcx>>,
     mplace: &MPlaceTy<'tcx>,
     cid: GlobalId<'tcx>,
 ) -> Result<(), ErrorHandled> {
@@ -447,7 +447,7 @@ fn const_validate_mplace<'tcx>(
 
 #[inline(always)]
 fn report_validation_error<'tcx>(
-    ecx: &InterpCx<'tcx, CompileTimeInterpreter<'tcx>>,
+    ecx: &InterpCx<'tcx, CompileTimeMachine<'tcx>>,
     error: InterpErrorInfo<'tcx>,
     alloc_id: AllocId,
 ) -> ErrorHandled {
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 79a161d3f03..4f6df857142 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -9,12 +9,13 @@ use rustc_data_structures::fx::IndexEntry;
 use rustc_hir::def_id::DefId;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::LangItem;
+use rustc_hir::{self as hir, CRATE_HIR_ID};
 use rustc_middle::bug;
 use rustc_middle::mir;
 use rustc_middle::mir::AssertMessage;
 use rustc_middle::query::TyCtxtAt;
-use rustc_middle::ty;
 use rustc_middle::ty::layout::{FnAbiOf, TyAndLayout};
+use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::lint::builtin::WRITES_THROUGH_IMMUTABLE_POINTER;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
@@ -44,7 +45,7 @@ const TINY_LINT_TERMINATOR_LIMIT: usize = 20;
 const PROGRESS_INDICATOR_START: usize = 4_000_000;
 
 /// Extra machine state for CTFE, and the Machine instance
-pub struct CompileTimeInterpreter<'tcx> {
+pub struct CompileTimeMachine<'tcx> {
     /// The number of terminators that have been evaluated.
     ///
     /// This is used to produce lints informing the user that the compiler is not stuck.
@@ -89,12 +90,12 @@ impl From<bool> for CanAccessMutGlobal {
     }
 }
 
-impl<'tcx> CompileTimeInterpreter<'tcx> {
+impl<'tcx> CompileTimeMachine<'tcx> {
     pub(crate) fn new(
         can_access_mut_global: CanAccessMutGlobal,
         check_alignment: CheckAlignment,
     ) -> Self {
-        CompileTimeInterpreter {
+        CompileTimeMachine {
             num_evaluated_steps: 0,
             stack: Vec::new(),
             can_access_mut_global,
@@ -163,7 +164,7 @@ impl<K: Hash + Eq, V> interpret::AllocMap<K, V> for FxIndexMap<K, V> {
     }
 }
 
-pub(crate) type CompileTimeEvalContext<'tcx> = InterpCx<'tcx, CompileTimeInterpreter<'tcx>>;
+pub(crate) type CompileTimeInterpCx<'tcx> = InterpCx<'tcx, CompileTimeMachine<'tcx>>;
 
 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
 pub enum MemoryKind {
@@ -195,7 +196,7 @@ impl interpret::MayLeak for ! {
     }
 }
 
-impl<'tcx> CompileTimeEvalContext<'tcx> {
+impl<'tcx> CompileTimeInterpCx<'tcx> {
     fn location_triple_for_span(&self, span: Span) -> (Symbol, u32, u32) {
         let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
         let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo());
@@ -369,7 +370,16 @@ impl<'tcx> CompileTimeEvalContext<'tcx> {
     }
 }
 
-impl<'tcx> interpret::Machine<'tcx> for CompileTimeInterpreter<'tcx> {
+impl<'tcx> CompileTimeMachine<'tcx> {
+    #[inline(always)]
+    /// Find the first stack frame that is within the current crate, if any.
+    /// Otherwise, return the crate's HirId
+    pub fn best_lint_scope(&self, tcx: TyCtxt<'tcx>) -> hir::HirId {
+        self.stack.iter().find_map(|frame| frame.lint_root(tcx)).unwrap_or(CRATE_HIR_ID)
+    }
+}
+
+impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
     compile_time_machine!(<'tcx>);
 
     type MemoryKind = MemoryKind;
@@ -600,7 +610,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeInterpreter<'tcx> {
                 // By default, we stop after a million steps, but the user can disable this lint
                 // to be able to run until the heat death of the universe or power loss, whichever
                 // comes first.
-                let hir_id = ecx.best_lint_scope();
+                let hir_id = ecx.machine.best_lint_scope(*ecx.tcx);
                 let is_error = ecx
                     .tcx
                     .lint_level_at_node(
diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
index 66993476bef..2e8ad445cf5 100644
--- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs
+++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
@@ -9,7 +9,7 @@ use rustc_target::abi::{Abi, VariantIdx};
 use tracing::{debug, instrument, trace};
 
 use super::eval_queries::{mk_eval_cx_to_read_const_val, op_to_const};
-use super::machine::CompileTimeEvalContext;
+use super::machine::CompileTimeInterpCx;
 use super::{ValTreeCreationError, ValTreeCreationResult, VALTREE_MAX_NODES};
 use crate::const_eval::CanAccessMutGlobal;
 use crate::errors::MaxNumNodesInConstErr;
@@ -21,7 +21,7 @@ use crate::interpret::{
 
 #[instrument(skip(ecx), level = "debug")]
 fn branches<'tcx>(
-    ecx: &CompileTimeEvalContext<'tcx>,
+    ecx: &CompileTimeInterpCx<'tcx>,
     place: &MPlaceTy<'tcx>,
     n: usize,
     variant: Option<VariantIdx>,
@@ -59,7 +59,7 @@ fn branches<'tcx>(
 
 #[instrument(skip(ecx), level = "debug")]
 fn slice_branches<'tcx>(
-    ecx: &CompileTimeEvalContext<'tcx>,
+    ecx: &CompileTimeInterpCx<'tcx>,
     place: &MPlaceTy<'tcx>,
     num_nodes: &mut usize,
 ) -> ValTreeCreationResult<'tcx> {
@@ -77,7 +77,7 @@ fn slice_branches<'tcx>(
 
 #[instrument(skip(ecx), level = "debug")]
 fn const_to_valtree_inner<'tcx>(
-    ecx: &CompileTimeEvalContext<'tcx>,
+    ecx: &CompileTimeInterpCx<'tcx>,
     place: &MPlaceTy<'tcx>,
     num_nodes: &mut usize,
 ) -> ValTreeCreationResult<'tcx> {
@@ -219,7 +219,7 @@ fn reconstruct_place_meta<'tcx>(
 
 #[instrument(skip(ecx), level = "debug", ret)]
 fn create_valtree_place<'tcx>(
-    ecx: &mut CompileTimeEvalContext<'tcx>,
+    ecx: &mut CompileTimeInterpCx<'tcx>,
     layout: TyAndLayout<'tcx>,
     valtree: ty::ValTree<'tcx>,
 ) -> MPlaceTy<'tcx> {
@@ -364,7 +364,7 @@ pub fn valtree_to_const_value<'tcx>(
 
 /// Put a valtree into memory and return a reference to that.
 fn valtree_to_ref<'tcx>(
-    ecx: &mut CompileTimeEvalContext<'tcx>,
+    ecx: &mut CompileTimeInterpCx<'tcx>,
     valtree: ty::ValTree<'tcx>,
     pointee_ty: Ty<'tcx>,
 ) -> Immediate {
@@ -380,7 +380,7 @@ fn valtree_to_ref<'tcx>(
 
 #[instrument(skip(ecx), level = "debug")]
 fn valtree_into_mplace<'tcx>(
-    ecx: &mut CompileTimeEvalContext<'tcx>,
+    ecx: &mut CompileTimeInterpCx<'tcx>,
     place: &MPlaceTy<'tcx>,
     valtree: ty::ValTree<'tcx>,
 ) {
@@ -457,6 +457,6 @@ fn valtree_into_mplace<'tcx>(
     }
 }
 
-fn dump_place<'tcx>(ecx: &CompileTimeEvalContext<'tcx>, place: &MPlaceTy<'tcx>) {
+fn dump_place<'tcx>(ecx: &CompileTimeInterpCx<'tcx>, place: &MPlaceTy<'tcx>) {
     trace!("{:?}", ecx.dump_place(&PlaceTy::from(place.clone())));
 }
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 63572197508..4d93038a81e 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -4,7 +4,6 @@ use std::{fmt, mem};
 use either::{Either, Left, Right};
 use tracing::{debug, info, info_span, instrument, trace};
 
-use hir::CRATE_HIR_ID;
 use rustc_errors::DiagCtxt;
 use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData};
 use rustc_index::IndexVec;
@@ -271,13 +270,18 @@ impl<'tcx, Prov: Provenance, Extra> Frame<'tcx, Prov, Extra> {
         }
     }
 
-    pub fn lint_root(&self) -> Option<hir::HirId> {
-        self.current_source_info().and_then(|source_info| {
-            match &self.body.source_scopes[source_info.scope].local_data {
+    pub fn lint_root(&self, tcx: TyCtxt<'tcx>) -> Option<hir::HirId> {
+        // We first try to get a HirId via the current source scope,
+        // and fall back to `body.source`.
+        self.current_source_info()
+            .and_then(|source_info| match &self.body.source_scopes[source_info.scope].local_data {
                 mir::ClearCrossCrate::Set(data) => Some(data.lint_root),
                 mir::ClearCrossCrate::Clear => None,
-            }
-        })
+            })
+            .or_else(|| {
+                let def_id = self.body.source.def_id().as_local();
+                def_id.map(|def_id| tcx.local_def_id_to_hir_id(def_id))
+            })
     }
 
     /// Returns the address of the buffer where the locals are stored. This is used by `Place` as a
@@ -509,17 +513,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         self.stack().last().map_or(self.tcx.span, |f| f.current_span())
     }
 
-    /// Find the first stack frame that is within the current crate, if any;
-    /// otherwise return the crate's HirId.
-    #[inline(always)]
-    pub fn best_lint_scope(&self) -> hir::HirId {
-        self.stack()
-            .iter()
-            .find_map(|frame| frame.body.source.def_id().as_local())
-            .map_or(CRATE_HIR_ID, |def_id| self.tcx.local_def_id_to_hir_id(def_id))
-    }
-
-    #[inline(always)]
     pub(crate) fn stack(&self) -> &[Frame<'tcx, M::Provenance, M::FrameExtra>] {
         M::stack(self)
     }
diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs
index 3066e0933d9..8b0a2afa4d6 100644
--- a/compiler/rustc_const_eval/src/interpret/intern.rs
+++ b/compiler/rustc_const_eval/src/interpret/intern.rs
@@ -45,7 +45,7 @@ pub trait HasStaticRootDefId {
     fn static_def_id(&self) -> Option<LocalDefId>;
 }
 
-impl HasStaticRootDefId for const_eval::CompileTimeInterpreter<'_> {
+impl HasStaticRootDefId for const_eval::CompileTimeMachine<'_> {
     fn static_def_id(&self) -> Option<LocalDefId> {
         Some(self.static_root_ids?.1)
     }
diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs
index 10fd6399b9a..f6537ed6ea9 100644
--- a/compiler/rustc_const_eval/src/interpret/util.rs
+++ b/compiler/rustc_const_eval/src/interpret/util.rs
@@ -1,4 +1,4 @@
-use crate::const_eval::{CompileTimeEvalContext, CompileTimeInterpreter, InterpretationResult};
+use crate::const_eval::{CompileTimeInterpCx, CompileTimeMachine, InterpretationResult};
 use rustc_hir::def_id::LocalDefId;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::{Allocation, InterpResult, Pointer};
@@ -84,7 +84,7 @@ where
 impl<'tcx> InterpretationResult<'tcx> for mir::interpret::ConstAllocation<'tcx> {
     fn make_result(
         mplace: MPlaceTy<'tcx>,
-        ecx: &mut InterpCx<'tcx, CompileTimeInterpreter<'tcx>>,
+        ecx: &mut InterpCx<'tcx, CompileTimeMachine<'tcx>>,
     ) -> Self {
         let alloc_id = mplace.ptr().provenance.unwrap().alloc_id();
         let alloc = ecx.memory.alloc_map.swap_remove(&alloc_id).unwrap().1;
@@ -93,7 +93,7 @@ impl<'tcx> InterpretationResult<'tcx> for mir::interpret::ConstAllocation<'tcx>
 }
 
 pub(crate) fn create_static_alloc<'tcx>(
-    ecx: &mut CompileTimeEvalContext<'tcx>,
+    ecx: &mut CompileTimeInterpCx<'tcx>,
     static_def_id: LocalDefId,
     layout: TyAndLayout<'tcx>,
 ) -> InterpResult<'tcx, MPlaceTy<'tcx>> {
diff --git a/compiler/rustc_const_eval/src/util/caller_location.rs b/compiler/rustc_const_eval/src/util/caller_location.rs
index 62c5f8734a2..3b07bee2d9c 100644
--- a/compiler/rustc_const_eval/src/util/caller_location.rs
+++ b/compiler/rustc_const_eval/src/util/caller_location.rs
@@ -7,12 +7,12 @@ use rustc_middle::ty::{self, Mutability};
 use rustc_span::symbol::Symbol;
 use tracing::trace;
 
-use crate::const_eval::{mk_eval_cx_to_read_const_val, CanAccessMutGlobal, CompileTimeEvalContext};
+use crate::const_eval::{mk_eval_cx_to_read_const_val, CanAccessMutGlobal, CompileTimeInterpCx};
 use crate::interpret::*;
 
 /// Allocate a `const core::panic::Location` with the provided filename and line/column numbers.
 fn alloc_caller_location<'tcx>(
-    ecx: &mut CompileTimeEvalContext<'tcx>,
+    ecx: &mut CompileTimeInterpCx<'tcx>,
     filename: Symbol,
     line: u32,
     col: u32,
diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
index 68fb122a765..daf57285ebe 100644
--- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
+++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
@@ -3,7 +3,7 @@ use rustc_middle::ty::layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout, Val
 use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Ty, TyCtxt};
 use rustc_target::abi::{Abi, FieldsShape, Scalar, Variants};
 
-use crate::const_eval::{CanAccessMutGlobal, CheckAlignment, CompileTimeInterpreter};
+use crate::const_eval::{CanAccessMutGlobal, CheckAlignment, CompileTimeMachine};
 use crate::interpret::{InterpCx, MemoryKind, OpTy};
 
 /// Determines if this type permits "raw" initialization by just transmuting some memory into an
@@ -45,7 +45,7 @@ fn might_permit_raw_init_strict<'tcx>(
     tcx: TyCtxt<'tcx>,
     kind: ValidityRequirement,
 ) -> Result<bool, &'tcx LayoutError<'tcx>> {
-    let machine = CompileTimeInterpreter::new(CanAccessMutGlobal::No, CheckAlignment::Error);
+    let machine = CompileTimeMachine::new(CanAccessMutGlobal::No, CheckAlignment::Error);
 
     let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine);
 
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index c3ccba487ed..69461957f80 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -244,7 +244,9 @@ language_item_table! {
     AsyncIterator,           sym::async_iterator,      async_iterator_trait,       Target::Trait,          GenericRequirement::Exact(0);
 
     CoroutineState,          sym::coroutine_state,     coroutine_state,            Target::Enum,           GenericRequirement::None;
-    Coroutine,               sym::coroutine,           coroutine_trait,            Target::Trait,          GenericRequirement::Minimum(1);
+    Coroutine,               sym::coroutine,           coroutine_trait,            Target::Trait,          GenericRequirement::Exact(1);
+    CoroutineReturn,         sym::coroutine_return,    coroutine_return,           Target::AssocTy,        GenericRequirement::Exact(1);
+    CoroutineYield,          sym::coroutine_yield,     coroutine_yield,            Target::AssocTy,        GenericRequirement::Exact(1);
     CoroutineResume,         sym::coroutine_resume,    coroutine_resume,           Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
 
     Unpin,                   sym::unpin,               unpin_trait,                Target::Trait,          GenericRequirement::None;
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index 01bd732a4cd..5e9c3c64e39 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -225,6 +225,50 @@ impl<'a, 'tcx> At<'a, 'tcx> {
         }
     }
 
+    /// Used in the new solver since we don't care about tracking an `ObligationCause`.
+    pub fn relate_no_trace<T>(
+        self,
+        expected: T,
+        variance: ty::Variance,
+        actual: T,
+    ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution>
+    where
+        T: Relate<TyCtxt<'tcx>>,
+    {
+        let mut fields = CombineFields::new(
+            self.infcx,
+            TypeTrace::dummy(self.cause),
+            self.param_env,
+            DefineOpaqueTypes::Yes,
+        );
+        fields.sub().relate_with_variance(
+            variance,
+            ty::VarianceDiagInfo::default(),
+            expected,
+            actual,
+        )?;
+        Ok(fields.goals)
+    }
+
+    /// Used in the new solver since we don't care about tracking an `ObligationCause`.
+    pub fn eq_structurally_relating_aliases_no_trace<T>(
+        self,
+        expected: T,
+        actual: T,
+    ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution>
+    where
+        T: Relate<TyCtxt<'tcx>>,
+    {
+        let mut fields = CombineFields::new(
+            self.infcx,
+            TypeTrace::dummy(self.cause),
+            self.param_env,
+            DefineOpaqueTypes::Yes,
+        );
+        fields.equate(StructurallyRelateAliases::Yes).relate(expected, actual)?;
+        Ok(fields.goals)
+    }
+
     /// Computes the least-upper-bound, or mutual supertype, of two
     /// values. The order of the arguments doesn't matter, but since
     /// this can result in an error (e.g., if asked to compute LUB of
@@ -303,7 +347,7 @@ impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
     ) -> TypeTrace<'tcx> {
         TypeTrace {
             cause: cause.clone(),
-            values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
+            values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
         }
     }
 }
@@ -315,7 +359,10 @@ impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> {
         a: Self,
         b: Self,
     ) -> TypeTrace<'tcx> {
-        TypeTrace { cause: cause.clone(), values: Regions(ExpectedFound::new(a_is_expected, a, b)) }
+        TypeTrace {
+            cause: cause.clone(),
+            values: ValuePairs::Regions(ExpectedFound::new(a_is_expected, a, b)),
+        }
     }
 }
 
@@ -328,7 +375,7 @@ impl<'tcx> ToTrace<'tcx> for Const<'tcx> {
     ) -> TypeTrace<'tcx> {
         TypeTrace {
             cause: cause.clone(),
-            values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
+            values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
         }
     }
 }
@@ -344,13 +391,13 @@ impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> {
             cause: cause.clone(),
             values: match (a.unpack(), b.unpack()) {
                 (GenericArgKind::Lifetime(a), GenericArgKind::Lifetime(b)) => {
-                    Regions(ExpectedFound::new(a_is_expected, a, b))
+                    ValuePairs::Regions(ExpectedFound::new(a_is_expected, a, b))
                 }
                 (GenericArgKind::Type(a), GenericArgKind::Type(b)) => {
-                    Terms(ExpectedFound::new(a_is_expected, a.into(), b.into()))
+                    ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into()))
                 }
                 (GenericArgKind::Const(a), GenericArgKind::Const(b)) => {
-                    Terms(ExpectedFound::new(a_is_expected, a.into(), b.into()))
+                    ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into()))
                 }
 
                 (
@@ -379,7 +426,10 @@ impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> {
         a: Self,
         b: Self,
     ) -> TypeTrace<'tcx> {
-        TypeTrace { cause: cause.clone(), values: Terms(ExpectedFound::new(a_is_expected, a, b)) }
+        TypeTrace {
+            cause: cause.clone(),
+            values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a, b)),
+        }
     }
 }
 
@@ -392,7 +442,7 @@ impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
     ) -> TypeTrace<'tcx> {
         TypeTrace {
             cause: cause.clone(),
-            values: TraitRefs(ExpectedFound::new(a_is_expected, a, b)),
+            values: ValuePairs::TraitRefs(ExpectedFound::new(a_is_expected, a, b)),
         }
     }
 }
@@ -406,7 +456,7 @@ impl<'tcx> ToTrace<'tcx> for ty::AliasTy<'tcx> {
     ) -> TypeTrace<'tcx> {
         TypeTrace {
             cause: cause.clone(),
-            values: Aliases(ExpectedFound::new(a_is_expected, a.into(), b.into())),
+            values: ValuePairs::Aliases(ExpectedFound::new(a_is_expected, a.into(), b.into())),
         }
     }
 }
@@ -418,7 +468,10 @@ impl<'tcx> ToTrace<'tcx> for ty::AliasTerm<'tcx> {
         a: Self,
         b: Self,
     ) -> TypeTrace<'tcx> {
-        TypeTrace { cause: cause.clone(), values: Aliases(ExpectedFound::new(a_is_expected, a, b)) }
+        TypeTrace {
+            cause: cause.clone(),
+            values: ValuePairs::Aliases(ExpectedFound::new(a_is_expected, a, b)),
+        }
     }
 }
 
@@ -431,7 +484,7 @@ impl<'tcx> ToTrace<'tcx> for ty::FnSig<'tcx> {
     ) -> TypeTrace<'tcx> {
         TypeTrace {
             cause: cause.clone(),
-            values: PolySigs(ExpectedFound::new(
+            values: ValuePairs::PolySigs(ExpectedFound::new(
                 a_is_expected,
                 ty::Binder::dummy(a),
                 ty::Binder::dummy(b),
@@ -449,7 +502,7 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyFnSig<'tcx> {
     ) -> TypeTrace<'tcx> {
         TypeTrace {
             cause: cause.clone(),
-            values: PolySigs(ExpectedFound::new(a_is_expected, a, b)),
+            values: ValuePairs::PolySigs(ExpectedFound::new(a_is_expected, a, b)),
         }
     }
 }
@@ -463,7 +516,7 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialTraitRef<'tcx> {
     ) -> TypeTrace<'tcx> {
         TypeTrace {
             cause: cause.clone(),
-            values: ExistentialTraitRef(ExpectedFound::new(a_is_expected, a, b)),
+            values: ValuePairs::ExistentialTraitRef(ExpectedFound::new(a_is_expected, a, b)),
         }
     }
 }
@@ -477,7 +530,7 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialProjection<'tcx> {
     ) -> TypeTrace<'tcx> {
         TypeTrace {
             cause: cause.clone(),
-            values: ExistentialProjection(ExpectedFound::new(a_is_expected, a, b)),
+            values: ValuePairs::ExistentialProjection(ExpectedFound::new(a_is_expected, a, b)),
         }
     }
 }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index ed483c6cbeb..7fb07a5d30c 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -1707,6 +1707,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     ValuePairs::ExistentialProjection(_) => {
                         (false, Mismatch::Fixed("existential projection"))
                     }
+                    ValuePairs::Dummy => {
+                        bug!("do not expect to report a type error from a ValuePairs::Dummy")
+                    }
                 };
                 let Some(vals) = self.values_str(values) else {
                     // Derived error. Cancel the emitter.
@@ -2250,12 +2253,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         values: ValuePairs<'tcx>,
     ) -> Option<(DiagStyledString, DiagStyledString, Option<PathBuf>)> {
         match values {
-            infer::Regions(exp_found) => self.expected_found_str(exp_found),
-            infer::Terms(exp_found) => self.expected_found_str_term(exp_found),
-            infer::Aliases(exp_found) => self.expected_found_str(exp_found),
-            infer::ExistentialTraitRef(exp_found) => self.expected_found_str(exp_found),
-            infer::ExistentialProjection(exp_found) => self.expected_found_str(exp_found),
-            infer::TraitRefs(exp_found) => {
+            ValuePairs::Regions(exp_found) => self.expected_found_str(exp_found),
+            ValuePairs::Terms(exp_found) => self.expected_found_str_term(exp_found),
+            ValuePairs::Aliases(exp_found) => self.expected_found_str(exp_found),
+            ValuePairs::ExistentialTraitRef(exp_found) => self.expected_found_str(exp_found),
+            ValuePairs::ExistentialProjection(exp_found) => self.expected_found_str(exp_found),
+            ValuePairs::TraitRefs(exp_found) => {
                 let pretty_exp_found = ty::error::ExpectedFound {
                     expected: exp_found.expected.print_trait_sugared(),
                     found: exp_found.found.print_trait_sugared(),
@@ -2267,7 +2270,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     ret => ret,
                 }
             }
-            infer::PolySigs(exp_found) => {
+            ValuePairs::PolySigs(exp_found) => {
                 let exp_found = self.resolve_vars_if_possible(exp_found);
                 if exp_found.references_error() {
                     return None;
@@ -2275,6 +2278,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 let (exp, fnd) = self.cmp_fn_sig(&exp_found.expected, &exp_found.found);
                 Some((exp, fnd, None))
             }
+            ValuePairs::Dummy => {
+                bug!("do not expect to report a type error from a ValuePairs::Dummy")
+            }
         }
     }
 
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 32b50053b50..dcf415e720f 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -9,9 +9,8 @@ pub use rustc_middle::ty::IntVarValue;
 pub use BoundRegionConversionTime::*;
 pub use RegionVariableOrigin::*;
 pub use SubregionOrigin::*;
-pub use ValuePairs::*;
 
-use crate::infer::relate::RelateResult;
+use crate::infer::relate::{Relate, RelateResult};
 use crate::traits::{self, ObligationCause, ObligationInspector, PredicateObligation, TraitEngine};
 use error_reporting::TypeErrCtxt;
 use free_regions::RegionRelations;
@@ -35,6 +34,7 @@ use rustc_middle::infer::unify_key::{ConstVidKey, EffectVidKey};
 use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult};
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::traits::select;
+use rustc_middle::traits::solve::{Goal, NoSolution};
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::fold::BoundVarReplacerDelegate;
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
@@ -44,7 +44,7 @@ use rustc_middle::ty::{ConstVid, EffectVid, FloatVid, IntVid, TyVid};
 use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgs, GenericArgsRef};
 use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::Symbol;
-use rustc_span::Span;
+use rustc_span::{Span, DUMMY_SP};
 use snapshot::undo_log::InferCtxtUndoLogs;
 use std::cell::{Cell, RefCell};
 use std::fmt;
@@ -352,27 +352,27 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> {
         }
     }
 
-    fn universe_of_ct(&self, ct: ConstVid) -> Option<ty::UniverseIndex> {
-        // Same issue as with `universe_of_ty`
-        match self.probe_const_var(ct) {
+    fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex> {
+        match self.inner.borrow_mut().unwrap_region_constraints().probe_value(lt) {
             Err(universe) => Some(universe),
             Ok(_) => None,
         }
     }
 
-    fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex> {
-        match self.inner.borrow_mut().unwrap_region_constraints().probe_value(lt) {
+    fn universe_of_ct(&self, ct: ConstVid) -> Option<ty::UniverseIndex> {
+        // Same issue as with `universe_of_ty`
+        match self.probe_const_var(ct) {
             Err(universe) => Some(universe),
             Ok(_) => None,
         }
     }
 
-    fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> {
-        self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid)
+    fn root_ty_var(&self, var: TyVid) -> TyVid {
+        self.root_var(var)
     }
 
-    fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> {
-        self.defining_opaque_types
+    fn root_const_var(&self, var: ConstVid) -> ConstVid {
+        self.root_const_var(var)
     }
 
     fn opportunistic_resolve_ty_var(&self, vid: TyVid) -> Ty<'tcx> {
@@ -405,6 +405,72 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> {
             }
         }
     }
+
+    fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> {
+        self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid)
+    }
+
+    fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> {
+        self.defining_opaque_types
+    }
+
+    fn next_ty_infer(&self) -> Ty<'tcx> {
+        self.next_ty_var(DUMMY_SP)
+    }
+
+    fn next_const_infer(&self) -> ty::Const<'tcx> {
+        self.next_const_var(DUMMY_SP)
+    }
+
+    fn fresh_args_for_item(&self, def_id: DefId) -> ty::GenericArgsRef<'tcx> {
+        self.fresh_args_for_item(DUMMY_SP, def_id)
+    }
+
+    fn instantiate_binder_with_infer<T: TypeFoldable<Self::Interner> + Copy>(
+        &self,
+        value: ty::Binder<'tcx, T>,
+    ) -> T {
+        self.instantiate_binder_with_fresh_vars(
+            DUMMY_SP,
+            BoundRegionConversionTime::HigherRankedType,
+            value,
+        )
+    }
+
+    fn enter_forall<T: TypeFoldable<TyCtxt<'tcx>> + Copy, U>(
+        &self,
+        value: ty::Binder<'tcx, T>,
+        f: impl FnOnce(T) -> U,
+    ) -> U {
+        self.enter_forall(value, f)
+    }
+
+    fn relate<T: Relate<TyCtxt<'tcx>>>(
+        &self,
+        param_env: ty::ParamEnv<'tcx>,
+        lhs: T,
+        variance: ty::Variance,
+        rhs: T,
+    ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
+        self.at(&ObligationCause::dummy(), param_env).relate_no_trace(lhs, variance, rhs)
+    }
+
+    fn eq_structurally_relating_aliases<T: Relate<TyCtxt<'tcx>>>(
+        &self,
+        param_env: ty::ParamEnv<'tcx>,
+        lhs: T,
+        rhs: T,
+    ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
+        self.at(&ObligationCause::dummy(), param_env)
+            .eq_structurally_relating_aliases_no_trace(lhs, rhs)
+    }
+
+    fn resolve_vars_if_possible<T>(&self, value: T) -> T
+    where
+        T: TypeFoldable<TyCtxt<'tcx>>,
+    {
+        self.resolve_vars_if_possible(value)
+    }
 }
 
 /// See the `error_reporting` module for more details.
@@ -417,6 +483,7 @@ pub enum ValuePairs<'tcx> {
     PolySigs(ExpectedFound<ty::PolyFnSig<'tcx>>),
     ExistentialTraitRef(ExpectedFound<ty::PolyExistentialTraitRef<'tcx>>),
     ExistentialProjection(ExpectedFound<ty::PolyExistentialProjection<'tcx>>),
+    Dummy,
 }
 
 impl<'tcx> ValuePairs<'tcx> {
@@ -1812,7 +1879,7 @@ impl<'tcx> TypeTrace<'tcx> {
     ) -> TypeTrace<'tcx> {
         TypeTrace {
             cause: cause.clone(),
-            values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
+            values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
         }
     }
 
@@ -1824,7 +1891,7 @@ impl<'tcx> TypeTrace<'tcx> {
     ) -> TypeTrace<'tcx> {
         TypeTrace {
             cause: cause.clone(),
-            values: TraitRefs(ExpectedFound::new(a_is_expected, a, b)),
+            values: ValuePairs::TraitRefs(ExpectedFound::new(a_is_expected, a, b)),
         }
     }
 
@@ -1836,9 +1903,13 @@ impl<'tcx> TypeTrace<'tcx> {
     ) -> TypeTrace<'tcx> {
         TypeTrace {
             cause: cause.clone(),
-            values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
+            values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
         }
     }
+
+    fn dummy(cause: &ObligationCause<'tcx>) -> TypeTrace<'tcx> {
+        TypeTrace { cause: cause.clone(), values: ValuePairs::Dummy }
+    }
 }
 
 impl<'tcx> SubregionOrigin<'tcx> {
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index 886dbd317af..a89ebe46c37 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -204,6 +204,23 @@ impl<'tcx> rustc_type_ir::inherent::AdtDef<TyCtxt<'tcx>> for AdtDef<'tcx> {
     fn def_id(self) -> DefId {
         self.did()
     }
+
+    fn is_phantom_data(self) -> bool {
+        self.is_phantom_data()
+    }
+
+    fn all_field_tys(
+        self,
+        tcx: TyCtxt<'tcx>,
+    ) -> ty::EarlyBinder<'tcx, impl Iterator<Item = Ty<'tcx>>> {
+        ty::EarlyBinder::bind(
+            self.all_fields().map(move |field| tcx.type_of(field.did).skip_binder()),
+        )
+    }
+
+    fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> Option<ty::EarlyBinder<'tcx, Ty<'tcx>>> {
+        self.sized_constraint(tcx)
+    }
 }
 
 #[derive(Copy, Clone, Debug, Eq, PartialEq, HashStable, TyEncodable, TyDecodable)]
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 65d744239a6..3651c990c97 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -70,9 +70,9 @@ use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx};
 use rustc_target::spec::abi;
 use rustc_type_ir::fold::TypeFoldable;
+use rustc_type_ir::lang_items::TraitSolverLangItem;
 use rustc_type_ir::TyKind::*;
-use rustc_type_ir::WithCachedTypeInfo;
-use rustc_type_ir::{CollectAndApply, Interner, TypeFlags};
+use rustc_type_ir::{CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo};
 use tracing::{debug, instrument};
 
 use std::assert_matches::assert_matches;
@@ -154,7 +154,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
 
     type VariancesOf = &'tcx [ty::Variance];
 
-    fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf {
+    fn variances_of(self, def_id: DefId) -> Self::VariancesOf {
         self.variances_of(def_id)
     }
 
@@ -198,7 +198,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
 
     fn trait_ref_and_own_args_for_alias(
         self,
-        def_id: Self::DefId,
+        def_id: DefId,
         args: Self::GenericArgs,
     ) -> (rustc_type_ir::TraitRef<Self>, Self::GenericArgsSlice) {
         assert_matches!(self.def_kind(def_id), DefKind::AssocTy | DefKind::AssocConst);
@@ -246,7 +246,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
         self.mk_type_list_from_iter(args)
     }
 
-    fn parent(self, def_id: Self::DefId) -> Self::DefId {
+    fn parent(self, def_id: DefId) -> DefId {
         self.parent(def_id)
     }
 
@@ -259,15 +259,85 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     fn features(self) -> Self::Features {
         self.features()
     }
+
+    fn bound_coroutine_hidden_types(
+        self,
+        def_id: DefId,
+    ) -> impl IntoIterator<Item = ty::EarlyBinder<'tcx, ty::Binder<'tcx, Ty<'tcx>>>> {
+        self.bound_coroutine_hidden_types(def_id)
+    }
+
+    fn fn_sig(self, def_id: DefId) -> ty::EarlyBinder<'tcx, ty::PolyFnSig<'tcx>> {
+        self.fn_sig(def_id)
+    }
+
+    fn coroutine_movability(self, def_id: DefId) -> rustc_ast::Movability {
+        self.coroutine_movability(def_id)
+    }
+
+    fn coroutine_for_closure(self, def_id: DefId) -> DefId {
+        self.coroutine_for_closure(def_id)
+    }
+
+    fn generics_require_sized_self(self, def_id: DefId) -> bool {
+        self.generics_require_sized_self(def_id)
+    }
+
+    fn item_bounds(
+        self,
+        def_id: DefId,
+    ) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Clause<'tcx>>> {
+        self.item_bounds(def_id).map_bound(IntoIterator::into_iter)
+    }
+
+    fn super_predicates_of(
+        self,
+        def_id: DefId,
+    ) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Clause<'tcx>>> {
+        ty::EarlyBinder::bind(
+            self.super_predicates_of(def_id).instantiate_identity(self).predicates.into_iter(),
+        )
+    }
+
+    fn has_target_features(self, def_id: DefId) -> bool {
+        !self.codegen_fn_attrs(def_id).target_features.is_empty()
+    }
+
+    fn require_lang_item(self, lang_item: TraitSolverLangItem) -> DefId {
+        self.require_lang_item(
+            match lang_item {
+                TraitSolverLangItem::Future => hir::LangItem::Future,
+                TraitSolverLangItem::FutureOutput => hir::LangItem::FutureOutput,
+                TraitSolverLangItem::AsyncFnKindHelper => hir::LangItem::AsyncFnKindHelper,
+                TraitSolverLangItem::AsyncFnKindUpvars => hir::LangItem::AsyncFnKindUpvars,
+            },
+            None,
+        )
+    }
+
+    fn associated_type_def_ids(self, def_id: DefId) -> impl IntoIterator<Item = DefId> {
+        self.associated_items(def_id)
+            .in_definition_order()
+            .filter(|assoc_item| matches!(assoc_item.kind, ty::AssocKind::Type))
+            .map(|assoc_item| assoc_item.def_id)
+    }
 }
 
 impl<'tcx> rustc_type_ir::inherent::Abi<TyCtxt<'tcx>> for abi::Abi {
+    fn rust() -> Self {
+        abi::Abi::Rust
+    }
+
     fn is_rust(self) -> bool {
         matches!(self, abi::Abi::Rust)
     }
 }
 
 impl<'tcx> rustc_type_ir::inherent::Safety<TyCtxt<'tcx>> for hir::Safety {
+    fn safe() -> Self {
+        hir::Safety::Safe
+    }
+
     fn is_safe(self) -> bool {
         matches!(self, hir::Safety::Safe)
     }
@@ -281,6 +351,10 @@ impl<'tcx> rustc_type_ir::inherent::Features<TyCtxt<'tcx>> for &'tcx rustc_featu
     fn generic_const_exprs(self) -> bool {
         self.generic_const_exprs
     }
+
+    fn coroutine_clone(self) -> bool {
+        self.coroutine_clone
+    }
 }
 
 type InternedSet<'tcx, T> = ShardedHashMap<InternedInSet<'tcx, T>, ()>;
diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs
index 7fff3d01324..54c88e48614 100644
--- a/compiler/rustc_middle/src/ty/generic_args.rs
+++ b/compiler/rustc_middle/src/ty/generic_args.rs
@@ -41,6 +41,8 @@ pub struct GenericArg<'tcx> {
     marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>)>,
 }
 
+impl<'tcx> rustc_type_ir::inherent::GenericArg<TyCtxt<'tcx>> for GenericArg<'tcx> {}
+
 impl<'tcx> rustc_type_ir::inherent::GenericArgs<TyCtxt<'tcx>> for ty::GenericArgsRef<'tcx> {
     fn type_at(self, i: usize) -> Ty<'tcx> {
         self.type_at(i)
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 83f8de6b6f9..c322c87bce4 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -488,6 +488,8 @@ pub struct Term<'tcx> {
     marker: PhantomData<(Ty<'tcx>, Const<'tcx>)>,
 }
 
+impl<'tcx> rustc_type_ir::inherent::Term<TyCtxt<'tcx>> for Term<'tcx> {}
+
 impl<'tcx> rustc_type_ir::inherent::IntoKind for Term<'tcx> {
     type Kind = TermKind<'tcx>;
 
diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs
index 785aa8d456f..ae36f2624ca 100644
--- a/compiler/rustc_middle/src/ty/predicate.rs
+++ b/compiler/rustc_middle/src/ty/predicate.rs
@@ -49,6 +49,18 @@ impl<'tcx> rustc_type_ir::inherent::Predicate<TyCtxt<'tcx>> for Predicate<'tcx>
     fn is_coinductive(self, interner: TyCtxt<'tcx>) -> bool {
         self.is_coinductive(interner)
     }
+
+    fn allow_normalization(self) -> bool {
+        self.allow_normalization()
+    }
+}
+
+impl<'tcx> rustc_type_ir::inherent::IntoKind for Predicate<'tcx> {
+    type Kind = ty::Binder<'tcx, ty::PredicateKind<'tcx>>;
+
+    fn kind(self) -> Self::Kind {
+        self.kind()
+    }
 }
 
 impl<'tcx> rustc_type_ir::visit::Flags for Predicate<'tcx> {
@@ -120,6 +132,7 @@ impl<'tcx> Predicate<'tcx> {
     /// unsoundly accept some programs. See #91068.
     #[inline]
     pub fn allow_normalization(self) -> bool {
+        // Keep this in sync with the one in `rustc_type_ir::inherent`!
         match self.kind().skip_binder() {
             PredicateKind::Clause(ClauseKind::WellFormed(_))
             | PredicateKind::AliasRelate(..)
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index ba9ed0d5b70..8308e537e5e 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -786,6 +786,10 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> {
         tcx.types.bool
     }
 
+    fn new_u8(tcx: TyCtxt<'tcx>) -> Self {
+        tcx.types.u8
+    }
+
     fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferTy) -> Self {
         Ty::new_infer(tcx, infer)
     }
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 121a3b99a39..0f8f28e3462 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -330,8 +330,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
         let is_sized = !self.feature_unsized_locals
             || self.local_decls[local].ty.is_sized(self.tcx, self.param_env);
         if is_sized {
-            self.rev_locals.ensure_contains_elem(value, SmallVec::new);
-            self.rev_locals[value].push(local);
+            self.rev_locals.ensure_contains_elem(value, SmallVec::new).push(local);
         }
     }
 
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index a72fbdb9021..6a74ddc5508 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -898,7 +898,7 @@ fn create_and_seed_worklist(
                     match tcx.def_kind(id) {
                         DefKind::Impl { .. } => false,
                         DefKind::AssocConst | DefKind::AssocFn => !matches!(tcx.associated_item(id).container, AssocItemContainer::ImplContainer),
-                        DefKind::Struct => struct_all_fields_are_public(tcx, id.to_def_id()),
+                        DefKind::Struct => struct_all_fields_are_public(tcx, id.to_def_id()) || has_allow_dead_code_or_lang_attr(tcx, id).is_some(),
                         _ => true
                     })
                 .map(|id| (id, ComesFromAllowExpect::No))
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index d1541527cf5..8d470c6c61e 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -2783,33 +2783,65 @@ fn show_candidates(
     // by iterating through a hash map, so make sure they are ordered:
     for path_strings in [&mut accessible_path_strings, &mut inaccessible_path_strings] {
         path_strings.sort_by(|a, b| a.0.cmp(&b.0));
+        path_strings.dedup_by(|a, b| a.0 == b.0);
         let core_path_strings =
             path_strings.extract_if(|p| p.0.starts_with("core::")).collect::<Vec<_>>();
-        path_strings.extend(core_path_strings);
-        path_strings.dedup_by(|a, b| a.0 == b.0);
+        let std_path_strings =
+            path_strings.extract_if(|p| p.0.starts_with("std::")).collect::<Vec<_>>();
+        let foreign_crate_path_strings =
+            path_strings.extract_if(|p| !p.0.starts_with("crate::")).collect::<Vec<_>>();
+
+        // We list the `crate` local paths first.
+        // Then we list the `std`/`core` paths.
+        if std_path_strings.len() == core_path_strings.len() {
+            // Do not list `core::` paths if we are already listing the `std::` ones.
+            path_strings.extend(std_path_strings);
+        } else {
+            path_strings.extend(std_path_strings);
+            path_strings.extend(core_path_strings);
+        }
+        // List all paths from foreign crates last.
+        path_strings.extend(foreign_crate_path_strings);
     }
-    accessible_path_strings.sort();
 
     if !accessible_path_strings.is_empty() {
-        let (determiner, kind, name, through) =
+        let (determiner, kind, s, name, through) =
             if let [(name, descr, _, _, via_import)] = &accessible_path_strings[..] {
                 (
                     "this",
                     *descr,
+                    "",
                     format!(" `{name}`"),
                     if *via_import { " through its public re-export" } else { "" },
                 )
             } else {
-                ("one of these", "items", String::new(), "")
+                // Get the unique item kinds and if there's only one, we use the right kind name
+                // instead of the more generic "items".
+                let mut kinds = accessible_path_strings
+                    .iter()
+                    .map(|(_, descr, _, _, _)| *descr)
+                    .collect::<FxHashSet<&str>>()
+                    .into_iter();
+                let kind = if let Some(kind) = kinds.next()
+                    && let None = kinds.next()
+                {
+                    kind
+                } else {
+                    "item"
+                };
+                let s = if kind.ends_with('s') { "es" } else { "s" };
+
+                ("one of these", kind, s, String::new(), "")
             };
 
         let instead = if let Instead::Yes = instead { " instead" } else { "" };
         let mut msg = if let DiagMode::Pattern = mode {
             format!(
-                "if you meant to match on {kind}{instead}{name}, use the full path in the pattern",
+                "if you meant to match on {kind}{s}{instead}{name}, use the full path in the \
+                 pattern",
             )
         } else {
-            format!("consider importing {determiner} {kind}{through}{instead}")
+            format!("consider importing {determiner} {kind}{s}{through}{instead}")
         };
 
         for note in accessible_path_strings.iter().flat_map(|cand| cand.3.as_ref()) {
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index e245dfb9f5d..c89323b7f16 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -635,7 +635,9 @@ symbols! {
         coroutine,
         coroutine_clone,
         coroutine_resume,
+        coroutine_return,
         coroutine_state,
+        coroutine_yield,
         coroutines,
         cosf128,
         cosf16,
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
index 98f98d9992d..d6074617caf 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
@@ -1,14 +1,14 @@
 //! Code which is used by built-in goals that match "structurally", such a auto
 //! traits, `Copy`/`Clone`.
+
+use rustc_ast_ir::{Movability, Mutability};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::LangItem;
-use rustc_hir::{def_id::DefId, Movability, Mutability};
-use rustc_infer::infer::InferCtxt;
-use rustc_infer::traits::query::NoSolution;
-use rustc_macros::{TypeFoldable, TypeVisitable};
-use rustc_middle::bug;
-use rustc_middle::traits::solve::Goal;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, Upcast};
+use rustc_next_trait_solver::solve::{Goal, NoSolution};
+use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
+use rustc_type_ir::inherent::*;
+use rustc_type_ir::lang_items::TraitSolverLangItem;
+use rustc_type_ir::{self as ty, InferCtxtLike, Interner, Upcast};
+use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
 
 use crate::solve::EvalCtxt;
 
@@ -17,12 +17,16 @@ use crate::solve::EvalCtxt;
 // For types with an "existential" binder, i.e. coroutine witnesses, we also
 // instantiate the binder with placeholders eagerly.
 #[instrument(level = "trace", skip(ecx), ret)]
-pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
-    ecx: &EvalCtxt<'_, InferCtxt<'tcx>>,
-    ty: Ty<'tcx>,
-) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution> {
+pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<Infcx, I>(
+    ecx: &EvalCtxt<'_, Infcx>,
+    ty: I::Ty,
+) -> Result<Vec<ty::Binder<I, I::Ty>>, NoSolution>
+where
+    Infcx: InferCtxtLike<Interner = I>,
+    I: Interner,
+{
     let tcx = ecx.interner();
-    match *ty.kind() {
+    match ty.kind() {
         ty::Uint(_)
         | ty::Int(_)
         | ty::Bool
@@ -34,7 +38,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
         | ty::Char => Ok(vec![]),
 
         // Treat `str` like it's defined as `struct str([u8]);`
-        ty::Str => Ok(vec![ty::Binder::dummy(Ty::new_slice(tcx, tcx.types.u8))]),
+        ty::Str => Ok(vec![ty::Binder::dummy(Ty::new_slice(tcx, Ty::new_u8(tcx)))]),
 
         ty::Dynamic(..)
         | ty::Param(..)
@@ -43,7 +47,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
         | ty::Placeholder(..)
         | ty::Bound(..)
         | ty::Infer(_) => {
-            bug!("unexpected type `{ty}`")
+            panic!("unexpected type `{ty:?}`")
         }
 
         ty::RawPtr(element_ty, _) | ty::Ref(_, element_ty, _) => {
@@ -56,7 +60,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
 
         ty::Tuple(tys) => {
             // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
-            Ok(tys.iter().map(ty::Binder::dummy).collect())
+            Ok(tys.into_iter().map(ty::Binder::dummy).collect())
         }
 
         ty::Closure(_, args) => Ok(vec![ty::Binder::dummy(args.as_closure().tupled_upvars_ty())]),
@@ -76,31 +80,38 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
         ty::CoroutineWitness(def_id, args) => Ok(ecx
             .interner()
             .bound_coroutine_hidden_types(def_id)
-            .map(|bty| bty.instantiate(tcx, args))
+            .into_iter()
+            .map(|bty| bty.instantiate(tcx, &args))
             .collect()),
 
         // For `PhantomData<T>`, we pass `T`.
         ty::Adt(def, args) if def.is_phantom_data() => Ok(vec![ty::Binder::dummy(args.type_at(0))]),
 
-        ty::Adt(def, args) => {
-            Ok(def.all_fields().map(|f| ty::Binder::dummy(f.ty(tcx, args))).collect())
-        }
+        ty::Adt(def, args) => Ok(def
+            .all_field_tys(tcx)
+            .iter_instantiated(tcx, &args)
+            .map(ty::Binder::dummy)
+            .collect()),
 
         ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
             // We can resolve the `impl Trait` to its concrete type,
             // which enforces a DAG between the functions requiring
             // the auto trait bounds in question.
-            Ok(vec![ty::Binder::dummy(tcx.type_of(def_id).instantiate(tcx, args))])
+            Ok(vec![ty::Binder::dummy(tcx.type_of(def_id).instantiate(tcx, &args))])
         }
     }
 }
 
 #[instrument(level = "trace", skip(ecx), ret)]
-pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
-    ecx: &EvalCtxt<'_, InferCtxt<'tcx>>,
-    ty: Ty<'tcx>,
-) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution> {
-    match *ty.kind() {
+pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<Infcx, I>(
+    ecx: &EvalCtxt<'_, Infcx>,
+    ty: I::Ty,
+) -> Result<Vec<ty::Binder<I, I::Ty>>, NoSolution>
+where
+    Infcx: InferCtxtLike<Interner = I>,
+    I: Interner,
+{
+    match ty.kind() {
         // impl Sized for u*, i*, bool, f*, FnDef, FnPtr, *(const/mut) T, char, &mut? T, [T; N], dyn* Trait, !
         // impl Sized for Coroutine, CoroutineWitness, Closure, CoroutineClosure
         ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
@@ -133,7 +144,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
 
         ty::Bound(..)
         | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
-            bug!("unexpected type `{ty}`")
+            panic!("unexpected type `{ty:?}`")
         }
 
         // impl Sized for ()
@@ -151,7 +162,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
         //   if the ADT is sized for all possible args.
         ty::Adt(def, args) => {
             if let Some(sized_crit) = def.sized_constraint(ecx.interner()) {
-                Ok(vec![ty::Binder::dummy(sized_crit.instantiate(ecx.interner(), args))])
+                Ok(vec![ty::Binder::dummy(sized_crit.instantiate(ecx.interner(), &args))])
             } else {
                 Ok(vec![])
             }
@@ -160,11 +171,15 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
 }
 
 #[instrument(level = "trace", skip(ecx), ret)]
-pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
-    ecx: &EvalCtxt<'_, InferCtxt<'tcx>>,
-    ty: Ty<'tcx>,
-) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution> {
-    match *ty.kind() {
+pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<Infcx, I>(
+    ecx: &EvalCtxt<'_, Infcx>,
+    ty: I::Ty,
+) -> Result<Vec<ty::Binder<I, I::Ty>>, NoSolution>
+where
+    Infcx: InferCtxtLike<Interner = I>,
+    I: Interner,
+{
+    match ty.kind() {
         // impl Copy/Clone for FnDef, FnPtr
         ty::FnDef(..) | ty::FnPtr(_) | ty::Error(_) => Ok(vec![]),
 
@@ -196,11 +211,11 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
 
         ty::Bound(..)
         | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
-            bug!("unexpected type `{ty}`")
+            panic!("unexpected type `{ty:?}`")
         }
 
         // impl Copy/Clone for (T1, T2, .., Tn) where T1: Copy/Clone, T2: Copy/Clone, .. Tn: Copy/Clone
-        ty::Tuple(tys) => Ok(tys.iter().map(ty::Binder::dummy).collect()),
+        ty::Tuple(tys) => Ok(tys.into_iter().map(ty::Binder::dummy).collect()),
 
         // impl Copy/Clone for Closure where Self::TupledUpvars: Copy/Clone
         ty::Closure(_, args) => Ok(vec![ty::Binder::dummy(args.as_closure().tupled_upvars_ty())]),
@@ -212,7 +227,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
         ty::Coroutine(def_id, args) => match ecx.interner().coroutine_movability(def_id) {
             Movability::Static => Err(NoSolution),
             Movability::Movable => {
-                if ecx.interner().features().coroutine_clone {
+                if ecx.interner().features().coroutine_clone() {
                     let coroutine = args.as_coroutine();
                     Ok(vec![
                         ty::Binder::dummy(coroutine.tupled_upvars_ty()),
@@ -228,27 +243,26 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
         ty::CoroutineWitness(def_id, args) => Ok(ecx
             .interner()
             .bound_coroutine_hidden_types(def_id)
-            .map(|bty| bty.instantiate(ecx.interner(), args))
+            .into_iter()
+            .map(|bty| bty.instantiate(ecx.interner(), &args))
             .collect()),
     }
 }
 
 // Returns a binder of the tupled inputs types and output type from a builtin callable type.
-pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    self_ty: Ty<'tcx>,
+pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<I: Interner>(
+    tcx: I,
+    self_ty: I::Ty,
     goal_kind: ty::ClosureKind,
-) -> Result<Option<ty::Binder<'tcx, (Ty<'tcx>, Ty<'tcx>)>>, NoSolution> {
-    match *self_ty.kind() {
+) -> Result<Option<ty::Binder<I, (I::Ty, I::Ty)>>, NoSolution> {
+    match self_ty.kind() {
         // keep this in sync with assemble_fn_pointer_candidates until the old solver is removed.
         ty::FnDef(def_id, args) => {
             let sig = tcx.fn_sig(def_id);
-            if sig.skip_binder().is_fn_trait_compatible()
-                && tcx.codegen_fn_attrs(def_id).target_features.is_empty()
-            {
+            if sig.skip_binder().is_fn_trait_compatible() && !tcx.has_target_features(def_id) {
                 Ok(Some(
-                    sig.instantiate(tcx, args)
-                        .map_bound(|sig| (Ty::new_tup(tcx, sig.inputs()), sig.output())),
+                    sig.instantiate(tcx, &args)
+                        .map_bound(|sig| (Ty::new_tup(tcx, &sig.inputs()), sig.output())),
                 ))
             } else {
                 Err(NoSolution)
@@ -257,7 +271,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
         // keep this in sync with assemble_fn_pointer_candidates until the old solver is removed.
         ty::FnPtr(sig) => {
             if sig.is_fn_trait_compatible() {
-                Ok(Some(sig.map_bound(|sig| (Ty::new_tup(tcx, sig.inputs()), sig.output()))))
+                Ok(Some(sig.map_bound(|sig| (Ty::new_tup(tcx, &sig.inputs()), sig.output()))))
             } else {
                 Err(NoSolution)
             }
@@ -311,7 +325,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
                     tcx,
                     goal_kind,
                     // No captures by ref, so this doesn't matter.
-                    tcx.lifetimes.re_static,
+                    Region::new_static(tcx),
                     def_id,
                     args,
                     sig,
@@ -326,7 +340,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
                 coroutine_closure_to_ambiguous_coroutine(
                     tcx,
                     goal_kind, // No captures by ref, so this doesn't matter.
-                    tcx.lifetimes.re_static,
+                    Region::new_static(tcx),
                     def_id,
                     args,
                     sig,
@@ -362,22 +376,24 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
 
         ty::Bound(..)
         | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
-            bug!("unexpected type `{self_ty}`")
+            panic!("unexpected type `{self_ty:?}`")
         }
     }
 }
 
 /// Relevant types for an async callable, including its inputs, output,
 /// and the return type you get from awaiting the output.
-#[derive(Copy, Clone, Debug, TypeVisitable, TypeFoldable)]
-pub(in crate::solve) struct AsyncCallableRelevantTypes<'tcx> {
-    pub tupled_inputs_ty: Ty<'tcx>,
+#[derive(derivative::Derivative)]
+#[derivative(Clone(bound = ""), Copy(bound = ""), Debug(bound = ""))]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+pub(in crate::solve) struct AsyncCallableRelevantTypes<I: Interner> {
+    pub tupled_inputs_ty: I::Ty,
     /// Type returned by calling the closure
     /// i.e. `f()`.
-    pub output_coroutine_ty: Ty<'tcx>,
+    pub output_coroutine_ty: I::Ty,
     /// Type returned by `await`ing the output
     /// i.e. `f().await`.
-    pub coroutine_return_ty: Ty<'tcx>,
+    pub coroutine_return_ty: I::Ty,
 }
 
 // Returns a binder of the tupled inputs types, output type, and coroutine type
@@ -385,16 +401,13 @@ pub(in crate::solve) struct AsyncCallableRelevantTypes<'tcx> {
 // the coroutine-closure, emit an additional trait predicate for `AsyncFnKindHelper`
 // which enforces the closure is actually callable with the given trait. When we
 // know the kind already, we can short-circuit this check.
-pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    self_ty: Ty<'tcx>,
+pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<I: Interner>(
+    tcx: I,
+    self_ty: I::Ty,
     goal_kind: ty::ClosureKind,
-    env_region: ty::Region<'tcx>,
-) -> Result<
-    (ty::Binder<'tcx, AsyncCallableRelevantTypes<'tcx>>, Vec<ty::Predicate<'tcx>>),
-    NoSolution,
-> {
-    match *self_ty.kind() {
+    env_region: I::Region,
+) -> Result<(ty::Binder<I, AsyncCallableRelevantTypes<I>>, Vec<I::Predicate>), NoSolution> {
+    match self_ty.kind() {
         ty::CoroutineClosure(def_id, args) => {
             let args = args.as_coroutine_closure();
             let kind_ty = args.kind_ty();
@@ -421,7 +434,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
                 nested.push(
                     ty::TraitRef::new(
                         tcx,
-                        tcx.require_lang_item(LangItem::AsyncFnKindHelper, None),
+                        tcx.require_lang_item(TraitSolverLangItem::AsyncFnKindHelper),
                         [kind_ty, Ty::from_closure_kind(tcx, goal_kind)],
                     )
                     .upcast(tcx),
@@ -445,7 +458,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
         ty::FnDef(..) | ty::FnPtr(..) => {
             let bound_sig = self_ty.fn_sig(tcx);
             let sig = bound_sig.skip_binder();
-            let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None);
+            let future_trait_def_id = tcx.require_lang_item(TraitSolverLangItem::Future);
             // `FnDef` and `FnPtr` only implement `AsyncFn*` when their
             // return type implements `Future`.
             let nested = vec![
@@ -453,11 +466,11 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
                     .rebind(ty::TraitRef::new(tcx, future_trait_def_id, [sig.output()]))
                     .upcast(tcx),
             ];
-            let future_output_def_id = tcx.require_lang_item(LangItem::FutureOutput, None);
+            let future_output_def_id = tcx.require_lang_item(TraitSolverLangItem::FutureOutput);
             let future_output_ty = Ty::new_projection(tcx, future_output_def_id, [sig.output()]);
             Ok((
                 bound_sig.rebind(AsyncCallableRelevantTypes {
-                    tupled_inputs_ty: Ty::new_tup(tcx, sig.inputs()),
+                    tupled_inputs_ty: Ty::new_tup(tcx, &sig.inputs()),
                     output_coroutine_ty: sig.output(),
                     coroutine_return_ty: future_output_ty,
                 }),
@@ -468,7 +481,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
             let args = args.as_closure();
             let bound_sig = args.sig();
             let sig = bound_sig.skip_binder();
-            let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None);
+            let future_trait_def_id = tcx.require_lang_item(TraitSolverLangItem::Future);
             // `Closure`s only implement `AsyncFn*` when their return type
             // implements `Future`.
             let mut nested = vec![
@@ -486,7 +499,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
                 }
             } else {
                 let async_fn_kind_trait_def_id =
-                    tcx.require_lang_item(LangItem::AsyncFnKindHelper, None);
+                    tcx.require_lang_item(TraitSolverLangItem::AsyncFnKindHelper);
                 // When we don't know the closure kind (and therefore also the closure's upvars,
                 // which are computed at the same time), we must delay the computation of the
                 // generator's upvars. We do this using the `AsyncFnKindHelper`, which as a trait
@@ -504,7 +517,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
                 );
             }
 
-            let future_output_def_id = tcx.require_lang_item(LangItem::FutureOutput, None);
+            let future_output_def_id = tcx.require_lang_item(TraitSolverLangItem::FutureOutput);
             let future_output_ty = Ty::new_projection(tcx, future_output_def_id, [sig.output()]);
             Ok((
                 bound_sig.rebind(AsyncCallableRelevantTypes {
@@ -542,21 +555,21 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
 
         ty::Bound(..)
         | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
-            bug!("unexpected type `{self_ty}`")
+            panic!("unexpected type `{self_ty:?}`")
         }
     }
 }
 
 /// Given a coroutine-closure, project to its returned coroutine when we are *certain*
 /// that the closure's kind is compatible with the goal.
-fn coroutine_closure_to_certain_coroutine<'tcx>(
-    tcx: TyCtxt<'tcx>,
+fn coroutine_closure_to_certain_coroutine<I: Interner>(
+    tcx: I,
     goal_kind: ty::ClosureKind,
-    goal_region: ty::Region<'tcx>,
-    def_id: DefId,
-    args: ty::CoroutineClosureArgs<TyCtxt<'tcx>>,
-    sig: ty::CoroutineClosureSignature<TyCtxt<'tcx>>,
-) -> Ty<'tcx> {
+    goal_region: I::Region,
+    def_id: I::DefId,
+    args: ty::CoroutineClosureArgs<I>,
+    sig: ty::CoroutineClosureSignature<I>,
+) -> I::Ty {
     sig.to_coroutine_given_kind_and_upvars(
         tcx,
         args.parent_args(),
@@ -573,20 +586,20 @@ fn coroutine_closure_to_certain_coroutine<'tcx>(
 /// yet what the closure's upvars are.
 ///
 /// Note that we do not also push a `AsyncFnKindHelper` goal here.
-fn coroutine_closure_to_ambiguous_coroutine<'tcx>(
-    tcx: TyCtxt<'tcx>,
+fn coroutine_closure_to_ambiguous_coroutine<I: Interner>(
+    tcx: I,
     goal_kind: ty::ClosureKind,
-    goal_region: ty::Region<'tcx>,
-    def_id: DefId,
-    args: ty::CoroutineClosureArgs<TyCtxt<'tcx>>,
-    sig: ty::CoroutineClosureSignature<TyCtxt<'tcx>>,
-) -> Ty<'tcx> {
-    let upvars_projection_def_id = tcx.require_lang_item(LangItem::AsyncFnKindUpvars, None);
+    goal_region: I::Region,
+    def_id: I::DefId,
+    args: ty::CoroutineClosureArgs<I>,
+    sig: ty::CoroutineClosureSignature<I>,
+) -> I::Ty {
+    let upvars_projection_def_id = tcx.require_lang_item(TraitSolverLangItem::AsyncFnKindUpvars);
     let tupled_upvars_ty = Ty::new_projection(
         tcx,
         upvars_projection_def_id,
         [
-            ty::GenericArg::from(args.kind_ty()),
+            I::GenericArg::from(args.kind_ty()),
             Ty::from_closure_kind(tcx, goal_kind).into(),
             goal_region.into(),
             sig.tupled_inputs_ty.into(),
@@ -643,41 +656,44 @@ fn coroutine_closure_to_ambiguous_coroutine<'tcx>(
 // This is unsound in general and once that is fixed, we don't need to
 // normalize eagerly here. See https://github.com/lcnr/solver-woes/issues/9
 // for more details.
-pub(in crate::solve) fn predicates_for_object_candidate<'tcx>(
-    ecx: &EvalCtxt<'_, InferCtxt<'tcx>>,
-    param_env: ty::ParamEnv<'tcx>,
-    trait_ref: ty::TraitRef<'tcx>,
-    object_bound: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
-) -> Vec<Goal<'tcx, ty::Predicate<'tcx>>> {
+pub(in crate::solve) fn predicates_for_object_candidate<Infcx, I>(
+    ecx: &EvalCtxt<'_, Infcx>,
+    param_env: I::ParamEnv,
+    trait_ref: ty::TraitRef<I>,
+    object_bounds: I::BoundExistentialPredicates,
+) -> Vec<Goal<I, I::Predicate>>
+where
+    Infcx: InferCtxtLike<Interner = I>,
+    I: Interner,
+{
     let tcx = ecx.interner();
     let mut requirements = vec![];
-    requirements.extend(
-        tcx.super_predicates_of(trait_ref.def_id).instantiate(tcx, trait_ref.args).predicates,
-    );
-    for item in tcx.associated_items(trait_ref.def_id).in_definition_order() {
-        // FIXME(associated_const_equality): Also add associated consts to
-        // the requirements here.
-        if item.kind == ty::AssocKind::Type {
-            // associated types that require `Self: Sized` do not show up in the built-in
-            // implementation of `Trait for dyn Trait`, and can be dropped here.
-            if tcx.generics_require_sized_self(item.def_id) {
-                continue;
-            }
-
-            requirements
-                .extend(tcx.item_bounds(item.def_id).iter_instantiated(tcx, trait_ref.args));
+    requirements
+        .extend(tcx.super_predicates_of(trait_ref.def_id).iter_instantiated(tcx, &trait_ref.args));
+
+    // FIXME(associated_const_equality): Also add associated consts to
+    // the requirements here.
+    for associated_type_def_id in tcx.associated_type_def_ids(trait_ref.def_id) {
+        // associated types that require `Self: Sized` do not show up in the built-in
+        // implementation of `Trait for dyn Trait`, and can be dropped here.
+        if tcx.generics_require_sized_self(associated_type_def_id) {
+            continue;
         }
+
+        requirements.extend(
+            tcx.item_bounds(associated_type_def_id).iter_instantiated(tcx, &trait_ref.args),
+        );
     }
 
     let mut replace_projection_with = FxHashMap::default();
-    for bound in object_bound {
+    for bound in object_bounds {
         if let ty::ExistentialPredicate::Projection(proj) = bound.skip_binder() {
             let proj = proj.with_self_ty(tcx, trait_ref.self_ty());
             let old_ty = replace_projection_with.insert(proj.def_id(), bound.rebind(proj));
             assert_eq!(
                 old_ty,
                 None,
-                "{} has two generic parameters: {} and {}",
+                "{:?} has two generic parameters: {:?} and {:?}",
                 proj.projection_term,
                 proj.term,
                 old_ty.unwrap()
@@ -696,20 +712,22 @@ pub(in crate::solve) fn predicates_for_object_candidate<'tcx>(
         .collect()
 }
 
-struct ReplaceProjectionWith<'a, 'tcx> {
-    ecx: &'a EvalCtxt<'a, InferCtxt<'tcx>>,
-    param_env: ty::ParamEnv<'tcx>,
-    mapping: FxHashMap<DefId, ty::PolyProjectionPredicate<'tcx>>,
-    nested: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
+struct ReplaceProjectionWith<'a, Infcx: InferCtxtLike<Interner = I>, I: Interner> {
+    ecx: &'a EvalCtxt<'a, Infcx>,
+    param_env: I::ParamEnv,
+    mapping: FxHashMap<I::DefId, ty::Binder<I, ty::ProjectionPredicate<I>>>,
+    nested: Vec<Goal<I, I::Predicate>>,
 }
 
-impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceProjectionWith<'_, 'tcx> {
-    fn interner(&self) -> TyCtxt<'tcx> {
+impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
+    for ReplaceProjectionWith<'_, Infcx, I>
+{
+    fn interner(&self) -> I {
         self.ecx.interner()
     }
 
-    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        if let ty::Alias(ty::Projection, alias_ty) = *ty.kind()
+    fn fold_ty(&mut self, ty: I::Ty) -> I::Ty {
+        if let ty::Alias(ty::Projection, alias_ty) = ty.kind()
             && let Some(replacement) = self.mapping.get(&alias_ty.def_id)
         {
             // We may have a case where our object type's projection bound is higher-ranked,
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
index 43013a01069..860c580374d 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
@@ -1,9 +1,6 @@
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir::def_id::DefId;
-use rustc_infer::infer::at::ToTrace;
-use rustc_infer::infer::{
-    BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk, TyCtxtInferExt,
-};
+use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::query::NoSolution;
 use rustc_infer::traits::solve::{MaybeCause, NestedNormalizationGoals};
 use rustc_infer::traits::ObligationCause;
@@ -15,11 +12,13 @@ use rustc_middle::traits::solve::{
 use rustc_middle::ty::AliasRelationDirection;
 use rustc_middle::ty::TypeFolder;
 use rustc_middle::ty::{
-    self, InferCtxtLike, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
-    TypeVisitable, TypeVisitableExt, TypeVisitor,
+    self, InferCtxtLike, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeVisitableExt,
 };
 use rustc_span::DUMMY_SP;
 use rustc_type_ir::fold::TypeSuperFoldable;
+use rustc_type_ir::inherent::*;
+use rustc_type_ir::relate::Relate;
+use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
 use rustc_type_ir::{self as ir, CanonicalVarValues, Interner};
 use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
 use std::ops::ControlFlow;
@@ -456,28 +455,6 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
         }
     }
 
-    #[instrument(level = "trace", skip(self))]
-    pub(super) fn add_normalizes_to_goal(&mut self, mut goal: Goal<'tcx, ty::NormalizesTo<'tcx>>) {
-        goal.predicate = goal
-            .predicate
-            .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env });
-        self.inspect.add_normalizes_to_goal(self.infcx, self.max_input_universe, goal);
-        self.nested_goals.normalizes_to_goals.push(goal);
-    }
-
-    #[instrument(level = "debug", skip(self))]
-    pub(super) fn add_goal(
-        &mut self,
-        source: GoalSource,
-        mut goal: Goal<'tcx, ty::Predicate<'tcx>>,
-    ) {
-        goal.predicate = goal
-            .predicate
-            .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env });
-        self.inspect.add_goal(self.infcx, self.max_input_universe, source, goal);
-        self.nested_goals.goals.push((source, goal));
-    }
-
     // Recursively evaluates all the goals added to this `EvalCtxt` to completion, returning
     // the certainty of all the goals.
     #[instrument(level = "trace", skip(self))]
@@ -600,27 +577,61 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
     pub(super) fn interner(&self) -> I {
         self.infcx.interner()
     }
-}
 
-impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
-    pub(super) fn next_ty_infer(&mut self) -> Ty<'tcx> {
-        let ty = self.infcx.next_ty_var(DUMMY_SP);
+    #[instrument(level = "trace", skip(self))]
+    pub(super) fn add_normalizes_to_goal(
+        &mut self,
+        mut goal: ir::solve::Goal<I, ir::NormalizesTo<I>>,
+    ) {
+        goal.predicate = goal
+            .predicate
+            .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env });
+        self.inspect.add_normalizes_to_goal(self.infcx, self.max_input_universe, goal);
+        self.nested_goals.normalizes_to_goals.push(goal);
+    }
+
+    #[instrument(level = "debug", skip(self))]
+    pub(super) fn add_goal(
+        &mut self,
+        source: GoalSource,
+        mut goal: ir::solve::Goal<I, I::Predicate>,
+    ) {
+        goal.predicate = goal
+            .predicate
+            .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env });
+        self.inspect.add_goal(self.infcx, self.max_input_universe, source, goal);
+        self.nested_goals.goals.push((source, goal));
+    }
+
+    #[instrument(level = "trace", skip(self, goals))]
+    pub(super) fn add_goals(
+        &mut self,
+        source: GoalSource,
+        goals: impl IntoIterator<Item = ir::solve::Goal<I, I::Predicate>>,
+    ) {
+        for goal in goals {
+            self.add_goal(source, goal);
+        }
+    }
+
+    pub(super) fn next_ty_infer(&mut self) -> I::Ty {
+        let ty = self.infcx.next_ty_infer();
         self.inspect.add_var_value(ty);
         ty
     }
 
-    pub(super) fn next_const_infer(&mut self) -> ty::Const<'tcx> {
-        let ct = self.infcx.next_const_var(DUMMY_SP);
+    pub(super) fn next_const_infer(&mut self) -> I::Const {
+        let ct = self.infcx.next_const_infer();
         self.inspect.add_var_value(ct);
         ct
     }
 
     /// Returns a ty infer or a const infer depending on whether `kind` is a `Ty` or `Const`.
     /// If `kind` is an integer inference variable this will still return a ty infer var.
-    pub(super) fn next_term_infer_of_kind(&mut self, kind: ty::Term<'tcx>) -> ty::Term<'tcx> {
-        match kind.unpack() {
-            ty::TermKind::Ty(_) => self.next_ty_infer().into(),
-            ty::TermKind::Const(_) => self.next_const_infer().into(),
+    pub(super) fn next_term_infer_of_kind(&mut self, kind: I::Term) -> I::Term {
+        match kind.kind() {
+            ir::TermKind::Ty(_) => self.next_ty_infer().into(),
+            ir::TermKind::Const(_) => self.next_const_infer().into(),
         }
     }
 
@@ -631,18 +642,18 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
     #[instrument(level = "trace", skip(self), ret)]
     pub(super) fn term_is_fully_unconstrained(
         &self,
-        goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
+        goal: ir::solve::Goal<I, ir::NormalizesTo<I>>,
     ) -> bool {
-        let universe_of_term = match goal.predicate.term.unpack() {
-            ty::TermKind::Ty(ty) => {
-                if let &ty::Infer(ty::TyVar(vid)) = ty.kind() {
+        let universe_of_term = match goal.predicate.term.kind() {
+            ir::TermKind::Ty(ty) => {
+                if let ir::Infer(ir::TyVar(vid)) = ty.kind() {
                     self.infcx.universe_of_ty(vid).unwrap()
                 } else {
                     return false;
                 }
             }
-            ty::TermKind::Const(ct) => {
-                if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() {
+            ir::TermKind::Const(ct) => {
+                if let ir::ConstKind::Infer(ir::InferConst::Var(vid)) = ct.kind() {
                     self.infcx.universe_of_ct(vid).unwrap()
                 } else {
                     return false;
@@ -650,14 +661,14 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
             }
         };
 
-        struct ContainsTermOrNotNameable<'a, 'tcx> {
-            term: ty::Term<'tcx>,
-            universe_of_term: ty::UniverseIndex,
-            infcx: &'a InferCtxt<'tcx>,
+        struct ContainsTermOrNotNameable<'a, Infcx: InferCtxtLike<Interner = I>, I: Interner> {
+            term: I::Term,
+            universe_of_term: ir::UniverseIndex,
+            infcx: &'a Infcx,
         }
 
-        impl<'a, 'tcx> ContainsTermOrNotNameable<'a, 'tcx> {
-            fn check_nameable(&self, universe: ty::UniverseIndex) -> ControlFlow<()> {
+        impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> ContainsTermOrNotNameable<'_, Infcx, I> {
+            fn check_nameable(&self, universe: ir::UniverseIndex) -> ControlFlow<()> {
                 if self.universe_of_term.can_name(universe) {
                     ControlFlow::Continue(())
                 } else {
@@ -666,21 +677,23 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
             }
         }
 
-        impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ContainsTermOrNotNameable<'_, 'tcx> {
+        impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeVisitor<I>
+            for ContainsTermOrNotNameable<'_, Infcx, I>
+        {
             type Result = ControlFlow<()>;
-            fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
-                match *t.kind() {
-                    ty::Infer(ty::TyVar(vid)) => {
-                        if let ty::TermKind::Ty(term) = self.term.unpack()
-                            && let Some(term_vid) = term.ty_vid()
-                            && self.infcx.root_var(vid) == self.infcx.root_var(term_vid)
+            fn visit_ty(&mut self, t: I::Ty) -> Self::Result {
+                match t.kind() {
+                    ir::Infer(ir::TyVar(vid)) => {
+                        if let ir::TermKind::Ty(term) = self.term.kind()
+                            && let ir::Infer(ir::TyVar(term_vid)) = term.kind()
+                            && self.infcx.root_ty_var(vid) == self.infcx.root_ty_var(term_vid)
                         {
                             ControlFlow::Break(())
                         } else {
                             self.check_nameable(self.infcx.universe_of_ty(vid).unwrap())
                         }
                     }
-                    ty::Placeholder(p) => self.check_nameable(p.universe),
+                    ir::Placeholder(p) => self.check_nameable(p.universe()),
                     _ => {
                         if t.has_non_region_infer() || t.has_placeholders() {
                             t.super_visit_with(self)
@@ -691,11 +704,11 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
                 }
             }
 
-            fn visit_const(&mut self, c: ty::Const<'tcx>) -> Self::Result {
+            fn visit_const(&mut self, c: I::Const) -> Self::Result {
                 match c.kind() {
-                    ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
-                        if let ty::TermKind::Const(term) = self.term.unpack()
-                            && let ty::ConstKind::Infer(ty::InferConst::Var(term_vid)) = term.kind()
+                    ir::ConstKind::Infer(ir::InferConst::Var(vid)) => {
+                        if let ir::TermKind::Const(term) = self.term.kind()
+                            && let ir::ConstKind::Infer(ir::InferConst::Var(term_vid)) = term.kind()
                             && self.infcx.root_const_var(vid) == self.infcx.root_const_var(term_vid)
                         {
                             ControlFlow::Break(())
@@ -703,7 +716,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
                             self.check_nameable(self.infcx.universe_of_ct(vid).unwrap())
                         }
                     }
-                    ty::ConstKind::Placeholder(p) => self.check_nameable(p.universe),
+                    ir::ConstKind::Placeholder(p) => self.check_nameable(p.universe()),
                     _ => {
                         if c.has_non_region_infer() || c.has_placeholders() {
                             c.super_visit_with(self)
@@ -725,23 +738,13 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
     }
 
     #[instrument(level = "trace", skip(self, param_env), ret)]
-    pub(super) fn eq<T: ToTrace<'tcx>>(
+    pub(super) fn eq<T: Relate<I>>(
         &mut self,
-        param_env: ty::ParamEnv<'tcx>,
+        param_env: I::ParamEnv,
         lhs: T,
         rhs: T,
     ) -> Result<(), NoSolution> {
-        self.infcx
-            .at(&ObligationCause::dummy(), param_env)
-            // New solver ignores DefineOpaqueTypes, so choose Yes for consistency
-            .eq(DefineOpaqueTypes::Yes, lhs, rhs)
-            .map(|InferOk { value: (), obligations }| {
-                self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));
-            })
-            .map_err(|e| {
-                trace!(?e, "failed to equate");
-                NoSolution
-            })
+        self.relate(param_env, lhs, ir::Variance::Invariant, rhs)
     }
 
     /// This should be used when relating a rigid alias with another type.
@@ -752,10 +755,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
     #[instrument(level = "trace", skip(self, param_env), ret)]
     pub(super) fn relate_rigid_alias_non_alias(
         &mut self,
-        param_env: ty::ParamEnv<'tcx>,
-        alias: ty::AliasTerm<'tcx>,
-        variance: ty::Variance,
-        term: ty::Term<'tcx>,
+        param_env: I::ParamEnv,
+        alias: ir::AliasTerm<I>,
+        variance: ir::Variance,
+        term: I::Term,
     ) -> Result<(), NoSolution> {
         // NOTE: this check is purely an optimization, the structural eq would
         // always fail if the term is not an inference variable.
@@ -770,12 +773,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
             // Alternatively we could modify `Equate` for this case by adding another
             // variant to `StructurallyRelateAliases`.
             let identity_args = self.fresh_args_for_item(alias.def_id);
-            let rigid_ctor = ty::AliasTerm::new(tcx, alias.def_id, identity_args);
+            let rigid_ctor = ir::AliasTerm::new(tcx, alias.def_id, identity_args);
             let ctor_term = rigid_ctor.to_term(tcx);
-            let InferOk { value: (), obligations } = self
-                .infcx
-                .at(&ObligationCause::dummy(), param_env)
-                .eq_structurally_relating_aliases(term, ctor_term)?;
+            let obligations =
+                self.infcx.eq_structurally_relating_aliases(param_env, term, ctor_term)?;
             debug_assert!(obligations.is_empty());
             self.relate(param_env, alias, variance, rigid_ctor)
         } else {
@@ -787,58 +788,38 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
     /// unconstrained "return value" or when we're sure that all aliases in
     /// the types are rigid.
     #[instrument(level = "trace", skip(self, param_env), ret)]
-    pub(super) fn eq_structurally_relating_aliases<T: ToTrace<'tcx>>(
+    pub(super) fn eq_structurally_relating_aliases<T: Relate<I>>(
         &mut self,
-        param_env: ty::ParamEnv<'tcx>,
+        param_env: I::ParamEnv,
         lhs: T,
         rhs: T,
     ) -> Result<(), NoSolution> {
-        let cause = ObligationCause::dummy();
-        let InferOk { value: (), obligations } =
-            self.infcx.at(&cause, param_env).eq_structurally_relating_aliases(lhs, rhs)?;
-        assert!(obligations.is_empty());
+        let result = self.infcx.eq_structurally_relating_aliases(param_env, lhs, rhs)?;
+        assert_eq!(result, vec![]);
         Ok(())
     }
 
     #[instrument(level = "trace", skip(self, param_env), ret)]
-    pub(super) fn sub<T: ToTrace<'tcx>>(
+    pub(super) fn sub<T: Relate<I>>(
         &mut self,
-        param_env: ty::ParamEnv<'tcx>,
+        param_env: I::ParamEnv,
         sub: T,
         sup: T,
     ) -> Result<(), NoSolution> {
-        self.infcx
-            .at(&ObligationCause::dummy(), param_env)
-            // New solver ignores DefineOpaqueTypes, so choose Yes for consistency
-            .sub(DefineOpaqueTypes::Yes, sub, sup)
-            .map(|InferOk { value: (), obligations }| {
-                self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));
-            })
-            .map_err(|e| {
-                trace!(?e, "failed to subtype");
-                NoSolution
-            })
+        self.relate(param_env, sub, ir::Variance::Covariant, sup)
     }
 
     #[instrument(level = "trace", skip(self, param_env), ret)]
-    pub(super) fn relate<T: ToTrace<'tcx>>(
+    pub(super) fn relate<T: Relate<I>>(
         &mut self,
-        param_env: ty::ParamEnv<'tcx>,
+        param_env: I::ParamEnv,
         lhs: T,
-        variance: ty::Variance,
+        variance: ir::Variance,
         rhs: T,
     ) -> Result<(), NoSolution> {
-        self.infcx
-            .at(&ObligationCause::dummy(), param_env)
-            // New solver ignores DefineOpaqueTypes, so choose Yes for consistency
-            .relate(DefineOpaqueTypes::Yes, lhs, variance, rhs)
-            .map(|InferOk { value: (), obligations }| {
-                self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));
-            })
-            .map_err(|e| {
-                trace!(?e, "failed to relate");
-                NoSolution
-            })
+        let goals = self.infcx.relate(param_env, lhs, variance, rhs)?;
+        self.add_goals(GoalSource::Misc, goals);
+        Ok(())
     }
 
     /// Equates two values returning the nested goals without adding them
@@ -847,58 +828,47 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
     /// If possible, try using `eq` instead which automatically handles nested
     /// goals correctly.
     #[instrument(level = "trace", skip(self, param_env), ret)]
-    pub(super) fn eq_and_get_goals<T: ToTrace<'tcx>>(
+    pub(super) fn eq_and_get_goals<T: Relate<I>>(
         &self,
-        param_env: ty::ParamEnv<'tcx>,
+        param_env: I::ParamEnv,
         lhs: T,
         rhs: T,
-    ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
-        self.infcx
-            .at(&ObligationCause::dummy(), param_env)
-            // New solver ignores DefineOpaqueTypes, so choose Yes for consistency
-            .eq(DefineOpaqueTypes::Yes, lhs, rhs)
-            .map(|InferOk { value: (), obligations }| {
-                obligations.into_iter().map(|o| o.into()).collect()
-            })
-            .map_err(|e| {
-                trace!(?e, "failed to equate");
-                NoSolution
-            })
+    ) -> Result<Vec<ir::solve::Goal<I, I::Predicate>>, NoSolution> {
+        self.infcx.relate(param_env, lhs, ir::Variance::Invariant, rhs)
     }
 
-    pub(super) fn instantiate_binder_with_infer<T: TypeFoldable<TyCtxt<'tcx>> + Copy>(
+    pub(super) fn instantiate_binder_with_infer<T: TypeFoldable<I> + Copy>(
         &self,
-        value: ty::Binder<'tcx, T>,
+        value: ir::Binder<I, T>,
     ) -> T {
-        self.infcx.instantiate_binder_with_fresh_vars(
-            DUMMY_SP,
-            BoundRegionConversionTime::HigherRankedType,
-            value,
-        )
+        self.infcx.instantiate_binder_with_infer(value)
     }
 
-    pub(super) fn enter_forall<T: TypeFoldable<TyCtxt<'tcx>> + Copy, U>(
+    pub(super) fn enter_forall<T: TypeFoldable<I> + Copy, U>(
         &self,
-        value: ty::Binder<'tcx, T>,
+        value: ir::Binder<I, T>,
         f: impl FnOnce(T) -> U,
     ) -> U {
         self.infcx.enter_forall(value, f)
     }
+
     pub(super) fn resolve_vars_if_possible<T>(&self, value: T) -> T
     where
-        T: TypeFoldable<TyCtxt<'tcx>>,
+        T: TypeFoldable<I>,
     {
         self.infcx.resolve_vars_if_possible(value)
     }
 
-    pub(super) fn fresh_args_for_item(&mut self, def_id: DefId) -> ty::GenericArgsRef<'tcx> {
-        let args = self.infcx.fresh_args_for_item(DUMMY_SP, def_id);
+    pub(super) fn fresh_args_for_item(&mut self, def_id: I::DefId) -> I::GenericArgs {
+        let args = self.infcx.fresh_args_for_item(def_id);
         for arg in args {
             self.inspect.add_var_value(arg);
         }
         args
     }
+}
 
+impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
     pub(super) fn register_ty_outlives(&self, ty: Ty<'tcx>, lt: ty::Region<'tcx>) {
         self.infcx.register_region_obligation_with_cause(ty, lt, &ObligationCause::dummy());
     }
@@ -1096,28 +1066,36 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
 ///
 /// This is a performance optimization to more eagerly detect cycles during trait
 /// solving. See tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.rs.
-struct ReplaceAliasWithInfer<'me, 'a, 'tcx> {
-    ecx: &'me mut EvalCtxt<'a, InferCtxt<'tcx>>,
-    param_env: ty::ParamEnv<'tcx>,
+struct ReplaceAliasWithInfer<'me, 'a, Infcx, I>
+where
+    Infcx: InferCtxtLike<Interner = I>,
+    I: Interner,
+{
+    ecx: &'me mut EvalCtxt<'a, Infcx>,
+    param_env: I::ParamEnv,
 }
 
-impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceAliasWithInfer<'_, '_, 'tcx> {
-    fn interner(&self) -> TyCtxt<'tcx> {
+impl<Infcx, I> TypeFolder<I> for ReplaceAliasWithInfer<'_, '_, Infcx, I>
+where
+    Infcx: InferCtxtLike<Interner = I>,
+    I: Interner,
+{
+    fn interner(&self) -> I {
         self.ecx.interner()
     }
 
-    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        match *ty.kind() {
-            ty::Alias(..) if !ty.has_escaping_bound_vars() => {
+    fn fold_ty(&mut self, ty: I::Ty) -> I::Ty {
+        match ty.kind() {
+            ir::Alias(..) if !ty.has_escaping_bound_vars() => {
                 let infer_ty = self.ecx.next_ty_infer();
-                let normalizes_to = ty::PredicateKind::AliasRelate(
+                let normalizes_to = ir::PredicateKind::AliasRelate(
                     ty.into(),
                     infer_ty.into(),
                     AliasRelationDirection::Equate,
                 );
                 self.ecx.add_goal(
                     GoalSource::Misc,
-                    Goal::new(self.interner(), self.param_env, normalizes_to),
+                    ir::solve::Goal::new(self.interner(), self.param_env, normalizes_to),
                 );
                 infer_ty
             }
@@ -1125,18 +1103,18 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceAliasWithInfer<'_, '_, 'tcx> {
         }
     }
 
-    fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+    fn fold_const(&mut self, ct: I::Const) -> I::Const {
         match ct.kind() {
-            ty::ConstKind::Unevaluated(..) if !ct.has_escaping_bound_vars() => {
+            ir::ConstKind::Unevaluated(..) if !ct.has_escaping_bound_vars() => {
                 let infer_ct = self.ecx.next_const_infer();
-                let normalizes_to = ty::PredicateKind::AliasRelate(
+                let normalizes_to = ir::PredicateKind::AliasRelate(
                     ct.into(),
                     infer_ct.into(),
                     AliasRelationDirection::Equate,
                 );
                 self.ecx.add_goal(
                     GoalSource::Misc,
-                    Goal::new(self.interner(), self.param_env, normalizes_to),
+                    ir::solve::Goal::new(self.interner(), self.param_env, normalizes_to),
                 );
                 infer_ct
             }
@@ -1144,7 +1122,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceAliasWithInfer<'_, '_, 'tcx> {
         }
     }
 
-    fn fold_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
+    fn fold_predicate(&mut self, predicate: I::Predicate) -> I::Predicate {
         if predicate.allow_normalization() { predicate.super_fold_with(self) } else { predicate }
     }
 }
diff --git a/compiler/rustc_trait_selection/src/solve/inspect/build.rs b/compiler/rustc_trait_selection/src/solve/inspect/build.rs
index 84c04900ae4..35750598bc7 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect/build.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect/build.rs
@@ -34,10 +34,11 @@ use rustc_type_ir::{self as ty, InferCtxtLike, Interner};
 /// trees. At the end of trait solving `ProofTreeBuilder::finalize`
 /// is called to recursively convert the whole structure to a
 /// finished proof tree.
-pub(in crate::solve) struct ProofTreeBuilder<
+pub(in crate::solve) struct ProofTreeBuilder<Infcx, I = <Infcx as InferCtxtLike>::Interner>
+where
     Infcx: InferCtxtLike<Interner = I>,
-    I: Interner = <Infcx as InferCtxtLike>::Interner,
-> {
+    I: Interner,
+{
     _infcx: PhantomData<Infcx>,
     state: Option<Box<DebugSolver<I>>>,
 }
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index c47b0194964..fdcf4ff11e4 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -235,17 +235,6 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
 }
 
 impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
-    #[instrument(level = "trace", skip(self, goals))]
-    fn add_goals(
-        &mut self,
-        source: GoalSource,
-        goals: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
-    ) {
-        for goal in goals {
-            self.add_goal(source, goal);
-        }
-    }
-
     /// Try to merge multiple possible ways to prove a goal, if that is not possible returns `None`.
     ///
     /// In this case we tend to flounder and return ambiguity by calling `[EvalCtxt::flounder]`.
diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
index 787f08a084e..50253d81528 100644
--- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
@@ -17,7 +17,7 @@ use rustc_middle::ty::NormalizesTo;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{TypeVisitableExt, Upcast};
 use rustc_middle::{bug, span_bug};
-use rustc_span::{sym, ErrorGuaranteed, DUMMY_SP};
+use rustc_span::{ErrorGuaranteed, DUMMY_SP};
 
 mod anon_const;
 mod inherent;
@@ -719,13 +719,16 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
 
         let coroutine = args.as_coroutine();
 
-        let name = tcx.associated_item(goal.predicate.def_id()).name;
-        let term = if name == sym::Return {
+        let lang_items = tcx.lang_items();
+        let term = if Some(goal.predicate.def_id()) == lang_items.coroutine_return() {
             coroutine.return_ty().into()
-        } else if name == sym::Yield {
+        } else if Some(goal.predicate.def_id()) == lang_items.coroutine_yield() {
             coroutine.yield_ty().into()
         } else {
-            bug!("unexpected associated item `<{self_ty} as Coroutine>::{name}`")
+            bug!(
+                "unexpected associated item `<{self_ty} as Coroutine>::{}`",
+                tcx.item_name(goal.predicate.def_id())
+            )
         };
 
         Self::probe_and_consider_implied_clause(
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 2c9cb79664b..32409e13842 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1373,15 +1373,16 @@ fn confirm_coroutine_candidate<'cx, 'tcx>(
         coroutine_sig,
     );
 
-    let name = tcx.associated_item(obligation.predicate.def_id).name;
-    let ty = if name == sym::Return {
+    let lang_items = tcx.lang_items();
+    let ty = if Some(obligation.predicate.def_id) == lang_items.coroutine_return() {
         return_ty
-    } else if name == sym::Yield {
+    } else if Some(obligation.predicate.def_id) == lang_items.coroutine_yield() {
         yield_ty
     } else {
         span_bug!(
             tcx.def_span(obligation.predicate.def_id),
-            "unexpected associated type: `Coroutine::{name}`"
+            "unexpected associated type: `Coroutine::{}`",
+            tcx.item_name(obligation.predicate.def_id),
         );
     };
 
diff --git a/compiler/rustc_type_ir/src/infcx.rs b/compiler/rustc_type_ir/src/infcx.rs
index 24e10722448..92a717a0d9e 100644
--- a/compiler/rustc_type_ir/src/infcx.rs
+++ b/compiler/rustc_type_ir/src/infcx.rs
@@ -1,23 +1,75 @@
-use crate::{ConstVid, EffectVid, FloatVid, IntVid, Interner, RegionVid, TyVid, UniverseIndex};
+use crate::fold::TypeFoldable;
+use crate::relate::Relate;
+use crate::solve::{Goal, NoSolution};
+use crate::{self as ty, Interner};
 
-pub trait InferCtxtLike {
+pub trait InferCtxtLike: Sized {
     type Interner: Interner;
 
     fn interner(&self) -> Self::Interner;
 
-    fn universe_of_ty(&self, ty: TyVid) -> Option<UniverseIndex>;
-    fn universe_of_lt(&self, lt: RegionVid) -> Option<UniverseIndex>;
-    fn universe_of_ct(&self, ct: ConstVid) -> Option<UniverseIndex>;
+    fn universe_of_ty(&self, ty: ty::TyVid) -> Option<ty::UniverseIndex>;
+    fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex>;
+    fn universe_of_ct(&self, ct: ty::ConstVid) -> Option<ty::UniverseIndex>;
 
-    fn opportunistic_resolve_ty_var(&self, vid: TyVid) -> <Self::Interner as Interner>::Ty;
-    fn opportunistic_resolve_int_var(&self, vid: IntVid) -> <Self::Interner as Interner>::Ty;
-    fn opportunistic_resolve_float_var(&self, vid: FloatVid) -> <Self::Interner as Interner>::Ty;
-    fn opportunistic_resolve_ct_var(&self, vid: ConstVid) -> <Self::Interner as Interner>::Const;
+    fn root_ty_var(&self, var: ty::TyVid) -> ty::TyVid;
+    fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid;
+
+    fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> <Self::Interner as Interner>::Ty;
+    fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> <Self::Interner as Interner>::Ty;
+    fn opportunistic_resolve_float_var(
+        &self,
+        vid: ty::FloatVid,
+    ) -> <Self::Interner as Interner>::Ty;
+    fn opportunistic_resolve_ct_var(
+        &self,
+        vid: ty::ConstVid,
+    ) -> <Self::Interner as Interner>::Const;
     fn opportunistic_resolve_effect_var(
         &self,
-        vid: EffectVid,
+        vid: ty::EffectVid,
     ) -> <Self::Interner as Interner>::Const;
-    fn opportunistic_resolve_lt_var(&self, vid: RegionVid) -> <Self::Interner as Interner>::Region;
+    fn opportunistic_resolve_lt_var(
+        &self,
+        vid: ty::RegionVid,
+    ) -> <Self::Interner as Interner>::Region;
 
     fn defining_opaque_types(&self) -> <Self::Interner as Interner>::DefiningOpaqueTypes;
+
+    fn next_ty_infer(&self) -> <Self::Interner as Interner>::Ty;
+    fn next_const_infer(&self) -> <Self::Interner as Interner>::Const;
+    fn fresh_args_for_item(
+        &self,
+        def_id: <Self::Interner as Interner>::DefId,
+    ) -> <Self::Interner as Interner>::GenericArgs;
+
+    fn instantiate_binder_with_infer<T: TypeFoldable<Self::Interner> + Copy>(
+        &self,
+        value: ty::Binder<Self::Interner, T>,
+    ) -> T;
+
+    fn enter_forall<T: TypeFoldable<Self::Interner> + Copy, U>(
+        &self,
+        value: ty::Binder<Self::Interner, T>,
+        f: impl FnOnce(T) -> U,
+    ) -> U;
+
+    fn relate<T: Relate<Self::Interner>>(
+        &self,
+        param_env: <Self::Interner as Interner>::ParamEnv,
+        lhs: T,
+        variance: ty::Variance,
+        rhs: T,
+    ) -> Result<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, NoSolution>;
+
+    fn eq_structurally_relating_aliases<T: Relate<Self::Interner>>(
+        &self,
+        param_env: <Self::Interner as Interner>::ParamEnv,
+        lhs: T,
+        rhs: T,
+    ) -> Result<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, NoSolution>;
+
+    fn resolve_vars_if_possible<T>(&self, value: T) -> T
+    where
+        T: TypeFoldable<Self::Interner>;
 }
diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs
index 2fc765f1c8f..6b84592978a 100644
--- a/compiler/rustc_type_ir/src/inherent.rs
+++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -29,6 +29,8 @@ pub trait Ty<I: Interner<Ty = Self>>:
 {
     fn new_bool(interner: I) -> Self;
 
+    fn new_u8(interner: I) -> Self;
+
     fn new_infer(interner: I, var: ty::InferTy) -> Self;
 
     fn new_var(interner: I, var: ty::TyVid) -> Self;
@@ -39,6 +41,18 @@ pub trait Ty<I: Interner<Ty = Self>>:
 
     fn new_alias(interner: I, kind: ty::AliasTyKind, alias_ty: ty::AliasTy<I>) -> Self;
 
+    fn new_projection(
+        interner: I,
+        def_id: I::DefId,
+        args: impl IntoIterator<Item: Into<I::GenericArg>>,
+    ) -> Self {
+        Ty::new_alias(
+            interner,
+            ty::AliasTyKind::Projection,
+            ty::AliasTy::new(interner, def_id, args),
+        )
+    }
+
     fn new_error(interner: I, guar: I::ErrorGuaranteed) -> Self;
 
     fn new_adt(interner: I, adt_def: I::AdtDef, args: I::GenericArgs) -> Self;
@@ -75,6 +89,12 @@ pub trait Ty<I: Interner<Ty = Self>>:
         It: Iterator<Item = T>,
         T: CollectAndApply<Self, Self>;
 
+    fn new_fn_def(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self;
+
+    fn new_fn_ptr(interner: I, sig: ty::Binder<I, ty::FnSig<I>>) -> Self;
+
+    fn new_pat(interner: I, ty: Self, pat: I::Pat) -> Self;
+
     fn tuple_fields(self) -> I::Tys;
 
     fn to_opt_closure_kind(self) -> Option<ty::ClosureKind>;
@@ -83,11 +103,29 @@ pub trait Ty<I: Interner<Ty = Self>>:
 
     fn from_coroutine_closure_kind(interner: I, kind: ty::ClosureKind) -> Self;
 
-    fn new_fn_def(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self;
-
-    fn new_fn_ptr(interner: I, sig: ty::Binder<I, ty::FnSig<I>>) -> Self;
-
-    fn new_pat(interner: I, ty: Self, pat: I::Pat) -> Self;
+    fn is_ty_var(self) -> bool {
+        matches!(self.kind(), ty::Infer(ty::TyVar(_)))
+    }
+
+    fn fn_sig(self, interner: I) -> ty::Binder<I, ty::FnSig<I>> {
+        match self.kind() {
+            ty::FnPtr(sig) => sig,
+            ty::FnDef(def_id, args) => interner.fn_sig(def_id).instantiate(interner, &args),
+            ty::Error(_) => {
+                // ignore errors (#54954)
+                ty::Binder::dummy(ty::FnSig {
+                    inputs_and_output: Default::default(),
+                    c_variadic: false,
+                    safety: I::Safety::safe(),
+                    abi: I::Abi::rust(),
+                })
+            }
+            ty::Closure(..) => panic!(
+                "to get the signature of a closure, use `args.as_closure().sig()` not `fn_sig()`",
+            ),
+            _ => panic!("Ty::fn_sig() called on non-fn type: {:?}", self),
+        }
+    }
 }
 
 pub trait Tys<I: Interner<Tys = Self>>:
@@ -103,12 +141,16 @@ pub trait Tys<I: Interner<Tys = Self>>:
     fn split_inputs_and_output(self) -> (I::FnInputTys, I::Ty);
 }
 
-pub trait Abi<I: Interner<Abi = Self>>: Copy + Debug + Hash + Eq + TypeVisitable<I> {
+pub trait Abi<I: Interner<Abi = Self>>: Copy + Debug + Hash + Eq + Relate<I> {
+    fn rust() -> Self;
+
     /// Whether this ABI is `extern "Rust"`.
     fn is_rust(self) -> bool;
 }
 
-pub trait Safety<I: Interner<Safety = Self>>: Copy + Debug + Hash + Eq + TypeVisitable<I> {
+pub trait Safety<I: Interner<Safety = Self>>: Copy + Debug + Hash + Eq + Relate<I> {
+    fn safe() -> Self;
+
     fn is_safe(self) -> bool;
 
     fn prefix_str(self) -> &'static str;
@@ -122,7 +164,6 @@ pub trait Region<I: Interner<Region = Self>>:
     + Into<I::GenericArg>
     + IntoKind<Kind = ty::RegionKind<I>>
     + Flags
-    + TypeVisitable<I>
     + Relate<I>
 {
     fn new_bound(interner: I, debruijn: ty::DebruijnIndex, var: I::BoundRegion) -> Self;
@@ -158,12 +199,57 @@ pub trait Const<I: Interner<Const = Self>>:
     fn new_unevaluated(interner: I, uv: ty::UnevaluatedConst<I>) -> Self;
 
     fn new_expr(interner: I, expr: I::ExprConst) -> Self;
+
+    fn is_ct_var(self) -> bool {
+        matches!(self.kind(), ty::ConstKind::Infer(ty::InferConst::Var(_)))
+    }
 }
 
 pub trait GenericsOf<I: Interner<GenericsOf = Self>> {
     fn count(&self) -> usize;
 }
 
+pub trait GenericArg<I: Interner<GenericArg = Self>>:
+    Copy
+    + Debug
+    + Hash
+    + Eq
+    + IntoKind<Kind = ty::GenericArgKind<I>>
+    + TypeVisitable<I>
+    + Relate<I>
+    + From<I::Ty>
+    + From<I::Region>
+    + From<I::Const>
+{
+}
+
+pub trait Term<I: Interner<Term = Self>>:
+    Copy + Debug + Hash + Eq + IntoKind<Kind = ty::TermKind<I>> + TypeFoldable<I> + Relate<I>
+{
+    fn as_type(&self) -> Option<I::Ty> {
+        if let ty::TermKind::Ty(ty) = self.kind() { Some(ty) } else { None }
+    }
+
+    fn expect_type(&self) -> I::Ty {
+        self.as_type().expect("expected a type, but found a const")
+    }
+
+    fn as_const(&self) -> Option<I::Const> {
+        if let ty::TermKind::Const(c) = self.kind() { Some(c) } else { None }
+    }
+
+    fn expect_const(&self) -> I::Const {
+        self.as_const().expect("expected a const, but found a type")
+    }
+
+    fn is_infer(self) -> bool {
+        match self.kind() {
+            ty::TermKind::Ty(ty) => ty.is_ty_var(),
+            ty::TermKind::Const(ct) => ct.is_ct_var(),
+        }
+    }
+}
+
 pub trait GenericArgs<I: Interner<GenericArgs = Self>>:
     Copy
     + Debug
@@ -172,7 +258,6 @@ pub trait GenericArgs<I: Interner<GenericArgs = Self>>:
     + IntoIterator<Item = I::GenericArg>
     + Deref<Target: Deref<Target = [I::GenericArg]>>
     + Default
-    + TypeFoldable<I>
     + Relate<I>
 {
     fn type_at(self, i: usize) -> I::Ty;
@@ -188,6 +273,16 @@ pub trait GenericArgs<I: Interner<GenericArgs = Self>>:
     fn split_closure_args(self) -> ty::ClosureArgsParts<I>;
     fn split_coroutine_closure_args(self) -> ty::CoroutineClosureArgsParts<I>;
     fn split_coroutine_args(self) -> ty::CoroutineArgsParts<I>;
+
+    fn as_closure(self) -> ty::ClosureArgs<I> {
+        ty::ClosureArgs { args: self }
+    }
+    fn as_coroutine_closure(self) -> ty::CoroutineClosureArgs<I> {
+        ty::CoroutineClosureArgs { args: self }
+    }
+    fn as_coroutine(self) -> ty::CoroutineArgs<I> {
+        ty::CoroutineArgs { args: self }
+    }
 }
 
 pub trait Predicate<I: Interner<Predicate = Self>>:
@@ -198,9 +293,20 @@ pub trait Predicate<I: Interner<Predicate = Self>>:
     + TypeSuperVisitable<I>
     + TypeSuperFoldable<I>
     + Flags
+    + UpcastFrom<I, ty::PredicateKind<I>>
+    + UpcastFrom<I, ty::Binder<I, ty::PredicateKind<I>>>
+    + UpcastFrom<I, ty::ClauseKind<I>>
+    + UpcastFrom<I, ty::Binder<I, ty::ClauseKind<I>>>
+    + UpcastFrom<I, I::Clause>
     + UpcastFrom<I, ty::NormalizesTo<I>>
+    + UpcastFrom<I, ty::TraitRef<I>>
+    + UpcastFrom<I, ty::Binder<I, ty::TraitRef<I>>>
+    + IntoKind<Kind = ty::Binder<I, ty::PredicateKind<I>>>
 {
     fn is_coinductive(self, interner: I) -> bool;
+
+    // FIXME: Eventually uplift the impl out of rustc and make this defaulted.
+    fn allow_normalization(self) -> bool;
 }
 
 pub trait Clause<I: Interner<Clause = Self>>:
@@ -208,6 +314,7 @@ pub trait Clause<I: Interner<Clause = Self>>:
     + Debug
     + Hash
     + Eq
+    + TypeFoldable<I>
     // FIXME: Remove these, uplift the `Upcast` impls.
     + UpcastFrom<I, ty::Binder<I, ty::TraitRef<I>>>
     + UpcastFrom<I, ty::Binder<I, ty::ProjectionPredicate<I>>>
@@ -242,8 +349,17 @@ pub trait ParamLike {
 
 pub trait AdtDef<I: Interner>: Copy + Debug + Hash + Eq {
     fn def_id(self) -> I::DefId;
+
+    fn is_phantom_data(self) -> bool;
+
+    // FIXME: perhaps use `all_fields` and expose `FieldDef`.
+    fn all_field_tys(self, interner: I) -> ty::EarlyBinder<I, impl Iterator<Item = I::Ty>>;
+
+    fn sized_constraint(self, interner: I) -> Option<ty::EarlyBinder<I, I::Ty>>;
 }
 
 pub trait Features<I: Interner>: Copy {
     fn generic_const_exprs(self) -> bool;
+
+    fn coroutine_clone(self) -> bool;
 }
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index b7f412ecb8e..a2b71e1fc25 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -1,3 +1,4 @@
+use rustc_ast_ir::Movability;
 use smallvec::SmallVec;
 use std::fmt::Debug;
 use std::hash::Hash;
@@ -6,6 +7,7 @@ use std::ops::Deref;
 use crate::fold::TypeFoldable;
 use crate::inherent::*;
 use crate::ir_print::IrPrint;
+use crate::lang_items::TraitSolverLangItem;
 use crate::relate::Relate;
 use crate::solve::inspect::CanonicalGoalEvaluationStep;
 use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
@@ -31,20 +33,8 @@ pub trait Interner:
 
     type GenericArgs: GenericArgs<Self>;
     type GenericArgsSlice: Copy + Debug + Hash + Eq + Deref<Target = [Self::GenericArg]>;
-    type GenericArg: Copy
-        + Debug
-        + Hash
-        + Eq
-        + IntoKind<Kind = ty::GenericArgKind<Self>>
-        + TypeVisitable<Self>
-        + Relate<Self>;
-    type Term: Copy
-        + Debug
-        + Hash
-        + Eq
-        + IntoKind<Kind = ty::TermKind<Self>>
-        + TypeFoldable<Self>
-        + Relate<Self>;
+    type GenericArg: GenericArg<Self>;
+    type Term: Term<Self>;
 
     type BoundVarKinds: Copy
         + Debug
@@ -74,11 +64,16 @@ pub trait Interner:
 
     // Things stored inside of tys
     type ErrorGuaranteed: Copy + Debug + Hash + Eq;
-    type BoundExistentialPredicates: Copy + Debug + Hash + Eq + Relate<Self>;
+    type BoundExistentialPredicates: Copy
+        + Debug
+        + Hash
+        + Eq
+        + Relate<Self>
+        + IntoIterator<Item = ty::Binder<Self, ty::ExistentialPredicate<Self>>>;
     type AllocId: Copy + Debug + Hash + Eq;
     type Pat: Copy + Debug + Hash + Eq + Debug + Relate<Self>;
-    type Safety: Safety<Self> + TypeFoldable<Self> + Relate<Self>;
-    type Abi: Abi<Self> + TypeFoldable<Self> + Relate<Self>;
+    type Safety: Safety<Self>;
+    type Abi: Abi<Self>;
 
     // Kinds of consts
     type Const: Const<Self>;
@@ -153,6 +148,38 @@ pub trait Interner:
 
     type Features: Features<Self>;
     fn features(self) -> Self::Features;
+
+    fn bound_coroutine_hidden_types(
+        self,
+        def_id: Self::DefId,
+    ) -> impl IntoIterator<Item = ty::EarlyBinder<Self, ty::Binder<Self, Self::Ty>>>;
+
+    fn fn_sig(
+        self,
+        def_id: Self::DefId,
+    ) -> ty::EarlyBinder<Self, ty::Binder<Self, ty::FnSig<Self>>>;
+
+    fn coroutine_movability(self, def_id: Self::DefId) -> Movability;
+
+    fn coroutine_for_closure(self, def_id: Self::DefId) -> Self::DefId;
+
+    fn generics_require_sized_self(self, def_id: Self::DefId) -> bool;
+
+    fn item_bounds(
+        self,
+        def_id: Self::DefId,
+    ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>>;
+
+    fn super_predicates_of(
+        self,
+        def_id: Self::DefId,
+    ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>>;
+
+    fn has_target_features(self, def_id: Self::DefId) -> bool;
+
+    fn require_lang_item(self, lang_item: TraitSolverLangItem) -> Self::DefId;
+
+    fn associated_type_def_ids(self, def_id: Self::DefId) -> impl IntoIterator<Item = Self::DefId>;
 }
 
 /// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter`
diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs
new file mode 100644
index 00000000000..9a3b324fcd7
--- /dev/null
+++ b/compiler/rustc_type_ir/src/lang_items.rs
@@ -0,0 +1,8 @@
+/// Lang items used by the new trait solver. This can be mapped to whatever internal
+/// representation of `LangItem`s used in the underlying compiler implementation.
+pub enum TraitSolverLangItem {
+    Future,
+    FutureOutput,
+    AsyncFnKindHelper,
+    AsyncFnKindUpvars,
+}
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index a76e278cc05..7f0c3df381d 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -32,6 +32,7 @@ pub mod error;
 pub mod fold;
 pub mod inherent;
 pub mod ir_print;
+pub mod lang_items;
 pub mod lift;
 pub mod relate;
 pub mod solve;
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index cd3534ecb12..6b5054a9f06 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -3043,8 +3043,7 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
     unsafe {
         ub_checks::assert_unsafe_precondition!(
             check_language_ub,
-            "ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null \
-            and the specified memory ranges do not overlap",
+            "ptr::copy requires that both pointer arguments are aligned and non-null",
             (
                 src: *const () = src as *const (),
                 dst: *mut () = dst as *mut (),
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index 863f0d61df3..5956a08593a 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -1059,7 +1059,7 @@ macro_rules! nonzero_integer_signedness_dependent_methods {
             unsafe { Self::new_unchecked(self.get().unchecked_add(other)) }
         }
 
-        /// Returns the smallest power of two greater than or equal to n.
+        /// Returns the smallest power of two greater than or equal to `self`.
         /// Checks for overflow and returns [`None`]
         /// if the next power of two is greater than the type’s maximum value.
         /// As a consequence, the result cannot wrap to zero.
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index 1491c27372b..cdbd695008e 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -2830,7 +2830,7 @@ macro_rules! uint_impl {
         ///
         /// When return value overflows (i.e., `self > (1 << (N-1))` for type
         /// `uN`), it panics in debug mode and the return value is wrapped to 0 in
-        /// release mode (the only situation in which method can return 0).
+        /// release mode (the only situation in which this method can return 0).
         ///
         /// # Examples
         ///
@@ -2851,7 +2851,7 @@ macro_rules! uint_impl {
             self.one_less_than_next_power_of_two() + 1
         }
 
-        /// Returns the smallest power of two greater than or equal to `n`. If
+        /// Returns the smallest power of two greater than or equal to `self`. If
         /// the next power of two is greater than the type's maximum value,
         /// `None` is returned, otherwise the power of two is wrapped in `Some`.
         ///
diff --git a/library/core/src/ops/coroutine.rs b/library/core/src/ops/coroutine.rs
index 6a6c5db1ab1..753f14c6b85 100644
--- a/library/core/src/ops/coroutine.rs
+++ b/library/core/src/ops/coroutine.rs
@@ -76,6 +76,7 @@ pub trait Coroutine<R = ()> {
     /// values which are allowed to be returned each time a coroutine yields.
     /// For example an iterator-as-a-coroutine would likely have this type as
     /// `T`, the type being iterated over.
+    #[cfg_attr(not(bootstrap), lang = "coroutine_yield")]
     type Yield;
 
     /// The type of value this coroutine returns.
@@ -84,6 +85,7 @@ pub trait Coroutine<R = ()> {
     /// `return` statement or implicitly as the last expression of a coroutine
     /// literal. For example futures would use this as `Result<T, E>` as it
     /// represents a completed future.
+    #[cfg_attr(not(bootstrap), lang = "coroutine_return")]
     type Return;
 
     /// Resumes the execution of this coroutine.
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index c926c89f7a9..f351dab78dc 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -629,6 +629,25 @@ impl Command {
     ///     .spawn()
     ///     .expect("sh command failed to start");
     /// ```
+    ///
+    /// # Caveats
+    ///
+    /// [`Command::new`] is only intended to accept the path of the program. If you pass a program
+    /// path along with arguments like `Command::new("ls -l").spawn()`, it will try to search for
+    /// `ls -l` literally. The arguments need to be passed separately, such as via [`arg`] or
+    /// [`args`].
+    ///
+    /// ```no_run
+    /// use std::process::Command;
+    ///
+    /// Command::new("ls")
+    ///     .arg("-l") // arg passed separately
+    ///     .spawn()
+    ///     .expect("ls command failed to start");
+    /// ```
+    ///
+    /// [`arg`]: Self::arg
+    /// [`args`]: Self::args
     #[stable(feature = "process", since = "1.0.0")]
     pub fn new<S: AsRef<OsStr>>(program: S) -> Command {
         Command { inner: imp::Command::new(program.as_ref()) }
diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs
index 2deb9168df2..b96e26dbb3a 100644
--- a/src/bootstrap/src/core/build_steps/format.rs
+++ b/src/bootstrap/src/core/build_steps/format.rs
@@ -93,7 +93,7 @@ fn get_modified_rs_files(build: &Builder<'_>) -> Result<Option<Vec<String>>, Str
         return Ok(None);
     }
 
-    get_git_modified_files(&build.config.git_config(), Some(&build.config.src), &vec!["rs"])
+    get_git_modified_files(&build.config.git_config(), Some(&build.config.src), &["rs"])
 }
 
 #[derive(serde_derive::Deserialize)]
diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs
index 354eb2b6003..9268b335db7 100644
--- a/src/bootstrap/src/core/build_steps/run.rs
+++ b/src/bootstrap/src/core/build_steps/run.rs
@@ -149,12 +149,14 @@ impl Step for Miri {
             &[],
         );
         miri.add_rustc_lib_path(builder);
-        // Forward arguments.
         miri.arg("--").arg("--target").arg(target.rustc_target_arg());
-        miri.args(builder.config.args());
 
         // miri tests need to know about the stage sysroot
-        miri.env("MIRI_SYSROOT", &miri_sysroot);
+        miri.arg("--sysroot").arg(miri_sysroot);
+
+        // Forward arguments. This may contain further arguments to the program
+        // after another --, so this must be at the end.
+        miri.args(builder.config.args());
 
         let mut miri = Command::from(miri);
         builder.run(&mut miri);
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index 9f33e431274..b4d47cba7c5 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -495,7 +495,7 @@ impl Builder {
                 Some(p) => p,
                 None => return false,
             };
-            pkg.target.get(&c.target).is_some()
+            pkg.target.contains_key(&c.target)
         };
         extensions.retain(&has_component);
         components.retain(&has_component);
diff --git a/src/tools/build_helper/src/git.rs b/src/tools/build_helper/src/git.rs
index a3c857b0268..b4522de6897 100644
--- a/src/tools/build_helper/src/git.rs
+++ b/src/tools/build_helper/src/git.rs
@@ -21,7 +21,7 @@ fn output_result(cmd: &mut Command) -> Result<String, String> {
             String::from_utf8(output.stderr).map_err(|err| format!("{err:?}"))?
         ));
     }
-    Ok(String::from_utf8(output.stdout).map_err(|err| format!("{err:?}"))?)
+    String::from_utf8(output.stdout).map_err(|err| format!("{err:?}"))
 }
 
 /// Finds the remote for rust-lang/rust.
@@ -64,18 +64,14 @@ pub fn rev_exists(rev: &str, git_dir: Option<&Path>) -> Result<bool, String> {
     match output.status.code() {
         Some(0) => Ok(true),
         Some(128) => Ok(false),
-        None => {
-            return Err(format!(
-                "git didn't exit properly: {}",
-                String::from_utf8(output.stderr).map_err(|err| format!("{err:?}"))?
-            ));
-        }
-        Some(code) => {
-            return Err(format!(
-                "git command exited with status code: {code}: {}",
-                String::from_utf8(output.stderr).map_err(|err| format!("{err:?}"))?
-            ));
-        }
+        None => Err(format!(
+            "git didn't exit properly: {}",
+            String::from_utf8(output.stderr).map_err(|err| format!("{err:?}"))?
+        )),
+        Some(code) => Err(format!(
+            "git command exited with status code: {code}: {}",
+            String::from_utf8(output.stderr).map_err(|err| format!("{err:?}"))?
+        )),
     }
 }
 
@@ -96,7 +92,7 @@ pub fn updated_master_branch(
         }
     }
 
-    Err(format!("Cannot find any suitable upstream master branch"))
+    Err("Cannot find any suitable upstream master branch".to_owned())
 }
 
 pub fn get_git_merge_base(
@@ -118,7 +114,7 @@ pub fn get_git_merge_base(
 pub fn get_git_modified_files(
     config: &GitConfig<'_>,
     git_dir: Option<&Path>,
-    extensions: &Vec<&str>,
+    extensions: &[&str],
 ) -> Result<Option<Vec<String>>, String> {
     let merge_base = get_git_merge_base(config, git_dir)?;
 
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr
index ce3b9495eb1..cd2031af1c6 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr
@@ -4,9 +4,7 @@ error[E0412]: cannot find type `PhantomData` in this scope
 LL |     _n: PhantomData,
    |         ^^^^^^^^^^^ not found in this scope
    |
-help: consider importing one of these items
-   |
-LL + use core::marker::PhantomData;
+help: consider importing this struct
    |
 LL + use std::marker::PhantomData;
    |
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index b0047770564..da7f03441e7 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -582,7 +582,7 @@ impl TargetCfgs {
                         name,
                         Some(
                             value
-                                .strip_suffix("\"")
+                                .strip_suffix('\"')
                                 .expect("key-value pair should be properly quoted"),
                         ),
                     )
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index cc972223f6d..ffc706d19a9 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -82,7 +82,7 @@ impl EarlyProps {
             panic!("errors encountered during EarlyProps parsing");
         }
 
-        return props;
+        props
     }
 }
 
@@ -382,7 +382,7 @@ impl TestProps {
                         // Individual flags can be single-quoted to preserve spaces; see
                         // <https://github.com/rust-lang/rust/pull/115948/commits/957c5db6>.
                         flags
-                            .split("'")
+                            .split('\'')
                             .enumerate()
                             .flat_map(|(i, f)| {
                                 if i % 2 == 1 { vec![f] } else { f.split_whitespace().collect() }
@@ -613,7 +613,7 @@ impl TestProps {
 
         for key in &["RUST_TEST_NOCAPTURE", "RUST_TEST_THREADS"] {
             if let Ok(val) = env::var(key) {
-                if self.exec_env.iter().find(|&&(ref x, _)| x == key).is_none() {
+                if !self.exec_env.iter().any(|&(ref x, _)| x == key) {
                     self.exec_env.push(((*key).to_owned(), val))
                 }
             }
@@ -991,7 +991,7 @@ pub(crate) fn check_directive(directive_ln: &str) -> CheckDirectiveResult<'_> {
     let trailing = post.trim().split_once(' ').map(|(pre, _)| pre).unwrap_or(post);
     let trailing_directive = {
         // 1. is the directive name followed by a space? (to exclude `:`)
-        matches!(directive_ln.get(directive_name.len()..), Some(s) if s.starts_with(" "))
+        matches!(directive_ln.get(directive_name.len()..), Some(s) if s.starts_with(' '))
             // 2. is what is after that directive also a directive (ex: "only-x86 only-arm")
             && KNOWN_DIRECTIVE_NAMES.contains(&trailing)
     }
@@ -1363,7 +1363,7 @@ pub fn extract_llvm_version_from_binary(binary_path: &str) -> Option<u32> {
     }
     let version = String::from_utf8(output.stdout).ok()?;
     for line in version.lines() {
-        if let Some(version) = line.split("LLVM version ").skip(1).next() {
+        if let Some(version) = line.split("LLVM version ").nth(1) {
             return extract_llvm_version(version);
         }
     }
@@ -1394,7 +1394,7 @@ where
 
     let min = parse(min)?;
     let max = match max {
-        Some(max) if max.is_empty() => return None,
+        Some("") => return None,
         Some(max) => parse(max)?,
         _ => min,
     };
@@ -1466,12 +1466,12 @@ pub fn make_test_description<R: Read>(
             decision!(ignore_gdb(config, ln));
             decision!(ignore_lldb(config, ln));
 
-            if config.target == "wasm32-unknown-unknown" {
-                if config.parse_name_directive(ln, directives::CHECK_RUN_RESULTS) {
-                    decision!(IgnoreDecision::Ignore {
-                        reason: "ignored on WASM as the run results cannot be checked there".into(),
-                    });
-                }
+            if config.target == "wasm32-unknown-unknown"
+                && config.parse_name_directive(ln, directives::CHECK_RUN_RESULTS)
+            {
+                decision!(IgnoreDecision::Ignore {
+                    reason: "ignored on WASM as the run results cannot be checked there".into(),
+                });
             }
 
             should_fail |= config.parse_name_directive(ln, "should-fail");
diff --git a/src/tools/compiletest/src/header/cfg.rs b/src/tools/compiletest/src/header/cfg.rs
index 510043e3bfd..522c52b1de2 100644
--- a/src/tools/compiletest/src/header/cfg.rs
+++ b/src/tools/compiletest/src/header/cfg.rs
@@ -58,7 +58,7 @@ pub(super) fn parse_cfg_name_directive<'a>(
 
     // Some of the matchers might be "" depending on what the target information is. To avoid
     // problems we outright reject empty directives.
-    if name == "" {
+    if name.is_empty() {
         return ParsedNameDirective::not_a_directive();
     }
 
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index 62e71e9b59d..0cf05b32e96 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -1147,7 +1147,7 @@ fn extract_lldb_version(full_version_line: &str) -> Option<(u32, bool)> {
 }
 
 fn not_a_digit(c: char) -> bool {
-    !c.is_digit(10)
+    !c.is_ascii_digit()
 }
 
 fn check_overlapping_tests(found_paths: &HashSet<PathBuf>) {
diff --git a/src/tools/compiletest/src/read2.rs b/src/tools/compiletest/src/read2.rs
index 3f1921cb6bd..8c06339f3c3 100644
--- a/src/tools/compiletest/src/read2.rs
+++ b/src/tools/compiletest/src/read2.rs
@@ -6,7 +6,6 @@ mod tests;
 
 pub use self::imp::read2;
 use std::io::{self, Write};
-use std::mem::replace;
 use std::process::{Child, Output};
 
 #[derive(Copy, Clone, Debug)]
@@ -101,10 +100,10 @@ impl ProcOutput {
                     return;
                 }
 
-                let mut head = replace(bytes, Vec::new());
+                let mut head = std::mem::take(bytes);
                 // Don't truncate if this as a whole line.
                 // That should make it less likely that we cut a JSON line in half.
-                if head.last() != Some(&('\n' as u8)) {
+                if head.last() != Some(&b'\n') {
                     head.truncate(MAX_OUT_LEN);
                 }
                 let skipped = new_len - head.len();
diff --git a/src/tools/compiletest/src/read2/tests.rs b/src/tools/compiletest/src/read2/tests.rs
index 5ad2db3cb83..9e052ff069b 100644
--- a/src/tools/compiletest/src/read2/tests.rs
+++ b/src/tools/compiletest/src/read2/tests.rs
@@ -64,9 +64,9 @@ fn test_abbreviate_filterss_are_detected() {
 #[test]
 fn test_abbreviate_filters_avoid_abbreviations() {
     let mut out = ProcOutput::new();
-    let filters = &[std::iter::repeat('a').take(64).collect::<String>()];
+    let filters = &["a".repeat(64)];
 
-    let mut expected = vec![b'.'; MAX_OUT_LEN - FILTERED_PATHS_PLACEHOLDER_LEN as usize];
+    let mut expected = vec![b'.'; MAX_OUT_LEN - FILTERED_PATHS_PLACEHOLDER_LEN];
     expected.extend_from_slice(filters[0].as_bytes());
 
     out.extend(&expected, filters);
@@ -81,7 +81,7 @@ fn test_abbreviate_filters_avoid_abbreviations() {
 #[test]
 fn test_abbreviate_filters_can_still_cause_abbreviations() {
     let mut out = ProcOutput::new();
-    let filters = &[std::iter::repeat('a').take(64).collect::<String>()];
+    let filters = &["a".repeat(64)];
 
     let mut input = vec![b'.'; MAX_OUT_LEN];
     input.extend_from_slice(filters[0].as_bytes());
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 9e1d5ea61aa..72b57d91c23 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -374,11 +374,11 @@ impl<'test> TestCx<'test> {
 
         // if a test does not crash, consider it an error
         if proc_res.status.success() || matches!(proc_res.status.code(), Some(1 | 0)) {
-            self.fatal(&format!(
+            self.fatal(
                 "test no longer crashes/triggers ICE! Please give it a mearningful name, \
             add a doc-comment to the start of the test explaining why it exists and \
-            move it to tests/ui or wherever you see fit."
-            ));
+            move it to tests/ui or wherever you see fit.",
+            );
         }
     }
 
@@ -697,10 +697,10 @@ impl<'test> TestCx<'test> {
             // since it is extensively used in the testsuite.
             check_cfg.push_str("cfg(FALSE");
             for revision in &self.props.revisions {
-                check_cfg.push_str(",");
-                check_cfg.push_str(&normalize_revision(&revision));
+                check_cfg.push(',');
+                check_cfg.push_str(&normalize_revision(revision));
             }
-            check_cfg.push_str(")");
+            check_cfg.push(')');
 
             cmd.args(&["--check-cfg", &check_cfg]);
         }
@@ -818,7 +818,7 @@ impl<'test> TestCx<'test> {
         // Append the other `cdb-command:`s
         for line in &dbg_cmds.commands {
             script_str.push_str(line);
-            script_str.push_str("\n");
+            script_str.push('\n');
         }
 
         script_str.push_str("qq\n"); // Quit the debugger (including remote debugger, if any)
@@ -1200,7 +1200,7 @@ impl<'test> TestCx<'test> {
         // Append the other commands
         for line in &dbg_cmds.commands {
             script_str.push_str(line);
-            script_str.push_str("\n");
+            script_str.push('\n');
         }
 
         // Finally, quit the debugger
@@ -1250,7 +1250,7 @@ impl<'test> TestCx<'test> {
         // Remove options that are either unwanted (-O) or may lead to duplicates due to RUSTFLAGS.
         let options_to_remove = ["-O".to_owned(), "-g".to_owned(), "--debuginfo".to_owned()];
 
-        options.iter().filter(|x| !options_to_remove.contains(x)).map(|x| x.clone()).collect()
+        options.iter().filter(|x| !options_to_remove.contains(x)).cloned().collect()
     }
 
     fn maybe_add_external_args(&self, cmd: &mut Command, args: &Vec<String>) {
@@ -2504,8 +2504,8 @@ impl<'test> TestCx<'test> {
             // This works with both `--emit asm` (as default output name for the assembly)
             // and `ptx-linker` because the latter can write output at requested location.
             let output_path = self.output_base_name().with_extension(extension);
-            let output_file = TargetLocation::ThisFile(output_path.clone());
-            output_file
+
+            TargetLocation::ThisFile(output_path.clone())
         }
     }
 
@@ -2752,7 +2752,7 @@ impl<'test> TestCx<'test> {
             for entry in walkdir::WalkDir::new(dir) {
                 let entry = entry.expect("failed to read file");
                 if entry.file_type().is_file()
-                    && entry.path().extension().and_then(|p| p.to_str()) == Some("html".into())
+                    && entry.path().extension().and_then(|p| p.to_str()) == Some("html")
                 {
                     let status =
                         Command::new("tidy").args(&tidy_args).arg(entry.path()).status().unwrap();
@@ -2783,8 +2783,7 @@ impl<'test> TestCx<'test> {
             &compare_dir,
             self.config.verbose,
             |file_type, extension| {
-                file_type.is_file()
-                    && (extension == Some("html".into()) || extension == Some("js".into()))
+                file_type.is_file() && (extension == Some("html") || extension == Some("js"))
             },
         ) {
             return;
@@ -2830,11 +2829,11 @@ impl<'test> TestCx<'test> {
                 }
                 match String::from_utf8(line.clone()) {
                     Ok(line) => {
-                        if line.starts_with("+") {
+                        if line.starts_with('+') {
                             write!(&mut out, "{}", line.green()).unwrap();
-                        } else if line.starts_with("-") {
+                        } else if line.starts_with('-') {
                             write!(&mut out, "{}", line.red()).unwrap();
-                        } else if line.starts_with("@") {
+                        } else if line.starts_with('@') {
                             write!(&mut out, "{}", line.blue()).unwrap();
                         } else {
                             out.write_all(line.as_bytes()).unwrap();
@@ -2907,7 +2906,7 @@ impl<'test> TestCx<'test> {
                     && line.ends_with(';')
                 {
                     if let Some(ref mut other_files) = other_files {
-                        other_files.push(line.rsplit("mod ").next().unwrap().replace(";", ""));
+                        other_files.push(line.rsplit("mod ").next().unwrap().replace(';', ""));
                     }
                     None
                 } else {
@@ -3139,7 +3138,7 @@ impl<'test> TestCx<'test> {
             let mut string = String::new();
             for cgu in cgus {
                 string.push_str(&cgu[..]);
-                string.push_str(" ");
+                string.push(' ');
             }
 
             string
@@ -3172,10 +3171,7 @@ impl<'test> TestCx<'test> {
         // CGUs joined with "--". This function splits such composite CGU names
         // and handles each component individually.
         fn remove_crate_disambiguators_from_set_of_cgu_names(cgus: &str) -> String {
-            cgus.split("--")
-                .map(|cgu| remove_crate_disambiguator_from_cgu(cgu))
-                .collect::<Vec<_>>()
-                .join("--")
+            cgus.split("--").map(remove_crate_disambiguator_from_cgu).collect::<Vec<_>>().join("--")
         }
     }
 
@@ -3357,7 +3353,7 @@ impl<'test> TestCx<'test> {
             //   endif
         }
 
-        if self.config.target.contains("msvc") && self.config.cc != "" {
+        if self.config.target.contains("msvc") && !self.config.cc.is_empty() {
             // We need to pass a path to `lib.exe`, so assume that `cc` is `cl.exe`
             // and that `lib.exe` lives next to it.
             let lib = Path::new(&self.config.cc).parent().unwrap().join("lib.exe");
@@ -3639,7 +3635,7 @@ impl<'test> TestCx<'test> {
             //   endif
         }
 
-        if self.config.target.contains("msvc") && self.config.cc != "" {
+        if self.config.target.contains("msvc") && !self.config.cc.is_empty() {
             // We need to pass a path to `lib.exe`, so assume that `cc` is `cl.exe`
             // and that `lib.exe` lives next to it.
             let lib = Path::new(&self.config.cc).parent().unwrap().join("lib.exe");
@@ -3830,7 +3826,7 @@ impl<'test> TestCx<'test> {
             && !self.props.dont_check_compiler_stderr
         {
             self.fatal_proc_rec(
-                &format!("compiler output got truncated, cannot compare with reference file"),
+                "compiler output got truncated, cannot compare with reference file",
                 &proc_res,
             );
         }
@@ -4011,8 +4007,8 @@ impl<'test> TestCx<'test> {
                     crate_name.to_str().expect("crate name implies file name must be valid UTF-8");
                 // replace `a.foo` -> `a__foo` for crate name purposes.
                 // replace `revision-name-with-dashes` -> `revision_name_with_underscore`
-                let crate_name = crate_name.replace(".", "__");
-                let crate_name = crate_name.replace("-", "_");
+                let crate_name = crate_name.replace('.', "__");
+                let crate_name = crate_name.replace('-', "_");
                 rustc.arg("--crate-name");
                 rustc.arg(crate_name);
             }
@@ -4060,7 +4056,7 @@ impl<'test> TestCx<'test> {
     fn check_mir_dump(&self, test_info: MiroptTest) {
         let test_dir = self.testpaths.file.parent().unwrap();
         let test_crate =
-            self.testpaths.file.file_stem().unwrap().to_str().unwrap().replace("-", "_");
+            self.testpaths.file.file_stem().unwrap().to_str().unwrap().replace('-', "_");
 
         let MiroptTest { run_filecheck, suffix, files, passes: _ } = test_info;
 
diff --git a/src/tools/compiletest/src/runtest/debugger.rs b/src/tools/compiletest/src/runtest/debugger.rs
index eebe5f3580b..ed6cc97a8ab 100644
--- a/src/tools/compiletest/src/runtest/debugger.rs
+++ b/src/tools/compiletest/src/runtest/debugger.rs
@@ -148,5 +148,5 @@ fn check_single_line(line: &str, check_line: &str) -> bool {
         rest = &rest[pos + current_fragment.len()..];
     }
 
-    if !can_end_anywhere && !rest.is_empty() { false } else { true }
+    can_end_anywhere || rest.is_empty()
 }
diff --git a/src/tools/compiletest/src/tests.rs b/src/tools/compiletest/src/tests.rs
index e6725dba260..4292f234adc 100644
--- a/src/tools/compiletest/src/tests.rs
+++ b/src/tools/compiletest/src/tests.rs
@@ -58,11 +58,11 @@ fn test_extract_lldb_version() {
 
 #[test]
 fn is_test_test() {
-    assert_eq!(true, is_test(&OsString::from("a_test.rs")));
-    assert_eq!(false, is_test(&OsString::from(".a_test.rs")));
-    assert_eq!(false, is_test(&OsString::from("a_cat.gif")));
-    assert_eq!(false, is_test(&OsString::from("#a_dog_gif")));
-    assert_eq!(false, is_test(&OsString::from("~a_temp_file")));
+    assert!(is_test(&OsString::from("a_test.rs")));
+    assert!(!is_test(&OsString::from(".a_test.rs")));
+    assert!(!is_test(&OsString::from("a_cat.gif")));
+    assert!(!is_test(&OsString::from("#a_dog_gif")));
+    assert!(!is_test(&OsString::from("~a_temp_file")));
 }
 
 #[test]
diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs
index 5e35ce242fe..1713a4d812c 100644
--- a/src/tools/jsondoclint/src/validator.rs
+++ b/src/tools/jsondoclint/src/validator.rs
@@ -418,15 +418,13 @@ impl<'a> Validator<'a> {
             } else {
                 self.fail_expecting(id, expected);
             }
-        } else {
-            if !self.missing_ids.contains(id) {
-                self.missing_ids.insert(id);
+        } else if !self.missing_ids.contains(id) {
+            self.missing_ids.insert(id);
 
-                let sels = json_find::find_selector(&self.krate_json, &Value::String(id.0.clone()));
-                assert_ne!(sels.len(), 0);
+            let sels = json_find::find_selector(&self.krate_json, &Value::String(id.0.clone()));
+            assert_ne!(sels.len(), 0);
 
-                self.fail(id, ErrorKind::NotFound(sels))
-            }
+            self.fail(id, ErrorKind::NotFound(sels))
         }
     }
 
diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs
index 73f5738469e..f246d71d499 100644
--- a/src/tools/lint-docs/src/groups.rs
+++ b/src/tools/lint-docs/src/groups.rs
@@ -121,13 +121,13 @@ impl<'a> LintExtractor<'a> {
             };
             to_link.extend(group_lints);
             let brackets: Vec<_> = group_lints.iter().map(|l| format!("[{}]", l)).collect();
-            write!(result, "| {} | {} | {} |\n", group_name, description, brackets.join(", "))
+            writeln!(result, "| {} | {} | {} |", group_name, description, brackets.join(", "))
                 .unwrap();
         }
         result.push('\n');
         result.push_str("[warn-by-default]: listing/warn-by-default.md\n");
         for lint_name in to_link {
-            let lint_def = match lints.iter().find(|l| l.name == lint_name.replace("-", "_")) {
+            let lint_def = match lints.iter().find(|l| l.name == lint_name.replace('-', "_")) {
                 Some(def) => def,
                 None => {
                     let msg = format!(
@@ -144,9 +144,9 @@ impl<'a> LintExtractor<'a> {
                     }
                 }
             };
-            write!(
+            writeln!(
                 result,
-                "[{}]: listing/{}#{}\n",
+                "[{}]: listing/{}#{}",
                 lint_name,
                 lint_def.level.doc_filename(),
                 lint_name
diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs
index c79b377727a..72d6a495e7e 100644
--- a/src/tools/lint-docs/src/lib.rs
+++ b/src/tools/lint-docs/src/lib.rs
@@ -84,8 +84,8 @@ impl Lint {
         for &expected in &["### Example", "### Explanation", "{{produces}}"] {
             if expected == "{{produces}}" && self.is_ignored() {
                 if self.doc_contains("{{produces}}") {
-                    return Err(format!(
-                        "the lint example has `ignore`, but also contains the {{{{produces}}}} marker\n\
+                    return Err(
+                        "the lint example has `ignore`, but also contains the {{produces}} marker\n\
                         \n\
                         The documentation generator cannot generate the example output when the \
                         example is ignored.\n\
@@ -111,7 +111,7 @@ impl Lint {
                         Replacing the output with the text of the example you \
                         compiled manually yourself.\n\
                         "
-                    ).into());
+                    .into());
                 }
                 continue;
             }
@@ -519,11 +519,11 @@ impl<'a> LintExtractor<'a> {
         let mut these_lints: Vec<_> = lints.iter().filter(|lint| lint.level == level).collect();
         these_lints.sort_unstable_by_key(|lint| &lint.name);
         for lint in &these_lints {
-            write!(result, "* [`{}`](#{})\n", lint.name, lint.name.replace("_", "-")).unwrap();
+            writeln!(result, "* [`{}`](#{})", lint.name, lint.name.replace('_', "-")).unwrap();
         }
         result.push('\n');
         for lint in &these_lints {
-            write!(result, "## {}\n\n", lint.name.replace("_", "-")).unwrap();
+            write!(result, "## {}\n\n", lint.name.replace('_', "-")).unwrap();
             for line in &lint.doc {
                 result.push_str(line);
                 result.push('\n');
@@ -583,7 +583,7 @@ fn add_rename_redirect(level: Level, output: &mut String) {
             let filename = level.doc_filename().replace(".md", ".html");
             output.push_str(RENAME_START);
             for (from, to) in *names {
-                write!(output, "        \"#{from}\": \"{filename}#{to}\",\n").unwrap();
+                writeln!(output, "        \"#{from}\": \"{filename}#{to}\",").unwrap();
             }
             output.push_str(RENAME_END);
         }
diff --git a/src/tools/opt-dist/src/training.rs b/src/tools/opt-dist/src/training.rs
index 89f4d8957c8..1237951b3f0 100644
--- a/src/tools/opt-dist/src/training.rs
+++ b/src/tools/opt-dist/src/training.rs
@@ -216,11 +216,9 @@ pub fn gather_bolt_profiles(
     log::info!("Profile file count: {}", profiles.len());
 
     // Delete the gathered profiles
-    for profile in glob::glob(&format!("{profile_prefix}*"))?.into_iter() {
-        if let Ok(profile) = profile {
-            if let Err(error) = std::fs::remove_file(&profile) {
-                log::error!("Cannot delete BOLT profile {}: {error:?}", profile.display());
-            }
+    for profile in glob::glob(&format!("{profile_prefix}*"))?.flatten() {
+        if let Err(error) = std::fs::remove_file(&profile) {
+            log::error!("Cannot delete BOLT profile {}: {error:?}", profile.display());
         }
     }
 
diff --git a/src/tools/remote-test-client/src/main.rs b/src/tools/remote-test-client/src/main.rs
index 590c735596e..dd2c09c430b 100644
--- a/src/tools/remote-test-client/src/main.rs
+++ b/src/tools/remote-test-client/src/main.rs
@@ -317,13 +317,11 @@ fn run(support_lib_count: usize, exe: String, all_args: Vec<String>) {
                 t!(io::copy(&mut (&mut client).take(amt), &mut stdout));
                 t!(stdout.flush());
             }
+        } else if amt == 0 {
+            stderr_done = true;
         } else {
-            if amt == 0 {
-                stderr_done = true;
-            } else {
-                t!(io::copy(&mut (&mut client).take(amt), &mut stderr));
-                t!(stderr.flush());
-            }
+            t!(io::copy(&mut (&mut client).take(amt), &mut stderr));
+            t!(stderr.flush());
         }
     }
 
diff --git a/src/tools/remote-test-server/src/main.rs b/src/tools/remote-test-server/src/main.rs
index 68d7aa56c43..79f96c50223 100644
--- a/src/tools/remote-test-server/src/main.rs
+++ b/src/tools/remote-test-server/src/main.rs
@@ -282,7 +282,7 @@ fn handle_run(socket: TcpStream, work: &Path, tmp: &Path, lock: &Mutex<()>, conf
     cmd.env(library_path, env::join_paths(paths).unwrap());
 
     // Some tests assume RUST_TEST_TMPDIR exists
-    cmd.env("RUST_TEST_TMPDIR", tmp.to_owned());
+    cmd.env("RUST_TEST_TMPDIR", tmp);
 
     let socket = Arc::new(Mutex::new(reader.into_inner()));
 
diff --git a/src/tools/tidy/src/alphabetical.rs b/src/tools/tidy/src/alphabetical.rs
index 150a9594350..a29286fa2c5 100644
--- a/src/tools/tidy/src/alphabetical.rs
+++ b/src/tools/tidy/src/alphabetical.rs
@@ -88,7 +88,7 @@ fn check_section<'a>(
         let trimmed_line = line.trim_start_matches(' ');
 
         if trimmed_line.starts_with("//")
-            || (trimmed_line.starts_with("#") && !trimmed_line.starts_with("#!"))
+            || (trimmed_line.starts_with('#') && !trimmed_line.starts_with("#!"))
             || trimmed_line.starts_with(is_close_bracket)
         {
             continue;
diff --git a/src/tools/tidy/src/bins.rs b/src/tools/tidy/src/bins.rs
index 64ba79dc185..c82e8b6fee9 100644
--- a/src/tools/tidy/src/bins.rs
+++ b/src/tools/tidy/src/bins.rs
@@ -61,7 +61,7 @@ mod os_impl {
                     fs::remove_file(&path).expect("Deleted temp file");
                     // If the file is executable, then we assume that this
                     // filesystem does not track executability, so skip this check.
-                    return if exec { Unsupported } else { Supported };
+                    if exec { Unsupported } else { Supported }
                 }
                 Err(e) => {
                     // If the directory is read-only or we otherwise don't have rights,
@@ -76,7 +76,7 @@ mod os_impl {
 
                     panic!("unable to create temporary file `{:?}`: {:?}", path, e);
                 }
-            };
+            }
         }
 
         for &source_dir in sources {
@@ -92,7 +92,7 @@ mod os_impl {
             }
         }
 
-        return true;
+        true
     }
 
     // FIXME: check when rust-installer test sh files will be removed,
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 2dd3d17f9e3..7337c9843c7 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -699,11 +699,9 @@ fn check_permitted_dependencies(
     for dep in deps {
         let dep = pkg_from_id(metadata, dep);
         // If this path is in-tree, we don't require it to be explicitly permitted.
-        if dep.source.is_some() {
-            if !permitted_dependencies.contains(dep.name.as_str()) {
-                tidy_error!(bad, "Dependency for {descr} not explicitly permitted: {}", dep.id);
-                has_permitted_dep_error = true;
-            }
+        if dep.source.is_some() && !permitted_dependencies.contains(dep.name.as_str()) {
+            tidy_error!(bad, "Dependency for {descr} not explicitly permitted: {}", dep.id);
+            has_permitted_dep_error = true;
         }
     }
 
diff --git a/src/tools/tidy/src/error_codes.rs b/src/tools/tidy/src/error_codes.rs
index 39f7e70b693..47e2be761e6 100644
--- a/src/tools/tidy/src/error_codes.rs
+++ b/src/tools/tidy/src/error_codes.rs
@@ -308,11 +308,9 @@ fn check_error_codes_tests(
         for line in file.lines() {
             let s = line.trim();
             // Assuming the line starts with `error[E`, we can substring the error code out.
-            if s.starts_with("error[E") {
-                if &s[6..11] == code {
-                    found_code = true;
-                    break;
-                }
+            if s.starts_with("error[E") && &s[6..11] == code {
+                found_code = true;
+                break;
             };
         }
 
diff --git a/src/tools/tidy/src/ext_tool_checks.rs b/src/tools/tidy/src/ext_tool_checks.rs
index b54fa5c6b2c..fb626cac3fa 100644
--- a/src/tools/tidy/src/ext_tool_checks.rs
+++ b/src/tools/tidy/src/ext_tool_checks.rs
@@ -78,9 +78,9 @@ fn check_impl(
     let mut py_path = None;
 
     let (cfg_args, file_args): (Vec<_>, Vec<_>) = pos_args
-        .into_iter()
+        .iter()
         .map(OsStr::new)
-        .partition(|arg| arg.to_str().is_some_and(|s| s.starts_with("-")));
+        .partition(|arg| arg.to_str().is_some_and(|s| s.starts_with('-')));
 
     if python_lint || python_fmt {
         let venv_path = outdir.join("venv");
@@ -277,10 +277,11 @@ fn create_venv_at_path(path: &Path) -> Result<(), Error> {
 
     let stderr = String::from_utf8_lossy(&out.stderr);
     let err = if stderr.contains("No module named virtualenv") {
-        Error::Generic(format!(
+        Error::Generic(
             "virtualenv not found: you may need to install it \
                                (`python3 -m pip install venv`)"
-        ))
+                .to_owned(),
+        )
     } else {
         Error::Generic(format!(
             "failed to create venv at '{}' using {sys_py}: {stderr}",
diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs
index 2d3888ec75f..7bcb85335e0 100644
--- a/src/tools/tidy/src/style.rs
+++ b/src/tools/tidy/src/style.rs
@@ -463,10 +463,13 @@ pub fn check(path: &Path, bad: &mut bool) {
                 }
             }
             // for now we just check libcore
-            if trimmed.contains("unsafe {") && !trimmed.starts_with("//") && !last_safety_comment {
-                if file.components().any(|c| c.as_os_str() == "core") && !is_test {
-                    suppressible_tidy_err!(err, skip_undocumented_unsafe, "undocumented unsafe");
-                }
+            if trimmed.contains("unsafe {")
+                && !trimmed.starts_with("//")
+                && !last_safety_comment
+                && file.components().any(|c| c.as_os_str() == "core")
+                && !is_test
+            {
+                suppressible_tidy_err!(err, skip_undocumented_unsafe, "undocumented unsafe");
             }
             if trimmed.contains("// SAFETY:") {
                 last_safety_comment = true;
@@ -487,10 +490,10 @@ pub fn check(path: &Path, bad: &mut bool) {
                     "copyright notices attributed to the Rust Project Developers are deprecated"
                 );
             }
-            if !file.components().any(|c| c.as_os_str() == "rustc_baked_icu_data") {
-                if is_unexplained_ignore(&extension, line) {
-                    err(UNEXPLAINED_IGNORE_DOCTEST_INFO);
-                }
+            if !file.components().any(|c| c.as_os_str() == "rustc_baked_icu_data")
+                && is_unexplained_ignore(&extension, line)
+            {
+                err(UNEXPLAINED_IGNORE_DOCTEST_INFO);
             }
 
             if filename.ends_with(".cpp") && line.contains("llvm_unreachable") {
@@ -525,26 +528,24 @@ pub fn check(path: &Path, bad: &mut bool) {
                         backtick_count += comment_text.chars().filter(|ch| *ch == '`').count();
                     }
                     comment_block = Some((start_line, backtick_count));
-                } else {
-                    if let Some((start_line, backtick_count)) = comment_block.take() {
-                        if backtick_count % 2 == 1 {
-                            let mut err = |msg: &str| {
-                                tidy_error!(bad, "{}:{start_line}: {msg}", file.display());
-                            };
-                            let block_len = (i + 1) - start_line;
-                            if block_len == 1 {
-                                suppressible_tidy_err!(
-                                    err,
-                                    skip_odd_backticks,
-                                    "comment with odd number of backticks"
-                                );
-                            } else {
-                                suppressible_tidy_err!(
-                                    err,
-                                    skip_odd_backticks,
-                                    "{block_len}-line comment block with odd number of backticks"
-                                );
-                            }
+                } else if let Some((start_line, backtick_count)) = comment_block.take() {
+                    if backtick_count % 2 == 1 {
+                        let mut err = |msg: &str| {
+                            tidy_error!(bad, "{}:{start_line}: {msg}", file.display());
+                        };
+                        let block_len = (i + 1) - start_line;
+                        if block_len == 1 {
+                            suppressible_tidy_err!(
+                                err,
+                                skip_odd_backticks,
+                                "comment with odd number of backticks"
+                            );
+                        } else {
+                            suppressible_tidy_err!(
+                                err,
+                                skip_odd_backticks,
+                                "{block_len}-line comment block with odd number of backticks"
+                            );
                         }
                     }
                 }
diff --git a/src/tools/tidy/src/walk.rs b/src/tools/tidy/src/walk.rs
index 63a03834166..1cecf998e28 100644
--- a/src/tools/tidy/src/walk.rs
+++ b/src/tools/tidy/src/walk.rs
@@ -79,13 +79,11 @@ pub(crate) fn walk_no_read(
     let walker = walker.filter_entry(move |e| {
         !skip(e.path(), e.file_type().map(|ft| ft.is_dir()).unwrap_or(false))
     });
-    for entry in walker.build() {
-        if let Ok(entry) = entry {
-            if entry.file_type().map_or(true, |kind| kind.is_dir() || kind.is_symlink()) {
-                continue;
-            }
-            f(&entry);
+    for entry in walker.build().flatten() {
+        if entry.file_type().map_or(true, |kind| kind.is_dir() || kind.is_symlink()) {
+            continue;
         }
+        f(&entry);
     }
 }
 
@@ -97,11 +95,9 @@ pub(crate) fn walk_dir(
 ) {
     let mut walker = ignore::WalkBuilder::new(path);
     let walker = walker.filter_entry(move |e| !skip(e.path()));
-    for entry in walker.build() {
-        if let Ok(entry) = entry {
-            if entry.path().is_dir() {
-                f(&entry);
-            }
+    for entry in walker.build().flatten() {
+        if entry.path().is_dir() {
+            f(&entry);
         }
     }
 }
diff --git a/src/tools/tidy/src/x_version.rs b/src/tools/tidy/src/x_version.rs
index c470d502a65..55bfbed8b0e 100644
--- a/src/tools/tidy/src/x_version.rs
+++ b/src/tools/tidy/src/x_version.rs
@@ -52,7 +52,7 @@ pub fn check(root: &Path, cargo: &Path, bad: &mut bool) {
             );
         }
     } else {
-        return tidy_error!(bad, "failed to check version of `x`: {}", cargo_list.status);
+        tidy_error!(bad, "failed to check version of `x`: {}", cargo_list.status)
     }
 }
 
diff --git a/tests/ui/const-generics/issues/issue-82956.stderr b/tests/ui/const-generics/issues/issue-82956.stderr
index d0fc7112426..a956fc741f4 100644
--- a/tests/ui/const-generics/issues/issue-82956.stderr
+++ b/tests/ui/const-generics/issues/issue-82956.stderr
@@ -4,7 +4,7 @@ error[E0433]: failed to resolve: use of undeclared type `IntoIter`
 LL |         let mut iter = IntoIter::new(self);
    |                        ^^^^^^^^ use of undeclared type `IntoIter`
    |
-help: consider importing one of these items
+help: consider importing one of these structs
    |
 LL + use std::array::IntoIter;
    |
diff --git a/tests/ui/consts/const_refs_to_static-ice-121413.rs b/tests/ui/consts/const_refs_to_static-ice-121413.rs
index 8a24fb799b6..8fc3912efd0 100644
--- a/tests/ui/consts/const_refs_to_static-ice-121413.rs
+++ b/tests/ui/consts/const_refs_to_static-ice-121413.rs
@@ -5,12 +5,16 @@
 // ignore-tidy-linelength
 #![feature(const_refs_to_static)]
 const REF_INTERIOR_MUT: &usize = {
+    //~^ HELP consider importing this struct
     static FOO: Sync = AtomicUsize::new(0);
     //~^ ERROR failed to resolve: use of undeclared type `AtomicUsize`
     //~| WARN trait objects without an explicit `dyn` are deprecated
     //~| ERROR the size for values of type `(dyn Sync + 'static)` cannot be known at compilation time
     //~| ERROR the size for values of type `(dyn Sync + 'static)` cannot be known at compilation time
     //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+    //~| HELP if this is an object-safe trait, use `dyn`
+    //~| HELP the trait `Sized` is not implemented for `(dyn Sync + 'static)`
+    //~| HELP the trait `Sized` is not implemented for `(dyn Sync + 'static)`
     unsafe { &*(&FOO as *const _ as *const usize) }
 };
 pub fn main() {}
diff --git a/tests/ui/consts/const_refs_to_static-ice-121413.stderr b/tests/ui/consts/const_refs_to_static-ice-121413.stderr
index c977c698a92..fbe32a70293 100644
--- a/tests/ui/consts/const_refs_to_static-ice-121413.stderr
+++ b/tests/ui/consts/const_refs_to_static-ice-121413.stderr
@@ -1,5 +1,5 @@
 error[E0433]: failed to resolve: use of undeclared type `AtomicUsize`
-  --> $DIR/const_refs_to_static-ice-121413.rs:8:24
+  --> $DIR/const_refs_to_static-ice-121413.rs:9:24
    |
 LL |     static FOO: Sync = AtomicUsize::new(0);
    |                        ^^^^^^^^^^^ use of undeclared type `AtomicUsize`
@@ -10,7 +10,7 @@ LL + use std::sync::atomic::AtomicUsize;
    |
 
 warning: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/const_refs_to_static-ice-121413.rs:8:17
+  --> $DIR/const_refs_to_static-ice-121413.rs:9:17
    |
 LL |     static FOO: Sync = AtomicUsize::new(0);
    |                 ^^^^
@@ -24,7 +24,7 @@ LL |     static FOO: dyn Sync = AtomicUsize::new(0);
    |                 +++
 
 error[E0277]: the size for values of type `(dyn Sync + 'static)` cannot be known at compilation time
-  --> $DIR/const_refs_to_static-ice-121413.rs:8:17
+  --> $DIR/const_refs_to_static-ice-121413.rs:9:17
    |
 LL |     static FOO: Sync = AtomicUsize::new(0);
    |                 ^^^^ doesn't have a size known at compile-time
@@ -32,7 +32,7 @@ LL |     static FOO: Sync = AtomicUsize::new(0);
    = help: the trait `Sized` is not implemented for `(dyn Sync + 'static)`
 
 error[E0277]: the size for values of type `(dyn Sync + 'static)` cannot be known at compilation time
-  --> $DIR/const_refs_to_static-ice-121413.rs:8:24
+  --> $DIR/const_refs_to_static-ice-121413.rs:9:24
    |
 LL |     static FOO: Sync = AtomicUsize::new(0);
    |                        ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
diff --git a/tests/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr b/tests/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr
index 5c610f36322..b1a15b8594a 100644
--- a/tests/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr
+++ b/tests/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr
@@ -22,7 +22,7 @@ error[E0425]: cannot find value `Set` in this scope
 LL | fn setup() -> Set { Set }
    |                     ^^^ not found in this scope
    |
-help: consider importing one of these items
+help: consider importing one of these unit variants
    |
 LL + use AffixHeart::Set;
    |
diff --git a/tests/ui/hygiene/extern-prelude-from-opaque-fail-2018.stderr b/tests/ui/hygiene/extern-prelude-from-opaque-fail-2018.stderr
index 78e6376bca2..cc229764ad3 100644
--- a/tests/ui/hygiene/extern-prelude-from-opaque-fail-2018.stderr
+++ b/tests/ui/hygiene/extern-prelude-from-opaque-fail-2018.stderr
@@ -24,8 +24,7 @@ LL |         fn f() { my_core::mem::drop(0); }
 LL | a!();
    | ---- in this macro invocation
    |
-   = help: consider importing one of these items:
-           core::mem
+   = help: consider importing this module:
            std::mem
    = note: this error originates in the macro `a` (in Nightly builds, run with -Z macro-backtrace for more info)
 
@@ -35,9 +34,7 @@ error[E0433]: failed to resolve: use of undeclared crate or module `my_core`
 LL |     fn f() { my_core::mem::drop(0); }
    |              ^^^^^^^ use of undeclared crate or module `my_core`
    |
-help: consider importing one of these items
-   |
-LL +     use core::mem;
+help: consider importing this module
    |
 LL +     use std::mem;
    |
diff --git a/tests/ui/imports/cycle-import-in-std-1.stderr b/tests/ui/imports/cycle-import-in-std-1.stderr
index d4e6f32cc10..a7dfc6231ba 100644
--- a/tests/ui/imports/cycle-import-in-std-1.stderr
+++ b/tests/ui/imports/cycle-import-in-std-1.stderr
@@ -4,8 +4,7 @@ error[E0432]: unresolved import `ops`
 LL | use ops::{self as std};
    |           ^^^^^^^^^^^ no external crate `ops`
    |
-   = help: consider importing one of these items instead:
-           core::ops
+   = help: consider importing this module instead:
            std::ops
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/imports/cycle-import-in-std-2.stderr b/tests/ui/imports/cycle-import-in-std-2.stderr
index dc0270dffe4..8d94693cd51 100644
--- a/tests/ui/imports/cycle-import-in-std-2.stderr
+++ b/tests/ui/imports/cycle-import-in-std-2.stderr
@@ -4,8 +4,7 @@ error[E0432]: unresolved import `ops`
 LL | use ops::{self as std};
    |           ^^^^^^^^^^^ no external crate `ops`
    |
-   = help: consider importing one of these items instead:
-           core::ops
+   = help: consider importing this module instead:
            std::ops
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/imports/import-alias-issue-121168.edition2018.stderr b/tests/ui/imports/import-alias-issue-121168.edition2018.stderr
index b61a0e3edd5..e14e700c33d 100644
--- a/tests/ui/imports/import-alias-issue-121168.edition2018.stderr
+++ b/tests/ui/imports/import-alias-issue-121168.edition2018.stderr
@@ -4,7 +4,7 @@ error[E0412]: cannot find type `Foo` in this scope
 LL |     let _: Foo<i32> = todo!();
    |            ^^^ not found in this scope
    |
-help: consider importing one of these items
+help: consider importing one of these structs
    |
 LL + use crate::nice_crate_name::Foo;
    |
diff --git a/tests/ui/imports/import-alias-issue-121168.edition2021.stderr b/tests/ui/imports/import-alias-issue-121168.edition2021.stderr
index b61a0e3edd5..e14e700c33d 100644
--- a/tests/ui/imports/import-alias-issue-121168.edition2021.stderr
+++ b/tests/ui/imports/import-alias-issue-121168.edition2021.stderr
@@ -4,7 +4,7 @@ error[E0412]: cannot find type `Foo` in this scope
 LL |     let _: Foo<i32> = todo!();
    |            ^^^ not found in this scope
    |
-help: consider importing one of these items
+help: consider importing one of these structs
    |
 LL + use crate::nice_crate_name::Foo;
    |
diff --git a/tests/ui/imports/issue-56125.stderr b/tests/ui/imports/issue-56125.stderr
index d2a0f436c42..0c4a569c7ea 100644
--- a/tests/ui/imports/issue-56125.stderr
+++ b/tests/ui/imports/issue-56125.stderr
@@ -4,16 +4,16 @@ error[E0432]: unresolved import `empty::issue_56125`
 LL |     use empty::issue_56125;
    |         ^^^^^^^^^^^^^^^^^^ no `issue_56125` in `m3::empty`
    |
-help: consider importing one of these items instead
+help: consider importing one of these modules instead
    |
+LL |     use crate::m3::last_segment::issue_56125;
+   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |     use crate::m3::non_last_segment::non_last_segment::issue_56125;
+   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 LL |     use ::issue_56125::issue_56125;
    |         ~~~~~~~~~~~~~~~~~~~~~~~~~~
 LL |     use ::issue_56125::last_segment::issue_56125;
    |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-LL |     use ::issue_56125::non_last_segment::non_last_segment::issue_56125;
-   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-LL |     use crate::m3::last_segment::issue_56125;
-   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      and 1 other candidate
 
 error[E0659]: `issue_56125` is ambiguous
diff --git a/tests/ui/lint/dead-code/allow-unconstructed-pub-struct.rs b/tests/ui/lint/dead-code/allow-unconstructed-pub-struct.rs
new file mode 100644
index 00000000000..8cd1524045b
--- /dev/null
+++ b/tests/ui/lint/dead-code/allow-unconstructed-pub-struct.rs
@@ -0,0 +1,33 @@
+//@ check-pass
+
+mod ffi {
+    use super::*;
+
+    extern "C" {
+        pub fn DomPromise_AddRef(promise: *const Promise);
+        pub fn DomPromise_Release(promise: *const Promise);
+    }
+}
+
+#[repr(C)]
+#[allow(unused)]
+pub struct Promise {
+    private: [u8; 0],
+    __nosync: ::std::marker::PhantomData<::std::rc::Rc<u8>>,
+}
+
+pub unsafe trait RefCounted {
+    unsafe fn addref(&self);
+    unsafe fn release(&self);
+}
+
+unsafe impl RefCounted for Promise {
+    unsafe fn addref(&self) {
+        ffi::DomPromise_AddRef(self)
+    }
+    unsafe fn release(&self) {
+        ffi::DomPromise_Release(self)
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/lint/use_suggestion_json.stderr b/tests/ui/lint/use_suggestion_json.stderr
index acc36550642..4683e5dd8f3 100644
--- a/tests/ui/lint/use_suggestion_json.stderr
+++ b/tests/ui/lint/use_suggestion_json.stderr
@@ -95,7 +95,7 @@ mod foo {
   ],
   "children": [
     {
-      "message": "consider importing one of these items",
+      "message": "consider importing one of these structs",
       "code": null,
       "level": "help",
       "spans": [
@@ -386,7 +386,7 @@ mod foo {
 \u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m    let x: Iter;\u001b[0m
 \u001b[0m   \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m            \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9m^^^^\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9mnot found in this scope\u001b[0m
 \u001b[0m   \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
-\u001b[0m\u001b[1m\u001b[38;5;14mhelp\u001b[0m\u001b[0m: consider importing one of these items\u001b[0m
+\u001b[0m\u001b[1m\u001b[38;5;14mhelp\u001b[0m\u001b[0m: consider importing one of these structs\u001b[0m
 \u001b[0m   \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
 \u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[38;5;10m+ use std::collections::binary_heap::Iter;\u001b[0m
 \u001b[0m   \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
diff --git a/tests/ui/namespace/namespace-mix.stderr b/tests/ui/namespace/namespace-mix.stderr
index 4eff08ead42..b80363fe8f8 100644
--- a/tests/ui/namespace/namespace-mix.stderr
+++ b/tests/ui/namespace/namespace-mix.stderr
@@ -12,7 +12,7 @@ help: a tuple struct with a similar name exists
    |
 LL |     check(m1::TS);
    |               ~~
-help: consider importing one of these items instead
+help: consider importing one of these constants instead
    |
 LL + use m2::S;
    |
@@ -40,7 +40,7 @@ help: a tuple struct with a similar name exists
    |
 LL |     check(xm1::TS);
    |                ~~
-help: consider importing one of these items instead
+help: consider importing one of these constants instead
    |
 LL + use m2::S;
    |
@@ -66,7 +66,7 @@ help: a tuple variant with a similar name exists
    |
 LL |     check(m7::TV);
    |               ~~
-help: consider importing one of these items instead
+help: consider importing one of these constants instead
    |
 LL + use m8::V;
    |
@@ -94,7 +94,7 @@ help: a tuple variant with a similar name exists
    |
 LL |     check(xm7::TV);
    |                ~~
-help: consider importing one of these items instead
+help: consider importing one of these constants instead
    |
 LL + use m8::V;
    |
diff --git a/tests/ui/resolve/issue-16058.stderr b/tests/ui/resolve/issue-16058.stderr
index 914990c35ff..12b1ac8a5fb 100644
--- a/tests/ui/resolve/issue-16058.stderr
+++ b/tests/ui/resolve/issue-16058.stderr
@@ -4,7 +4,7 @@ error[E0574]: expected struct, variant or union type, found enum `Result`
 LL |         Result {
    |         ^^^^^^ not a struct, variant or union type
    |
-help: consider importing one of these items instead
+help: consider importing one of these type aliases instead
    |
 LL + use std::fmt::Result;
    |
diff --git a/tests/ui/resolve/issue-21221-1.stderr b/tests/ui/resolve/issue-21221-1.stderr
index a38116cd728..ccf03afaa19 100644
--- a/tests/ui/resolve/issue-21221-1.stderr
+++ b/tests/ui/resolve/issue-21221-1.stderr
@@ -4,14 +4,14 @@ error[E0405]: cannot find trait `Mul` in this scope
 LL | impl Mul for Foo {
    |      ^^^ not found in this scope
    |
-help: consider importing one of these items
+help: consider importing one of these traits
+   |
+LL + use std::ops::Mul;
    |
 LL + use mul1::Mul;
    |
 LL + use mul2::Mul;
    |
-LL + use std::ops::Mul;
-   |
 
 error[E0412]: cannot find type `Mul` in this scope
   --> $DIR/issue-21221-1.rs:58:16
@@ -19,14 +19,14 @@ error[E0412]: cannot find type `Mul` in this scope
 LL | fn getMul() -> Mul {
    |                ^^^ not found in this scope
    |
-help: consider importing one of these items
+help: consider importing one of these traits
+   |
+LL + use std::ops::Mul;
    |
 LL + use mul1::Mul;
    |
 LL + use mul2::Mul;
    |
-LL + use std::ops::Mul;
-   |
 
 error[E0405]: cannot find trait `ThisTraitReallyDoesntExistInAnyModuleReally` in this scope
   --> $DIR/issue-21221-1.rs:63:6
diff --git a/tests/ui/resolve/issue-21221-2.stderr b/tests/ui/resolve/issue-21221-2.stderr
index 3bd4c1a5d13..5db327955eb 100644
--- a/tests/ui/resolve/issue-21221-2.stderr
+++ b/tests/ui/resolve/issue-21221-2.stderr
@@ -4,7 +4,7 @@ error[E0405]: cannot find trait `T` in this scope
 LL | impl T for Foo { }
    |      ^ not found in this scope
    |
-help: consider importing one of these items
+help: consider importing one of these traits
    |
 LL + use baz::T;
    |
diff --git a/tests/ui/resolve/issue-50599.stderr b/tests/ui/resolve/issue-50599.stderr
index e5eacd741fb..24fb3d580b8 100644
--- a/tests/ui/resolve/issue-50599.stderr
+++ b/tests/ui/resolve/issue-50599.stderr
@@ -4,7 +4,7 @@ error[E0425]: cannot find value `LOG10_2` in module `std::f64`
 LL |     const M: usize = (f64::from(N) * std::f64::LOG10_2) as usize;
    |                                                ^^^^^^^ not found in `std::f64`
    |
-help: consider importing one of these items
+help: consider importing one of these constants
    |
 LL + use std::f128::consts::LOG10_2;
    |
diff --git a/tests/ui/resolve/issue-73427.stderr b/tests/ui/resolve/issue-73427.stderr
index c5e245d884b..0a9a504f79c 100644
--- a/tests/ui/resolve/issue-73427.stderr
+++ b/tests/ui/resolve/issue-73427.stderr
@@ -105,7 +105,7 @@ help: the following enum variant is available
    |
 LL |     (E::TupleWithFields(/* fields */)).foo();
    |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-help: consider importing one of these items instead
+help: consider importing one of these constants instead
    |
 LL + use std::f128::consts::E;
    |
diff --git a/tests/ui/resolve/privacy-enum-ctor.stderr b/tests/ui/resolve/privacy-enum-ctor.stderr
index 01c8a38d2a4..ee3aecddcc3 100644
--- a/tests/ui/resolve/privacy-enum-ctor.stderr
+++ b/tests/ui/resolve/privacy-enum-ctor.stderr
@@ -82,7 +82,7 @@ help: a function with a similar name exists
    |
 LL |     let _: E = m::f;
    |                   ~
-help: consider importing one of these items instead
+help: consider importing one of these constants instead
    |
 LL + use std::f128::consts::E;
    |
@@ -123,7 +123,7 @@ help: alternatively, the following enum variant is available
    |
 LL |     let _: E = (E::Fn(/* fields */));
    |                ~~~~~~~~~~~~~~~~~~~~~
-help: consider importing one of these items instead
+help: consider importing one of these constants instead
    |
 LL + use std::f128::consts::E;
    |
diff --git a/tests/ui/rfcs/rfc-2126-extern-absolute-paths/not-allowed.stderr b/tests/ui/rfcs/rfc-2126-extern-absolute-paths/not-allowed.stderr
index 7f989c15f1c..d0c084f7bd5 100644
--- a/tests/ui/rfcs/rfc-2126-extern-absolute-paths/not-allowed.stderr
+++ b/tests/ui/rfcs/rfc-2126-extern-absolute-paths/not-allowed.stderr
@@ -4,10 +4,8 @@ error[E0432]: unresolved import `alloc`
 LL | use alloc;
    |     ^^^^^ no external crate `alloc`
    |
-help: consider importing one of these items instead
+help: consider importing this module instead
    |
-LL | use core::alloc;
-   |     ~~~~~~~~~~~
 LL | use std::alloc;
    |     ~~~~~~~~~~
 
diff --git a/tests/ui/rust-2018/issue-52202-use-suggestions.stderr b/tests/ui/rust-2018/issue-52202-use-suggestions.stderr
index 49736205f20..ee1a336ea98 100644
--- a/tests/ui/rust-2018/issue-52202-use-suggestions.stderr
+++ b/tests/ui/rust-2018/issue-52202-use-suggestions.stderr
@@ -4,7 +4,7 @@ error[E0422]: cannot find struct, variant or union type `Drain` in this scope
 LL |     let _d = Drain {};
    |              ^^^^^ not found in this scope
    |
-help: consider importing one of these items
+help: consider importing one of these structs
    |
 LL + use crate::plumbing::Drain;
    |
diff --git a/tests/ui/suggestions/core-std-import-order-issue-83564.no_std.fixed b/tests/ui/suggestions/core-std-import-order-issue-83564.no_std.fixed
new file mode 100644
index 00000000000..02d667d9844
--- /dev/null
+++ b/tests/ui/suggestions/core-std-import-order-issue-83564.no_std.fixed
@@ -0,0 +1,22 @@
+//@ edition:2018
+//
+// This is a regression test for #83564.
+// For some reason, Rust 2018 or higher is required to reproduce the bug.
+//@ run-rustfix
+//@ revisions: no_std std
+//@ [no_std]compile-flags: --cfg=no_std -C panic=abort
+#![cfg_attr(no_std, no_std)]
+
+use core::num::NonZero;
+
+fn main() {
+    //~^ HELP consider importing this struct
+    let _x = NonZero::new(5u32).unwrap();
+    //~^ ERROR failed to resolve: use of undeclared type `NonZero`
+}
+
+#[allow(dead_code)]
+#[cfg_attr(no_std, panic_handler)]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+    loop {}
+}
diff --git a/tests/ui/suggestions/core-std-import-order-issue-83564.stderr b/tests/ui/suggestions/core-std-import-order-issue-83564.no_std.stderr
index 8665cc6d87c..d73f613bf9c 100644
--- a/tests/ui/suggestions/core-std-import-order-issue-83564.stderr
+++ b/tests/ui/suggestions/core-std-import-order-issue-83564.no_std.stderr
@@ -1,15 +1,13 @@
 error[E0433]: failed to resolve: use of undeclared type `NonZero`
-  --> $DIR/core-std-import-order-issue-83564.rs:8:14
+  --> $DIR/core-std-import-order-issue-83564.rs:12:14
    |
 LL |     let _x = NonZero::new(5u32).unwrap();
    |              ^^^^^^^ use of undeclared type `NonZero`
    |
-help: consider importing one of these items
+help: consider importing this struct
    |
 LL + use core::num::NonZero;
    |
-LL + use std::num::NonZero;
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/suggestions/core-std-import-order-issue-83564.rs b/tests/ui/suggestions/core-std-import-order-issue-83564.rs
index 6f2bdd7a38a..5bb5bfe176b 100644
--- a/tests/ui/suggestions/core-std-import-order-issue-83564.rs
+++ b/tests/ui/suggestions/core-std-import-order-issue-83564.rs
@@ -2,9 +2,19 @@
 //
 // This is a regression test for #83564.
 // For some reason, Rust 2018 or higher is required to reproduce the bug.
+//@ run-rustfix
+//@ revisions: no_std std
+//@ [no_std]compile-flags: --cfg=no_std -C panic=abort
+#![cfg_attr(no_std, no_std)]
 
 fn main() {
-    //~^ HELP consider importing one of these items
+    //~^ HELP consider importing this struct
     let _x = NonZero::new(5u32).unwrap();
     //~^ ERROR failed to resolve: use of undeclared type `NonZero`
 }
+
+#[allow(dead_code)]
+#[cfg_attr(no_std, panic_handler)]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+    loop {}
+}
diff --git a/tests/ui/suggestions/core-std-import-order-issue-83564.std.fixed b/tests/ui/suggestions/core-std-import-order-issue-83564.std.fixed
new file mode 100644
index 00000000000..3492b42c685
--- /dev/null
+++ b/tests/ui/suggestions/core-std-import-order-issue-83564.std.fixed
@@ -0,0 +1,22 @@
+//@ edition:2018
+//
+// This is a regression test for #83564.
+// For some reason, Rust 2018 or higher is required to reproduce the bug.
+//@ run-rustfix
+//@ revisions: no_std std
+//@ [no_std]compile-flags: --cfg=no_std -C panic=abort
+#![cfg_attr(no_std, no_std)]
+
+use std::num::NonZero;
+
+fn main() {
+    //~^ HELP consider importing this struct
+    let _x = NonZero::new(5u32).unwrap();
+    //~^ ERROR failed to resolve: use of undeclared type `NonZero`
+}
+
+#[allow(dead_code)]
+#[cfg_attr(no_std, panic_handler)]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+    loop {}
+}
diff --git a/tests/ui/suggestions/core-std-import-order-issue-83564.std.stderr b/tests/ui/suggestions/core-std-import-order-issue-83564.std.stderr
new file mode 100644
index 00000000000..ebfe197b45d
--- /dev/null
+++ b/tests/ui/suggestions/core-std-import-order-issue-83564.std.stderr
@@ -0,0 +1,14 @@
+error[E0433]: failed to resolve: use of undeclared type `NonZero`
+  --> $DIR/core-std-import-order-issue-83564.rs:12:14
+   |
+LL |     let _x = NonZero::new(5u32).unwrap();
+   |              ^^^^^^^ use of undeclared type `NonZero`
+   |
+help: consider importing this struct
+   |
+LL + use std::num::NonZero;
+   |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/tests/ui/suggestions/crate-or-module-typo.stderr b/tests/ui/suggestions/crate-or-module-typo.stderr
index 457d7790646..084d0408a8e 100644
--- a/tests/ui/suggestions/crate-or-module-typo.stderr
+++ b/tests/ui/suggestions/crate-or-module-typo.stderr
@@ -30,9 +30,7 @@ help: there is a crate or module with a similar name
    |
 LL |     bar: std::cell::Cell<bool>
    |          ~~~
-help: consider importing one of these items
-   |
-LL + use core::cell;
+help: consider importing this module
    |
 LL + use std::cell;
    |
diff --git a/tests/ui/suggestions/suggest-tryinto-edition-change.rs b/tests/ui/suggestions/suggest-tryinto-edition-change.rs
index 37321774874..f45670ae7c1 100644
--- a/tests/ui/suggestions/suggest-tryinto-edition-change.rs
+++ b/tests/ui/suggestions/suggest-tryinto-edition-change.rs
@@ -1,5 +1,5 @@
 // Make sure that trying to access `TryInto`, `TryFrom`, `FromIterator` in pre-2021 mentions
-// Edition 2021 change
+// Edition 2021 change.
 //@ edition:2018
 
 fn test() {
@@ -11,19 +11,16 @@ fn test() {
     //~^ ERROR failed to resolve: use of undeclared type
     //~| NOTE use of undeclared type
     //~| NOTE 'std::convert::TryFrom' is included in the prelude starting in Edition 2021
-    //~| NOTE 'core::convert::TryFrom' is included in the prelude starting in Edition 2021
 
     let _i: i16 = TryInto::try_into(0_i32).unwrap();
     //~^ ERROR failed to resolve: use of undeclared type
     //~| NOTE use of undeclared type
     //~| NOTE 'std::convert::TryInto' is included in the prelude starting in Edition 2021
-    //~| NOTE 'core::convert::TryInto' is included in the prelude starting in Edition 2021
 
     let _v: Vec<_> = FromIterator::from_iter(&[1]);
     //~^ ERROR failed to resolve: use of undeclared type
     //~| NOTE use of undeclared type
     //~| NOTE 'std::iter::FromIterator' is included in the prelude starting in Edition 2021
-    //~| NOTE 'core::iter::FromIterator' is included in the prelude starting in Edition 2021
 }
 
 fn main() {
diff --git a/tests/ui/suggestions/suggest-tryinto-edition-change.stderr b/tests/ui/suggestions/suggest-tryinto-edition-change.stderr
index db7c40101cd..5be55f75cd1 100644
--- a/tests/ui/suggestions/suggest-tryinto-edition-change.stderr
+++ b/tests/ui/suggestions/suggest-tryinto-edition-change.stderr
@@ -4,45 +4,36 @@ error[E0433]: failed to resolve: use of undeclared type `TryFrom`
 LL |     let _i: i16 = TryFrom::try_from(0_i32).unwrap();
    |                   ^^^^^^^ use of undeclared type `TryFrom`
    |
-   = note: 'core::convert::TryFrom' is included in the prelude starting in Edition 2021
    = note: 'std::convert::TryFrom' is included in the prelude starting in Edition 2021
-help: consider importing one of these items
-   |
-LL + use core::convert::TryFrom;
+help: consider importing this trait
    |
 LL + use std::convert::TryFrom;
    |
 
 error[E0433]: failed to resolve: use of undeclared type `TryInto`
-  --> $DIR/suggest-tryinto-edition-change.rs:16:19
+  --> $DIR/suggest-tryinto-edition-change.rs:15:19
    |
 LL |     let _i: i16 = TryInto::try_into(0_i32).unwrap();
    |                   ^^^^^^^ use of undeclared type `TryInto`
    |
-   = note: 'core::convert::TryInto' is included in the prelude starting in Edition 2021
    = note: 'std::convert::TryInto' is included in the prelude starting in Edition 2021
-help: consider importing one of these items
-   |
-LL + use core::convert::TryInto;
+help: consider importing this trait
    |
 LL + use std::convert::TryInto;
    |
 
 error[E0433]: failed to resolve: use of undeclared type `FromIterator`
-  --> $DIR/suggest-tryinto-edition-change.rs:22:22
+  --> $DIR/suggest-tryinto-edition-change.rs:20:22
    |
 LL |     let _v: Vec<_> = FromIterator::from_iter(&[1]);
    |                      ^^^^^^^^^^^^ use of undeclared type `FromIterator`
    |
-   = note: 'core::iter::FromIterator' is included in the prelude starting in Edition 2021
    = note: 'std::iter::FromIterator' is included in the prelude starting in Edition 2021
 help: a trait with a similar name exists
    |
 LL |     let _v: Vec<_> = IntoIterator::from_iter(&[1]);
    |                      ~~~~~~~~~~~~
-help: consider importing one of these items
-   |
-LL + use core::iter::FromIterator;
+help: consider importing this trait
    |
 LL + use std::iter::FromIterator;
    |