report unconstrained region in hidden types lazily
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs
index 0c4a82f..23ad964 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs
@@ -24,13 +24,13 @@
 use tracing::{debug, instrument};
 
 use super::reverse_sccs::ReverseSccGraph;
-use crate::BorrowckInferCtxt;
 use crate::consumers::RegionInferenceContext;
 use crate::session_diagnostics::LifetimeMismatchOpaqueParam;
 use crate::type_check::canonical::fully_perform_op_raw;
 use crate::type_check::free_region_relations::UniversalRegionRelations;
 use crate::type_check::{Locations, MirTypeckRegionConstraints};
 use crate::universal_regions::{RegionClassification, UniversalRegions};
+use crate::{BorrowckInferCtxt, CollectRegionConstraintsResult};
 
 mod member_constraints;
 mod region_ctxt;
@@ -126,6 +126,31 @@ fn nll_var_to_universal_region<'tcx>(
     }
 }
 
+/// Record info needed to report the same name error later.
+#[derive(Copy, Clone, Debug)]
+pub(crate) struct UnexpectedHiddenRegion<'tcx> {
+    // The def_id of the body where this error occurs.
+    // Needed to handle region vars with their corresponding `infcx`.
+    def_id: LocalDefId,
+    opaque_type_key: OpaqueTypeKey<'tcx>,
+    hidden_type: ProvisionalHiddenType<'tcx>,
+    member_region: Region<'tcx>,
+}
+
+impl<'tcx> UnexpectedHiddenRegion<'tcx> {
+    pub(crate) fn to_error(self) -> (LocalDefId, DeferredOpaqueTypeError<'tcx>) {
+        let UnexpectedHiddenRegion { def_id, opaque_type_key, hidden_type, member_region } = self;
+        (
+            def_id,
+            DeferredOpaqueTypeError::UnexpectedHiddenRegion {
+                opaque_type_key,
+                hidden_type,
+                member_region,
+            },
+        )
+    }
+}
+
 /// Collect all defining uses of opaque types inside of this typeck root. This
 /// expects the hidden type to be mapped to the definition parameters of the opaque
 /// and errors if we end up with distinct hidden types.
@@ -176,11 +201,13 @@ struct DefiningUse<'tcx> {
 /// It also means that this whole function is not really soundness critical as we
 /// recheck all uses of the opaques regardless.
 pub(crate) fn compute_definition_site_hidden_types<'tcx>(
+    def_id: LocalDefId,
     infcx: &BorrowckInferCtxt<'tcx>,
     universal_region_relations: &Frozen<UniversalRegionRelations<'tcx>>,
     constraints: &MirTypeckRegionConstraints<'tcx>,
     location_map: Rc<DenseLocationMap>,
     hidden_types: &mut FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>,
+    unconstrained_hidden_type_errors: &mut Vec<UnexpectedHiddenRegion<'tcx>>,
     opaque_types: &[(OpaqueTypeKey<'tcx>, ProvisionalHiddenType<'tcx>)],
 ) -> Vec<DeferredOpaqueTypeError<'tcx>> {
     let mut errors = Vec::new();
@@ -204,8 +231,10 @@ pub(crate) fn compute_definition_site_hidden_types<'tcx>(
     // up equal to one of their choice regions and compute the actual hidden type of
     // the opaque type definition. This is stored in the `root_cx`.
     compute_definition_site_hidden_types_from_defining_uses(
+        def_id,
         &rcx,
         hidden_types,
+        unconstrained_hidden_type_errors,
         &defining_uses,
         &mut errors,
     );
@@ -274,8 +303,10 @@ fn collect_defining_uses<'tcx>(
 
 #[instrument(level = "debug", skip(rcx, hidden_types, defining_uses, errors))]
 fn compute_definition_site_hidden_types_from_defining_uses<'tcx>(
+    def_id: LocalDefId,
     rcx: &RegionCtxt<'_, 'tcx>,
     hidden_types: &mut FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>,
