@@ -7,6 +7,7 @@ use super::{Certainty, EvalCtxt, Goal, QueryResult};
77use rustc_errors:: ErrorGuaranteed ;
88use rustc_hir:: def:: DefKind ;
99use rustc_hir:: def_id:: DefId ;
10+ use rustc_hir:: LangItem ;
1011use rustc_infer:: infer:: InferCtxt ;
1112use rustc_infer:: traits:: query:: NoSolution ;
1213use rustc_infer:: traits:: specialization_graph:: LeafDef ;
@@ -391,6 +392,96 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
391392 ) -> QueryResult < ' tcx > {
392393 bug ! ( "`Tuple` does not have an associated type: {:?}" , goal) ;
393394 }
395+
396+ fn consider_builtin_pointee_candidate (
397+ ecx : & mut EvalCtxt < ' _ , ' tcx > ,
398+ goal : Goal < ' tcx , Self > ,
399+ ) -> QueryResult < ' tcx > {
400+ let tcx = ecx. tcx ( ) ;
401+ ecx. infcx . probe ( |_| {
402+ let metadata_ty = match goal. predicate . self_ty ( ) . kind ( ) {
403+ ty:: Bool
404+ | ty:: Char
405+ | ty:: Int ( ..)
406+ | ty:: Uint ( ..)
407+ | ty:: Float ( ..)
408+ | ty:: Array ( ..)
409+ | ty:: RawPtr ( ..)
410+ | ty:: Ref ( ..)
411+ | ty:: FnDef ( ..)
412+ | ty:: FnPtr ( ..)
413+ | ty:: Closure ( ..)
414+ | ty:: Infer ( ty:: IntVar ( ..) | ty:: FloatVar ( ..) )
415+ | ty:: Generator ( ..)
416+ | ty:: GeneratorWitness ( ..)
417+ | ty:: Never
418+ | ty:: Foreign ( ..) => tcx. types . unit ,
419+
420+ ty:: Error ( e) => tcx. ty_error_with_guaranteed ( * e) ,
421+
422+ ty:: Str | ty:: Slice ( _) => tcx. types . usize ,
423+
424+ ty:: Dynamic ( _, _, _) => {
425+ let dyn_metadata = tcx. require_lang_item ( LangItem :: DynMetadata , None ) ;
426+ tcx. bound_type_of ( dyn_metadata)
427+ . subst ( tcx, & [ ty:: GenericArg :: from ( goal. predicate . self_ty ( ) ) ] )
428+ }
429+
430+ ty:: Infer ( ty:: TyVar ( ..) ) | ty:: Alias ( _, _) | ty:: Param ( _) | ty:: Placeholder ( ..) => {
431+ // FIXME(ptr_metadata): It would also be possible to return a `Ok(Ambig)` with no constraints.
432+ let sized_predicate = ty:: Binder :: dummy ( tcx. at ( DUMMY_SP ) . mk_trait_ref (
433+ LangItem :: Sized ,
434+ [ ty:: GenericArg :: from ( goal. predicate . self_ty ( ) ) ] ,
435+ ) ) ;
436+
437+ let mut nested_goals = ecx. infcx . eq (
438+ goal. param_env ,
439+ goal. predicate . term . ty ( ) . unwrap ( ) ,
440+ tcx. types . unit ,
441+ ) ?;
442+ nested_goals. push ( goal. with ( tcx, sized_predicate) ) ;
443+
444+ return ecx. evaluate_all_and_make_canonical_response ( nested_goals) ;
445+ }
446+
447+ ty:: Adt ( def, substs) if def. is_struct ( ) => {
448+ match def. non_enum_variant ( ) . fields . last ( ) {
449+ None => tcx. types . unit ,
450+ Some ( field_def) => {
451+ let self_ty = field_def. ty ( tcx, substs) ;
452+ let new_goal = goal. with (
453+ tcx,
454+ ty:: Binder :: dummy ( goal. predicate . with_self_ty ( tcx, self_ty) ) ,
455+ ) ;
456+ return ecx. evaluate_all_and_make_canonical_response ( vec ! [ new_goal] ) ;
457+ }
458+ }
459+ }
460+ ty:: Adt ( _, _) => tcx. types . unit ,
461+
462+ ty:: Tuple ( elements) => match elements. last ( ) {
463+ None => tcx. types . unit ,
464+ Some ( & self_ty) => {
465+ let new_goal = goal. with (
466+ tcx,
467+ ty:: Binder :: dummy ( goal. predicate . with_self_ty ( tcx, self_ty) ) ,
468+ ) ;
469+ return ecx. evaluate_all_and_make_canonical_response ( vec ! [ new_goal] ) ;
470+ }
471+ } ,
472+
473+ ty:: Infer ( ty:: FreshTy ( ..) | ty:: FreshIntTy ( ..) | ty:: FreshFloatTy ( ..) )
474+ | ty:: Bound ( ..) => bug ! (
475+ "unexpected self ty `{:?}` when normalizing `<T as Pointee>::Metadata`" ,
476+ goal. predicate. self_ty( )
477+ ) ,
478+ } ;
479+
480+ let nested_goals =
481+ ecx. infcx . eq ( goal. param_env , goal. predicate . term . ty ( ) . unwrap ( ) , metadata_ty) ?;
482+ ecx. evaluate_all_and_make_canonical_response ( nested_goals)
483+ } )
484+ }
394485}
395486
396487/// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code.
0 commit comments