Change:
} } <ins> fn find_opaque_ty_constraints_for_rpit( tcx: TyCtxt<'_>, def_id: LocalDefId, owner_def_id: LocalDefId, ) -> Ty<'_> { use rustc_hir::{Expr, ImplItem, Item, TraitItem}; struct ConstraintChecker<'tcx> { tcx: TyCtxt<'tcx>, /// def_id of the opaque type whose defining uses are being checked def_id: LocalDefId, found: ty::OpaqueHiddenType<'tcx>, } impl ConstraintChecker<'_> { #[instrument(skip(self), level = "debug")] fn check(&self, def_id: LocalDefId) { // Use borrowck to get the type with unerased regions. let concrete_opaque_types = &self.tcx.mir_borrowck(def_id).concrete_opaque_types; debug!(?concrete_opaque_types); for &(def_id, concrete_type) in concrete_opaque_types { if def_id != self.def_id { // Ignore constraints for other opaque types. continue; } debug!(?concrete_type, "found constraint"); if concrete_type.ty != self.found.ty && !(concrete_type, self.found).references_error() { self.found.report_mismatch(&concrete_type, self.tcx); } } } } impl<'tcx> intravisit::Visitor<'tcx> for ConstraintChecker<'tcx> { type NestedFilter = nested_filter::OnlyBodies; fn nested_visit_map(&mut self) -> Self::Map { self.tcx.hir() } fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { if let hir::ExprKind::Closure { .. } = ex.kind { let def_id = self.tcx.hir().local_def_id(ex.hir_id); self.check(def_id); } intravisit::walk_expr(self, ex); } fn visit_item(&mut self, it: &'tcx Item<'tcx>) { trace!(?it.def_id); // The opaque type itself or its children are not within its reveal scope. if it.def_id != self.def_id { self.check(it.def_id); intravisit::walk_item(self, it); } } fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) { trace!(?it.def_id); // The opaque type itself or its children are not within its reveal scope. if it.def_id != self.def_id { self.check(it.def_id); intravisit::walk_impl_item(self, it); } } fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) { trace!(?it.def_id); self.check(it.def_id); intravisit::walk_trait_item(self, it); } } let concrete = tcx.mir_borrowck(owner_def_id).concrete_opaque_types.get(&def_id).copied(); if let Some(concrete) = concrete { let scope = tcx.hir().local_def_id_to_hir_id(owner_def_id); debug!(?scope); let mut locator = ConstraintChecker { def_id: def_id, tcx, found: concrete }; match tcx.hir().get(scope) { Node::Item(it) => intravisit::walk_item(&mut locator, it), Node::ImplItem(it) => intravisit::walk_impl_item(&mut locator, it), Node::TraitItem(it) => intravisit::walk_trait_item(&mut locator, it), other => bug!("{:?} is not a valid scope for an opaque type item", other), } } concrete.map(|concrete| concrete.ty).unwrap_or_else(|| { let table = tcx.typeck(owner_def_id); if let Some(_) = table.tainted_by_errors { // Some error in the // owner fn prevented us from populating // the `concrete_opaque_types` table. tcx.ty_error() } else { table .concrete_opaque_types .get(&def_id) .copied() .unwrap_or_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. Some(tcx.mk_diverging_default()) }) .expect("RPIT always have a hidden type from typeck") } }) } </ins> fn infer_placeholder_type<'a>( tcx: TyCtxt<'a>, def_id: LocalDefId,

Discussion:
Messing around with a Haskell-like implementation of , I encountered two presumably similar ICEs (would think they're the same, but the error messages are obviously different). The other one is . I'm pretty sure this should be an error, based on the reasoning that returns an opaque type, so, while the output of might be , it also might not (and in this case, isn't), and since only accepts s, should be an error. Note that this implementation throws the ICE even without the main method, but I'm leaving it there for contrast to the other ICE. : Same ICE on nightly: <details<summary<strongBacktrace</strong</summary<p</p</details
This regressed in
I was able to "weaponize" this into a transmute, lol: So the issue here is that, at least in the case of RPITs, we are not checking for opaque type mismatches in closures correctly. The closure, in this example, is able to incorrectly constrain even though in the enclosing function, we define . During mir borrowck, we never check these two together, so we never report a type mismatch. I think I have a fix, though.
WG-prioritization assigning priority (). label -I-prioritize +P-critical