From 390246c8e11a28f2087ac25cc419300f03bde693 Mon Sep 17 00:00:00 2001 From: Boxy Date: Sun, 26 Feb 2023 20:49:08 +0000 Subject: [PATCH] use `ObligationCtxt` not `QueryNormalizer` --- .../src/traits/query/normalize.rs | 12 ++--- src/librustdoc/clean/mod.rs | 50 ++++++++++++++----- 2 files changed, 41 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 a986a9b6a71b1..af6c4049029a6 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -284,14 +284,10 @@ impl<'cx, 'tcx> FallibleTypeFolder> for QueryNormalizer<'cx, 'tcx> let result = tcx.normalize_projection_ty(c_data)?; // 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 } = diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 2d247bd537bdf..191f89ebe0583 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1666,22 +1666,46 @@ 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`: {:?} has pre existing infer vars before `InferCtxt` creation", + ty + ); + 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 {:?} to {:?}", ty, 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 {:?} did not make progress", ty); + None + } + [] => { + debug!("normalized {:?} to {:?}", ty, 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 } }