about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_borrowck/src/lib.rs38
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs18
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs1
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs59
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs261
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs51
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs6
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types/mod.rs35
-rw-r--r--compiler/rustc_middle/src/query/mod.rs8
-rw-r--r--compiler/rustc_middle/src/ty/context.rs8
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs37
-rw-r--r--compiler/rustc_middle/src/ty/opaque_types.rs36
-rw-r--r--compiler/rustc_middle/src/ty/typeck_results.rs2
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/mod.rs1
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs36
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/search_graph.rs1
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs1
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc.rs5
-rw-r--r--compiler/rustc_session/src/options.rs3
-rw-r--r--compiler/rustc_trait_selection/src/opaque_types.rs27
-rw-r--r--compiler/rustc_trait_selection/src/solve/delegate.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/normalize.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs4
-rw-r--r--compiler/rustc_ty_utils/src/instance.rs1
-rw-r--r--compiler/rustc_type_ir/src/infer_ctxt.rs12
-rw-r--r--compiler/rustc_type_ir/src/interner.rs2
-rw-r--r--compiler/rustc_type_ir/src/relate/combine.rs1
29 files changed, 409 insertions, 250 deletions
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 7f0ee28531c..240bd20053b 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -35,7 +35,7 @@ use rustc_infer::infer::{
 };
 use rustc_middle::mir::*;
 use rustc_middle::query::Providers;
-use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt, TypingMode, fold_regions};
+use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt, TypingMode};
 use rustc_middle::{bug, span_bug};
 use rustc_mir_dataflow::impls::{
     EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces,
@@ -171,12 +171,6 @@ fn do_mir_borrowck<'tcx>(
     let free_regions = nll::replace_regions_in_mir(&infcx, &mut body_owned, &mut promoted);
     let body = &body_owned; // no further changes
 
-    // FIXME(-Znext-solver): A bit dubious that we're only registering
-    // predefined opaques in the typeck root.
-    if infcx.next_trait_solver() && !infcx.tcx.is_typeck_child(body.source.def_id()) {
-        infcx.register_predefined_opaques_for_next_solver(def);
-    }
-
     let location_table = PoloniusLocationTable::new(body);
 
     let move_data = MoveData::gather_moves(body, tcx, |_| true);
@@ -431,7 +425,12 @@ pub(crate) struct BorrowckInferCtxt<'tcx> {
 
 impl<'tcx> BorrowckInferCtxt<'tcx> {
     pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
-        let infcx = tcx.infer_ctxt().build(TypingMode::analysis_in_body(tcx, def_id));
+        let typing_mode = if tcx.use_typing_mode_borrowck() {
+            TypingMode::borrowck(tcx, def_id)
+        } else {
+            TypingMode::analysis_in_body(tcx, def_id)
+        };
+        let infcx = tcx.infer_ctxt().build(typing_mode);
         let param_env = tcx.param_env(def_id);
         BorrowckInferCtxt { infcx, reg_var_to_origin: RefCell::new(Default::default()), param_env }
     }
@@ -478,29 +477,6 @@ impl<'tcx> BorrowckInferCtxt<'tcx> {
 
         next_region
     }
-
-    /// With the new solver we prepopulate the opaque type storage during
-    /// MIR borrowck with the hidden types from HIR typeck. This is necessary
-    /// to avoid ambiguities as earlier goals can rely on the hidden type
-    /// of an opaque which is only constrained by a later goal.
-    fn register_predefined_opaques_for_next_solver(&self, def_id: LocalDefId) {
-        let tcx = self.tcx;
-        // OK to use the identity arguments for each opaque type key, since
-        // we remap opaques from HIR typeck back to their definition params.
-        for data in tcx.typeck(def_id).concrete_opaque_types.iter().map(|(k, v)| (*k, *v)) {
-            // HIR typeck did not infer the regions of the opaque, so we instantiate
-            // them with fresh inference variables.
-            let (key, hidden_ty) = fold_regions(tcx, data, |_, _| {
-                self.next_nll_region_var_in_universe(
-                    NllRegionVariableOrigin::Existential { from_forall: false },
-                    ty::UniverseIndex::ROOT,
-                )
-            });
-
-            let prev = self.register_hidden_type_in_storage(key, hidden_ty);
-            assert_eq!(prev, None);
-        }
-    }
 }
 
 impl<'tcx> Deref for BorrowckInferCtxt<'tcx> {
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index 2f15c2bc464..a098450352f 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -2,7 +2,8 @@ use rustc_data_structures::fx::FxIndexMap;
 use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
 use rustc_macros::extension;
 use rustc_middle::ty::{
-    self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, fold_regions,
+    self, DefiningScopeKind, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable,
+    TypeVisitableExt, fold_regions,
 };
 use rustc_span::Span;
 use rustc_trait_selection::opaque_types::check_opaque_type_parameter_valid;
@@ -266,14 +267,21 @@ impl<'tcx> InferCtxt<'tcx> {
             return Ty::new_error(self.tcx, e);
         }
 
-        if let Err(guar) =
-            check_opaque_type_parameter_valid(self, opaque_type_key, instantiated_ty.span)
-        {
+        if let Err(guar) = check_opaque_type_parameter_valid(
+            self,
+            opaque_type_key,
+            instantiated_ty.span,
+            DefiningScopeKind::MirBorrowck,
+        ) {
             return Ty::new_error(self.tcx, guar);
         }
 
         let definition_ty = instantiated_ty
-            .remap_generic_params_to_declaration_params(opaque_type_key, self.tcx, false)
+            .remap_generic_params_to_declaration_params(
+                opaque_type_key,
+                self.tcx,
+                DefiningScopeKind::MirBorrowck,
+            )
             .ty;
 
         if let Err(e) = definition_ty.error_reported() {
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 075abc32594..625f51dd29e 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -61,6 +61,7 @@ pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers {
         type_of: type_of::type_of,
         type_of_opaque: type_of::type_of_opaque,
+        type_of_opaque_hir_typeck: type_of::type_of_opaque_hir_typeck,
         type_alias_is_lazy: type_of::type_alias_is_lazy,
         item_bounds: item_bounds::item_bounds,
         explicit_item_bounds: item_bounds::explicit_item_bounds,
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index afda2c142e2..694c1228859 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -7,7 +7,9 @@ use rustc_hir::{self as hir, AmbigArg, HirId};
 use rustc_middle::query::plumbing::CyclePlaceholder;
 use rustc_middle::ty::print::with_forced_trimmed_paths;
 use rustc_middle::ty::util::IntTypeExt;
-use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt, TypeVisitableExt, fold_regions};
+use rustc_middle::ty::{
+    self, DefiningScopeKind, IsSuggestable, Ty, TyCtxt, TypeVisitableExt, fold_regions,
+};
 use rustc_middle::{bug, span_bug};
 use rustc_span::{DUMMY_SP, Ident, Span};
 
@@ -324,10 +326,18 @@ pub(super) fn type_of_opaque(
     if let Some(def_id) = def_id.as_local() {
         Ok(ty::EarlyBinder::bind(match tcx.hir_node_by_def_id(def_id).expect_opaque_ty().origin {
             hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false, .. } => {
-                opaque::find_opaque_ty_constraints_for_tait(tcx, def_id)
+                opaque::find_opaque_ty_constraints_for_tait(
+                    tcx,
+                    def_id,
+                    DefiningScopeKind::MirBorrowck,
+                )
             }
             hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: true, .. } => {
-                opaque::find_opaque_ty_constraints_for_impl_trait_in_assoc_type(tcx, def_id)
+                opaque::find_opaque_ty_constraints_for_impl_trait_in_assoc_type(
+                    tcx,
+                    def_id,
+                    DefiningScopeKind::MirBorrowck,
+                )
             }
             // Opaque types desugared from `impl Trait`.
             hir::OpaqueTyOrigin::FnReturn { parent: owner, in_trait_or_impl }
@@ -340,7 +350,12 @@ pub(super) fn type_of_opaque(
                         "tried to get type of this RPITIT with no definition"
                     );
                 }
-                opaque::find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
+                opaque::find_opaque_ty_constraints_for_rpit(
+                    tcx,
+                    def_id,
+                    owner,
+                    DefiningScopeKind::MirBorrowck,
+                )
             }
         }))
     } else {
@@ -350,6 +365,42 @@ pub(super) fn type_of_opaque(
     }
 }
 
