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