11//! Code for the 'normalization' query. This consists of a wrapper
22//! which folds deeply, invoking the underlying
3- //! `normalize_canonicalized_projection_ty ` query when it encounters projections.
3+ //! `normalize_canonicalized_projection ` query when it encounters projections.
44
55use rustc_data_structures:: sso:: SsoHashMap ;
66use rustc_data_structures:: stack:: ensure_sufficient_stack;
7+ use rustc_hir:: def:: DefKind ;
78use rustc_infer:: traits:: PredicateObligations ;
89use rustc_macros:: extension;
910pub use rustc_middle:: traits:: query:: NormalizationResult ;
@@ -253,76 +254,9 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> {
253254 }
254255 }
255256
256- ty:: Projection | ty:: Inherent | ty:: Free => {
257- // See note in `rustc_trait_selection::traits::project`
258-
259- let infcx = self . infcx ;
260- let tcx = infcx. tcx ;
261- // Just an optimization: When we don't have escaping bound vars,
262- // we don't need to replace them with placeholders.
263- let ( data, maps) = if data. has_escaping_bound_vars ( ) {
264- let ( data, mapped_regions, mapped_types, mapped_consts) =
265- BoundVarReplacer :: replace_bound_vars ( infcx, & mut self . universes , data) ;
266- ( data, Some ( ( mapped_regions, mapped_types, mapped_consts) ) )
267- } else {
268- ( data, None )
269- } ;
270- let data = data. try_fold_with ( self ) ?;
271-
272- let mut orig_values = OriginalQueryValues :: default ( ) ;
273- let c_data = infcx. canonicalize_query ( self . param_env . and ( data) , & mut orig_values) ;
274- debug ! ( "QueryNormalizer: c_data = {:#?}" , c_data) ;
275- debug ! ( "QueryNormalizer: orig_values = {:#?}" , orig_values) ;
276- let result = match kind {
277- ty:: Projection => tcx. normalize_canonicalized_projection_ty ( c_data) ,
278- ty:: Free => tcx. normalize_canonicalized_free_alias ( c_data) ,
279- ty:: Inherent => tcx. normalize_canonicalized_inherent_projection_ty ( c_data) ,
280- kind => unreachable ! ( "did not expect {kind:?} due to match arm above" ) ,
281- } ?;
282- // We don't expect ambiguity.
283- if !result. value . is_proven ( ) {
284- // Rustdoc normalizes possibly not well-formed types, so only
285- // treat this as a bug if we're not in rustdoc.
286- if !tcx. sess . opts . actually_rustdoc {
287- tcx. dcx ( )
288- . delayed_bug ( format ! ( "unexpected ambiguity: {c_data:?} {result:?}" ) ) ;
289- }
290- return Err ( NoSolution ) ;
291- }
292- let InferOk { value : result, obligations } = infcx
293- . instantiate_query_response_and_region_obligations (
294- self . cause ,
295- self . param_env ,
296- & orig_values,
297- result,
298- ) ?;
299- debug ! ( "QueryNormalizer: result = {:#?}" , result) ;
300- debug ! ( "QueryNormalizer: obligations = {:#?}" , obligations) ;
301- self . obligations . extend ( obligations) ;
302- let res = if let Some ( ( mapped_regions, mapped_types, mapped_consts) ) = maps {
303- PlaceholderReplacer :: replace_placeholders (
304- infcx,
305- mapped_regions,
306- mapped_types,
307- mapped_consts,
308- & self . universes ,
309- result. normalized_ty ,
310- )
311- } else {
312- result. normalized_ty
313- } ;
314- // `tcx.normalize_canonicalized_projection_ty` may normalize to a type that
315- // still has unevaluated consts, so keep normalizing here if that's the case.
316- // Similarly, `tcx.normalize_canonicalized_free_alias` will only unwrap one layer
317- // of type and we need to continue folding it to reveal the TAIT behind it.
318- if res != ty
319- && ( res. has_type_flags ( ty:: TypeFlags :: HAS_CT_PROJECTION ) || kind == ty:: Free )
320- {
321- res. try_fold_with ( self ) ?
322- } else {
323- res
324- }
325- }
257+ ty:: Projection | ty:: Inherent | ty:: Free => self
258+ . try_fold_free_or_assoc ( ty:: AliasTerm :: new ( self . cx ( ) , data. def_id , data. args ) ) ?
259+ . expect_type ( ) ,
326260 } ;
327261
328262 self . cache . insert ( ty, res) ;
@@ -337,12 +271,22 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> {
337271 return Ok ( constant) ;
338272 }
339273
340- let constant = crate :: traits:: with_replaced_escaping_bound_vars (
341- self . infcx ,
342- & mut self . universes ,
343- constant,
344- |constant| crate :: traits:: evaluate_const ( & self . infcx , constant, self . param_env ) ,
345- ) ;
274+ let uv = match constant. kind ( ) {
275+ ty:: ConstKind :: Unevaluated ( uv) => uv,
276+ _ => return constant. try_super_fold_with ( self ) ,
277+ } ;
278+
279+ let constant = match self . cx ( ) . def_kind ( uv. def ) {
280+ DefKind :: AnonConst => crate :: traits:: with_replaced_escaping_bound_vars (
281+ self . infcx ,
282+ & mut self . universes ,
283+ constant,
284+ |constant| crate :: traits:: evaluate_const ( & self . infcx , constant, self . param_env ) ,
285+ ) ,
286+ _ => self
287+ . try_fold_free_or_assoc ( ty:: AliasTerm :: new ( self . cx ( ) , uv. def , uv. args ) ) ?
288+ . expect_const ( ) ,
289+ } ;
346290 debug ! ( ?constant, ?self . param_env) ;
347291 constant. try_super_fold_with ( self )
348292 }
@@ -359,3 +303,85 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> {
359303 }
360304 }
361305}
306+
307+ impl < ' a , ' tcx > QueryNormalizer < ' a , ' tcx > {
308+ fn try_fold_free_or_assoc (
309+ & mut self ,
310+ term : ty:: AliasTerm < ' tcx > ,
311+ ) -> Result < ty:: Term < ' tcx > , NoSolution > {
312+ let infcx = self . infcx ;
313+ let tcx = infcx. tcx ;
314+ // Just an optimization: When we don't have escaping bound vars,
315+ // we don't need to replace them with placeholders.
316+ let ( term, maps) = if term. has_escaping_bound_vars ( ) {
317+ let ( term, mapped_regions, mapped_types, mapped_consts) =
318+ BoundVarReplacer :: replace_bound_vars ( infcx, & mut self . universes , term) ;
319+ ( term, Some ( ( mapped_regions, mapped_types, mapped_consts) ) )
320+ } else {
321+ ( term, None )
322+ } ;
323+ let term = term. try_fold_with ( self ) ?;
324+
325+ let mut orig_values = OriginalQueryValues :: default ( ) ;
326+ let c_term = infcx. canonicalize_query ( self . param_env . and ( term) , & mut orig_values) ;
327+ debug ! ( "QueryNormalizer: c_term = {:#?}" , c_term) ;
328+ debug ! ( "QueryNormalizer: orig_values = {:#?}" , orig_values) ;
329+ let result = match term. kind ( tcx) {
330+ ty:: AliasTermKind :: ProjectionTy | ty:: AliasTermKind :: ProjectionConst => {
331+ tcx. normalize_canonicalized_projection ( c_term)
332+ }
333+ ty:: AliasTermKind :: FreeTy | ty:: AliasTermKind :: FreeConst => {
334+ tcx. normalize_canonicalized_free_alias ( c_term)
335+ }
336+ ty:: AliasTermKind :: InherentTy | ty:: AliasTermKind :: InherentConst => {
337+ tcx. normalize_canonicalized_inherent_projection ( c_term)
338+ }
339+ kind @ ( ty:: AliasTermKind :: OpaqueTy | ty:: AliasTermKind :: UnevaluatedConst ) => {
340+ unreachable ! ( "did not expect {kind:?} due to match arm above" )
341+ }
342+ } ?;
343+ // We don't expect ambiguity.
344+ if !result. value . is_proven ( ) {
345+ // Rustdoc normalizes possibly not well-formed types, so only
346+ // treat this as a bug if we're not in rustdoc.
347+ if !tcx. sess . opts . actually_rustdoc {
348+ tcx. dcx ( ) . delayed_bug ( format ! ( "unexpected ambiguity: {c_term:?} {result:?}" ) ) ;
349+ }
350+ return Err ( NoSolution ) ;
351+ }
352+ let InferOk { value : result, obligations } = infcx
353+ . instantiate_query_response_and_region_obligations (
354+ self . cause ,
355+ self . param_env ,
356+ & orig_values,
357+ result,
358+ ) ?;
359+ debug ! ( "QueryNormalizer: result = {:#?}" , result) ;
360+ debug ! ( "QueryNormalizer: obligations = {:#?}" , obligations) ;
361+ self . obligations . extend ( obligations) ;
362+ let res = if let Some ( ( mapped_regions, mapped_types, mapped_consts) ) = maps {
363+ PlaceholderReplacer :: replace_placeholders (
364+ infcx,
365+ mapped_regions,
366+ mapped_types,
367+ mapped_consts,
368+ & self . universes ,
369+ result. normalized_term ,
370+ )
371+ } else {
372+ result. normalized_term
373+ } ;
374+ // `tcx.normalize_canonicalized_projection` may normalize to a type that
375+ // still has unevaluated consts, so keep normalizing here if that's the case.
376+ // Similarly, `tcx.normalize_canonicalized_free_alias` will only unwrap one layer
377+ // of type and we need to continue folding it to reveal the TAIT behind it.
378+ if res != term. to_term ( tcx)
379+ && ( res. as_type ( ) . map_or ( false , |t| t. has_type_flags ( ty:: TypeFlags :: HAS_CT_PROJECTION ) )
380+ || term. kind ( tcx) == ty:: AliasTermKind :: FreeTy )
381+ {
382+ res. try_fold_with ( self )
383+ } else {
384+ Ok ( res)
385+ }
386+ }
387+ }
0 commit comments