diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 03bbc9c0a7c9b..2fc1f1ab01d27 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1063,6 +1063,70 @@ fn lower_fn_sig_recovering_infer_ret_ty<'tcx>( ) } +/// Convert `ReLateParam`s in `value` back into `ReBound`s and bind it with `bound_vars`. +fn late_param_regions_to_bound<'tcx, T>( + tcx: TyCtxt<'tcx>, + scope: DefId, + bound_vars: &'tcx ty::List>, + value: T, +) -> ty::Binder<'tcx, T> +where + T: ty::TypeFoldable>, +{ + let value = fold_regions(tcx, value, |r, debruijn| match r.kind() { + ty::ReLateParam(lp) => { + // Should be in scope, otherwise inconsistency happens somewhere. + assert_eq!(lp.scope, scope); + + let br = match lp.kind { + // These variants preserve the bound var index. + kind @ (ty::LateParamRegionKind::Anon(idx) + | ty::LateParamRegionKind::NamedAnon(idx, _)) => { + let idx = idx as usize; + let var = ty::BoundVar::from_usize(idx); + + let Some(ty::BoundVariableKind::Region(kind)) = bound_vars.get(idx).copied() + else { + bug!("unexpected late-bound region {kind:?} for bound vars {bound_vars:?}"); + }; + + ty::BoundRegion { var, kind } + } + + // For named regions, look up the corresponding bound var. + ty::LateParamRegionKind::Named(def_id) => bound_vars + .iter() + .enumerate() + .find_map(|(idx, bv)| match bv { + ty::BoundVariableKind::Region(kind @ ty::BoundRegionKind::Named(did)) + if did == def_id => + { + Some(ty::BoundRegion { var: ty::BoundVar::from_usize(idx), kind }) + } + _ => None, + }) + .unwrap(), + + ty::LateParamRegionKind::ClosureEnv => bound_vars + .iter() + .enumerate() + .find_map(|(idx, bv)| match bv { + ty::BoundVariableKind::Region(kind @ ty::BoundRegionKind::ClosureEnv) => { + Some(ty::BoundRegion { var: ty::BoundVar::from_usize(idx), kind }) + } + _ => None, + }) + .unwrap(), + }; + + ty::Region::new_bound(tcx, debruijn, br) + } + _ => r, + }); + + ty::Binder::bind_with_vars(value, bound_vars) +} + fn recover_infer_ret_ty<'tcx>( icx: &ItemCtxt<'tcx>, infer_ret_ty: &'tcx hir::Ty<'tcx>, @@ -1138,13 +1202,22 @@ fn recover_infer_ret_ty<'tcx>( ); } let guar = diag.emit(); - ty::Binder::dummy(tcx.mk_fn_sig( + + // If we return a dummy binder here, we can ICE later in borrowck when it encounters + // `ReLateParam` regions (e.g. in a local type annotation) which weren't registered via the + // signature binder. See #135845. + let bound_vars = tcx.late_bound_vars(hir_id); + let scope = def_id.to_def_id(); + + let fn_sig = tcx.mk_fn_sig( fn_sig.inputs().iter().copied(), recovered_ret_ty.unwrap_or_else(|| Ty::new_error(tcx, guar)), fn_sig.c_variadic, fn_sig.safety, fn_sig.abi, - )) + ); + + late_param_regions_to_bound(tcx, scope, bound_vars, fn_sig) } pub fn suggest_impl_trait<'tcx>( diff --git a/tests/crashes/135845.rs b/tests/crashes/135845.rs deleted file mode 100644 index ed038d8a1f187..0000000000000 --- a/tests/crashes/135845.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ known-bug: #135845 -struct S<'a, T: ?Sized>(&'a T); - -fn b<'a>() -> S<'static, _> { - S::<'a>(&0) -} diff --git a/tests/ui/lifetimes/recover-infer-ret-ty-issue-135845.rs b/tests/ui/lifetimes/recover-infer-ret-ty-issue-135845.rs new file mode 100644 index 0000000000000..acce49b1af72f --- /dev/null +++ b/tests/ui/lifetimes/recover-infer-ret-ty-issue-135845.rs @@ -0,0 +1,11 @@ +// Regression test for #135845. + +use std::marker::PhantomData; + +fn b<'a>() -> _ { + //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types [E0121] + let _: PhantomData<&'a ()> = PhantomData; + 0 +} + +fn main() {} diff --git a/tests/ui/lifetimes/recover-infer-ret-ty-issue-135845.stderr b/tests/ui/lifetimes/recover-infer-ret-ty-issue-135845.stderr new file mode 100644 index 0000000000000..9f3695e88f828 --- /dev/null +++ b/tests/ui/lifetimes/recover-infer-ret-ty-issue-135845.stderr @@ -0,0 +1,15 @@ +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types + --> $DIR/recover-infer-ret-ty-issue-135845.rs:5:15 + | +LL | fn b<'a>() -> _ { + | ^ not allowed in type signatures + | +help: replace with the correct return type + | +LL - fn b<'a>() -> _ { +LL + fn b<'a>() -> i32 { + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0121`.