From db3c9b640e8adabbee20e212f9ebb473513bad8b Mon Sep 17 00:00:00 2001 From: jackh726 Date: Tue, 30 Sep 2025 04:32:19 +0000 Subject: [PATCH 1/7] When computing opaque types in the next solver, take an initial pass pre-fallback where we equate hidden types but do not report errors --- compiler/rustc_hir_typeck/src/lib.rs | 6 ++ compiler/rustc_hir_typeck/src/opaque_types.rs | 57 ++++++++++++++++--- .../hidden-types-equate-before-fallback.rs | 27 +++++++++ 3 files changed, 83 insertions(+), 7 deletions(-) create mode 100644 tests/ui/traits/next-solver/opaques/hidden-types-equate-before-fallback.rs diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 9f5a85b692642..a615ac9d912dd 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -219,6 +219,12 @@ fn typeck_with_inspect<'tcx>( // the future. fcx.check_repeat_exprs(); + // We need to handle opaque types before emitting ambiguity errors as applying + // defining uses may guide type inference. + if fcx.next_trait_solver() { + fcx.try_handle_opaque_type_uses_next(); + } + fcx.type_inference_fallback(); // Even though coercion casts provide type hints, we check casts after fallback for diff --git a/compiler/rustc_hir_typeck/src/opaque_types.rs b/compiler/rustc_hir_typeck/src/opaque_types.rs index 4c1fe69405e91..9b5f26cefff79 100644 --- a/compiler/rustc_hir_typeck/src/opaque_types.rs +++ b/compiler/rustc_hir_typeck/src/opaque_types.rs @@ -22,6 +22,29 @@ impl<'tcx> FnCtxt<'_, 'tcx> { /// inference variables. /// /// It then uses these defining uses to guide inference for all other uses. + /// + /// Unlike `handle_opaque_type_uses_next`, this does not report errors. + pub(super) fn try_handle_opaque_type_uses_next(&mut self) { + // We clone the opaques instead of stealing them here as they are still used for + // normalization in the next generation trait solver. + let mut opaque_types: Vec<_> = self.infcx.clone_opaque_types(); + for entry in &mut opaque_types { + *entry = self.resolve_vars_if_possible(*entry); + } + debug!(?opaque_types); + + self.compute_definition_site_hidden_types(&opaque_types, true); + self.apply_definition_site_hidden_types(&opaque_types); + } + + /// This takes all the opaque type uses during HIR typeck. It first computes + /// the concrete hidden type by iterating over all defining uses. + /// + /// A use during HIR typeck is defining if all non-lifetime arguments are + /// unique generic parameters and the hidden type does not reference any + /// inference variables. + /// + /// It then uses these defining uses to guide inference for all other uses. #[instrument(level = "debug", skip(self))] pub(super) fn handle_opaque_type_uses_next(&mut self) { // We clone the opaques instead of stealing them here as they are still used for @@ -35,7 +58,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { } debug!(?opaque_types); - self.compute_definition_site_hidden_types(&opaque_types); + self.compute_definition_site_hidden_types(&opaque_types, false); self.apply_definition_site_hidden_types(&opaque_types); } } @@ -74,6 +97,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { fn compute_definition_site_hidden_types( &mut self, opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)], + first_pass: bool, ) { let tcx = self.tcx; let TypingMode::Analysis { defining_opaque_types_and_generators } = self.typing_mode() @@ -94,12 +118,22 @@ impl<'tcx> FnCtxt<'_, 'tcx> { continue; } - usage_kind.merge(self.consider_opaque_type_use(opaque_type_key, hidden_type)); + usage_kind.merge(self.consider_opaque_type_use( + opaque_type_key, + hidden_type, + first_pass, + )); if let UsageKind::HasDefiningUse = usage_kind { break; } } + // If this the first pass (`try_handle_opaque_type_uses_next`), + // then do not report any errors. + if first_pass { + continue; + } + let guar = match usage_kind { UsageKind::None => { if let Some(guar) = self.tainted_by_errors() { @@ -152,6 +186,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { &mut self, opaque_type_key: OpaqueTypeKey<'tcx>, hidden_type: OpaqueHiddenType<'tcx>, + first_pass: bool, ) -> UsageKind<'tcx> { if let Err(err) = opaque_type_has_defining_use_args( &self, @@ -199,7 +234,13 @@ impl<'tcx> FnCtxt<'_, 'tcx> { .borrow_mut() .hidden_types .insert(opaque_type_key.def_id, hidden_type); - assert!(prev.is_none()); + + // We do want to insert opaque types the first pass, because we want to + // equate them. So, the second pass (where we report errors) will have + // a hidden type inserted. + if first_pass { + assert!(prev.is_none()); + } UsageKind::HasDefiningUse } @@ -209,10 +250,12 @@ impl<'tcx> FnCtxt<'_, 'tcx> { ) { let tcx = self.tcx; for &(key, hidden_type) in opaque_types { - let expected = *self.typeck_results.borrow_mut().hidden_types.get(&key.def_id).unwrap(); - - let expected = EarlyBinder::bind(expected.ty).instantiate(tcx, key.args); - self.demand_eqtype(hidden_type.span, expected, hidden_type.ty); + // On the first pass to this function, some opaque types may not + // have a hidden type assigned. + if let Some(expected) = self.typeck_results.borrow_mut().hidden_types.get(&key.def_id) { + let expected = EarlyBinder::bind(expected.ty).instantiate(tcx, key.args); + self.demand_eqtype(hidden_type.span, expected, hidden_type.ty); + } } } diff --git a/tests/ui/traits/next-solver/opaques/hidden-types-equate-before-fallback.rs b/tests/ui/traits/next-solver/opaques/hidden-types-equate-before-fallback.rs new file mode 100644 index 0000000000000..9fdeecfa1a530 --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/hidden-types-equate-before-fallback.rs @@ -0,0 +1,27 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ check-pass + +// Regression test for trait-system-refactor-initiative#240. Hidden types should +// equate *before* inference var fallback, otherwise we can get mismatched types. + + +#[derive(Clone, Copy)] +struct FileSystem; +impl FileSystem { + fn build(self, commands: T) -> Option { + match false { + true => Some(commands), + false => { + drop(match self.build::<_>(commands) { + Some(x) => x, + None => return None, + }); + panic!() + }, + } + } +} + +fn main() {} From 9a5cef155f5bc337563bdd09ad2f6ea0c8c2f1c7 Mon Sep 17 00:00:00 2001 From: jackh726 Date: Wed, 1 Oct 2025 22:51:17 +0000 Subject: [PATCH 2/7] Cleanup opaque_type computation a bit --- compiler/rustc_hir_typeck/src/opaque_types.rs | 103 ++++++++++-------- 1 file changed, 56 insertions(+), 47 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/opaque_types.rs b/compiler/rustc_hir_typeck/src/opaque_types.rs index 9b5f26cefff79..0c8edbac4f2b5 100644 --- a/compiler/rustc_hir_typeck/src/opaque_types.rs +++ b/compiler/rustc_hir_typeck/src/opaque_types.rs @@ -4,6 +4,7 @@ use rustc_middle::ty::{ self, DefiningScopeKind, EarlyBinder, OpaqueHiddenType, OpaqueTypeKey, TypeVisitableExt, TypingMode, }; +use rustc_span::ErrorGuaranteed; use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded; use rustc_trait_selection::opaque_types::{ NonDefiningUseReason, opaque_type_has_defining_use_args, report_item_does_not_constrain_error, @@ -24,6 +25,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { /// It then uses these defining uses to guide inference for all other uses. /// /// Unlike `handle_opaque_type_uses_next`, this does not report errors. + #[instrument(level = "debug", skip(self))] pub(super) fn try_handle_opaque_type_uses_next(&mut self) { // We clone the opaques instead of stealing them here as they are still used for // normalization in the next generation trait solver. @@ -34,7 +36,6 @@ impl<'tcx> FnCtxt<'_, 'tcx> { debug!(?opaque_types); self.compute_definition_site_hidden_types(&opaque_types, true); - self.apply_definition_site_hidden_types(&opaque_types); } /// This takes all the opaque type uses during HIR typeck. It first computes @@ -59,22 +60,29 @@ impl<'tcx> FnCtxt<'_, 'tcx> { debug!(?opaque_types); self.compute_definition_site_hidden_types(&opaque_types, false); - self.apply_definition_site_hidden_types(&opaque_types); } } +#[derive(Copy, Clone, Debug)] enum UsageKind<'tcx> { None, NonDefiningUse(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>), UnconstrainedHiddenType(OpaqueHiddenType<'tcx>), - HasDefiningUse, + HasDefiningUse(OpaqueHiddenType<'tcx>), + // `type_of_opaque_hir_typeck` reported an error + HasError(ErrorGuaranteed), } impl<'tcx> UsageKind<'tcx> { fn merge(&mut self, other: UsageKind<'tcx>) { match (&*self, &other) { - (UsageKind::HasDefiningUse, _) | (_, UsageKind::None) => unreachable!(), + (UsageKind::HasDefiningUse(_), _) | (_, UsageKind::None) => unreachable!(), (UsageKind::None, _) => *self = other, + // If `type_of_opaque_hir_typeck` reported an error, then the hidden + // type is an error, but we also want to still report errors for + // remaining hidden types (really just normalization errors). + (UsageKind::HasError(_), _) => {} + (_, UsageKind::HasError(_)) => *self = other, // When mergining non-defining uses, prefer earlier ones. This means // the error happens as early as possible. ( @@ -87,7 +95,7 @@ impl<'tcx> UsageKind<'tcx> { // intended to be defining. ( UsageKind::NonDefiningUse(..) | UsageKind::UnconstrainedHiddenType(..), - UsageKind::UnconstrainedHiddenType(..) | UsageKind::HasDefiningUse, + UsageKind::UnconstrainedHiddenType(..) | UsageKind::HasDefiningUse(_), ) => *self = other, } } @@ -112,22 +120,55 @@ impl<'tcx> FnCtxt<'_, 'tcx> { _ => unreachable!("not opaque or generator: {def_id:?}"), } + // We do actually need to check this the second pass (we can't just + // store this), because we can go from `UnconstrainedHiddenType` to + // `HasDefiningUse` (because of fallback) let mut usage_kind = UsageKind::None; for &(opaque_type_key, hidden_type) in opaque_types { if opaque_type_key.def_id != def_id { continue; } - usage_kind.merge(self.consider_opaque_type_use( - opaque_type_key, - hidden_type, - first_pass, - )); - if let UsageKind::HasDefiningUse = usage_kind { + usage_kind.merge(self.consider_opaque_type_use(opaque_type_key, hidden_type)); + + if let UsageKind::HasDefiningUse(..) = usage_kind { break; } } + if let UsageKind::HasDefiningUse(first_use) = usage_kind { + for &(opaque_type_key, hidden_type) in opaque_types { + if opaque_type_key.def_id != def_id { + continue; + } + + let expected = + EarlyBinder::bind(first_use.ty).instantiate(tcx, opaque_type_key.args); + self.demand_eqtype(hidden_type.span, expected, hidden_type.ty); + } + } + + match usage_kind { + UsageKind::HasDefiningUse(hidden_type) => { + let prev = + self.typeck_results.borrow_mut().hidden_types.insert(def_id, hidden_type); + + // We do want to insert opaque types the first pass, because + // we want to equate them. So, the second pass (where we + // report errors) may have a hidden type inserted. + if first_pass { + assert!(prev.is_none()); + } + } + UsageKind::HasError(guar) => { + self.typeck_results + .borrow_mut() + .hidden_types + .insert(def_id, OpaqueHiddenType::new_error(self.tcx, guar)); + } + _ => {} + } + // If this the first pass (`try_handle_opaque_type_uses_next`), // then do not report any errors. if first_pass { @@ -135,6 +176,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { } let guar = match usage_kind { + UsageKind::HasDefiningUse(_) | UsageKind::HasError(_) => continue, UsageKind::None => { if let Some(guar) = self.tainted_by_errors() { guar @@ -171,7 +213,6 @@ impl<'tcx> FnCtxt<'_, 'tcx> { .emit() } } - UsageKind::HasDefiningUse => continue, }; self.typeck_results @@ -182,11 +223,11 @@ impl<'tcx> FnCtxt<'_, 'tcx> { } } + #[tracing::instrument(skip(self), ret)] fn consider_opaque_type_use( &mut self, opaque_type_key: OpaqueTypeKey<'tcx>, hidden_type: OpaqueHiddenType<'tcx>, - first_pass: bool, ) -> UsageKind<'tcx> { if let Err(err) = opaque_type_has_defining_use_args( &self, @@ -196,11 +237,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { ) { match err { NonDefiningUseReason::Tainted(guar) => { - self.typeck_results.borrow_mut().hidden_types.insert( - opaque_type_key.def_id, - OpaqueHiddenType::new_error(self.tcx, guar), - ); - return UsageKind::HasDefiningUse; + return UsageKind::HasError(guar); } _ => return UsageKind::NonDefiningUse(opaque_type_key, hidden_type), }; @@ -228,35 +265,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { self.tcx, DefiningScopeKind::HirTypeck, ); - - let prev = self - .typeck_results - .borrow_mut() - .hidden_types - .insert(opaque_type_key.def_id, hidden_type); - - // We do want to insert opaque types the first pass, because we want to - // equate them. So, the second pass (where we report errors) will have - // a hidden type inserted. - if first_pass { - assert!(prev.is_none()); - } - UsageKind::HasDefiningUse - } - - fn apply_definition_site_hidden_types( - &mut self, - opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)], - ) { - let tcx = self.tcx; - for &(key, hidden_type) in opaque_types { - // On the first pass to this function, some opaque types may not - // have a hidden type assigned. - if let Some(expected) = self.typeck_results.borrow_mut().hidden_types.get(&key.def_id) { - let expected = EarlyBinder::bind(expected.ty).instantiate(tcx, key.args); - self.demand_eqtype(hidden_type.span, expected, hidden_type.ty); - } - } + UsageKind::HasDefiningUse(hidden_type) } /// We may in theory add further uses of an opaque after cloning the opaque From c6c58e3fff86747f8d8d67d2f83541099465ca88 Mon Sep 17 00:00:00 2001 From: jackh726 Date: Wed, 1 Oct 2025 23:03:14 +0000 Subject: [PATCH 3/7] Remove UsageKind::HasError --- compiler/rustc_hir_typeck/src/opaque_types.rs | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/opaque_types.rs b/compiler/rustc_hir_typeck/src/opaque_types.rs index 0c8edbac4f2b5..8731a16da5027 100644 --- a/compiler/rustc_hir_typeck/src/opaque_types.rs +++ b/compiler/rustc_hir_typeck/src/opaque_types.rs @@ -4,7 +4,6 @@ use rustc_middle::ty::{ self, DefiningScopeKind, EarlyBinder, OpaqueHiddenType, OpaqueTypeKey, TypeVisitableExt, TypingMode, }; -use rustc_span::ErrorGuaranteed; use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded; use rustc_trait_selection::opaque_types::{ NonDefiningUseReason, opaque_type_has_defining_use_args, report_item_does_not_constrain_error, @@ -69,8 +68,6 @@ enum UsageKind<'tcx> { NonDefiningUse(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>), UnconstrainedHiddenType(OpaqueHiddenType<'tcx>), HasDefiningUse(OpaqueHiddenType<'tcx>), - // `type_of_opaque_hir_typeck` reported an error - HasError(ErrorGuaranteed), } impl<'tcx> UsageKind<'tcx> { @@ -78,11 +75,6 @@ impl<'tcx> UsageKind<'tcx> { match (&*self, &other) { (UsageKind::HasDefiningUse(_), _) | (_, UsageKind::None) => unreachable!(), (UsageKind::None, _) => *self = other, - // If `type_of_opaque_hir_typeck` reported an error, then the hidden - // type is an error, but we also want to still report errors for - // remaining hidden types (really just normalization errors). - (UsageKind::HasError(_), _) => {} - (_, UsageKind::HasError(_)) => *self = other, // When mergining non-defining uses, prefer earlier ones. This means // the error happens as early as possible. ( @@ -160,12 +152,6 @@ impl<'tcx> FnCtxt<'_, 'tcx> { assert!(prev.is_none()); } } - UsageKind::HasError(guar) => { - self.typeck_results - .borrow_mut() - .hidden_types - .insert(def_id, OpaqueHiddenType::new_error(self.tcx, guar)); - } _ => {} } @@ -176,7 +162,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { } let guar = match usage_kind { - UsageKind::HasDefiningUse(_) | UsageKind::HasError(_) => continue, + UsageKind::HasDefiningUse(_) => continue, UsageKind::None => { if let Some(guar) = self.tainted_by_errors() { guar @@ -237,7 +223,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { ) { match err { NonDefiningUseReason::Tainted(guar) => { - return UsageKind::HasError(guar); + return UsageKind::HasDefiningUse(OpaqueHiddenType::new_error(self.tcx, guar)); } _ => return UsageKind::NonDefiningUse(opaque_type_key, hidden_type), }; From a3fbae599c756c80c9ff42f83afbed65d06fe8c6 Mon Sep 17 00:00:00 2001 From: jackh726 Date: Wed, 1 Oct 2025 23:07:10 +0000 Subject: [PATCH 4/7] Merge match and if --- compiler/rustc_hir_typeck/src/opaque_types.rs | 23 +++++++------------ .../hidden-types-equate-before-fallback.rs | 1 - 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/opaque_types.rs b/compiler/rustc_hir_typeck/src/opaque_types.rs index 8731a16da5027..9d0e6d5abe181 100644 --- a/compiler/rustc_hir_typeck/src/opaque_types.rs +++ b/compiler/rustc_hir_typeck/src/opaque_types.rs @@ -128,31 +128,24 @@ impl<'tcx> FnCtxt<'_, 'tcx> { } } - if let UsageKind::HasDefiningUse(first_use) = usage_kind { + if let UsageKind::HasDefiningUse(ty) = usage_kind { for &(opaque_type_key, hidden_type) in opaque_types { if opaque_type_key.def_id != def_id { continue; } - let expected = - EarlyBinder::bind(first_use.ty).instantiate(tcx, opaque_type_key.args); + let expected = EarlyBinder::bind(ty.ty).instantiate(tcx, opaque_type_key.args); self.demand_eqtype(hidden_type.span, expected, hidden_type.ty); } - } - match usage_kind { - UsageKind::HasDefiningUse(hidden_type) => { - let prev = - self.typeck_results.borrow_mut().hidden_types.insert(def_id, hidden_type); + let prev = self.typeck_results.borrow_mut().hidden_types.insert(def_id, ty); - // We do want to insert opaque types the first pass, because - // we want to equate them. So, the second pass (where we - // report errors) may have a hidden type inserted. - if first_pass { - assert!(prev.is_none()); - } + // We do want to insert opaque types the first pass, because + // we want to equate them. So, the second pass (where we + // report errors) may have a hidden type inserted. + if first_pass { + assert!(prev.is_none()); } - _ => {} } // If this the first pass (`try_handle_opaque_type_uses_next`), diff --git a/tests/ui/traits/next-solver/opaques/hidden-types-equate-before-fallback.rs b/tests/ui/traits/next-solver/opaques/hidden-types-equate-before-fallback.rs index 9fdeecfa1a530..dd5ff26da4f7f 100644 --- a/tests/ui/traits/next-solver/opaques/hidden-types-equate-before-fallback.rs +++ b/tests/ui/traits/next-solver/opaques/hidden-types-equate-before-fallback.rs @@ -6,7 +6,6 @@ // Regression test for trait-system-refactor-initiative#240. Hidden types should // equate *before* inference var fallback, otherwise we can get mismatched types. - #[derive(Clone, Copy)] struct FileSystem; impl FileSystem { From 283ad6699cb806f6b5d38efc13a40dbd9a3321ca Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Fri, 3 Oct 2025 16:56:33 -0400 Subject: [PATCH 5/7] Fix comment, change first_pass to error_on_missing_defining_use, remove the assert in favor over a comment, and change to & for &mut --- compiler/rustc_hir_typeck/src/opaque_types.rs | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/opaque_types.rs b/compiler/rustc_hir_typeck/src/opaque_types.rs index 9d0e6d5abe181..a46e1a5f75fa7 100644 --- a/compiler/rustc_hir_typeck/src/opaque_types.rs +++ b/compiler/rustc_hir_typeck/src/opaque_types.rs @@ -26,15 +26,15 @@ impl<'tcx> FnCtxt<'_, 'tcx> { /// Unlike `handle_opaque_type_uses_next`, this does not report errors. #[instrument(level = "debug", skip(self))] pub(super) fn try_handle_opaque_type_uses_next(&mut self) { - // We clone the opaques instead of stealing them here as they are still used for - // normalization in the next generation trait solver. + // We clone the opaques instead of stealing them here as we still need + // to use them after fallback. let mut opaque_types: Vec<_> = self.infcx.clone_opaque_types(); for entry in &mut opaque_types { *entry = self.resolve_vars_if_possible(*entry); } debug!(?opaque_types); - self.compute_definition_site_hidden_types(&opaque_types, true); + self.compute_definition_site_hidden_types(&opaque_types, false); } /// This takes all the opaque type uses during HIR typeck. It first computes @@ -58,7 +58,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { } debug!(?opaque_types); - self.compute_definition_site_hidden_types(&opaque_types, false); + self.compute_definition_site_hidden_types(&opaque_types, true); } } @@ -97,7 +97,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { fn compute_definition_site_hidden_types( &mut self, opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)], - first_pass: bool, + error_on_missing_defining_use: bool, ) { let tcx = self.tcx; let TypingMode::Analysis { defining_opaque_types_and_generators } = self.typing_mode() @@ -138,19 +138,16 @@ impl<'tcx> FnCtxt<'_, 'tcx> { self.demand_eqtype(hidden_type.span, expected, hidden_type.ty); } - let prev = self.typeck_results.borrow_mut().hidden_types.insert(def_id, ty); - - // We do want to insert opaque types the first pass, because - // we want to equate them. So, the second pass (where we - // report errors) may have a hidden type inserted. - if first_pass { - assert!(prev.is_none()); - } + // Being explicit here: it may be possible that we in a + // previous call to this function we did an insert, but this + // should be just fine, since they all get equated anyways and + // we shouldn't ever go from `HasDefiningUse` to anyway else. + let _ = self.typeck_results.borrow_mut().hidden_types.insert(def_id, ty); } // If this the first pass (`try_handle_opaque_type_uses_next`), // then do not report any errors. - if first_pass { + if !error_on_missing_defining_use { continue; } @@ -204,7 +201,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { #[tracing::instrument(skip(self), ret)] fn consider_opaque_type_use( - &mut self, + &self, opaque_type_key: OpaqueTypeKey<'tcx>, hidden_type: OpaqueHiddenType<'tcx>, ) -> UsageKind<'tcx> { From 8b178272c7f7c9df3e2b49d740614c3497de2fb8 Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Sun, 5 Oct 2025 00:50:19 -0400 Subject: [PATCH 6/7] Remove unneeded get_hidden_type --- .../src/region_infer/opaque_types/mod.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) 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 8d89f3e0d8700..fe9f9a37b862c 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs @@ -155,13 +155,6 @@ fn add_hidden_type<'tcx>( } } -fn get_hidden_type<'tcx>( - hidden_types: &DefinitionSiteHiddenTypes<'tcx>, - def_id: LocalDefId, -) -> Option>> { - hidden_types.0.get(&def_id).map(|ty| EarlyBinder::bind(*ty)) -} - #[derive(Debug)] struct DefiningUse<'tcx> { /// The opaque type using non NLL vars. This uses the actual @@ -501,7 +494,8 @@ pub(crate) fn apply_definition_site_hidden_types<'tcx>( let tcx = infcx.tcx; let mut errors = Vec::new(); for &(key, hidden_type) in opaque_types { - let Some(expected) = get_hidden_type(hidden_types, key.def_id) else { + let Some(expected) = hidden_types.0.get(&key.def_id).map(|ty| EarlyBinder::bind(*ty)) + else { if !tcx.use_typing_mode_borrowck() { if let ty::Alias(ty::Opaque, alias_ty) = hidden_type.ty.kind() && alias_ty.def_id == key.def_id.to_def_id() From d51f09e5ba425183bef648abecce13c5ac9cdb8b Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Sun, 12 Oct 2025 13:17:02 -0400 Subject: [PATCH 7/7] Review comments. Move resolve_vars_if_possible into fn and add test minimizations. Update comment and test. --- compiler/rustc_hir_typeck/src/opaque_types.rs | 31 +++++++++---------- .../hidden-types-equate-before-fallback.rs | 18 +++++++++++ 2 files changed, 32 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/opaque_types.rs b/compiler/rustc_hir_typeck/src/opaque_types.rs index a46e1a5f75fa7..05b5b1a8af803 100644 --- a/compiler/rustc_hir_typeck/src/opaque_types.rs +++ b/compiler/rustc_hir_typeck/src/opaque_types.rs @@ -28,13 +28,9 @@ impl<'tcx> FnCtxt<'_, 'tcx> { pub(super) fn try_handle_opaque_type_uses_next(&mut self) { // We clone the opaques instead of stealing them here as we still need // to use them after fallback. - let mut opaque_types: Vec<_> = self.infcx.clone_opaque_types(); - for entry in &mut opaque_types { - *entry = self.resolve_vars_if_possible(*entry); - } - debug!(?opaque_types); + let opaque_types: Vec<_> = self.infcx.clone_opaque_types(); - self.compute_definition_site_hidden_types(&opaque_types, false); + self.compute_definition_site_hidden_types(opaque_types, false); } /// This takes all the opaque type uses during HIR typeck. It first computes @@ -49,16 +45,12 @@ impl<'tcx> FnCtxt<'_, 'tcx> { pub(super) fn handle_opaque_type_uses_next(&mut self) { // We clone the opaques instead of stealing them here as they are still used for // normalization in the next generation trait solver. - let mut opaque_types: Vec<_> = self.infcx.clone_opaque_types(); + let opaque_types: Vec<_> = self.infcx.clone_opaque_types(); let num_entries = self.inner.borrow_mut().opaque_types().num_entries(); let prev = self.checked_opaque_types_storage_entries.replace(Some(num_entries)); debug_assert_eq!(prev, None); - for entry in &mut opaque_types { - *entry = self.resolve_vars_if_possible(*entry); - } - debug!(?opaque_types); - self.compute_definition_site_hidden_types(&opaque_types, true); + self.compute_definition_site_hidden_types(opaque_types, true); } } @@ -96,9 +88,14 @@ impl<'tcx> UsageKind<'tcx> { impl<'tcx> FnCtxt<'_, 'tcx> { fn compute_definition_site_hidden_types( &mut self, - opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)], + mut opaque_types: Vec<(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)>, error_on_missing_defining_use: bool, ) { + for entry in opaque_types.iter_mut() { + *entry = self.resolve_vars_if_possible(*entry); + } + debug!(?opaque_types); + let tcx = self.tcx; let TypingMode::Analysis { defining_opaque_types_and_generators } = self.typing_mode() else { @@ -116,7 +113,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { // store this), because we can go from `UnconstrainedHiddenType` to // `HasDefiningUse` (because of fallback) let mut usage_kind = UsageKind::None; - for &(opaque_type_key, hidden_type) in opaque_types { + for &(opaque_type_key, hidden_type) in &opaque_types { if opaque_type_key.def_id != def_id { continue; } @@ -129,7 +126,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { } if let UsageKind::HasDefiningUse(ty) = usage_kind { - for &(opaque_type_key, hidden_type) in opaque_types { + for &(opaque_type_key, hidden_type) in &opaque_types { if opaque_type_key.def_id != def_id { continue; } @@ -145,8 +142,8 @@ impl<'tcx> FnCtxt<'_, 'tcx> { let _ = self.typeck_results.borrow_mut().hidden_types.insert(def_id, ty); } - // If this the first pass (`try_handle_opaque_type_uses_next`), - // then do not report any errors. + // If we're in `fn try_handle_opaque_type_uses_next` then do not + // report any errors. if !error_on_missing_defining_use { continue; } diff --git a/tests/ui/traits/next-solver/opaques/hidden-types-equate-before-fallback.rs b/tests/ui/traits/next-solver/opaques/hidden-types-equate-before-fallback.rs index dd5ff26da4f7f..0bd01e66b02b8 100644 --- a/tests/ui/traits/next-solver/opaques/hidden-types-equate-before-fallback.rs +++ b/tests/ui/traits/next-solver/opaques/hidden-types-equate-before-fallback.rs @@ -23,4 +23,22 @@ impl FileSystem { } } +fn build2() -> impl Sized { + if false { + build2::() + } else { + loop {} + }; + 1u32 +} + +fn build3<'a>() -> impl Sized + use<'a> { + if false { + build3() + } else { + loop {} + }; + 1u32 +} + fn main() {}