+pub(super) fn type_of_opaque_hir_typeck(
+    tcx: TyCtxt<'_>,
+    def_id: LocalDefId,
+) -> ty::EarlyBinder<'_, Ty<'_>> {
+    ty::EarlyBinder::bind(match tcx.hir_node_by_def_id(def_id).expect_opaque_ty().origin {
+        hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false, .. } => {
+            opaque::find_opaque_ty_constraints_for_tait(tcx, def_id, DefiningScopeKind::HirTypeck)
+        }
+        hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: true, .. } => {
+            opaque::find_opaque_ty_constraints_for_impl_trait_in_assoc_type(
+                tcx,
+                def_id,
+                DefiningScopeKind::HirTypeck,
+            )
+        }
+        // Opaque types desugared from `impl Trait`.
+        hir::OpaqueTyOrigin::FnReturn { parent: owner, in_trait_or_impl }
+        | hir::OpaqueTyOrigin::AsyncFn { parent: owner, in_trait_or_impl } => {
+            if in_trait_or_impl == Some(hir::RpitContext::Trait)
+                && !tcx.defaultness(owner).has_value()
+            {
+                span_bug!(
+                    tcx.def_span(def_id),
+                    "tried to get type of this RPITIT with no definition"
+                );
+            }
+            opaque::find_opaque_ty_constraints_for_rpit(
+                tcx,
+                def_id,
+                owner,
+                DefiningScopeKind::HirTypeck,
+            )
+        }
+    })
+}
+
 fn infer_placeholder_type<'tcx>(
     cx: &dyn HirTyLowerer<'tcx>,
     def_id: LocalDefId,
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
index 8a3a6a8be11..3fe3d71b32d 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
@@ -3,8 +3,7 @@ use rustc_hir::def_id::LocalDefId;
 use rustc_hir::{self as hir, Expr, ImplItem, Item, Node, TraitItem, def, intravisit};
 use rustc_middle::bug;
 use rustc_middle::hir::nested_filter;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
-use rustc_span::DUMMY_SP;
+use rustc_middle::ty::{self, DefiningScopeKind, Ty, TyCtxt, TypeVisitableExt};
 use tracing::{debug, instrument, trace};
 
 use crate::errors::{TaitForwardCompat2, UnconstrainedOpaqueType};
