From 2ccfd041ad3ef69a6b9c5a43370654e993b65a52 Mon Sep 17 00:00:00 2001 From: Boxy Date: Sun, 26 Feb 2023 20:49:08 +0000 Subject: [PATCH 1/2] use `ObligationCtxt` not `QueryNormalizer` --- .../src/traits/query/normalize.rs | 12 ++--- src/librustdoc/clean/mod.rs | 49 ++++++++++++++----- 2 files changed, 40 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index f785211c54861..b3b4a58652711 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -294,14 +294,10 @@ impl<'cx, 'tcx> FallibleTypeFolder> for QueryNormalizer<'cx, 'tcx> }?; // We don't expect ambiguity. if result.is_ambiguous() { - // Rustdoc normalizes possibly not well-formed types, so only - // treat this as a bug if we're not in rustdoc. - if !tcx.sess.opts.actually_rustdoc { - tcx.sess.delay_span_bug( - DUMMY_SP, - format!("unexpected ambiguity: {c_data:?} {result:?}"), - ); - } + tcx.sess.delay_span_bug( + DUMMY_SP, + format!("unexpected ambiguity: {c_data:?} {result:?}"), + ); return Err(NoSolution); } let InferOk { value: result, obligations } = infcx diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 190b1b038b68a..c9ac5053b5eee 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1902,22 +1902,45 @@ fn normalize<'tcx>( } use crate::rustc_trait_selection::infer::TyCtxtInferExt; - use crate::rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; + use crate::rustc_trait_selection::traits::ObligationCtxt; use rustc_middle::traits::ObligationCause; - // Try to normalize `::T` to a type + assert!( + !ty.has_non_region_infer(), + "`ty`: {ty:?} has pre existing infer vars before `InferCtxt` creation", + ); + let infcx = cx.tcx.infer_ctxt().build(); - let normalized = infcx - .at(&ObligationCause::dummy(), cx.param_env) - .query_normalize(ty) - .map(|resolved| infcx.resolve_vars_if_possible(resolved.value)); - match normalized { - Ok(normalized_value) => { - debug!("normalized {ty:?} to {normalized_value:?}"); - Some(normalized_value) - } - Err(err) => { - debug!("failed to normalize {ty:?}: {err:?}"); + // use an `ObligationCtxt` as it has a nice API for dealing with returned obligations from normalization + // and does not expect us to be inside of typeck. It also does not ICE when the projection could not be + // normalized like some other normalization routines (`QueryNormalizer`, `normalize_erasing_regions`, etc) + let ocx = ObligationCtxt::new(&infcx); + + // Try to normalize `::T` to a type + let normalized = ocx.normalize(&ObligationCause::dummy(), cx.param_env, ty); + // We have to ensure that we deal with nested obligations from attempting to normalize as `ty` + // normalizing to `normalized` is only the case if the nested obligations hold. + let errs = ocx.select_all_or_error(); + // Evaluating nested obligations might constrain infer vars that were created during normalization + // so we should resolve any infer vars in `normalized` to their new values. + let normalized = infcx.resolve_vars_if_possible(normalized); + + match errs.as_slice() { + [] if normalized == ty => { + debug!("normalizing {ty:?} did not make progress"); + None + } + [] => { + debug!("normalized {ty:?} to {normalized:?}"); + + assert!( + !normalized.has_non_region_infer(), + "`normalized` has infer vars which would escape the `InferCtxt` they were created in" + ); + Some(normalized) + } + errs => { + debug!("failed to normalize {ty:?}: {errs:?}"); None } } From 1543e6ba42f0039b0af685c63ff07c52584f4923 Mon Sep 17 00:00:00 2001 From: Boxy Date: Thu, 21 Sep 2023 19:18:31 +0100 Subject: [PATCH 2/2] regression test --- tests/rustdoc-ui/normalization_uses_ocx.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 tests/rustdoc-ui/normalization_uses_ocx.rs diff --git a/tests/rustdoc-ui/normalization_uses_ocx.rs b/tests/rustdoc-ui/normalization_uses_ocx.rs new file mode 100644 index 0000000000000..7c7a07ca7a2c8 --- /dev/null +++ b/tests/rustdoc-ui/normalization_uses_ocx.rs @@ -0,0 +1,16 @@ +// check-pass +// compile-flags: -Znormalize-docs +// regression test for #112242 + +trait MyTrait<'a> { + type MyItem; +} +struct Inner(Q); +struct Outer(Inner); + +unsafe impl<'a, Q> Send for Inner +where + Q: MyTrait<'a>, + >::MyItem: Copy, +{ +}