+    unconstrained_hidden_type_errors: &mut Vec<UnexpectedHiddenRegion<'tcx>>,
     defining_uses: &[DefiningUse<'tcx>],
     errors: &mut Vec<DeferredOpaqueTypeError<'tcx>>,
 ) {
@@ -293,16 +324,29 @@ fn compute_definition_site_hidden_types_from_defining_uses<'tcx>(
                 Ok(hidden_type) => hidden_type,
                 Err(r) => {
                     debug!("UnexpectedHiddenRegion: {:?}", r);
-                    errors.push(DeferredOpaqueTypeError::UnexpectedHiddenRegion {
-                        hidden_type,
-                        opaque_type_key,
-                        member_region: ty::Region::new_var(tcx, r),
-                    });
-                    let guar = tcx.dcx().span_delayed_bug(
-                        hidden_type.span,
-                        "opaque type with non-universal region args",
-                    );
-                    ty::ProvisionalHiddenType::new_error(tcx, guar)
+                    // If we're using the next solver, the unconstrained region may be resolved by a
+                    // fully defining use from another body.
+                    // So we don't generate error eagerly here.
+                    if rcx.infcx.tcx.use_typing_mode_borrowck() {
+                        unconstrained_hidden_type_errors.push(UnexpectedHiddenRegion {
+                            def_id,
+                            hidden_type,
+                            opaque_type_key,
+                            member_region: ty::Region::new_var(tcx, r),
+                        });
+                        continue;
+                    } else {
+                        errors.push(DeferredOpaqueTypeError::UnexpectedHiddenRegion {
+                            hidden_type,
+                            opaque_type_key,
+                            member_region: ty::Region::new_var(tcx, r),
+                        });
+                        let guar = tcx.dcx().span_delayed_bug(
+                            hidden_type.span,
+                            "opaque type with non-universal region args",
+                        );
+                        ty::ProvisionalHiddenType::new_error(tcx, guar)
+                    }
                 }
             };
 
@@ -570,6 +614,40 @@ pub(crate) fn apply_definition_site_hidden_types<'tcx>(
     errors
 }
 
+/// We handle `UnexpectedHiddenRegion` error lazily in the next solver as
+/// there may be a fully defining use in another body.
+///
+/// In case such a defining use does not exist, we register an error here.
+pub(crate) fn handle_unconstrained_hidden_type_errors<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    hidden_types: &mut FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>,
+    unconstrained_hidden_type_errors: &mut Vec<UnexpectedHiddenRegion<'tcx>>,
+    collect_region_constraints_results: &mut FxIndexMap<
+        LocalDefId,
+        CollectRegionConstraintsResult<'tcx>,
+    >,
+) {
+    let mut unconstrained_hidden_type_errors = std::mem::take(unconstrained_hidden_type_errors);
+    unconstrained_hidden_type_errors
+        .retain(|unconstrained| !hidden_types.contains_key(&unconstrained.opaque_type_key.def_id));
+
+    unconstrained_hidden_type_errors.iter().for_each(|t| {
+        tcx.dcx()
+            .span_delayed_bug(t.hidden_type.span, "opaque type with non-universal region args");
+    });
+
+    // `UnexpectedHiddenRegion` error contains region var which only makes sense in the
+    // corresponding `infcx`.
+    // So we need to insert the error to the body where it originates from.
+    for error in unconstrained_hidden_type_errors {
+        let (def_id, error) = error.to_error();
+        let Some(result) = collect_region_constraints_results.get_mut(&def_id) else {
+            unreachable!("the body should depend on opaques type if it has opaque use");
+        };
+        result.deferred_opaque_type_errors.push(error);
+    }
+}
+
 /// In theory `apply_definition_site_hidden_types` could introduce new uses of opaque types.
 /// We do not check these new uses so this could be unsound.
 ///
