about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs13
-rw-r--r--compiler/rustc_borrowck/src/facts.rs15
-rw-r--r--compiler/rustc_borrowck/src/place_ext.rs14
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs12
-rw-r--r--compiler/rustc_borrowck/src/universal_regions.rs24
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs37
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs24
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs14
-rw-r--r--compiler/rustc_infer/src/infer/canonical/instantiate.rs26
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs15
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs7
-rw-r--r--compiler/rustc_infer/src/traits/engine.rs15
-rw-r--r--compiler/rustc_macros/src/extension.rs154
-rw-r--r--compiler/rustc_macros/src/lib.rs6
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs24
-rw-r--r--compiler/rustc_middle/src/ty/util.rs9
-rw-r--r--compiler/rustc_mir_transform/src/const_prop_lint.rs5
-rw-r--r--compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs13
-rw-r--r--compiler/rustc_trait_selection/src/infer.rs82
-rw-r--r--compiler/rustc_trait_selection/src/regions.rs10
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs14
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs10
-rw-r--r--compiler/rustc_trait_selection/src/solve/inspect/analyse.rs11
-rw-r--r--compiler/rustc_trait_selection/src/solve/mod.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/engine.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs37
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs21
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs276
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs286
-rw-r--r--compiler/rustc_trait_selection/src/traits/outlives_bounds.rs25
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs33
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs34
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs22
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs34
-rw-r--r--compiler/rustc_trait_selection/src/traits/structural_normalize.rs11
36 files changed, 360 insertions, 993 deletions
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index e9e1095a4ae..a5be91bb872 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -57,6 +57,7 @@ use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
 use rustc_hir::def_id::{LocalDefId, LocalDefIdMap, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::{ConstArg, GenericArg, ItemLocalMap, ParamName, TraitCandidate};
 use rustc_index::{Idx, IndexSlice, IndexVec};
+use rustc_macros::extension;
 use rustc_middle::span_bug;
 use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
 use rustc_session::parse::{add_feature_diagnostics, feature_err};
@@ -190,16 +191,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     }
 }
 
