@@ -1919,7 +1919,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
19191919 // type parameters, opaques, and unnormalized projections have pointer
19201920 // metadata if they're known (e.g. by the param_env) to be sized
19211921 ty:: Param ( _) | ty:: Alias ( ..)
1922- if selcx. infcx . predicate_must_hold_modulo_regions (
1922+ if self_ty != tail || selcx. infcx . predicate_must_hold_modulo_regions (
19231923 & obligation. with (
19241924 selcx. tcx ( ) ,
19251925 ty:: TraitRef :: from_lang_item ( selcx. tcx ( ) , LangItem :: Sized , obligation. cause . span ( ) , [ self_ty] ) ,
@@ -2278,7 +2278,8 @@ fn confirm_builtin_candidate<'cx, 'tcx>(
22782278 let args = tcx. mk_args ( & [ self_ty. into ( ) ] ) ;
22792279 let lang_items = tcx. lang_items ( ) ;
22802280 let item_def_id = obligation. predicate . def_id ;
2281- let trait_def_id = tcx. trait_of_item ( item_def_id) . unwrap ( ) ;
2281+ let trait_def_id: rustc_span:: def_id:: DefId = tcx. trait_of_item ( item_def_id) . unwrap ( ) ;
2282+ let mut potentially_unnormalized = false ;
22822283 let ( term, obligations) = if lang_items. discriminant_kind_trait ( ) == Some ( trait_def_id) {
22832284 let discriminant_def_id = tcx. require_lang_item ( LangItem :: Discriminant , None ) ;
22842285 assert_eq ! ( discriminant_def_id, item_def_id) ;
@@ -2289,7 +2290,7 @@ fn confirm_builtin_candidate<'cx, 'tcx>(
22892290 assert_eq ! ( metadata_def_id, item_def_id) ;
22902291
22912292 let mut obligations = Vec :: new ( ) ;
2292- let ( metadata_ty , check_is_sized ) = self_ty . ptr_metadata_ty ( tcx , |ty| {
2293+ let normalize = |ty| {
22932294 normalize_with_depth_to (
22942295 selcx,
22952296 obligation. param_env ,
@@ -2298,27 +2299,49 @@ fn confirm_builtin_candidate<'cx, 'tcx>(
22982299 ty,
22992300 & mut obligations,
23002301 )
2301- } ) ;
2302- if check_is_sized {
2303- let sized_predicate = ty:: TraitRef :: from_lang_item (
2304- tcx,
2305- LangItem :: Sized ,
2306- obligation. cause . span ( ) ,
2307- [ self_ty] ,
2308- ) ;
2309- obligations. push ( obligation. with ( tcx, sized_predicate) ) ;
2310- }
2311- ( metadata_ty. into ( ) , obligations)
2302+ } ;
2303+ let metadata = match self_ty. ptr_metadata_ty_or_tail ( tcx, normalize) {
2304+ Ok ( metadata) => metadata,
2305+ Err ( tail) => {
2306+ let sized_predicate = ty:: TraitRef :: from_lang_item (
2307+ tcx,
2308+ LangItem :: Sized ,
2309+ obligation. cause . span ( ) ,
2310+ [ self_ty] ,
2311+ ) ;
2312+ let sized_obligation = obligation. with ( tcx, sized_predicate) ;
2313+ if self_ty == tail
2314+ || selcx. infcx . predicate_must_hold_considering_regions ( & sized_obligation)
2315+ {
2316+ // If the `self_ty` is `Sized`, then the metadata is `()`.
2317+ // We check this before projecting to the metadata of `tail`,
2318+ // because we may know `self_ty: Sized`, but not `tail: Sized`.
2319+ obligations. push ( sized_obligation) ;
2320+ tcx. types . unit
2321+ } else {
2322+ // We know that `self_ty` has the same metadata as `tail`. This allows
2323+ // us to prove predicates like `Wrapper<T>::Metadata == T::Metadata`.
2324+ potentially_unnormalized = true ;
2325+ Ty :: new_projection ( tcx, metadata_def_id, [ tail] )
2326+ }
2327+ }
2328+ } ;
2329+ ( metadata. into ( ) , obligations)
23122330 } else {
23132331 bug ! ( "unexpected builtin trait with associated type: {:?}" , obligation. predicate) ;
23142332 } ;
23152333
23162334 let predicate =
23172335 ty:: ProjectionPredicate { projection_ty : ty:: AliasTy :: new ( tcx, item_def_id, args) , term } ;
23182336
2319- confirm_param_env_candidate ( selcx, obligation, ty:: Binder :: dummy ( predicate) , false )
2320- . with_addl_obligations ( obligations)
2321- . with_addl_obligations ( data)
2337+ confirm_param_env_candidate (
2338+ selcx,
2339+ obligation,
2340+ ty:: Binder :: dummy ( predicate) ,
2341+ potentially_unnormalized,
2342+ )
2343+ . with_addl_obligations ( obligations)
2344+ . with_addl_obligations ( data)
23222345}
23232346
23242347fn confirm_fn_pointer_candidate < ' cx , ' tcx > (
0 commit comments