@@ -1902,22 +1902,45 @@ fn normalize<'tcx>(
1902
1902
}
1903
1903
1904
1904
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 ;
1906
1906
use rustc_middle:: traits:: ObligationCause ;
1907
1907
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
+
1909
1913
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:?}" ) ;
1921
1944
None
1922
1945
}
1923
1946
}
0 commit comments