-trait ResolverAstLoweringExt {
-    fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>>;
-    fn get_partial_res(&self, id: NodeId) -> Option<PartialRes>;
-    fn get_import_res(&self, id: NodeId) -> PerNS<Option<Res<NodeId>>>;
-    fn get_label_res(&self, id: NodeId) -> Option<NodeId>;
-    fn get_lifetime_res(&self, id: NodeId) -> Option<LifetimeRes>;
-    fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)>;
-}
-
-impl ResolverAstLoweringExt for ResolverAstLowering {
+#[extension(trait ResolverAstLoweringExt)]
+impl ResolverAstLowering {
     fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>> {
         if let ExprKind::Path(None, path) = &expr.kind {
             // Don't perform legacy const generics rewriting if the path already
diff --git a/compiler/rustc_borrowck/src/facts.rs b/compiler/rustc_borrowck/src/facts.rs
index 68dc9a6764b..e7faec7bbac 100644
--- a/compiler/rustc_borrowck/src/facts.rs
+++ b/compiler/rustc_borrowck/src/facts.rs
@@ -2,6 +2,7 @@ use crate::location::{LocationIndex, LocationTable};
 use crate::BorrowIndex;
 use polonius_engine::AllFacts as PoloniusFacts;
 use polonius_engine::Atom;
+use rustc_macros::extension;
 use rustc_middle::mir::Local;
 use rustc_middle::ty::{RegionVid, TyCtxt};
 use rustc_mir_dataflow::move_paths::MovePathIndex;
@@ -24,20 +25,10 @@ impl polonius_engine::FactTypes for RustcFacts {
 
 pub type AllFacts = PoloniusFacts<RustcFacts>;
 
-pub(crate) trait AllFactsExt {
+#[extension(pub(crate) trait AllFactsExt)]
+impl AllFacts {
     /// Returns `true` if there is a need to gather `AllFacts` given the
     /// current `-Z` flags.
-    fn enabled(tcx: TyCtxt<'_>) -> bool;
-
-    fn write_to_dir(
-        &self,
-        dir: impl AsRef<Path>,
-        location_table: &LocationTable,
-    ) -> Result<(), Box<dyn Error>>;
-}
-
-impl AllFactsExt for AllFacts {
-    /// Return
     fn enabled(tcx: TyCtxt<'_>) -> bool {
         tcx.sess.opts.unstable_opts.nll_facts
             || tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled()
diff --git a/compiler/rustc_borrowck/src/place_ext.rs b/compiler/rustc_borrowck/src/place_ext.rs
index b59ab7fafa5..0f806df9da1 100644
--- a/compiler/rustc_borrowck/src/place_ext.rs
+++ b/compiler/rustc_borrowck/src/place_ext.rs
@@ -1,11 +1,12 @@
 use crate::borrow_set::LocalsStateAtExit;
 use rustc_hir as hir;
+use rustc_macros::extension;
 use rustc_middle::mir::ProjectionElem;
 use rustc_middle::mir::{Body, Mutability, Place};
 use rustc_middle::ty::{self, TyCtxt};
 
-/// Extension methods for the `Place` type.
-pub trait PlaceExt<'tcx> {
+#[extension(pub trait PlaceExt<'tcx>)]
+impl<'tcx> Place<'tcx> {
     /// Returns `true` if we can safely ignore borrows of this place.
     /// This is true whenever there is no action that the user can do
     /// to the place `self` that would invalidate the borrow. This is true
@@ -15,15 +16,6 @@ pub trait PlaceExt<'tcx> {
         tcx: TyCtxt<'tcx>,
         body: &Body<'tcx>,
         locals_state_at_exit: &LocalsStateAtExit,
-    ) -> bool;
-}
-
-impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
-    fn ignore_borrow(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        body: &Body<'tcx>,
-        locals_state_at_exit: &LocalsStateAtExit,
     ) -> bool {
         // If a local variable is immutable, then we only need to track borrows to guard
         // against two kinds of errors:
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index cd2fe56ca49..a5a906658b8 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -6,6 +6,7 @@ use rustc_hir::OpaqueTyOrigin;
 use rustc_infer::infer::InferCtxt;
 use rustc_infer::infer::TyCtxtInferExt as _;
 use rustc_infer::traits::{Obligation, ObligationCause};
+use rustc_macros::extension;
 use rustc_middle::traits::DefiningAnchor;
 use rustc_middle::ty::visit::TypeVisitableExt;
 use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable};
@@ -225,15 +226,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     }
 }
 
-pub trait InferCtxtExt<'tcx> {
-    fn infer_opaque_definition_from_instantiation(
-        &self,
-        opaque_type_key: OpaqueTypeKey<'tcx>,
-        instantiated_ty: OpaqueHiddenType<'tcx>,
-    ) -> Ty<'tcx>;
-}
-
-impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
+#[extension(pub trait InferCtxtExt<'tcx>)]
+impl<'tcx> InferCtxt<'tcx> {
     /// Given the fully resolved, instantiated type for an opaque
     /// type, i.e., the value of an inference variable like C1 or C2
     /// (*), computes the "definition type" for an opaque type
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index 90e8f1b93b2..a69f5335f71 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -22,6 +22,7 @@ use rustc_hir::lang_items::LangItem;
 use rustc_hir::BodyOwnerKind;
 use rustc_index::IndexVec;
 use rustc_infer::infer::NllRegionVariableOrigin;
+use rustc_macros::extension;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, InlineConstArgs, InlineConstArgsParts, RegionVid, Ty, TyCtxt};
@@ -793,27 +794,8 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
     }
 }
 
-trait InferCtxtExt<'tcx> {
-    fn replace_free_regions_with_nll_infer_vars<T>(
-        &self,
-        origin: NllRegionVariableOrigin,
-        value: T,
-    ) -> T
-    where
-        T: TypeFoldable<TyCtxt<'tcx>>;
-
-    fn replace_bound_regions_with_nll_infer_vars<T>(
-        &self,
-        origin: NllRegionVariableOrigin,
-        all_outlive_scope: LocalDefId,
-        value: ty::Binder<'tcx, T>,
-        indices: &mut UniversalRegionIndices<'tcx>,
-    ) -> T
-    where
-        T: TypeFoldable<TyCtxt<'tcx>>;
-}
-
-impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> {
+#[extension(trait InferCtxtExt<'tcx>)]
+impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> {
     #[instrument(skip(self), level = "debug")]
     fn replace_free_regions_with_nll_infer_vars<T>(
         &self,
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index 96c9e740568..a3c4734f0a3 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -344,7 +344,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
         visitor.visit_ty(ty);
     }
 
-    fn check_mut_borrow(&mut self, local: Local, kind: hir::BorrowKind) {
+    fn check_mut_borrow(&mut self, place: &Place<'_>, kind: hir::BorrowKind) {
         match self.const_kind() {
             // In a const fn all borrows are transient or point to the places given via
             // references in the arguments (so we already checked them with
@@ -355,10 +355,19 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
             // to mutable memory.
             hir::ConstContext::ConstFn => self.check_op(ops::TransientMutBorrow(kind)),
             _ => {
+                // For indirect places, we are not creating a new permanent borrow, it's just as
+                // transient as the already existing one. For reborrowing references this is handled
+                // at the top of `visit_rvalue`, but for raw pointers we handle it here.
+                // Pointers/references to `static mut` and cases where the `*` is not the first
+                // projection also end up here.
                 // Locals with StorageDead do not live beyond the evaluation and can
                 // thus safely be borrowed without being able to be leaked to the final
                 // value of the constant.
-                if self.local_has_storage_dead(local) {
+                // Note: This is only sound if every local that has a `StorageDead` has a
+                // `StorageDead` in every control flow path leading to a `return` terminator.
+                // The good news is that interning will detect if any unexpected mutable
+                // pointer slips through.
+                if place.is_indirect() || self.local_has_storage_dead(place.local) {
                     self.check_op(ops::TransientMutBorrow(kind));
                 } else {
                     self.check_op(ops::MutBorrow(kind));
@@ -390,6 +399,11 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
         trace!("visit_rvalue: rvalue={:?} location={:?}", rvalue, location);
 
         // Special-case reborrows to be more like a copy of a reference.
+        // FIXME: this does not actually handle all reborrows. It only detects cases where `*` is the outermost
+        // projection of the borrowed place, it skips deref'ing raw pointers and it skips `static`.
+        // All those cases are handled below with shared/mutable borrows.
+        // Once `const_mut_refs` is stable, we should be able to entirely remove this special case.
+        // (`const_refs_to_cell` is not needed, we already allow all borrows of indirect places anyway.)
         match *rvalue {
             Rvalue::Ref(_, kind, place) => {
                 if let Some(reborrowed_place_ref) = place_as_reborrow(self.tcx, self.body, place) {
@@ -460,7 +474,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
 
                 if !is_allowed {
                     self.check_mut_borrow(
-                        place.local,
+                        place,
                         if matches!(rvalue, Rvalue::Ref(..)) {
                             hir::BorrowKind::Ref
                         } else {
@@ -478,7 +492,14 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                     place.as_ref(),
                 );
 
-                if borrowed_place_has_mut_interior {
+                // If the place is indirect, this is basically a reborrow. We have a reborrow
+                // special case above, but for raw pointers and pointers/references to `static` and
+                // when the `*` is not the first projection, `place_as_reborrow` does not recognize
+                // them as such, so we end up here. This should probably be considered a
+                // `TransientCellBorrow` (we consider the equivalent mutable case a
+                // `TransientMutBorrow`), but such reborrows got accidentally stabilized already and
+                // it is too much of a breaking change to take back.
+                if borrowed_place_has_mut_interior && !place.is_indirect() {
                     match self.const_kind() {
                         // In a const fn all borrows are transient or point to the places given via
                         // references in the arguments (so we already checked them with
@@ -495,6 +516,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                             // final value.
                             // Note: This is only sound if every local that has a `StorageDead` has a
                             // `StorageDead` in every control flow path leading to a `return` terminator.
+                            // The good news is that interning will detect if any unexpected mutable
+                            // pointer slips through.
                             if self.local_has_storage_dead(place.local) {
                                 self.check_op(ops::TransientCellBorrow);
                             } else {
@@ -948,6 +971,12 @@ fn place_as_reborrow<'tcx>(
 ) -> Option<PlaceRef<'tcx>> {
     match place.as_ref().last_projection() {
         Some((place_base, ProjectionElem::Deref)) => {
+            // FIXME: why do statics and raw pointers get excluded here? This makes
+            // some code involving mutable pointers unstable, but it is unclear
+            // why that code is treated differently from mutable references.
+            // Once TransientMutBorrow and TransientCellBorrow are stable,
+            // this can probably be cleaned up without any behavioral changes.
+
             // A borrow of a `static` also looks like `&(*_1)` in the MIR, but `_1` is a `const`
             // that points to the allocation for the static. Don't treat these as reborrows.
             if body.local_decls[place_base.local].is_ref_to_static() {
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
index 67fef208079..7eb3c181d69 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -74,6 +74,13 @@ pub trait Qualif {
         adt: AdtDef<'tcx>,
         args: GenericArgsRef<'tcx>,
     ) -> bool;
+
+    /// Returns `true` if this `Qualif` behaves sructurally for pointers and references:
+    /// the pointer/reference qualifies if and only if the pointee qualifies.
+    ///
+    /// (This is currently `false` for all our instances, but that may change in the future. Also,
+    /// by keeping it abstract, the handling of `Deref` in `in_place` becomes more clear.)
+    fn deref_structural<'tcx>(cx: &ConstCx<'_, 'tcx>) -> bool;
 }
 
 /// Constant containing interior mutability (`UnsafeCell<T>`).
@@ -103,6 +110,10 @@ impl Qualif for HasMutInterior {
         // It arises structurally for all other types.
         adt.is_unsafe_cell()
     }
+
+    fn deref_structural<'tcx>(_cx: &ConstCx<'_, 'tcx>) -> bool {
+        false
+    }
 }
 
 /// Constant containing an ADT that implements `Drop`.
@@ -131,6 +142,10 @@ impl Qualif for NeedsDrop {
     ) -> bool {
         adt.has_dtor(cx.tcx)
     }
+
+    fn deref_structural<'tcx>(_cx: &ConstCx<'_, 'tcx>) -> bool {
+        false
+    }
 }
 
 /// Constant containing an ADT that implements non-const `Drop`.
@@ -210,6 +225,10 @@ impl Qualif for NeedsNonConstDrop {
     ) -> bool {
         adt.has_non_const_dtor(cx.tcx)
     }
+
+    fn deref_structural<'tcx>(_cx: &ConstCx<'_, 'tcx>) -> bool {
+        false
+    }
 }
 
 // FIXME: Use `mir::visit::Visitor` for the `in_*` functions if/when it supports early return.
@@ -303,6 +322,11 @@ where
             return false;
         }
 
+        if matches!(elem, ProjectionElem::Deref) && !Q::deref_structural(cx) {
+            // We have to assume that this qualifies.
+            return true;
+        }
+
         place = place_base;
     }
 
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index f0f6bfff64a..903c98e8317 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -407,9 +407,9 @@ pub fn check_intrinsic_type(
             }
             sym::float_to_int_unchecked => (2, 0, vec![param(0)], param(1)),
 
-            sym::assume => (0, 0, vec![tcx.types.bool], Ty::new_unit(tcx)),
-            sym::likely => (0, 0, vec![tcx.types.bool], tcx.types.bool),
-            sym::unlikely => (0, 0, vec![tcx.types.bool], tcx.types.bool),
+            sym::assume => (0, 1, vec![tcx.types.bool], Ty::new_unit(tcx)),
+            sym::likely => (0, 1, vec![tcx.types.bool], tcx.types.bool),
+            sym::unlikely => (0, 1, vec![tcx.types.bool], tcx.types.bool),
 
             sym::read_via_copy => (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)),
             sym::write_via_move => {
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index 287cb880908..325a0ee9a18 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -14,6 +14,7 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirIdMap, LifetimeName, Node};
+use rustc_macros::extension;
 use rustc_middle::bug;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::resolve_bound_vars::*;
@@ -27,17 +28,8 @@ use std::fmt;
 
 use crate::errors;
 
-trait RegionExt {
-    fn early(param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg);
-
-    fn late(index: u32, param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg);
-
-    fn id(&self) -> Option<DefId>;
-
-    fn shifted(self, amount: u32) -> ResolvedArg;
-}
-
-impl RegionExt for ResolvedArg {
+#[extension(trait RegionExt)]
+impl ResolvedArg {
     fn early(param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg) {
         debug!("ResolvedArg::early: def_id={:?}", param.def_id);
         (param.def_id, ResolvedArg::EarlyBound(param.def_id.to_def_id()))
diff --git a/compiler/rustc_infer/src/infer/canonical/instantiate.rs b/compiler/rustc_infer/src/infer/canonical/instantiate.rs
index f6b583151fd..c8adbf7f57a 100644
--- a/compiler/rustc_infer/src/infer/canonical/instantiate.rs
+++ b/compiler/rustc_infer/src/infer/canonical/instantiate.rs
@@ -13,12 +13,16 @@ use rustc_middle::ty::{self, TyCtxt};
 
 /// FIXME(-Znext-solver): This or public because it is shared with the
 /// new trait solver implementation. We should deduplicate canonicalization.
-pub trait CanonicalExt<'tcx, V> {
+#[extension(pub trait CanonicalExt<'tcx, V>)]
+impl<'tcx, V> Canonical<'tcx, V> {
     /// Instantiate the wrapped value, replacing each canonical value
     /// with the value given in `var_values`.
     fn instantiate(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V
     where
-        V: TypeFoldable<TyCtxt<'tcx>>;
+        V: TypeFoldable<TyCtxt<'tcx>>,
+    {
+        self.instantiate_projected(tcx, var_values, |value| value.clone())
+    }
 
     /// Allows one to apply a instantiation to some subset of
     /// `self.value`. Invoke `projection_fn` with `self.value` to get
@@ -33,24 +37,6 @@ pub trait CanonicalExt<'tcx, V> {
         projection_fn: impl FnOnce(&V) -> T,
     ) -> T
     where
-        T: TypeFoldable<TyCtxt<'tcx>>;
-}
-
-impl<'tcx, V> CanonicalExt<'tcx, V> for Canonical<'tcx, V> {
-    fn instantiate(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V
-    where
-        V: TypeFoldable<TyCtxt<'tcx>>,
-    {
-        self.instantiate_projected(tcx, var_values, |value| value.clone())
-    }
-
-    fn instantiate_projected<T>(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        var_values: &CanonicalVarValues<'tcx>,
-        projection_fn: impl FnOnce(&V) -> T,
-    ) -> T
-    where
         T: TypeFoldable<TyCtxt<'tcx>>,
     {
         assert_eq!(self.variables.len(), var_values.len());
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 104bf4a5be8..8f06a5eeb5f 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -2786,19 +2786,8 @@ pub enum FailureCode {
     Error0644,
 }
 
-pub trait ObligationCauseExt<'tcx> {
-    fn as_failure_code(&self, terr: TypeError<'tcx>) -> FailureCode;
-
-    fn as_failure_code_diag(
-        &self,
-        terr: TypeError<'tcx>,
-        span: Span,
-        subdiags: Vec<TypeErrorAdditionalDiags>,
-    ) -> ObligationCauseFailureCode;
-    fn as_requirement_str(&self) -> &'static str;
-}
-
-impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> {
+#[extension(pub trait ObligationCauseExt<'tcx>)]
+impl<'tcx> ObligationCause<'tcx> {
     fn as_failure_code(&self, terr: TypeError<'tcx>) -> FailureCode {
         use self::FailureCode::*;
         use crate::traits::ObligationCauseCode::*;
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 2caf3b3cc93..243558b11a8 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -626,11 +626,8 @@ pub struct InferCtxtBuilder<'tcx> {
     next_trait_solver: bool,
 }
 
-pub trait TyCtxtInferExt<'tcx> {
-    fn infer_ctxt(self) -> InferCtxtBuilder<'tcx>;
-}
-
-impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> {
+#[extension(pub trait TyCtxtInferExt<'tcx>)]
+impl<'tcx> TyCtxt<'tcx> {
     fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
         InferCtxtBuilder {
             tcx: self,
diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs
index 64b9714c7c0..c495810858f 100644
--- a/compiler/rustc_infer/src/traits/engine.rs
+++ b/compiler/rustc_infer/src/traits/engine.rs
@@ -52,18 +52,8 @@ pub trait TraitEngine<'tcx>: 'tcx {
     ) -> Vec<PredicateObligation<'tcx>>;
 }
 
-pub trait TraitEngineExt<'tcx> {
-    fn register_predicate_obligations(
-        &mut self,
-        infcx: &InferCtxt<'tcx>,
-        obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>,
-    );
-
-    #[must_use]
-    fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>;
-}
-
-impl<'tcx, T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T {
+#[extension(pub trait TraitEngineExt<'tcx>)]
+impl<'tcx, T: ?Sized + TraitEngine<'tcx>> T {
     fn register_predicate_obligations(
         &mut self,
         infcx: &InferCtxt<'tcx>,
@@ -74,6 +64,7 @@ impl<'tcx, T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T {
         }
     }
 
+    #[must_use]
     fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
         let errors = self.select_where_possible(infcx);
         if !errors.is_empty() {
diff --git a/compiler/rustc_macros/src/extension.rs b/compiler/rustc_macros/src/extension.rs
new file mode 100644
index 00000000000..5377bbdfeab
--- /dev/null
+++ b/compiler/rustc_macros/src/extension.rs
@@ -0,0 +1,154 @@
+use proc_macro2::Ident;
+use quote::quote;
+use syn::parse::{Parse, ParseStream};
+use syn::punctuated::Punctuated;
+use syn::spanned::Spanned;
+use syn::{
+    braced, parse_macro_input, Attribute, Generics, ImplItem, Pat, PatIdent, Path, Signature,
+    Token, TraitItem, TraitItemConst, TraitItemFn, TraitItemMacro, TraitItemType, Type, Visibility,
+};
+
+pub(crate) fn extension(
+    attr: proc_macro::TokenStream,
+    input: proc_macro::TokenStream,
+) -> proc_macro::TokenStream {
+    let ExtensionAttr { vis, trait_ } = parse_macro_input!(attr as ExtensionAttr);
+    let Impl { attrs, generics, self_ty, items } = parse_macro_input!(input as Impl);
+    let headers: Vec<_> = items
+        .iter()
+        .map(|item| match item {
+            ImplItem::Fn(f) => TraitItem::Fn(TraitItemFn {
+                attrs: scrub_attrs(&f.attrs),
+                sig: scrub_header(f.sig.clone()),
+                default: None,
+                semi_token: Some(Token![;](f.block.span())),
+            }),
+            ImplItem::Const(ct) => TraitItem::Const(TraitItemConst {
+                attrs: scrub_attrs(&ct.attrs),
+                const_token: ct.const_token,
+                ident: ct.ident.clone(),
+                generics: ct.generics.clone(),
+                colon_token: ct.colon_token,
+                ty: ct.ty.clone(),
+                default: None,
+                semi_token: ct.semi_token,
+            }),
+            ImplItem::Type(ty) => TraitItem::Type(TraitItemType {
+                attrs: scrub_attrs(&ty.attrs),
+                type_token: ty.type_token,
+                ident: ty.ident.clone(),
+                generics: ty.generics.clone(),
+                colon_token: None,
+                bounds: Punctuated::new(),
+                default: None,
+                semi_token: ty.semi_token,
+            }),
+            ImplItem::Macro(mac) => TraitItem::Macro(TraitItemMacro {
+                attrs: scrub_attrs(&mac.attrs),
+                mac: mac.mac.clone(),
+                semi_token: mac.semi_token,
+            }),
+            ImplItem::Verbatim(stream) => TraitItem::Verbatim(stream.clone()),
+            _ => unimplemented!(),
+        })
+        .collect();
+
+    quote! {
+        #(#attrs)*
+        #vis trait #trait_ {
+            #(#headers)*
+        }
+
+        impl #generics #trait_ for #self_ty {
+            #(#items)*
+        }
+    }
+    .into()
+}
+
+/// Only keep `#[doc]` attrs.
+fn scrub_attrs(attrs: &[Attribute]) -> Vec<Attribute> {
+    attrs
+        .into_iter()
+        .cloned()
+        .filter(|attr| {
+            let ident = &attr.path().segments[0].ident;
+            ident == "doc" || ident == "must_use"
+        })
+        .collect()
+}
+
+/// Scrub arguments so that they're valid for trait signatures.
+fn scrub_header(mut sig: Signature) -> Signature {
+    for (idx, input) in sig.inputs.iter_mut().enumerate() {
+        match input {
+            syn::FnArg::Receiver(rcvr) => {
+                // `mut self` -> `self`
+                if rcvr.reference.is_none() {
+                    rcvr.mutability.take();
+                }
+            }
+            syn::FnArg::Typed(arg) => match &mut *arg.pat {
+                Pat::Ident(arg) => {
+                    // `ref mut ident @ pat` -> `ident`
+                    arg.by_ref.take();
+                    arg.mutability.take();
+                    arg.subpat.take();
+                }
+                _ => {
+                    // `pat` -> `__arg0`
+                    arg.pat = Box::new(
+                        PatIdent {
+                            attrs: vec![],
+                            by_ref: None,
+                            mutability: None,
+                            ident: Ident::new(&format!("__arg{idx}"), arg.pat.span()),
+                            subpat: None,
+                        }
+                        .into(),
+                    )
+                }
+            },
+        }
+    }
+    sig
+}
+
+struct ExtensionAttr {
+    vis: Visibility,
+    trait_: Path,
+}
+
+impl Parse for ExtensionAttr {
+    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+        let vis = input.parse()?;
+        let _: Token![trait] = input.parse()?;
+        let trait_ = input.parse()?;
+        Ok(ExtensionAttr { vis, trait_ })
+    }
+}
+
+struct Impl {
+    attrs: Vec<Attribute>,
+    generics: Generics,
+    self_ty: Type,
+    items: Vec<ImplItem>,
+}
+
+impl Parse for Impl {
+    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+        let attrs = input.call(Attribute::parse_outer)?;
+        let _: Token![impl] = input.parse()?;
+        let generics = input.parse()?;
+        let self_ty = input.parse()?;
+
+        let content;
+        let _brace_token = braced!(content in input);
+        let mut items = Vec::new();
+        while !content.is_empty() {
+            items.push(content.parse()?);
+        }
+
+        Ok(Impl { attrs, generics, self_ty, items })
+    }
+}
diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs
index af65c908ee6..619f93c8a53 100644
--- a/compiler/rustc_macros/src/lib.rs
+++ b/compiler/rustc_macros/src/lib.rs
@@ -14,6 +14,7 @@ use proc_macro::TokenStream;
 
 mod current_version;
 mod diagnostics;
+mod extension;
 mod hash_stable;
 mod lift;
 mod query;
@@ -40,6 +41,11 @@ pub fn symbols(input: TokenStream) -> TokenStream {
     symbols::symbols(input.into()).into()
 }
 
+#[proc_macro_attribute]
+pub fn extension(attr: TokenStream, input: TokenStream) -> TokenStream {
+    extension::extension(attr, input)
+}
+
 decl_derive!([HashStable, attributes(stable_hasher)] => hash_stable::hash_stable_derive);
 decl_derive!(
     [HashStable_Generic, attributes(stable_hasher)] =>
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 2b34f5daaf6..c1e33fe114f 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -23,20 +23,8 @@ use std::fmt;
 use std::num::NonZero;
 use std::ops::Bound;
 
-pub trait IntegerExt {
-    fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>, signed: bool) -> Ty<'tcx>;
-    fn from_int_ty<C: HasDataLayout>(cx: &C, ity: ty::IntTy) -> Integer;
-    fn from_uint_ty<C: HasDataLayout>(cx: &C, uty: ty::UintTy) -> Integer;
-    fn repr_discr<'tcx>(
-        tcx: TyCtxt<'tcx>,
-        ty: Ty<'tcx>,
-        repr: &ReprOptions,
-        min: i128,
-        max: i128,
-    ) -> (Integer, bool);
-}
-
-impl IntegerExt for Integer {
+#[extension(pub trait IntegerExt)]
+impl Integer {
     #[inline]
     fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>, signed: bool) -> Ty<'tcx> {
         match (*self, signed) {
@@ -123,12 +111,8 @@ impl IntegerExt for Integer {
     }
 }
 
-pub trait PrimitiveExt {
-    fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>;
-    fn to_int_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>;
-}
-
-impl PrimitiveExt for Primitive {
+#[extension(pub trait PrimitiveExt)]
+impl Primitive {
     #[inline]
     fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
         match *self {
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 2addfa37f8b..3f539945841 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -96,13 +96,8 @@ impl<'tcx> Discr<'tcx> {
     }
 }
 
-pub trait IntTypeExt {
-    fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>;
-    fn disr_incr<'tcx>(&self, tcx: TyCtxt<'tcx>, val: Option<Discr<'tcx>>) -> Option<Discr<'tcx>>;
-    fn initial_discriminant<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Discr<'tcx>;
-}
-
-impl IntTypeExt for IntegerType {
+#[extension(pub trait IntTypeExt)]
+impl IntegerType {
     fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
         match self {
             IntegerType::Pointer(true) => tcx.types.isize,
diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs
index f8e6905282c..6212155a8fe 100644
--- a/compiler/rustc_mir_transform/src/const_prop_lint.rs
+++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs
@@ -32,11 +32,6 @@ impl<'tcx> MirLint<'tcx> for ConstPropLint {
             return;
         }
 
-        // will be evaluated by miri and produce its errors there
-        if body.source.promoted.is_some() {
-            return;
-        }
-
         let def_id = body.source.def_id().expect_local();
         let def_kind = tcx.def_kind(def_id);
         let is_fn_like = def_kind.is_fn_like();
diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
index 9517ede288f..2db358379fe 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
@@ -132,18 +132,23 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>(
     bcb_data.basic_blocks.iter().flat_map(move |&bb| {
         let data = &mir_body[bb];
 
+        let unexpand = move |expn_span| {
+            unexpand_into_body_span_with_visible_macro(expn_span, body_span)
+                // Discard any spans that fill the entire body, because they tend
+                // to represent compiler-inserted code, e.g. implicitly returning `()`.
+                .filter(|(span, _)| !span.source_equal(body_span))
+        };
+
         let statement_spans = data.statements.iter().filter_map(move |statement| {
             let expn_span = filtered_statement_span(statement)?;
-            let (span, visible_macro) =
-                unexpand_into_body_span_with_visible_macro(expn_span, body_span)?;
+            let (span, visible_macro) = unexpand(expn_span)?;
 
             Some(SpanFromMir::new(span, visible_macro, bcb, is_closure_like(statement)))
         });
 
         let terminator_span = Some(data.terminator()).into_iter().filter_map(move |terminator| {
             let expn_span = filtered_terminator_span(terminator)?;
-            let (span, visible_macro) =
-                unexpand_into_body_span_with_visible_macro(expn_span, body_span)?;
+            let (span, visible_macro) = unexpand(expn_span)?;
 
             Some(SpanFromMir::new(span, visible_macro, bcb, false))
         });
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index ef4a0f52f9e..f694dd00703 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -17,49 +17,8 @@ use std::fmt::Debug;
 
 pub use rustc_infer::infer::*;
 
-pub trait InferCtxtExt<'tcx> {
-    fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool;
-
-    fn type_is_sized_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool;
-
-    /// Check whether a `ty` implements given trait(trait_def_id) without side-effects.
-    ///
-    /// The inputs are:
-    ///
-    /// - the def-id of the trait
-    /// - the type parameters of the trait, including the self-type
-    /// - the parameter environment
-    ///
-    /// Invokes `evaluate_obligation`, so in the event that evaluating
-    /// `Ty: Trait` causes overflow, EvaluatedToErrStackDependent
-    /// (or EvaluatedToAmbigStackDependent) will be returned.
-    fn type_implements_trait(
-        &self,
-        trait_def_id: DefId,
-        params: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
-        param_env: ty::ParamEnv<'tcx>,
-    ) -> traits::EvaluationResult;
-
-    /// Returns `Some` if a type implements a trait shallowly, without side-effects,
-    /// along with any errors that would have been reported upon further obligation
-    /// processing.
-    ///
-    /// - If this returns `Some([])`, then the trait holds modulo regions.
-    /// - If this returns `Some([errors..])`, then the trait has an impl for
-    /// the self type, but some nested obligations do not hold.
-    /// - If this returns `None`, no implementation that applies could be found.
-    ///
-    /// FIXME(-Znext-solver): Due to the recursive nature of the new solver,
-    /// this will probably only ever return `Some([])` or `None`.
-    fn type_implements_trait_shallow(
-        &self,
-        trait_def_id: DefId,
-        ty: Ty<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-    ) -> Option<Vec<traits::FulfillmentError<'tcx>>>;
-}
-
-impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
+#[extension(pub trait InferCtxtExt<'tcx>)]
+impl<'tcx> InferCtxt<'tcx> {
     fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
         let ty = self.resolve_vars_if_possible(ty);
 
@@ -81,6 +40,17 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
         traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item)
     }
 
+    /// Check whether a `ty` implements given trait(trait_def_id) without side-effects.
+    ///
+    /// The inputs are:
+    ///
+    /// - the def-id of the trait
+    /// - the type parameters of the trait, including the self-type
+    /// - the parameter environment
+    ///
+    /// Invokes `evaluate_obligation`, so in the event that evaluating
+    /// `Ty: Trait` causes overflow, EvaluatedToErrStackDependent
+    /// (or EvaluatedToAmbigStackDependent) will be returned.
     #[instrument(level = "debug", skip(self, params), ret)]
     fn type_implements_trait(
         &self,
@@ -99,6 +69,17 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
         self.evaluate_obligation(&obligation).unwrap_or(traits::EvaluationResult::EvaluatedToErr)
     }
 
+    /// Returns `Some` if a type implements a trait shallowly, without side-effects,
+    /// along with any errors that would have been reported upon further obligation
+    /// processing.
+    ///
+    /// - If this returns `Some([])`, then the trait holds modulo regions.
+    /// - If this returns `Some([errors..])`, then the trait has an impl for
+    /// the self type, but some nested obligations do not hold.
+    /// - If this returns `None`, no implementation that applies could be found.
+    ///
+    /// FIXME(-Znext-solver): Due to the recursive nature of the new solver,
+    /// this will probably only ever return `Some([])` or `None`.
     fn type_implements_trait_shallow(
         &self,
         trait_def_id: DefId,
@@ -124,19 +105,8 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
     }
 }
 
-pub trait InferCtxtBuilderExt<'tcx> {
-    fn enter_canonical_trait_query<K, R>(
-        self,
-        canonical_key: &Canonical<'tcx, K>,
-        operation: impl FnOnce(&ObligationCtxt<'_, 'tcx>, K) -> Result<R, NoSolution>,
-    ) -> Result<CanonicalQueryResponse<'tcx, R>, NoSolution>
-    where
-        K: TypeFoldable<TyCtxt<'tcx>>,
-        R: Debug + TypeFoldable<TyCtxt<'tcx>>,
-        Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>;
-}
-
-impl<'tcx> InferCtxtBuilderExt<'tcx> for InferCtxtBuilder<'tcx> {
+#[extension(pub trait InferCtxtBuilderExt<'tcx>)]
+impl<'tcx> InferCtxtBuilder<'tcx> {
     /// The "main method" for a canonicalized trait query. Given the
     /// canonical key `canonical_key`, this method will create a new
     /// inference context, instantiate the key, and run your operation
diff --git a/compiler/rustc_trait_selection/src/regions.rs b/compiler/rustc_trait_selection/src/regions.rs
index 756db7cc206..222d0b4d5e7 100644
--- a/compiler/rustc_trait_selection/src/regions.rs
+++ b/compiler/rustc_trait_selection/src/regions.rs
@@ -3,7 +3,8 @@ use rustc_infer::infer::{InferCtxt, RegionResolutionError};
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::traits::ObligationCause;
 
-pub trait InferCtxtRegionExt<'tcx> {
+#[extension(pub trait InferCtxtRegionExt<'tcx>)]
+impl<'tcx> InferCtxt<'tcx> {
     /// Resolve regions, using the deep normalizer to normalize any type-outlives
     /// obligations in the process. This is in `rustc_trait_selection` because
     /// we need to normalize.
@@ -13,13 +14,6 @@ pub trait InferCtxtRegionExt<'tcx> {
     fn resolve_regions(
         &self,
         outlives_env: &OutlivesEnvironment<'tcx>,
-    ) -> Vec<RegionResolutionError<'tcx>>;
-}
-
-impl<'tcx> InferCtxtRegionExt<'tcx> for InferCtxt<'tcx> {
-    fn resolve_regions(
-        &self,
-        outlives_env: &OutlivesEnvironment<'tcx>,
     ) -> Vec<RegionResolutionError<'tcx>> {
         self.resolve_regions_with_normalize(outlives_env, |ty, origin| {
             let ty = self.resolve_vars_if_possible(ty);
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 803379af005..5c1e8bf616f 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
@@ -131,22 +131,12 @@ pub enum GenerateProofTree {
     Never,
 }
 
-pub trait InferCtxtEvalExt<'tcx> {
+#[extension(pub trait InferCtxtEvalExt<'tcx>)]
+impl<'tcx> InferCtxt<'tcx> {
     /// Evaluates a goal from **outside** of the trait solver.
     ///
     /// Using this while inside of the solver is wrong as it uses a new
     /// search graph which would break cycle detection.
-    fn evaluate_root_goal(
-        &self,
-        goal: Goal<'tcx, ty::Predicate<'tcx>>,
-        generate_proof_tree: GenerateProofTree,
-    ) -> (
-        Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution>,
-        Option<inspect::GoalEvaluation<'tcx>>,
-    );
-}
-
-impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
     #[instrument(level = "debug", skip(self))]
     fn evaluate_root_goal(
         &self,
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
index eab59624436..7196a5af259 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
@@ -17,14 +17,8 @@ use crate::solve::inspect::ProofTreeBuilder;
 use crate::traits::StructurallyNormalizeExt;
 use crate::traits::TraitEngineExt;
 
-pub trait InferCtxtSelectExt<'tcx> {
-    fn select_in_new_trait_solver(
-        &self,
-        obligation: &PolyTraitObligation<'tcx>,
-    ) -> SelectionResult<'tcx, Selection<'tcx>>;
-}
-
-impl<'tcx> InferCtxtSelectExt<'tcx> for InferCtxt<'tcx> {
+#[extension(pub trait InferCtxtSelectExt<'tcx>)]
+impl<'tcx> InferCtxt<'tcx> {
     fn select_in_new_trait_solver(
         &self,
         obligation: &PolyTraitObligation<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
index f33d0f397ce..47f207e1d75 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
@@ -216,15 +216,8 @@ pub trait ProofTreeVisitor<'tcx> {
     fn visit_goal(&mut self, goal: &InspectGoal<'_, 'tcx>) -> ControlFlow<Self::BreakTy>;
 }
 
-pub trait ProofTreeInferCtxtExt<'tcx> {
-    fn visit_proof_tree<V: ProofTreeVisitor<'tcx>>(
-        &self,
-        goal: Goal<'tcx, ty::Predicate<'tcx>>,
-        visitor: &mut V,
-    ) -> ControlFlow<V::BreakTy>;
-}
-
-impl<'tcx> ProofTreeInferCtxtExt<'tcx> for InferCtxt<'tcx> {
+#[extension(pub trait ProofTreeInferCtxtExt<'tcx>)]
+impl<'tcx> InferCtxt<'tcx> {
     fn visit_proof_tree<V: ProofTreeVisitor<'tcx>>(
         &self,
         goal: Goal<'tcx, ty::Predicate<'tcx>>,
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index 94a3cef8ad1..8b163d47d34 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -61,11 +61,8 @@ enum GoalEvaluationKind {
     Nested { is_normalizes_to_hack: IsNormalizesToHack },
 }
 
-trait CanonicalResponseExt {
-    fn has_no_inference_or_external_constraints(&self) -> bool;
-}
-
-impl<'tcx> CanonicalResponseExt for Canonical<'tcx, Response<'tcx>> {
+#[extension(trait CanonicalResponseExt)]
+impl<'tcx> Canonical<'tcx, Response<'tcx>> {
     fn has_no_inference_or_external_constraints(&self) -> bool {
         self.value.external_constraints.region_constraints.is_empty()
             && self.value.var_values.is_identity()
diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs
index caf950037fd..1aaadf6cf04 100644
--- a/compiler/rustc_trait_selection/src/traits/engine.rs
+++ b/compiler/rustc_trait_selection/src/traits/engine.rs
@@ -27,11 +27,8 @@ use rustc_middle::ty::TypeFoldable;
 use rustc_middle::ty::Variance;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 
-pub trait TraitEngineExt<'tcx> {
-    fn new(infcx: &InferCtxt<'tcx>) -> Box<Self>;
-}
-
-impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> {
+#[extension(pub trait TraitEngineExt<'tcx>)]
+impl<'tcx> dyn TraitEngine<'tcx> {
     fn new(infcx: &InferCtxt<'tcx>) -> Box<Self> {
         if infcx.next_trait_solver() {
             Box::new(NextFulfillmentCtxt::new(infcx))
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs
index 15d064d4036..4788ecbe3e2 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs
@@ -11,38 +11,8 @@ use super::ArgKind;
 
 pub use rustc_infer::traits::error_reporting::*;
 
-pub trait InferCtxtExt<'tcx> {
-    /// Given some node representing a fn-like thing in the HIR map,
-    /// returns a span and `ArgKind` information that describes the
-    /// arguments it expects. This can be supplied to
-    /// `report_arg_count_mismatch`.
-    fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Option<Span>, Vec<ArgKind>)>;
-
-    /// Reports an error when the number of arguments needed by a
-    /// trait match doesn't match the number that the expression
-    /// provides.
-    fn report_arg_count_mismatch(
-        &self,
-        span: Span,
-        found_span: Option<Span>,
-        expected_args: Vec<ArgKind>,
-        found_args: Vec<ArgKind>,
-        is_closure: bool,
-        closure_pipe_span: Option<Span>,
-    ) -> DiagnosticBuilder<'tcx>;
-
-    /// Checks if the type implements one of `Fn`, `FnMut`, or `FnOnce`
-    /// in that order, and returns the generic type corresponding to the
-    /// argument of that trait (corresponding to the closure arguments).
-    fn type_implements_fn_trait(
-        &self,
-        param_env: ty::ParamEnv<'tcx>,
-        ty: ty::Binder<'tcx, Ty<'tcx>>,
-        polarity: ty::ImplPolarity,
-    ) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()>;
-}
-
-impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
+#[extension(pub trait InferCtxtExt<'tcx>)]
+impl<'tcx> InferCtxt<'tcx> {
     /// Given some node representing a fn-like thing in the HIR map,
     /// returns a span and `ArgKind` information that describes the
     /// arguments it expects. This can be supplied to
@@ -229,6 +199,9 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
         err
     }
 
+    /// Checks if the type implements one of `Fn`, `FnMut`, or `FnOnce`
+    /// in that order, and returns the generic type corresponding to the
+    /// argument of that trait (corresponding to the closure arguments).
     fn type_implements_fn_trait(
         &self,
         param_env: ty::ParamEnv<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
index f0773fd1671..4ba2da95fb3 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
@@ -23,24 +23,6 @@ use crate::errors::{
 
 use crate::traits::error_reporting::type_err_ctxt_ext::InferCtxtPrivExt;
 
-pub trait TypeErrCtxtExt<'tcx> {
-    /*private*/
-    fn impl_similar_to(
-        &self,
-        trait_ref: ty::PolyTraitRef<'tcx>,
-        obligation: &PredicateObligation<'tcx>,
-    ) -> Option<(DefId, GenericArgsRef<'tcx>)>;
-
-    /*private*/
-    fn describe_enclosure(&self, def_id: LocalDefId) -> Option<&'static str>;
-
-    fn on_unimplemented_note(
-        &self,
-        trait_ref: ty::PolyTraitRef<'tcx>,
-        obligation: &PredicateObligation<'tcx>,
-    ) -> OnUnimplementedNote;
-}
-
 /// The symbols which are always allowed in a format string
 static ALLOWED_FORMAT_SYMBOLS: &[Symbol] = &[
     kw::SelfUpper,
@@ -56,7 +38,8 @@ static ALLOWED_FORMAT_SYMBOLS: &[Symbol] = &[
     sym::Trait,
 ];
 
-impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
+#[extension(pub trait TypeErrCtxtExt<'tcx>)]
+impl<'tcx> TypeErrCtxt<'_, 'tcx> {
     fn impl_similar_to(
         &self,
         trait_ref: ty::PolyTraitRef<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 335e6ff2822..7de13bf0c02 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -106,279 +106,6 @@ impl<'tcx, 'a> CoroutineData<'tcx, 'a> {
     }
 }
 
-// This trait is public to expose the diagnostics methods to clippy.
-pub trait TypeErrCtxtExt<'tcx> {
-    fn suggest_restricting_param_bound(
-        &self,
-        err: &mut Diagnostic,
-        trait_pred: ty::PolyTraitPredicate<'tcx>,
-        associated_item: Option<(&'static str, Ty<'tcx>)>,
-        body_id: LocalDefId,
-    );
-
-    fn suggest_dereferences(
-        &self,
-        obligation: &PredicateObligation<'tcx>,
-        err: &mut Diagnostic,
-        trait_pred: ty::PolyTraitPredicate<'tcx>,
-    ) -> bool;
-
-    fn get_closure_name(
-        &self,
-        def_id: DefId,
-        err: &mut Diagnostic,
-        msg: Cow<'static, str>,
-    ) -> Option<Symbol>;
-
-    fn suggest_fn_call(
-        &self,
-        obligation: &PredicateObligation<'tcx>,
-        err: &mut Diagnostic,
-        trait_pred: ty::PolyTraitPredicate<'tcx>,
-    ) -> bool;
-
-    fn check_for_binding_assigned_block_without_tail_expression(
-        &self,
-        obligation: &PredicateObligation<'tcx>,
-        err: &mut Diagnostic,
-        trait_pred: ty::PolyTraitPredicate<'tcx>,
-    );
-
-    fn suggest_add_clone_to_arg(
-        &self,
-        obligation: &PredicateObligation<'tcx>,
-        err: &mut Diagnostic,
-        trait_pred: ty::PolyTraitPredicate<'tcx>,
-    ) -> bool;
-
-    fn extract_callable_info(
-        &self,
-        body_id: LocalDefId,
-        param_env: ty::ParamEnv<'tcx>,
-        found: Ty<'tcx>,
-    ) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)>;
-
-    fn suggest_add_reference_to_arg(
-        &self,
-        obligation: &PredicateObligation<'tcx>,
-        err: &mut Diagnostic,
-        trait_pred: ty::PolyTraitPredicate<'tcx>,
-        has_custom_message: bool,
-    ) -> bool;
-
-    fn suggest_borrowing_for_object_cast(
-        &self,
-        err: &mut Diagnostic,
-        obligation: &PredicateObligation<'tcx>,
-        self_ty: Ty<'tcx>,
-        object_ty: Ty<'tcx>,
-    );
-
-    fn suggest_remove_reference(
-        &self,
-        obligation: &PredicateObligation<'tcx>,
-        err: &mut Diagnostic,
-        trait_pred: ty::PolyTraitPredicate<'tcx>,
-    ) -> bool;
-
-    fn suggest_remove_await(&self, obligation: &PredicateObligation<'tcx>, err: &mut Diagnostic);
-
-    fn suggest_change_mut(
-        &self,
-        obligation: &PredicateObligation<'tcx>,
-        err: &mut Diagnostic,
-        trait_pred: ty::PolyTraitPredicate<'tcx>,
-    );
-
-    fn suggest_semicolon_removal(
-        &self,
-        obligation: &PredicateObligation<'tcx>,
-        err: &mut Diagnostic,
-        span: Span,
-        trait_pred: ty::PolyTraitPredicate<'tcx>,
-    ) -> bool;
-
-    fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option<Span>;
-
-    fn suggest_impl_trait(
-        &self,
-        err: &mut Diagnostic,
-        obligation: &PredicateObligation<'tcx>,
-        trait_pred: ty::PolyTraitPredicate<'tcx>,
-    ) -> bool;
-
-    fn point_at_returns_when_relevant(
-        &self,
-        err: &mut DiagnosticBuilder<'tcx>,
-        obligation: &PredicateObligation<'tcx>,
-    );
-
-    fn report_closure_arg_mismatch(
-        &self,
-        span: Span,
-        found_span: Option<Span>,
-        found: ty::PolyTraitRef<'tcx>,
-        expected: ty::PolyTraitRef<'tcx>,
-        cause: &ObligationCauseCode<'tcx>,
-        found_node: Option<Node<'_>>,
-        param_env: ty::ParamEnv<'tcx>,
-    ) -> DiagnosticBuilder<'tcx>;
-
-    fn note_conflicting_fn_args(
-        &self,
-        err: &mut Diagnostic,
-        cause: &ObligationCauseCode<'tcx>,
-        expected: Ty<'tcx>,
-        found: Ty<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-    );
-
-    fn note_conflicting_closure_bounds(
-        &self,
-        cause: &ObligationCauseCode<'tcx>,
-        err: &mut DiagnosticBuilder<'tcx>,
-    );
-
-    fn suggest_fully_qualified_path(
-        &self,
-        err: &mut Diagnostic,
-        item_def_id: DefId,
-        span: Span,
-        trait_ref: DefId,
-    );
-
-    fn maybe_note_obligation_cause_for_async_await(
-        &self,
-        err: &mut Diagnostic,
-        obligation: &PredicateObligation<'tcx>,
-    ) -> bool;
-
-    fn note_obligation_cause_for_async_await(
-        &self,
-        err: &mut Diagnostic,
-        interior_or_upvar_span: CoroutineInteriorOrUpvar,
-        is_async: bool,
-        outer_coroutine: Option<DefId>,
-        trait_pred: ty::TraitPredicate<'tcx>,
-        target_ty: Ty<'tcx>,
-        obligation: &PredicateObligation<'tcx>,
-        next_code: Option<&ObligationCauseCode<'tcx>>,
-    );
-
-    fn note_obligation_cause_code<T>(
-        &self,
-        body_id: LocalDefId,
-        err: &mut Diagnostic,
-        predicate: T,
-        param_env: ty::ParamEnv<'tcx>,
-        cause_code: &ObligationCauseCode<'tcx>,
-        obligated_types: &mut Vec<Ty<'tcx>>,
-        seen_requirements: &mut FxHashSet<DefId>,
-    ) where
-        T: ToPredicate<'tcx>;
-
-    /// Suggest to await before try: future? => future.await?
-    fn suggest_await_before_try(
-        &self,
-        err: &mut Diagnostic,
-        obligation: &PredicateObligation<'tcx>,
-        trait_pred: ty::PolyTraitPredicate<'tcx>,
-        span: Span,
-    );
-
-    fn suggest_floating_point_literal(
-        &self,
-        obligation: &PredicateObligation<'tcx>,
-        err: &mut Diagnostic,
-        trait_ref: &ty::PolyTraitRef<'tcx>,
-    );
-
-    fn suggest_derive(
-        &self,
-        obligation: &PredicateObligation<'tcx>,
-        err: &mut Diagnostic,
-        trait_pred: ty::PolyTraitPredicate<'tcx>,
-    );
-
-    fn suggest_dereferencing_index(
-        &self,
-        obligation: &PredicateObligation<'tcx>,
-        err: &mut Diagnostic,
-        trait_pred: ty::PolyTraitPredicate<'tcx>,
-    );
-
-    fn suggest_option_method_if_applicable(
-        &self,
-        failed_pred: ty::Predicate<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-        err: &mut Diagnostic,
-        expr: &hir::Expr<'_>,
-    );
-
-    fn note_function_argument_obligation(
-        &self,
-        body_id: LocalDefId,
-        err: &mut Diagnostic,
-        arg_hir_id: HirId,
-        parent_code: &ObligationCauseCode<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-        predicate: ty::Predicate<'tcx>,
-        call_hir_id: HirId,
-    );
-
-    fn look_for_iterator_item_mistakes(
-        &self,
-        assocs_in_this_method: &[Option<(Span, (DefId, Ty<'tcx>))>],
-        typeck_results: &TypeckResults<'tcx>,
-        type_diffs: &[TypeError<'tcx>],
-        param_env: ty::ParamEnv<'tcx>,
-        path_segment: &hir::PathSegment<'_>,
-        args: &[hir::Expr<'_>],
-        err: &mut Diagnostic,
-    );
-
-    fn point_at_chain(
-        &self,
-        expr: &hir::Expr<'_>,
-        typeck_results: &TypeckResults<'tcx>,
-        type_diffs: Vec<TypeError<'tcx>>,
-        param_env: ty::ParamEnv<'tcx>,
-        err: &mut Diagnostic,
-    );
-
-    fn probe_assoc_types_at_expr(
-        &self,
-        type_diffs: &[TypeError<'tcx>],
-        span: Span,
-        prev_ty: Ty<'tcx>,
-        body_id: hir::HirId,
-        param_env: ty::ParamEnv<'tcx>,
-    ) -> Vec<Option<(Span, (DefId, Ty<'tcx>))>>;
-
-    fn suggest_convert_to_slice(
-        &self,
-        err: &mut Diagnostic,
-        obligation: &PredicateObligation<'tcx>,
-        trait_ref: ty::PolyTraitRef<'tcx>,
-        candidate_impls: &[ImplCandidate<'tcx>],
-        span: Span,
-    );
-
-    fn explain_hrtb_projection(
-        &self,
-        diag: &mut Diagnostic,
-        pred: ty::PolyTraitPredicate<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-        cause: &ObligationCause<'tcx>,
-    );
-
-    fn suggest_desugaring_async_fn_in_trait(
-        &self,
-        err: &mut Diagnostic,
-        trait_ref: ty::PolyTraitRef<'tcx>,
-    );
-}
-
 fn predicate_constraint(generics: &hir::Generics<'_>, pred: ty::Predicate<'_>) -> (Span, String) {
     (
         generics.tail_span_for_predicate_suggestion(),
@@ -509,7 +236,8 @@ pub fn suggest_restriction<'tcx>(
     }
 }
 
-impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
+#[extension(pub trait TypeErrCtxtExt<'tcx>)]
+impl<'tcx> TypeErrCtxt<'_, 'tcx> {
     fn suggest_restricting_param_bound(
         &self,
         err: &mut Diagnostic,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
index 661a444d049..67bd18d7404 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
@@ -57,78 +57,8 @@ use super::{
 
 pub use rustc_infer::traits::error_reporting::*;
 
-pub trait TypeErrCtxtExt<'tcx> {
-    fn build_overflow_error<T>(
-        &self,
-        predicate: &T,
-        span: Span,
-        suggest_increasing_limit: bool,
-    ) -> DiagnosticBuilder<'tcx>
-    where
-        T: fmt::Display + TypeFoldable<TyCtxt<'tcx>> + Print<'tcx, FmtPrinter<'tcx, 'tcx>>;
-
-    fn report_overflow_error<T>(
-        &self,
-        predicate: &T,
-        span: Span,
-        suggest_increasing_limit: bool,
-        mutate: impl FnOnce(&mut Diagnostic),
-    ) -> !
-    where
-        T: fmt::Display + TypeFoldable<TyCtxt<'tcx>> + Print<'tcx, FmtPrinter<'tcx, 'tcx>>;
-
-    fn report_overflow_no_abort(&self, obligation: PredicateObligation<'tcx>) -> ErrorGuaranteed;
-
-    fn report_fulfillment_errors(&self, errors: Vec<FulfillmentError<'tcx>>) -> ErrorGuaranteed;
-
-    fn report_overflow_obligation<T>(
-        &self,
-        obligation: &Obligation<'tcx, T>,
-        suggest_increasing_limit: bool,
-    ) -> !
-    where
-        T: ToPredicate<'tcx> + Clone;
-
-    fn suggest_new_overflow_limit(&self, err: &mut Diagnostic);
-
-    fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> !;
-
-    /// The `root_obligation` parameter should be the `root_obligation` field
-    /// from a `FulfillmentError`. If no `FulfillmentError` is available,
-    /// then it should be the same as `obligation`.
-    fn report_selection_error(
-        &self,
-        obligation: PredicateObligation<'tcx>,
-        root_obligation: &PredicateObligation<'tcx>,
-        error: &SelectionError<'tcx>,
-    ) -> ErrorGuaranteed;
-
-    fn emit_specialized_closure_kind_error(
-        &self,
-        obligation: &PredicateObligation<'tcx>,
-        trait_ref: ty::PolyTraitRef<'tcx>,
-    ) -> Option<ErrorGuaranteed>;
-
-    fn fn_arg_obligation(
-        &self,
-        obligation: &PredicateObligation<'tcx>,
-    ) -> Result<(), ErrorGuaranteed>;
-
-    fn try_conversion_context(
-        &self,
-        obligation: &PredicateObligation<'tcx>,
-        trait_ref: ty::TraitRef<'tcx>,
-        err: &mut Diagnostic,
-    ) -> bool;
-
-    fn report_const_param_not_wf(
-        &self,
-        ty: Ty<'tcx>,
-        obligation: &PredicateObligation<'tcx>,
-    ) -> DiagnosticBuilder<'tcx>;
-}
-
-impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
+#[extension(pub trait TypeErrCtxtExt<'tcx>)]
+impl<'tcx> TypeErrCtxt<'_, 'tcx> {
     fn report_fulfillment_errors(
         &self,
         mut errors: Vec<FulfillmentError<'tcx>>,
@@ -382,6 +312,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         err.emit()
     }
 
+    /// The `root_obligation` parameter should be the `root_obligation` field
+    /// from a `FulfillmentError`. If no `FulfillmentError` is available,
+    /// then it should be the same as `obligation`.
     fn report_selection_error(
         &self,
         mut obligation: PredicateObligation<'tcx>,
@@ -1393,209 +1326,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
     }
 }
 
-pub(super) trait InferCtxtPrivExt<'tcx> {
-    // returns if `cond` not occurring implies that `error` does not occur - i.e., that
-    // `error` occurring implies that `cond` occurs.
-    fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool;
-
-    fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) -> ErrorGuaranteed;
-
-    fn report_projection_error(
-        &self,
-        obligation: &PredicateObligation<'tcx>,
-        error: &MismatchedProjectionTypes<'tcx>,
-    ) -> ErrorGuaranteed;
-
-    fn maybe_detailed_projection_msg(
-        &self,
-        pred: ty::ProjectionPredicate<'tcx>,
-        normalized_ty: ty::Term<'tcx>,
-        expected_ty: ty::Term<'tcx>,
-    ) -> Option<String>;
-
-    fn fuzzy_match_tys(
-        &self,
-        a: Ty<'tcx>,
-        b: Ty<'tcx>,
-        ignoring_lifetimes: bool,
-    ) -> Option<CandidateSimilarity>;
-
-    fn describe_closure(&self, kind: hir::ClosureKind) -> &'static str;
-
-    fn find_similar_impl_candidates(
-        &self,
-        trait_pred: ty::PolyTraitPredicate<'tcx>,
-    ) -> Vec<ImplCandidate<'tcx>>;
-
-    fn report_similar_impl_candidates(
-        &self,
-        impl_candidates: &[ImplCandidate<'tcx>],
-        trait_ref: ty::PolyTraitRef<'tcx>,
-        body_def_id: LocalDefId,
-        err: &mut Diagnostic,
-        other: bool,
-        param_env: ty::ParamEnv<'tcx>,
-    ) -> bool;
-
-    fn report_similar_impl_candidates_for_root_obligation(
-        &self,
-        obligation: &PredicateObligation<'tcx>,
-        trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
-        body_def_id: LocalDefId,
-        err: &mut Diagnostic,
-    );
-
-    /// Gets the parent trait chain start
-    fn get_parent_trait_ref(
-        &self,
-        code: &ObligationCauseCode<'tcx>,
-    ) -> Option<(Ty<'tcx>, Option<Span>)>;
-
-    /// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait
-    /// with the same path as `trait_ref`, a help message about
-    /// a probable version mismatch is added to `err`
-    fn note_version_mismatch(
-        &self,
-        err: &mut Diagnostic,
-        trait_ref: &ty::PolyTraitRef<'tcx>,
-    ) -> bool;
-
-    /// Creates a `PredicateObligation` with `new_self_ty` replacing the existing type in the
-    /// `trait_ref`.
-    ///
-    /// For this to work, `new_self_ty` must have no escaping bound variables.
-    fn mk_trait_obligation_with_new_self_ty(
-        &self,
-        param_env: ty::ParamEnv<'tcx>,
-        trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>,
-    ) -> PredicateObligation<'tcx>;
-
-    fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) -> ErrorGuaranteed;
-
-    fn predicate_can_apply(
-        &self,
-        param_env: ty::ParamEnv<'tcx>,
-        pred: ty::PolyTraitPredicate<'tcx>,
-    ) -> bool;
-
-    fn note_obligation_cause(&self, err: &mut Diagnostic, obligation: &PredicateObligation<'tcx>);
-
-    fn suggest_unsized_bound_if_applicable(
-        &self,
-        err: &mut Diagnostic,
-        obligation: &PredicateObligation<'tcx>,
-    );
-
-    fn annotate_source_of_ambiguity(
-        &self,
-        err: &mut Diagnostic,
-        impls: &[ambiguity::Ambiguity],
-        predicate: ty::Predicate<'tcx>,
-    );
-
-    fn maybe_suggest_unsized_generics(&self, err: &mut Diagnostic, span: Span, node: Node<'tcx>);
-
-    fn maybe_indirection_for_unsized(
-        &self,
-        err: &mut Diagnostic,
-        item: &'tcx Item<'tcx>,
-        param: &'tcx GenericParam<'tcx>,
-    ) -> bool;
-
-    fn is_recursive_obligation(
-        &self,
-        obligated_types: &mut Vec<Ty<'tcx>>,
-        cause_code: &ObligationCauseCode<'tcx>,
-    ) -> bool;
-
-    fn get_standard_error_message(
-        &self,
-        trait_predicate: &ty::PolyTraitPredicate<'tcx>,
-        message: Option<String>,
-        predicate_is_const: bool,
-        append_const_msg: Option<AppendConstMessage>,
-        post_message: String,
-    ) -> String;
-
-    fn get_safe_transmute_error_and_reason(
-        &self,
-        obligation: PredicateObligation<'tcx>,
-        trait_ref: ty::PolyTraitRef<'tcx>,
-        span: Span,
-    ) -> GetSafeTransmuteErrorAndReason;
-
-    fn add_tuple_trait_message(
-        &self,
-        obligation_cause_code: &ObligationCauseCode<'tcx>,
-        err: &mut Diagnostic,
-    );
-
-    fn try_to_add_help_message(
-        &self,
-        obligation: &PredicateObligation<'tcx>,
-        trait_ref: ty::PolyTraitRef<'tcx>,
-        trait_predicate: &ty::PolyTraitPredicate<'tcx>,
-        err: &mut Diagnostic,
-        span: Span,
-        is_fn_trait: bool,
-        suggested: bool,
-        unsatisfied_const: bool,
-    );
-
-    fn add_help_message_for_fn_trait(
-        &self,
-        trait_ref: ty::PolyTraitRef<'tcx>,
-        err: &mut Diagnostic,
-        implemented_kind: ty::ClosureKind,
-        params: ty::Binder<'tcx, Ty<'tcx>>,
-    );
-
-    fn maybe_add_note_for_unsatisfied_const(
-        &self,
-        trait_predicate: &ty::PolyTraitPredicate<'tcx>,
-        err: &mut Diagnostic,
-        span: Span,
-    ) -> UnsatisfiedConst;
-
-    fn report_closure_error(
-        &self,
-        obligation: &PredicateObligation<'tcx>,
-        closure_def_id: DefId,
-        found_kind: ty::ClosureKind,
-        kind: ty::ClosureKind,
-        trait_prefix: &'static str,
-    ) -> DiagnosticBuilder<'tcx>;
-
-    fn report_cyclic_signature_error(
-        &self,
-        obligation: &PredicateObligation<'tcx>,
-        found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
-        expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
-        terr: TypeError<'tcx>,
-    ) -> DiagnosticBuilder<'tcx>;
-
-    fn report_opaque_type_auto_trait_leakage(
-        &self,
-        obligation: &PredicateObligation<'tcx>,
-        def_id: DefId,
-    ) -> DiagnosticBuilder<'tcx>;
-
-    fn report_signature_mismatch_error(
-        &self,
-        obligation: &PredicateObligation<'tcx>,
-        span: Span,
-        found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
-        expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
-    ) -> Result<DiagnosticBuilder<'tcx>, ErrorGuaranteed>;
-
-    fn report_not_const_evaluatable_error(
-        &self,
-        obligation: &PredicateObligation<'tcx>,
-        span: Span,
-    ) -> Result<DiagnosticBuilder<'tcx>, ErrorGuaranteed>;
-}
-
-impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
+#[extension(pub(super) trait InferCtxtPrivExt<'tcx>)]
+impl<'tcx> TypeErrCtxt<'_, 'tcx> {
     // returns if `cond` not occurring implies that `error` does not occur - i.e., that
     // `error` occurring implies that `cond` occurs.
     fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool {
@@ -2414,6 +2146,10 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         suggested
     }
 
+    /// Creates a `PredicateObligation` with `new_self_ty` replacing the existing type in the
+    /// `trait_ref`.
+    ///
+    /// For this to work, `new_self_ty` must have no escaping bound variables.
     fn mk_trait_obligation_with_new_self_ty(
         &self,
         param_env: ty::ParamEnv<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
index 52631d4353b..6825dd4ac71 100644
--- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
@@ -11,25 +11,6 @@ pub use rustc_middle::traits::query::OutlivesBound;
 
 pub type BoundsCompat<'a, 'tcx: 'a> = impl Iterator<Item = OutlivesBound<'tcx>> + 'a;
 pub type Bounds<'a, 'tcx: 'a> = impl Iterator<Item = OutlivesBound<'tcx>> + 'a;
-pub trait InferCtxtExt<'a, 'tcx> {
-    /// Do *NOT* call this directly.
-    fn implied_bounds_tys_compat(
-        &'a self,
-        param_env: ty::ParamEnv<'tcx>,
-        body_id: LocalDefId,
-        tys: &'a FxIndexSet<Ty<'tcx>>,
-        compat: bool,
-    ) -> BoundsCompat<'a, 'tcx>;
-
-    /// If `-Z no-implied-bounds-compat` is set, calls `implied_bounds_tys_compat`
-    /// with `compat` set to `true`, otherwise `false`.
-    fn implied_bounds_tys(
-        &'a self,
-        param_env: ty::ParamEnv<'tcx>,
-        body_id: LocalDefId,
-        tys: &'a FxIndexSet<Ty<'tcx>>,
-    ) -> Bounds<'a, 'tcx>;
-}
 
 /// Implied bounds are region relationships that we deduce
 /// automatically. The idea is that (e.g.) a caller must check that a
@@ -130,7 +111,9 @@ fn implied_outlives_bounds<'a, 'tcx>(
     bounds
 }
 
-impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
+#[extension(pub trait InferCtxtExt<'a, 'tcx>)]
+impl<'a, 'tcx: 'a> InferCtxt<'tcx> {
+    /// Do *NOT* call this directly.
     fn implied_bounds_tys_compat(
         &'a self,
         param_env: ParamEnv<'tcx>,
@@ -142,6 +125,8 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
             .flat_map(move |ty| implied_outlives_bounds(self, param_env, body_id, *ty, compat))
     }
 
+    /// If `-Z no-implied-bounds-compat` is set, calls `implied_bounds_tys_compat`
+    /// with `compat` set to `true`, otherwise `false`.
     fn implied_bounds_tys(
         &'a self,
         param_env: ParamEnv<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 049877bc5fe..279c0003187 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -52,12 +52,22 @@ pub type ProjectionTyObligation<'tcx> = Obligation<'tcx, ty::AliasTy<'tcx>>;
 
 pub(super) struct InProgress;
 
-pub trait NormalizeExt<'tcx> {
+#[extension(pub trait NormalizeExt<'tcx>)]
+impl<'tcx> At<'_, 'tcx> {
     /// Normalize a value using the `AssocTypeNormalizer`.
     ///
     /// This normalization should be used when the type contains inference variables or the
     /// projection may be fallible.
-    fn normalize<T: TypeFoldable<TyCtxt<'tcx>>>(&self, t: T) -> InferOk<'tcx, T>;
+    fn normalize<T: TypeFoldable<TyCtxt<'tcx>>>(&self, value: T) -> InferOk<'tcx, T> {
+        if self.infcx.next_trait_solver() {
+            InferOk { value, obligations: Vec::new() }
+        } else {
+            let mut selcx = SelectionContext::new(self.infcx);
+            let Normalized { value, obligations } =
+                normalize_with_depth(&mut selcx, self.param_env, self.cause.clone(), 0, value);
+            InferOk { value, obligations }
+        }
+    }
 
     /// Deeply normalizes `value`, replacing all aliases which can by normalized in
     /// the current environment. In the new solver this errors in case normalization
@@ -77,25 +87,6 @@ pub trait NormalizeExt<'tcx> {
         self,
         value: T,
         fulfill_cx: &mut dyn TraitEngine<'tcx>,
-    ) -> Result<T, Vec<FulfillmentError<'tcx>>>;
-}
-
-impl<'tcx> NormalizeExt<'tcx> for At<'_, 'tcx> {
-    fn normalize<T: TypeFoldable<TyCtxt<'tcx>>>(&self, value: T) -> InferOk<'tcx, T> {
-        if self.infcx.next_trait_solver() {
-            InferOk { value, obligations: Vec::new() }
-        } else {
-            let mut selcx = SelectionContext::new(self.infcx);
-            let Normalized { value, obligations } =
-                normalize_with_depth(&mut selcx, self.param_env, self.cause.clone(), 0, value);
-            InferOk { value, obligations }
-        }
-    }
-
-    fn deeply_normalize<T: TypeFoldable<TyCtxt<'tcx>>>(
-        self,
-        value: T,
-        fulfill_cx: &mut dyn TraitEngine<'tcx>,
     ) -> Result<T, Vec<FulfillmentError<'tcx>>> {
         if self.infcx.next_trait_solver() {
             crate::solve::deeply_normalize(self, value)
diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
index a050b30317a..16ee9fadab4 100644
--- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
@@ -4,32 +4,8 @@ use crate::infer::canonical::OriginalQueryValues;
 use crate::infer::InferCtxt;
 use crate::traits::{EvaluationResult, OverflowError, PredicateObligation, SelectionContext};
 
-pub trait InferCtxtExt<'tcx> {
-    fn predicate_may_hold(&self, obligation: &PredicateObligation<'tcx>) -> bool;
-
-    fn predicate_must_hold_considering_regions(
-        &self,
-        obligation: &PredicateObligation<'tcx>,
-    ) -> bool;
-
-    fn predicate_must_hold_modulo_regions(&self, obligation: &PredicateObligation<'tcx>) -> bool;
-
-    fn evaluate_obligation(
-        &self,
-        obligation: &PredicateObligation<'tcx>,
-    ) -> Result<EvaluationResult, OverflowError>;
-
-    // Helper function that canonicalizes and runs the query. If an
-    // overflow results, we re-run it in the local context so we can
-    // report a nice error.
-    /*crate*/
-    fn evaluate_obligation_no_overflow(
-        &self,
-        obligation: &PredicateObligation<'tcx>,
-    ) -> EvaluationResult;
-}
-
-impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
+#[extension(pub trait InferCtxtExt<'tcx>)]
+impl<'tcx> InferCtxt<'tcx> {
     /// Evaluates whether the predicate can be satisfied (by any means)
     /// in the given `ParamEnv`.
     fn predicate_may_hold(&self, obligation: &PredicateObligation<'tcx>) -> bool {
@@ -114,9 +90,9 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
         }
     }
 
-    // Helper function that canonicalizes and runs the query. If an
-    // overflow results, we re-run it in the local context so we can
-    // report a nice error.
+    /// Helper function that canonicalizes and runs the query. If an
+    /// overflow results, we re-run it in the local context so we can
+    /// report a nice error.
     fn evaluate_obligation_no_overflow(
         &self,
         obligation: &PredicateObligation<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index 0b73fefd2da..0f6c0abd280 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -22,20 +22,8 @@ use super::NoSolution;
 
 pub use rustc_middle::traits::query::NormalizationResult;
 
-pub trait QueryNormalizeExt<'tcx> {
-    /// Normalize a value using the `QueryNormalizer`.
-    ///
-    /// This normalization should *only* be used when the projection does not
-    /// have possible ambiguity or may not be well-formed.
-    ///
-    /// After codegen, when lifetimes do not matter, it is preferable to instead
-    /// use [`TyCtxt::normalize_erasing_regions`], which wraps this procedure.
-    fn query_normalize<T>(self, value: T) -> Result<Normalized<'tcx, T>, NoSolution>
-    where
-        T: TypeFoldable<TyCtxt<'tcx>>;
-}
-
-impl<'cx, 'tcx> QueryNormalizeExt<'tcx> for At<'cx, 'tcx> {
+#[extension(pub trait QueryNormalizeExt<'tcx>)]
+impl<'cx, 'tcx> At<'cx, 'tcx> {
     /// Normalize `value` in the context of the inference context,
     /// yielding a resulting type, or an error if `value` cannot be
     /// normalized. If you don't care about regions, you should prefer
@@ -49,6 +37,12 @@ impl<'cx, 'tcx> QueryNormalizeExt<'tcx> for At<'cx, 'tcx> {
     /// normalizing, but for now should be used only when we actually
     /// know that normalization will succeed, since error reporting
     /// and other details are still "under development".
+    ///
+    /// This normalization should *only* be used when the projection does not
+    /// have possible ambiguity or may not be well-formed.
+    ///
+    /// After codegen, when lifetimes do not matter, it is preferable to instead
+    /// use [`TyCtxt::normalize_erasing_regions`], which wraps this procedure.
     fn query_normalize<T>(self, value: T) -> Result<Normalized<'tcx, T>, NoSolution>
     where
         T: TypeFoldable<TyCtxt<'tcx>>,
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
index e9a592bdee7..f3b77d68922 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
@@ -33,20 +33,8 @@ enum Inserted<'tcx> {
     ShouldRecurseOn(DefId),
 }
 
-trait ChildrenExt<'tcx> {
-    fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId);
-    fn remove_existing(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId);
-
-    fn insert(
-        &mut self,
-        tcx: TyCtxt<'tcx>,
-        impl_def_id: DefId,
-        simplified_self: Option<SimplifiedType>,
-        overlap_mode: OverlapMode,
-    ) -> Result<Inserted<'tcx>, OverlapError<'tcx>>;
-}
-
-impl<'tcx> ChildrenExt<'tcx> for Children {
+#[extension(trait ChildrenExt<'tcx>)]
+impl<'tcx> Children {
     /// Insert an impl into this set of children without comparing to any existing impls.
     fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) {
         let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder();
@@ -247,22 +235,8 @@ where
     }
 }
 
-pub trait GraphExt<'tcx> {
-    /// Insert a local impl into the specialization graph. If an existing impl
-    /// conflicts with it (has overlap, but neither specializes the other),
-    /// information about the area of overlap is returned in the `Err`.
-    fn insert(
-        &mut self,
-        tcx: TyCtxt<'tcx>,
-        impl_def_id: DefId,
-        overlap_mode: OverlapMode,
-    ) -> Result<Option<FutureCompatOverlapError<'tcx>>, OverlapError<'tcx>>;
-
-    /// Insert cached metadata mapping from a child impl back to its parent.
-    fn record_impl_from_cstore(&mut self, tcx: TyCtxt<'tcx>, parent: DefId, child: DefId);
-}
-
-impl<'tcx> GraphExt<'tcx> for Graph {
+#[extension(pub trait GraphExt<'tcx>)]
+impl<'tcx> Graph {
     /// Insert a local impl into the specialization graph. If an existing impl
     /// conflicts with it (has overlap, but neither specializes the other),
     /// information about the area of overlap is returned in the `Err`.
diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
index ed5d01d7048..2f428564ae7 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
@@ -5,15 +5,8 @@ use rustc_middle::ty::{self, Ty};
 
 use crate::traits::{NormalizeExt, Obligation};
 
-pub trait StructurallyNormalizeExt<'tcx> {
-    fn structurally_normalize(
-        &self,
-        ty: Ty<'tcx>,
-        fulfill_cx: &mut dyn TraitEngine<'tcx>,
-    ) -> Result<Ty<'tcx>, Vec<FulfillmentError<'tcx>>>;
-}
-
-impl<'tcx> StructurallyNormalizeExt<'tcx> for At<'_, 'tcx> {
+#[extension(pub trait StructurallyNormalizeExt<'tcx>)]
+impl<'tcx> At<'_, 'tcx> {
     fn structurally_normalize(
         &self,
         ty: Ty<'tcx>,