diff --git a/compiler/rustc_borrowck/src/root_cx.rs b/compiler/rustc_borrowck/src/root_cx.rs
index 4d42055..a082aba 100644
--- a/compiler/rustc_borrowck/src/root_cx.rs
+++ b/compiler/rustc_borrowck/src/root_cx.rs
@@ -12,8 +12,9 @@
 use crate::consumers::BorrowckConsumer;
 use crate::nll::compute_closure_requirements_modulo_opaques;
 use crate::region_infer::opaque_types::{
-    apply_definition_site_hidden_types, clone_and_resolve_opaque_types,
+    UnexpectedHiddenRegion, apply_definition_site_hidden_types, clone_and_resolve_opaque_types,
     compute_definition_site_hidden_types, detect_opaque_types_added_while_handling_opaque_types,
+    handle_unconstrained_hidden_type_errors,
 };
 use crate::type_check::{Locations, constraint_conversion};
 use crate::{
@@ -26,7 +27,12 @@
 pub(super) struct BorrowCheckRootCtxt<'tcx> {
     pub tcx: TyCtxt<'tcx>,
     root_def_id: LocalDefId,
+    /// This contains fully resolved hidden types or `ty::Error`.
     hidden_types: FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>,
+    /// This contains unconstrained regions in hidden types.
+    /// Only used for deferred error reporting. See
+    /// [`crate::region_infer::opaque_types::handle_unconstrained_hidden_type_errors`]
+    unconstrained_hidden_type_errors: Vec<UnexpectedHiddenRegion<'tcx>>,
     /// The region constraints computed by [borrowck_collect_region_constraints]. This uses
     /// an [FxIndexMap] to guarantee that iterating over it visits nested bodies before
     /// their parents.
@@ -49,6 +55,7 @@ pub(super) fn new(
             tcx,
             root_def_id,
             hidden_types: Default::default(),
+            unconstrained_hidden_type_errors: Default::default(),
             collect_region_constraints_results: Default::default(),
             propagated_borrowck_results: Default::default(),
             tainted_by_errors: None,
@@ -84,23 +91,32 @@ pub(super) fn finalize(
 
     fn handle_opaque_type_uses(&mut self) {
         let mut per_body_info = Vec::new();
-        for input in self.collect_region_constraints_results.values_mut() {
+        for (def_id, input) in &mut self.collect_region_constraints_results {
             let (num_entries, opaque_types) = clone_and_resolve_opaque_types(
                 &input.infcx,
                 &input.universal_region_relations,
                 &mut input.constraints,
             );
             input.deferred_opaque_type_errors = compute_definition_site_hidden_types(
+                *def_id,
                 &input.infcx,
                 &input.universal_region_relations,
                 &input.constraints,
                 Rc::clone(&input.location_map),
                 &mut self.hidden_types,
+                &mut self.unconstrained_hidden_type_errors,
                 &opaque_types,
             );
             per_body_info.push((num_entries, opaque_types));
         }
 
+        handle_unconstrained_hidden_type_errors(
+            self.tcx,
+            &mut self.hidden_types,
+            &mut self.unconstrained_hidden_type_errors,
+            &mut self.collect_region_constraints_results,
+        );
+
         for (input, (opaque_types_storage_num_entries, opaque_types)) in
             self.collect_region_constraints_results.values_mut().zip(per_body_info)
         {
diff --git a/tests/ui/traits/next-solver/opaques/eventually-constrained-region.rs b/tests/ui/traits/next-solver/opaques/eventually-constrained-region.rs
new file mode 100644
index 0000000..997bcd6
--- /dev/null
+++ b/tests/ui/traits/next-solver/opaques/eventually-constrained-region.rs
@@ -0,0 +1,21 @@
+//@ check-pass
+//@ compile-flags: -Znext-solver
+
+// Regression test for trait-system-refactor-initiative#264.
+//
+// Some defining uses of opaque types can't constrain captured regions to universals.
+// Previouly, we eagerly report error in this case.
+// Now we report error only if there's no fully defining use from all bodies of the typeck root.
+
+struct Inv<'a>(*mut &'a ());
+
+fn mk_static() -> Inv<'static> { todo!() }
+
+fn guide_closure_sig<'a>(f: impl FnOnce() -> Inv<'a>) {}
+
+fn unconstrained_in_closure() -> impl Sized {
+    guide_closure_sig(|| unconstrained_in_closure());
+    mk_static()
+}
+
+fn main() {}
diff --git a/tests/ui/traits/next-solver/opaques/report-all-unexpected-hidden-errors.rs b/tests/ui/traits/next-solver/opaques/report-all-unexpected-hidden-errors.rs
new file mode 100644
index 0000000..61823c1
--- /dev/null
+++ b/tests/ui/traits/next-solver/opaques/report-all-unexpected-hidden-errors.rs
@@ -0,0 +1,34 @@
+//@ compile-flags: -Znext-solver
+
+// Just for diagnostics completeness.
+// This is probably unimportant as we only report one error for such case in HIR typeck.
+
+#![feature(type_alias_impl_trait)]
+
+struct Invar<'a>(*mut &'a ());
+
+fn mk_invar<'a>(a: &'a i32) -> Invar<'a> {
+    todo!()
+}
+
+type MultiUse = impl Sized;
+
+#[define_opaque(MultiUse)]
+fn capture_different_universals_not_on_bounds<'a, 'b, 'c>(a: &'a i32, b: &'b i32, c: &'c i32)  {
+    let _ = || -> MultiUse {
+        //~^ ERROR: hidden type for `MultiUse` captures lifetime that does not appear in bounds [E0700]
+        mk_invar(a)
+    };
+    let _ = || -> MultiUse {
+        //~^ ERROR: hidden type for `MultiUse` captures lifetime that does not appear in bounds [E0700]
+        mk_invar(b)
+    };
+    let _ = || {
+        let _ = || -> MultiUse {
+            //~^ ERROR: hidden type for `MultiUse` captures lifetime that does not appear in bounds [E0700]
+            mk_invar(c)
+        };
+    };
+}
+
+fn main() {}
diff --git a/tests/ui/traits/next-solver/opaques/report-all-unexpected-hidden-errors.stderr b/tests/ui/traits/next-solver/opaques/report-all-unexpected-hidden-errors.stderr
new file mode 100644
index 0000000..28d9da3
--- /dev/null
+++ b/tests/ui/traits/next-solver/opaques/report-all-unexpected-hidden-errors.stderr
@@ -0,0 +1,36 @@
+error[E0700]: hidden type for `MultiUse` captures lifetime that does not appear in bounds
+  --> $DIR/report-all-unexpected-hidden-errors.rs:18:19
+   |
+LL | type MultiUse = impl Sized;
+   |                 ---------- opaque type defined here
+...
+LL |     let _ = || -> MultiUse {
+   |                   ^^^^^^^^
+   |
+   = note: hidden type `Invar<'_>` captures lifetime `'_`
+
+error[E0700]: hidden type for `MultiUse` captures lifetime that does not appear in bounds
+  --> $DIR/report-all-unexpected-hidden-errors.rs:22:19
+   |
+LL | type MultiUse = impl Sized;
+   |                 ---------- opaque type defined here
+...
+LL |     let _ = || -> MultiUse {
+   |                   ^^^^^^^^
+   |
+   = note: hidden type `Invar<'_>` captures lifetime `'_`
+
+error[E0700]: hidden type for `MultiUse` captures lifetime that does not appear in bounds
+  --> $DIR/report-all-unexpected-hidden-errors.rs:27:23
+   |
+LL | type MultiUse = impl Sized;
+   |                 ---------- opaque type defined here
+...
+LL |         let _ = || -> MultiUse {
+   |                       ^^^^^^^^
+   |
+   = note: hidden type `Invar<'_>` captures lifetime `'_`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0700`.