@@ -15,6 +14,7 @@ use crate::errors::{TaitForwardCompat2, UnconstrainedOpaqueType};
 pub(super) fn find_opaque_ty_constraints_for_impl_trait_in_assoc_type(
     tcx: TyCtxt<'_>,
     def_id: LocalDefId,
+    opaque_types_from: DefiningScopeKind,
 ) -> Ty<'_> {
     let mut parent_def_id = def_id;
     while tcx.def_kind(parent_def_id) == def::DefKind::OpaqueTy {
@@ -27,7 +27,7 @@ pub(super) fn find_opaque_ty_constraints_for_impl_trait_in_assoc_type(
         other => bug!("invalid impl trait in assoc type parent: {other:?}"),
     }
 
-    let mut locator = TaitConstraintLocator { def_id, tcx, found: None, typeck_types: vec![] };
+    let mut locator = TaitConstraintLocator { def_id, tcx, found: None, opaque_types_from };
 
     for &assoc_id in tcx.associated_item_def_ids(impl_def_id) {
         let assoc = tcx.associated_item(assoc_id);
@@ -39,25 +39,14 @@ pub(super) fn find_opaque_ty_constraints_for_impl_trait_in_assoc_type(
     }
 
     if let Some(hidden) = locator.found {
-        // Only check against typeck if we didn't already error
-        if !hidden.ty.references_error() {
-            for concrete_type in locator.typeck_types {
-                if concrete_type.ty != tcx.erase_regions(hidden.ty) {
-                    if let Ok(d) = hidden.build_mismatch_error(&concrete_type, tcx) {
-                        d.emit();
-                    }
-                }
-            }
-        }
-
         hidden.ty
     } else {
-        let reported = tcx.dcx().emit_err(UnconstrainedOpaqueType {
+        let guar = tcx.dcx().emit_err(UnconstrainedOpaqueType {
             span: tcx.def_span(def_id),
             name: tcx.item_ident(parent_def_id.to_def_id()),
             what: "impl",
         });
-        Ty::new_error(tcx, reported)
+        Ty::new_error(tcx, guar)
     }
 }
 
@@ -80,23 +69,16 @@ pub(super) fn find_opaque_ty_constraints_for_impl_trait_in_assoc_type(
 /// fn b<T>() -> Foo<T, u32> { .. }
 /// ```
 #[instrument(skip(tcx), level = "debug")]
-pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
-    let mut locator = TaitConstraintLocator { def_id, tcx, found: None, typeck_types: vec![] };
+pub(super) fn find_opaque_ty_constraints_for_tait(
+    tcx: TyCtxt<'_>,
+    def_id: LocalDefId,
+    opaque_types_from: DefiningScopeKind,
+) -> Ty<'_> {
+    let mut locator = TaitConstraintLocator { def_id, tcx, found: None, opaque_types_from };
 
     tcx.hir_walk_toplevel_module(&mut locator);
 
     if let Some(hidden) = locator.found {
-        // Only check against typeck if we didn't already error
-        if !hidden.ty.references_error() {
-            for concrete_type in locator.typeck_types {
-                if concrete_type.ty != tcx.erase_regions(hidden.ty) {
-                    if let Ok(d) = hidden.build_mismatch_error(&concrete_type, tcx) {
-                        d.emit();
-                    }
-                }
-            }
-        }
-
         hidden.ty
     } else {
         let mut parent_def_id = def_id;
@@ -104,12 +86,12 @@ pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: Local
             // Account for `type Alias = impl Trait<Foo = impl Trait>;` (#116031)
             parent_def_id = tcx.local_parent(parent_def_id);
         }
-        let reported = tcx.dcx().emit_err(UnconstrainedOpaqueType {
+        let guar = tcx.dcx().emit_err(UnconstrainedOpaqueType {
             span: tcx.def_span(def_id),
             name: tcx.item_ident(parent_def_id.to_def_id()),
             what: "crate",
         });
-        Ty::new_error(tcx, reported)
+        Ty::new_error(tcx, guar)
     }
 }
 
@@ -126,22 +108,44 @@ struct TaitConstraintLocator<'tcx> {
     /// type).
     found: Option<ty::OpaqueHiddenType<'tcx>>,
 
-    /// In the presence of dead code, typeck may figure out a hidden type
-    /// while borrowck will not. We collect these cases here and check at
-    /// the end that we actually found a type that matches (modulo regions).
-    typeck_types: Vec<ty::OpaqueHiddenType<'tcx>>,
+    opaque_types_from: DefiningScopeKind,
 }
 
-impl TaitConstraintLocator<'_> {
+impl<'tcx> TaitConstraintLocator<'tcx> {
+    fn insert_found(&mut self, hidden_ty: ty::OpaqueHiddenType<'tcx>) {
+        if let Some(prev) = &mut self.found {
+            if hidden_ty.ty != prev.ty {
+                let (Ok(guar) | Err(guar)) =
+                    prev.build_mismatch_error(&hidden_ty, self.tcx).map(|d| d.emit());
+                prev.ty = Ty::new_error(self.tcx, guar);
+            }
+        } else {
+            self.found = Some(hidden_ty);
+        }
+    }
+
+    fn non_defining_use_in_defining_scope(&mut self, item_def_id: LocalDefId) {
+        let guar = self.tcx.dcx().emit_err(TaitForwardCompat2 {
+            span: self
+                .tcx
+                .def_ident_span(item_def_id)
+                .unwrap_or_else(|| self.tcx.def_span(item_def_id)),
+            opaque_type_span: self.tcx.def_span(self.def_id),
+            opaque_type: self.tcx.def_path_str(self.def_id),
+        });
+        self.insert_found(ty::OpaqueHiddenType::new_error(self.tcx, guar));
+    }
+
     #[instrument(skip(self), level = "debug")]
     fn check(&mut self, item_def_id: LocalDefId) {
         // Don't try to check items that cannot possibly constrain the type.
-        if !self.tcx.has_typeck_results(item_def_id) {
+        let tcx = self.tcx;
+        if !tcx.has_typeck_results(item_def_id) {
             debug!("no constraint: no typeck results");
             return;
         }
 
-        let opaque_types_defined_by = self.tcx.opaque_types_defined_by(item_def_id);
+        let opaque_types_defined_by = tcx.opaque_types_defined_by(item_def_id);
         // Don't try to check items that cannot possibly constrain the type.
         if !opaque_types_defined_by.contains(&self.def_id) {
             debug!("no constraint: no opaque types defined");
@@ -152,7 +156,7 @@ impl TaitConstraintLocator<'_> {
         // "non-defining use" errors for them.
         // Note that we use `Node::fn_sig` instead of `Node::fn_decl` here, because the former
         // excludes closures, which are allowed to have `_` in their return type.
-        let hir_node = self.tcx.hir_node_by_def_id(item_def_id);
+        let hir_node = tcx.hir_node_by_def_id(item_def_id);
         debug_assert!(
             !matches!(hir_node, Node::ForeignItem(..)),
             "foreign items cannot constrain opaque types",
@@ -164,88 +168,39 @@ impl TaitConstraintLocator<'_> {
                 hir_sig.decl.output.span(),
                 "inferring return types and opaque types do not mix well",
             );
-            self.found =
-                Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: Ty::new_error(self.tcx, guar) });
-            return;
-        }
-
-        // Calling `mir_borrowck` can lead to cycle errors through
-        // const-checking, avoid calling it if we don't have to.
-        // ```rust
-        // type Foo = impl Fn() -> usize; // when computing type for this
-        // const fn bar() -> Foo {
-        //     || 0usize
-        // }
-        // const BAZR: Foo = bar(); // we would mir-borrowck this, causing cycles
-        // // because we again need to reveal `Foo` so we can check whether the
-        // // constant does not contain interior mutability.
-        // ```
-        let tables = self.tcx.typeck(item_def_id);
-        if let Some(guar) = tables.tainted_by_errors {
-            self.found =
-                Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: Ty::new_error(self.tcx, guar) });
+            self.found = Some(ty::OpaqueHiddenType::new_error(tcx, guar));
             return;
         }
 
-        let mut constrained = false;
-        for (&opaque_type_key, &hidden_type) in &tables.concrete_opaque_types {
-            if opaque_type_key.def_id != self.def_id {
-                continue;
-            }
-            constrained = true;
-
-            let concrete_type =
-                self.tcx.erase_regions(hidden_type.remap_generic_params_to_declaration_params(
-                    opaque_type_key,
-                    self.tcx,
-                    true,
-                ));
-            if self.typeck_types.iter().all(|prev| prev.ty != concrete_type.ty) {
-                self.typeck_types.push(concrete_type);
-            }
-        }
-
-        if !constrained {
-            debug!("no constraints in typeck results");
-            if opaque_types_defined_by.contains(&self.def_id) {
-                let guar = self.tcx.dcx().emit_err(TaitForwardCompat2 {
-                    span: self
-                        .tcx
-                        .def_ident_span(item_def_id)
-                        .unwrap_or_else(|| self.tcx.def_span(item_def_id)),
-                    opaque_type_span: self.tcx.def_span(self.def_id),
-                    opaque_type: self.tcx.def_path_str(self.def_id),
-                });
-                // Avoid "opaque type not constrained" errors on the opaque itself.
-                self.found = Some(ty::OpaqueHiddenType {
-                    span: DUMMY_SP,
-                    ty: Ty::new_error(self.tcx, guar),
-                });
+        match self.opaque_types_from {
+            DefiningScopeKind::HirTypeck => {
+                let tables = tcx.typeck(item_def_id);
+                if let Some(guar) = tables.tainted_by_errors {
+                    self.insert_found(ty::OpaqueHiddenType::new_error(tcx, guar));
+                } else if let Some(&hidden_type) = tables.concrete_opaque_types.get(&self.def_id) {
+                    self.insert_found(hidden_type);
+                } else {
+                    self.non_defining_use_in_defining_scope(item_def_id);
+                }
             }
-            return;
-        };
-
-        // Use borrowck to get the type with unerased regions.
-        let borrowck_results = &self.tcx.mir_borrowck(item_def_id);
-
-        // If the body was tainted, then assume the opaque may have been constrained and just set it to error.
-        if let Some(guar) = borrowck_results.tainted_by_errors {
-            self.found =
-                Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: Ty::new_error(self.tcx, guar) });
-            return;
-        }
-
-        debug!(?borrowck_results.concrete_opaque_types);
-        if let Some(&concrete_type) = borrowck_results.concrete_opaque_types.get(&self.def_id) {
-            debug!(?concrete_type, "found constraint");
-            if let Some(prev) = &mut self.found {
-                if concrete_type.ty != prev.ty {
-                    let (Ok(guar) | Err(guar)) =
-                        prev.build_mismatch_error(&concrete_type, self.tcx).map(|d| d.emit());
-                    prev.ty = Ty::new_error(self.tcx, guar);
+            DefiningScopeKind::MirBorrowck => {
+                let borrowck_result = tcx.mir_borrowck(item_def_id);
+                if let Some(guar) = borrowck_result.tainted_by_errors {
+                    self.insert_found(ty::OpaqueHiddenType::new_error(tcx, guar));
+                } else if let Some(&hidden_type) =
+                    borrowck_result.concrete_opaque_types.get(&self.def_id)
+                {
+                    debug!(?hidden_type, "found constraint");
+                    self.insert_found(hidden_type);
+                } else if let Err(guar) = tcx
+                    .type_of_opaque_hir_typeck(self.def_id)
+                    .instantiate_identity()
+                    .error_reported()
+                {
+                    self.insert_found(ty::OpaqueHiddenType::new_error(tcx, guar));
+                } else {
+                    self.non_defining_use_in_defining_scope(item_def_id);
                 }
-            } else {
-                self.found = Some(concrete_type);
             }
         }
     }
@@ -287,54 +242,42 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: LocalDefId,
     owner_def_id: LocalDefId,
+    opaque_types_from: DefiningScopeKind,
 ) -> Ty<'tcx> {
-    let tables = tcx.typeck(owner_def_id);
+    match opaque_types_from {
+        DefiningScopeKind::HirTypeck => {
+            let tables = tcx.typeck(owner_def_id);
+            if let Some(guar) = tables.tainted_by_errors {
+                Ty::new_error(tcx, guar)
+            } else if let Some(hidden_ty) = tables.concrete_opaque_types.get(&def_id) {
+                hidden_ty.ty
+            } else {
+                // FIXME(-Znext-solver): This should not be necessary and we should
+                // instead rely on inference variable fallback inside of typeck itself.
 
-    // Check that all of the opaques we inferred during HIR are compatible.
-    // FIXME: We explicitly don't check that the types inferred during HIR
-    // typeck are compatible with the one that we infer during borrowck,
-    // because that one actually sometimes has consts evaluated eagerly so
-    // using strict type equality will fail.
-    let mut hir_opaque_ty: Option<ty::OpaqueHiddenType<'tcx>> = None;
-    if tables.tainted_by_errors.is_none() {
-        for (&opaque_type_key, &hidden_type) in &tables.concrete_opaque_types {
-            if opaque_type_key.def_id != def_id {
-                continue;
+                // We failed to resolve the opaque type or it
+                // resolves to itself. We interpret this as the
+                // no values of the hidden type ever being constructed,
+                // so we can just make the hidden type be `!`.
+                // For backwards compatibility reasons, we fall back to
+                // `()` until we the diverging default is changed.
+                Ty::new_diverging_default(tcx)
             }
-            let concrete_type = tcx.erase_regions(
-                hidden_type.remap_generic_params_to_declaration_params(opaque_type_key, tcx, true),
-            );
-            if let Some(prev) = &mut hir_opaque_ty {
-                if concrete_type.ty != prev.ty {
-                    if let Ok(d) = prev.build_mismatch_error(&concrete_type, tcx) {
-                        d.emit();
-                    }
-                }
+        }
+        DefiningScopeKind::MirBorrowck => {
+            let borrowck_result = tcx.mir_borrowck(owner_def_id);
+            if let Some(guar) = borrowck_result.tainted_by_errors {
+                Ty::new_error(tcx, guar)
+            } else if let Some(hidden_ty) = borrowck_result.concrete_opaque_types.get(&def_id) {
+                hidden_ty.ty
             } else {
-                hir_opaque_ty = Some(concrete_type);
+                let hir_ty = tcx.type_of_opaque_hir_typeck(def_id).instantiate_identity();
+                if let Err(guar) = hir_ty.error_reported() {
+                    Ty::new_error(tcx, guar)
+                } else {
+                    hir_ty
+                }
             }
         }
     }
-
-    let mir_opaque_ty = tcx.mir_borrowck(owner_def_id).concrete_opaque_types.get(&def_id).copied();
-    if let Some(mir_opaque_ty) = mir_opaque_ty {
-        mir_opaque_ty.ty
-    } else if let Some(guar) = tables.tainted_by_errors {
-        // Some error in the owner fn prevented us from populating
-        // the `concrete_opaque_types` table.
-        Ty::new_error(tcx, guar)
-    } else {
-        // Fall back to the RPIT we inferred during HIR typeck
-        if let Some(hir_opaque_ty) = hir_opaque_ty {
-            hir_opaque_ty.ty
-        } else {
-            // We failed to resolve the opaque type or it
-            // resolves to itself. We interpret this as the
-            // no values of the hidden type ever being constructed,
-            // so we can just make the hidden type be `!`.
-            // For backwards compatibility reasons, we fall back to
-            // `()` until we the diverging default is changed.
-            Ty::new_diverging_default(tcx)
-        }
-    }
 }
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 588383534f6..4d7e2c7629f 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -12,10 +12,12 @@ use rustc_middle::span_bug;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion};
 use rustc_middle::ty::{
-    self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, fold_regions,
+    self, DefiningScopeKind, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
+    TypeVisitableExt, fold_regions,
 };
 use rustc_span::{Span, sym};
 use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
+use rustc_trait_selection::opaque_types::check_opaque_type_parameter_valid;
 use rustc_trait_selection::solve;
 use tracing::{debug, instrument};
 
@@ -553,6 +555,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
 
     #[instrument(skip(self), level = "debug")]
     fn visit_opaque_types(&mut self) {
+        let tcx = self.tcx();
         // We clone the opaques instead of stealing them here as they are still used for
         // normalization in the next generation trait solver.
         //
@@ -575,16 +578,46 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
                 }
             }
 
-            // Here we only detect impl trait definition conflicts when they
-            // are equal modulo regions.
-            if let Some(last_opaque_ty) =
-                self.typeck_results.concrete_opaque_types.insert(opaque_type_key, hidden_type)
-                && last_opaque_ty.ty != hidden_type.ty
+            if let Err(guar) = check_opaque_type_parameter_valid(
+                &self.fcx,
+                opaque_type_key,
+                hidden_type.span,
+                DefiningScopeKind::HirTypeck,
+            ) {
+                self.typeck_results
+                    .concrete_opaque_types
+                    .insert(opaque_type_key.def_id, ty::OpaqueHiddenType::new_error(tcx, guar));
+            }
+
+            let hidden_type = hidden_type.remap_generic_params_to_declaration_params(
+                opaque_type_key,
+                tcx,
+                DefiningScopeKind::HirTypeck,
+            );
+
+            if let Some(prev) = self
+                .typeck_results
+                .concrete_opaque_types
+                .insert(opaque_type_key.def_id, hidden_type)
             {
-                assert!(!self.fcx.next_trait_solver());
-                if let Ok(d) = hidden_type.build_mismatch_error(&last_opaque_ty, self.tcx()) {
-                    d.emit();
+                let entry = &mut self
+                    .typeck_results
+                    .concrete_opaque_types
+                    .get_mut(&opaque_type_key.def_id)
+                    .unwrap();
+                if prev.ty != hidden_type.ty {
+                    if let Some(guar) = self.typeck_results.tainted_by_errors {
+                        entry.ty = Ty::new_error(tcx, guar);
+                    } else {
+                        let (Ok(guar) | Err(guar)) =
+                            prev.build_mismatch_error(&hidden_type, tcx).map(|d| d.emit());
+                        entry.ty = Ty::new_error(tcx, guar);
+                    }
                 }
+
+                // Pick a better span if there is one.
+                // FIXME(oli-obk): collect multiple spans for better diagnostics down the road.
+                entry.span = prev.span.substitute_dummy(hidden_type.span);
             }
         }
     }
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index fa8dea064da..20aa8e44f43 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -966,7 +966,8 @@ impl<'tcx> InferCtxt<'tcx> {
     pub fn can_define_opaque_ty(&self, id: impl Into<DefId>) -> bool {
         debug_assert!(!self.next_trait_solver());
         match self.typing_mode() {
-            TypingMode::Analysis { defining_opaque_types } => {
+            TypingMode::Analysis { defining_opaque_types }
+            | TypingMode::Borrowck { defining_opaque_types } => {
                 id.into().as_local().is_some_and(|def_id| defining_opaque_types.contains(&def_id))
             }
             // FIXME(#132279): This function is quite weird in post-analysis
@@ -1260,7 +1261,8 @@ impl<'tcx> InferCtxt<'tcx> {
             // to handle them without proper canonicalization. This means we may cause cycle
             // errors and fail to reveal opaques while inside of bodies. We should rename this
             // function and require explicit comments on all use-sites in the future.
-            ty::TypingMode::Analysis { defining_opaque_types: _ } => {
+            ty::TypingMode::Analysis { defining_opaque_types: _ }
+            | ty::TypingMode::Borrowck { defining_opaque_types: _ } => {
                 TypingMode::non_body_analysis()
             }
             mode @ (ty::TypingMode::Coherence
diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs
index d9297fb4194..ce5d2e6e17a 100644
--- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs
@@ -12,7 +12,7 @@ use rustc_middle::ty::{
 use rustc_span::Span;
 use tracing::{debug, instrument};
 
-use super::DefineOpaqueTypes;
+use super::{DefineOpaqueTypes, RegionVariableOrigin};
 use crate::errors::OpaqueHiddenTypeDiag;
 use crate::infer::{InferCtxt, InferOk};
 use crate::traits::{self, Obligation, PredicateObligations};
@@ -221,6 +221,7 @@ impl<'tcx> InferCtxt<'tcx> {
         hidden_ty: Ty<'tcx>,
         goals: &mut Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
     ) -> Result<(), TypeError<'tcx>> {
+        let tcx = self.tcx;
         // Ideally, we'd get the span where *this specific `ty` came
         // from*, but right now we just use the span from the overall
         // value being folded. In simple cases like `-> impl Foo`,
@@ -231,7 +232,7 @@ impl<'tcx> InferCtxt<'tcx> {
                 // During intercrate we do not define opaque types but instead always
                 // force ambiguity unless the hidden type is known to not implement
                 // our trait.
-                goals.push(Goal::new(self.tcx, param_env, ty::PredicateKind::Ambiguous));
+                goals.push(Goal::new(tcx, param_env, ty::PredicateKind::Ambiguous));
             }
             ty::TypingMode::Analysis { .. } => {
                 let prev = self
@@ -249,6 +250,36 @@ impl<'tcx> InferCtxt<'tcx> {
                     );
                 }
             }
+            ty::TypingMode::Borrowck { .. } => {
+                let prev = self
+                    .inner
+                    .borrow_mut()
+                    .opaque_types()
+                    .register(opaque_type_key, OpaqueHiddenType { ty: hidden_ty, span });
+
+                // We either equate the new hidden type with the previous entry or with the type
+                // inferred by HIR typeck.
+                let actual = prev.unwrap_or_else(|| {
+                    let actual = tcx
+                        .type_of_opaque_hir_typeck(opaque_type_key.def_id)
+                        .instantiate(self.tcx, opaque_type_key.args);
+                    let actual = ty::fold_regions(tcx, actual, |re, _dbi| match re.kind() {
+                        ty::ReErased => {
+                            self.next_region_var(RegionVariableOrigin::MiscVariable(span))
+                        }
+                        _ => re,
+                    });
+                    actual
+                });
+
+                goals.extend(
+                    self.at(&ObligationCause::dummy_with_span(span), param_env)
+                        .eq(DefineOpaqueTypes::Yes, hidden_ty, actual)?
+                        .obligations
+                        .into_iter()
+                        .map(|obligation| obligation.as_goal()),
+                );
+            }
             mode @ (ty::TypingMode::PostBorrowckAnalysis { .. } | ty::TypingMode::PostAnalysis) => {
                 bug!("insert hidden type in {mode:?}")
             }
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 698859c663b..0d5fba3cc69 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -267,6 +267,8 @@ rustc_queries! {
     ///
     /// This is a specialized instance of [`Self::type_of`] that detects query cycles.
     /// Unless `CyclePlaceholder` needs to be handled separately, call [`Self::type_of`] instead.
+    /// This is used to improve the error message in cases where revealing the hidden type
+    /// for auto-trait leakage cycles.
     ///
     /// # Panics
     ///
@@ -278,6 +280,12 @@ rustc_queries! {
         }
         cycle_stash
     }
+    query type_of_opaque_hir_typeck(key: LocalDefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> {
+        desc { |tcx|
+            "computing type of opaque `{path}` via HIR typeck",
+            path = tcx.def_path_str(key),
+        }
+    }
 
     /// Returns whether the type alias given by `DefId` is lazy.
     ///
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 618a65a0186..b1ace674404 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -206,6 +206,9 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     fn type_of(self, def_id: DefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> {
         self.type_of(def_id)
     }
+    fn type_of_opaque_hir_typeck(self, def_id: LocalDefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> {
+        self.type_of_opaque_hir_typeck(def_id)
+    }
 
     type AdtDef = ty::AdtDef<'tcx>;
     fn adt_def(self, adt_def_id: DefId) -> Self::AdtDef {
@@ -3248,6 +3251,11 @@ impl<'tcx> TyCtxt<'tcx> {
         self.sess.opts.unstable_opts.next_solver.coherence
     }
 
+    #[allow(rustc::bad_opt_access)]
+    pub fn use_typing_mode_borrowck(self) -> bool {
+        self.next_trait_solver_globally() || self.sess.opts.unstable_opts.typing_mode_borrowck
+    }
+
     pub fn is_impl_trait_in_trait(self, def_id: DefId) -> bool {
         self.opt_rpitit_info(def_id).is_some()
     }
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 255d464d265..8db0c7c9b3a 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -48,7 +48,7 @@ use rustc_serialize::{Decodable, Encodable};
 use rustc_session::lint::LintBuffer;
 pub use rustc_session::lint::RegisteredTools;
 use rustc_span::hygiene::MacroKind;
-use rustc_span::{ExpnId, ExpnKind, Ident, Span, Symbol, kw, sym};
+use rustc_span::{DUMMY_SP, ExpnId, ExpnKind, Ident, Span, Symbol, kw, sym};
 pub use rustc_type_ir::relate::VarianceDiagInfo;
 pub use rustc_type_ir::*;
 use tracing::{debug, instrument};
@@ -782,7 +782,22 @@ pub struct OpaqueHiddenType<'tcx> {
     pub ty: Ty<'tcx>,
 }
 
+/// Whether we're currently in HIR typeck or MIR borrowck.
+#[derive(Debug, Clone, Copy)]
+pub enum DefiningScopeKind {
+    /// During writeback in typeck, we don't care about regions and simply
+    /// erase them. This means we also don't check whether regions are
+    /// universal in the opaque type key. This will only be checked in
+    /// MIR borrowck.
+    HirTypeck,
+    MirBorrowck,
+}
+
 impl<'tcx> OpaqueHiddenType<'tcx> {
+    pub fn new_error(tcx: TyCtxt<'tcx>, guar: ErrorGuaranteed) -> OpaqueHiddenType<'tcx> {
+        OpaqueHiddenType { span: DUMMY_SP, ty: Ty::new_error(tcx, guar) }
+    }
+
     pub fn build_mismatch_error(
         &self,
         other: &Self,
@@ -808,8 +823,7 @@ impl<'tcx> OpaqueHiddenType<'tcx> {
         self,
         opaque_type_key: OpaqueTypeKey<'tcx>,
         tcx: TyCtxt<'tcx>,
-        // typeck errors have subpar spans for opaque types, so delay error reporting until borrowck.
-        ignore_errors: bool,
+        defining_scope_kind: DefiningScopeKind,
     ) -> Self {
         let OpaqueTypeKey { def_id, args } = opaque_type_key;
 
@@ -828,10 +842,19 @@ impl<'tcx> OpaqueHiddenType<'tcx> {
         let map = args.iter().zip(id_args).collect();
         debug!("map = {:#?}", map);
 
-        // Convert the type from the function into a type valid outside
-        // the function, by replacing invalid regions with 'static,
-        // after producing an error for each of them.
-        self.fold_with(&mut opaque_types::ReverseMapper::new(tcx, map, self.span, ignore_errors))
+        // Convert the type from the function into a type valid outside by mapping generic
+        // parameters to into the context of the opaque.
+        //
+        // We erase regions when doing this during HIR typeck.
+        let this = match defining_scope_kind {
+            DefiningScopeKind::HirTypeck => tcx.erase_regions(self),
+            DefiningScopeKind::MirBorrowck => self,
+        };
+        let result = this.fold_with(&mut opaque_types::ReverseMapper::new(tcx, map, self.span));
+        if cfg!(debug_assertions) && matches!(defining_scope_kind, DefiningScopeKind::HirTypeck) {
+            assert_eq!(result.ty, tcx.erase_regions(result.ty));
+        }
+        result
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs
index 56c44c8a84c..c72efde0994 100644
--- a/compiler/rustc_middle/src/ty/opaque_types.rs
+++ b/compiler/rustc_middle/src/ty/opaque_types.rs
@@ -20,12 +20,6 @@ pub(super) struct ReverseMapper<'tcx> {
     /// for an explanation of this field.
     do_not_error: bool,
 
-    /// We do not want to emit any errors in typeck because
-    /// the spans in typeck are subpar at the moment.
-    /// Borrowck will do the same work again (this time with
-    /// lifetime information) and thus report better errors.
-    ignore_errors: bool,
-
     /// Span of function being checked.
     span: Span,
 }
@@ -35,9 +29,8 @@ impl<'tcx> ReverseMapper<'tcx> {
         tcx: TyCtxt<'tcx>,
         map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
         span: Span,
-        ignore_errors: bool,
     ) -> Self {
-        Self { tcx, map, do_not_error: false, ignore_errors, span }
+        Self { tcx, map, do_not_error: false, span }
     }
 
     fn fold_kind_no_missing_regions_error(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> {
@@ -176,20 +169,18 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> {
                     Some(u) => panic!("type mapped to unexpected kind: {u:?}"),
                     None => {
                         debug!(?param, ?self.map);
-                        if !self.ignore_errors {
-                            self.tcx
-                                .dcx()
-                                .struct_span_err(
-                                    self.span,
-                                    format!(
-                                        "type parameter `{ty}` is part of concrete type but not \
+                        let guar = self
+                            .tcx
+                            .dcx()
+                            .struct_span_err(
+                                self.span,
+                                format!(
+                                    "type parameter `{ty}` is part of concrete type but not \
                                           used in parameter list for the `impl Trait` type alias"
-                                    ),
-                                )
-                                .emit();
-                        }
-
-                        Ty::new_misc_error(self.tcx)
+                                ),
+                            )
+                            .emit();
+                        Ty::new_error(self.tcx, guar)
                     }
                 }
             }
@@ -217,8 +208,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> {
                                 ct: ct.to_string(),
                                 span: self.span,
                             })
-                            .emit_unless(self.ignore_errors);
-
+                            .emit();
                         ty::Const::new_error(self.tcx, guar)
                     }
                 }
diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs
index 3d3f4e2773a..7c437abfe24 100644
--- a/compiler/rustc_middle/src/ty/typeck_results.rs
+++ b/compiler/rustc_middle/src/ty/typeck_results.rs
@@ -158,7 +158,7 @@ pub struct TypeckResults<'tcx> {
     /// We also store the type here, so that the compiler can use it as a hint
     /// for figuring out hidden types, even if they are only set in dead code
     /// (which doesn't show up in MIR).
-    pub concrete_opaque_types: FxIndexMap<ty::OpaqueTypeKey<'tcx>, ty::OpaqueHiddenType<'tcx>>,
+    pub concrete_opaque_types: FxIndexMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>,
 
     /// Tracks the minimum captures required for a closure;
     /// see `MinCaptureInformationMap` for more details.
diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs
index 199f0c7512e..7641e9a16ee 100644
--- a/compiler/rustc_next_trait_solver/src/solve/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs
@@ -330,6 +330,7 @@ where
             // During analysis, opaques are rigid unless they may be defined by
             // the current body.
             TypingMode::Analysis { defining_opaque_types: non_rigid_opaques }
+            | TypingMode::Borrowck { defining_opaque_types: non_rigid_opaques }
             | TypingMode::PostBorrowckAnalysis { defined_opaque_types: non_rigid_opaques } => {
                 !def_id.as_local().is_some_and(|def_id| non_rigid_opaques.contains(&def_id))
             }
diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs
index 82dae51b3d0..aa89e77bb6f 100644
--- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs
@@ -96,6 +96,42 @@ where
                 );
                 self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
             }
+            // Very similar to `TypingMode::Analysis` with some notably differences:
+            // - we accept opaque types even if they have non-universal arguments
+            // - we do a structural lookup instead of semantically unifying regions
+            // - the hidden type starts out as the type from HIR typeck with fresh region
+            //   variables instead of a fully unconstrained inference variable
+            TypingMode::Borrowck { defining_opaque_types } => {
+                let Some(def_id) = opaque_ty
+                    .def_id
+                    .as_local()
+                    .filter(|&def_id| defining_opaque_types.contains(&def_id))
+                else {
+                    self.structurally_instantiate_normalizes_to_term(goal, goal.predicate.alias);
+                    return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
+                };
+
+                let opaque_type_key = ty::OpaqueTypeKey { def_id, args: opaque_ty.args };
+                let actual = self
+                    .register_hidden_type_in_storage(opaque_type_key, expected)
+                    .unwrap_or_else(|| {
+                        let actual =
+                            cx.type_of_opaque_hir_typeck(def_id).instantiate(cx, opaque_ty.args);
+                        let actual = fold_regions(cx, actual, |re, _dbi| match re.kind() {
+                            ty::ReErased => self.next_region_var(),
+                            _ => re,
+                        });
+                        actual
+                    });
+                self.eq(goal.param_env, expected, actual)?;
+                self.add_item_bounds_for_hidden_type(
+                    def_id.into(),
+                    opaque_ty.args,
+                    goal.param_env,
+                    expected,
+                );
+                self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+            }
             TypingMode::PostBorrowckAnalysis { defined_opaque_types } => {
                 let Some(def_id) = opaque_ty
                     .def_id
diff --git a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs
index eba496fa226..ecffbbff7a2 100644
--- a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs
@@ -62,6 +62,7 @@ where
                     response_no_constraints(cx, input, Certainty::overflow(false))
                 }
                 TypingMode::Analysis { .. }
+                | TypingMode::Borrowck { .. }
                 | TypingMode::PostBorrowckAnalysis { .. }
                 | TypingMode::PostAnalysis => Err(NoSolution),
             },
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index b72f776e5cb..2a1196735cd 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -72,6 +72,7 @@ where
             (ty::ImplPolarity::Reservation, _) => match ecx.typing_mode() {
                 TypingMode::Coherence => Certainty::AMBIGUOUS,
                 TypingMode::Analysis { .. }
+                | TypingMode::Borrowck { .. }
                 | TypingMode::PostBorrowckAnalysis { .. }
                 | TypingMode::PostAnalysis => return Err(NoSolution),
             },
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index a25a80cd45f..31c4ee0fa0b 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -135,7 +135,10 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
     /// Returns the hidden type corresponding to this key if the body under analysis is allowed to
     /// know it.
     fn reveal_opaque_key(&self, key: OpaqueTypeKey<'tcx>) -> Option<Ty<'tcx>> {
-        self.typeck_results.concrete_opaque_types.get(&key).map(|x| x.ty)
+        self.typeck_results
+            .concrete_opaque_types
+            .get(&key.def_id)
+            .map(|x| ty::EarlyBinder::bind(x.ty).instantiate(self.tcx, key.args))
     }
     // This can take a non-revealed `Ty` because it reveals opaques itself.
     pub fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index cd5e2c4173e..36f7486f1d4 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -2553,6 +2553,9 @@ written to standard error output)"),
         "in diagnostics, use heuristics to shorten paths referring to items"),
     tune_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
         "select processor to schedule for (`rustc --print target-cpus` for details)"),
+    #[rustc_lint_opt_deny_field_access("use `TyCtxt::use_typing_mode_borrowck` instead of this field")]
+    typing_mode_borrowck: bool = (false, parse_bool, [TRACKED],
+        "enable `TypingMode::Borrowck`, changing the way opaque types are handled during MIR borrowck"),
     #[rustc_lint_opt_deny_field_access("use `Session::ub_checks` instead of this field")]
     ub_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "emit runtime checks for Undefined Behavior (default: -Cdebug-assertions)"),
diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs
index 5af912fee54..c7b8f063196 100644
--- a/compiler/rustc_trait_selection/src/opaque_types.rs
+++ b/compiler/rustc_trait_selection/src/opaque_types.rs
@@ -4,7 +4,7 @@ use rustc_hir::def_id::LocalDefId;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_middle::ty::{
-    self, GenericArgKind, GenericArgs, OpaqueTypeKey, TyCtxt, TypeVisitableExt,
+    self, DefiningScopeKind, GenericArgKind, GenericArgs, OpaqueTypeKey, TyCtxt, TypeVisitableExt,
     TypingMode, fold_regions,
 };
 use rustc_span::{ErrorGuaranteed, Span};
@@ -21,19 +21,36 @@ pub fn check_opaque_type_parameter_valid<'tcx>(
     infcx: &InferCtxt<'tcx>,
     opaque_type_key: OpaqueTypeKey<'tcx>,
     span: Span,
+    defining_scope_kind: DefiningScopeKind,
 ) -> Result<(), ErrorGuaranteed> {
     let tcx = infcx.tcx;
     let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
     let opaque_env = LazyOpaqueTyEnv::new(tcx, opaque_type_key.def_id);
     let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default();
 
+    // Avoid duplicate errors in case the opaque has already been malformed in
+    // HIR typeck.
+    if let DefiningScopeKind::MirBorrowck = defining_scope_kind {
+        if let Err(guar) = infcx
+            .tcx
+            .type_of_opaque_hir_typeck(opaque_type_key.def_id)
+            .instantiate_identity()
+            .error_reported()
+        {
+            return Err(guar);
+        }
+    }
+
     for (i, arg) in opaque_type_key.iter_captured_args(tcx) {
         let arg_is_param = match arg.unpack() {
+            GenericArgKind::Lifetime(lt) => match defining_scope_kind {
+                DefiningScopeKind::HirTypeck => continue,
+                DefiningScopeKind::MirBorrowck => {
+                    matches!(*lt, ty::ReEarlyParam(_) | ty::ReLateParam(_))
+                        || (lt.is_static() && opaque_env.param_equal_static(i))
+                }
+            },
             GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
-            GenericArgKind::Lifetime(lt) => {
-                matches!(*lt, ty::ReEarlyParam(_) | ty::ReLateParam(_))
-                    || (lt.is_static() && opaque_env.param_equal_static(i))
-            }
             GenericArgKind::Const(ct) => matches!(ct.kind(), ty::ConstKind::Param(_)),
         };
 
diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs
index f2725411e13..e0b425fa739 100644
--- a/compiler/rustc_trait_selection/src/solve/delegate.rs
+++ b/compiler/rustc_trait_selection/src/solve/delegate.rs
@@ -195,6 +195,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
             match self.typing_mode() {
                 TypingMode::Coherence
                 | TypingMode::Analysis { .. }
+                | TypingMode::Borrowck { .. }
                 | TypingMode::PostBorrowckAnalysis { .. } => false,
                 TypingMode::PostAnalysis => {
                     let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref);
diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs
index ad62b456ad4..4ac45172a0e 100644
--- a/compiler/rustc_trait_selection/src/traits/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/normalize.rs
@@ -130,6 +130,7 @@ pub(super) fn needs_normalization<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
         // FIXME(#132279): We likely want to reveal opaques during post borrowck analysis
         TypingMode::Coherence
         | TypingMode::Analysis { .. }
+        | TypingMode::Borrowck { .. }
         | TypingMode::PostBorrowckAnalysis { .. } => flags.remove(ty::TypeFlags::HAS_TY_OPAQUE),
         TypingMode::PostAnalysis => {}
     }
@@ -226,6 +227,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
                     // FIXME(#132279): We likely want to reveal opaques during post borrowck analysis
                     TypingMode::Coherence
                     | TypingMode::Analysis { .. }
+                    | TypingMode::Borrowck { .. }
                     | TypingMode::PostBorrowckAnalysis { .. } => ty.super_fold_with(self),
                     TypingMode::PostAnalysis => {
                         let recursion_limit = self.cx().recursion_limit();
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 6057b66c483..349569d750e 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -952,6 +952,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                             match selcx.infcx.typing_mode() {
                                 TypingMode::Coherence
                                 | TypingMode::Analysis { .. }
+                                | TypingMode::Borrowck { .. }
                                 | TypingMode::PostBorrowckAnalysis { .. } => {
                                     debug!(
                                         assoc_ty = ?selcx.tcx().def_path_str(node_item.item.def_id),
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index 165c63f3745..5dbb4382fd1 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -216,6 +216,7 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> {
                 match self.infcx.typing_mode() {
                     TypingMode::Coherence
                     | TypingMode::Analysis { .. }
+                    | TypingMode::Borrowck { .. }
                     | TypingMode::PostBorrowckAnalysis { .. } => ty.try_super_fold_with(self)?,
 
                     TypingMode::PostAnalysis => {
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 0679dbf1296..d78938225f1 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -1446,6 +1446,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         match self.infcx.typing_mode() {
             TypingMode::Coherence => {}
             TypingMode::Analysis { .. }
+            | TypingMode::Borrowck { .. }
             | TypingMode::PostBorrowckAnalysis { .. }
             | TypingMode::PostAnalysis => return Ok(()),
         }
@@ -1491,7 +1492,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             // However, if we disqualify *all* goals from being cached, perf suffers.
             // This is likely fixed by better caching in general in the new solver.
             // See: <https://github.com/rust-lang/rust/issues/132064>.
-            TypingMode::Analysis { defining_opaque_types } => {
+            TypingMode::Analysis { defining_opaque_types }
+            | TypingMode::Borrowck { defining_opaque_types } => {
                 defining_opaque_types.is_empty() || !pred.has_opaque_types()
             }
             // The hidden types of `defined_opaque_types` is not local to the current
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index 962e1353ebc..66c18bed5e7 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -149,6 +149,7 @@ fn resolve_associated_item<'tcx>(
                 match typing_env.typing_mode {
                     ty::TypingMode::Coherence
                     | ty::TypingMode::Analysis { .. }
+                    | ty::TypingMode::Borrowck { .. }
                     | ty::TypingMode::PostBorrowckAnalysis { .. } => false,
                     ty::TypingMode::PostAnalysis => !trait_ref.still_further_specializable(),
                 }
diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs
index e512e8fc838..fec6e24e2cb 100644
--- a/compiler/rustc_type_ir/src/infer_ctxt.rs
+++ b/compiler/rustc_type_ir/src/infer_ctxt.rs
@@ -66,6 +66,14 @@ pub enum TypingMode<I: Interner> {
     /// }
     /// ```
     Analysis { defining_opaque_types: I::DefiningOpaqueTypes },
+    /// The behavior during MIR borrowck is identical to `TypingMode::Analysis`
+    /// except that the initial value for opaque types is the type computed during
+    /// HIR typeck with unique unconstrained region inference variables.
+    ///
+    /// This is currently only used with by the new solver as it results in new
+    /// non-universal defining uses of opaque types, which is a breaking change.
+    /// See tests/ui/impl-trait/non-defining-use/as-projection-term.rs.
+    Borrowck { defining_opaque_types: I::DefiningOpaqueTypes },
     /// Any analysis after borrowck for a given body should be able to use all the
     /// hidden types defined by borrowck, without being able to define any new ones.
     ///
@@ -95,6 +103,10 @@ impl<I: Interner> TypingMode<I> {
         TypingMode::Analysis { defining_opaque_types: cx.opaque_types_defined_by(body_def_id) }
     }
 
+    pub fn borrowck(cx: I, body_def_id: I::LocalDefId) -> TypingMode<I> {
+        TypingMode::Borrowck { defining_opaque_types: cx.opaque_types_defined_by(body_def_id) }
+    }
+
     pub fn post_borrowck_analysis(cx: I, body_def_id: I::LocalDefId) -> TypingMode<I> {
         TypingMode::PostBorrowckAnalysis {
             defined_opaque_types: cx.opaque_types_defined_by(body_def_id),
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index 8f86270d7dc..44b260ddd3a 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -149,6 +149,8 @@ pub trait Interner:
     ) -> Option<Self::VariancesOf>;
 
     fn type_of(self, def_id: Self::DefId) -> ty::EarlyBinder<Self, Self::Ty>;
+    fn type_of_opaque_hir_typeck(self, def_id: Self::LocalDefId)
+    -> ty::EarlyBinder<Self, Self::Ty>;
 
     type AdtDef: AdtDef<Self>;
     fn adt_def(self, adt_def_id: Self::DefId) -> Self::AdtDef;
diff --git a/compiler/rustc_type_ir/src/relate/combine.rs b/compiler/rustc_type_ir/src/relate/combine.rs
index d49f8d3093d..8dd7c4df244 100644
--- a/compiler/rustc_type_ir/src/relate/combine.rs
+++ b/compiler/rustc_type_ir/src/relate/combine.rs
@@ -137,6 +137,7 @@ where
                     Ok(a)
                 }
                 TypingMode::Analysis { .. }
+                | TypingMode::Borrowck { .. }
                 | TypingMode::PostBorrowckAnalysis { .. }
                 | TypingMode::PostAnalysis => structurally_relate_tys(relation, a, b),
             }