@@ -1666,22 +1666,46 @@ fn normalize<'tcx>(
16661666 }
16671667
16681668 use crate :: rustc_trait_selection:: infer:: TyCtxtInferExt ;
1669- use crate :: rustc_trait_selection:: traits:: query :: normalize :: QueryNormalizeExt ;
1669+ use crate :: rustc_trait_selection:: traits:: ObligationCtxt ;
16701670 use rustc_middle:: traits:: ObligationCause ;
16711671
1672- // Try to normalize `<X as Y>::T` to a type
1672+ assert ! (
1673+ !ty. has_non_region_infer( ) ,
1674+ "`ty`: {:?} has pre existing infer vars before `InferCtxt` creation" ,
1675+ ty
1676+ ) ;
1677+
16731678 let infcx = cx. tcx . infer_ctxt ( ) . build ( ) ;
1674- let normalized = infcx
1675- . at ( & ObligationCause :: dummy ( ) , cx. param_env )
1676- . query_normalize ( ty)
1677- . map ( |resolved| infcx. resolve_vars_if_possible ( resolved. value ) ) ;
1678- match normalized {
1679- Ok ( normalized_value) => {
1680- debug ! ( "normalized {:?} to {:?}" , ty, normalized_value) ;
1681- Some ( normalized_value)
1682- }
1683- Err ( err) => {
1684- debug ! ( "failed to normalize {:?}: {:?}" , ty, err) ;
1679+ // use an `ObligationCtxt` as it has a nice API for dealing with returned obligations from normalization
1680+ // and does not expect us to be inside of typeck. It also does not ICE when the projection could not be
1681+ // normalized like some other normalization routines (`QueryNormalizer`, `normalize_erasing_regions`, etc)
1682+ let ocx = ObligationCtxt :: new ( & infcx) ;
1683+
1684+ // Try to normalize `<X as Y>::T` to a type
1685+ let normalized = ocx. normalize ( & ObligationCause :: dummy ( ) , cx. param_env , ty) ;
1686+ // We have to ensure that we deal with nested obligations from attempting to normalize as `ty`
1687+ // normalizing to `normalized` is only the case if the nested obligations hold.
1688+ let errs = ocx. select_all_or_error ( ) ;
1689+ // Evaluating nested obligations might constrain infer vars that were created during normalization
1690+ // so we should resolve any infer vars in `normalized` to their new values.
1691+ let normalized = infcx. resolve_vars_if_possible ( normalized) ;
1692+
1693+ match errs. as_slice ( ) {
1694+ [ ] if normalized == ty => {
1695+ debug ! ( "normalizing {:?} did not make progress" , ty) ;
1696+ None
1697+ }
1698+ [ ] => {
1699+ debug ! ( "normalized {:?} to {:?}" , ty, normalized) ;
1700+
1701+ assert ! (
1702+ !normalized. has_non_region_infer( ) ,
1703+ "`normalized` has infer vars which would escape the `InferCtxt` they were created in"
1704+ ) ;
1705+ Some ( normalized)
1706+ }
1707+ errs => {
1708+ debug ! ( "failed to normalize {:?}: {:?}" , ty, errs) ;
16851709 None
16861710 }
16871711 }
0 commit comments