@@ -1902,22 +1902,45 @@ fn normalize<'tcx>(
19021902 }
19031903
19041904 use crate :: rustc_trait_selection:: infer:: TyCtxtInferExt ;
1905- use crate :: rustc_trait_selection:: traits:: query :: normalize :: QueryNormalizeExt ;
1905+ use crate :: rustc_trait_selection:: traits:: ObligationCtxt ;
19061906 use rustc_middle:: traits:: ObligationCause ;
19071907
1908- // Try to normalize `<X as Y>::T` to a type
1908+ assert ! (
1909+ !ty. has_non_region_infer( ) ,
1910+ "`ty`: {ty:?} has pre existing infer vars before `InferCtxt` creation" ,
1911+ ) ;
1912+
19091913 let infcx = cx. tcx . infer_ctxt ( ) . build ( ) ;
1910- let normalized = infcx
1911- . at ( & ObligationCause :: dummy ( ) , cx. param_env )
1912- . query_normalize ( ty)
1913- . map ( |resolved| infcx. resolve_vars_if_possible ( resolved. value ) ) ;
1914- match normalized {
1915- Ok ( normalized_value) => {
1916- debug ! ( "normalized {ty:?} to {normalized_value:?}" ) ;
1917- Some ( normalized_value)
1918- }
1919- Err ( err) => {
1920- debug ! ( "failed to normalize {ty:?}: {err:?}" ) ;
1914+ // use an `ObligationCtxt` as it has a nice API for dealing with returned obligations from normalization
1915+ // and does not expect us to be inside of typeck. It also does not ICE when the projection could not be
1916+ // normalized like some other normalization routines (`QueryNormalizer`, `normalize_erasing_regions`, etc)
1917+ let ocx = ObligationCtxt :: new ( & infcx) ;
1918+
1919+ // Try to normalize `<X as Y>::T` to a type
1920+ let normalized = ocx. normalize ( & ObligationCause :: dummy ( ) , cx. param_env , ty) ;
1921+ // We have to ensure that we deal with nested obligations from attempting to normalize as `ty`
1922+ // normalizing to `normalized` is only the case if the nested obligations hold.
1923+ let errs = ocx. select_all_or_error ( ) ;
1924+ // Evaluating nested obligations might constrain infer vars that were created during normalization
1925+ // so we should resolve any infer vars in `normalized` to their new values.
1926+ let normalized = infcx. resolve_vars_if_possible ( normalized) ;
1927+
1928+ match errs. as_slice ( ) {
1929+ [ ] if normalized == ty => {
1930+ debug ! ( "normalizing {ty:?} did not make progress" ) ;
1931+ None
1932+ }
1933+ [ ] => {
1934+ debug ! ( "normalized {ty:?} to {normalized:?}" ) ;
1935+
1936+ assert ! (
1937+ !normalized. has_non_region_infer( ) ,
1938+ "`normalized` has infer vars which would escape the `InferCtxt` they were created in"
1939+ ) ;
1940+ Some ( normalized)
1941+ }
1942+ errs => {
1943+ debug ! ( "failed to normalize {ty:?}: {errs:?}" ) ;
19211944 None
19221945 }
19231946 }
0 commit comments