@@ -8,6 +8,7 @@ use rustc_data_structures::fx::FxIndexSet;
88use rustc_hir:: def_id:: DefId ;
99use rustc_infer:: traits:: query:: NoSolution ;
1010use rustc_infer:: traits:: util:: elaborate;
11+ use rustc_infer:: traits:: Reveal ;
1112use rustc_middle:: traits:: solve:: { CanonicalResponse , Certainty , Goal , MaybeCause , QueryResult } ;
1213use rustc_middle:: ty:: fast_reject:: TreatProjections ;
1314use rustc_middle:: ty:: TypeFoldable ;
@@ -87,7 +88,9 @@ pub(super) enum CandidateSource {
8788}
8889
8990/// Methods used to assemble candidates for either trait or projection goals.
90- pub ( super ) trait GoalKind < ' tcx > : TypeFoldable < TyCtxt < ' tcx > > + Copy + Eq {
91+ pub ( super ) trait GoalKind < ' tcx > :
92+ TypeFoldable < TyCtxt < ' tcx > > + Copy + Eq + std:: fmt:: Display
93+ {
9194 fn self_ty ( self ) -> Ty < ' tcx > ;
9295
9396 fn trait_ref ( self , tcx : TyCtxt < ' tcx > ) -> ty:: TraitRef < ' tcx > ;
@@ -106,6 +109,16 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<TyCtxt<'tcx>> + Copy + Eq {
106109 requirements : impl IntoIterator < Item = Goal < ' tcx , ty:: Predicate < ' tcx > > > ,
107110 ) -> QueryResult < ' tcx > ;
108111
112+ /// Consider a bound originating from the item bounds of an alias. For this we
113+ /// require that the well-formed requirements of the self type of the goal
114+ /// are "satisfied from the param-env".
115+ /// See [`EvalCtxt::validate_alias_bound_self_from_param_env`].
116+ fn consider_alias_bound_candidate (
117+ ecx : & mut EvalCtxt < ' _ , ' tcx > ,
118+ goal : Goal < ' tcx , Self > ,
119+ assumption : ty:: Predicate < ' tcx > ,
120+ ) -> QueryResult < ' tcx > ;
121+
109122 // Consider a clause specifically for a `dyn Trait` self type. This requires
110123 // additionally checking all of the supertraits and object bounds to hold,
111124 // since they're not implied by the well-formedness of the object type.
@@ -463,7 +476,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
463476
464477 for assumption in self . tcx ( ) . item_bounds ( alias_ty. def_id ) . subst ( self . tcx ( ) , alias_ty. substs )
465478 {
466- match G :: consider_implied_clause ( self , goal, assumption, [ ] ) {
479+ match G :: consider_alias_bound_candidate ( self , goal, assumption) {
467480 Ok ( result) => {
468481 candidates. push ( Candidate { source : CandidateSource :: AliasBound , result } )
469482 }
@@ -472,6 +485,105 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
472485 }
473486 }
474487
488+ /// Check that we are allowed to use an alias bound originating from the self
489+ /// type of this goal. This means something different depending on the self type's
490+ /// alias kind.
491+ ///
492+ /// * Projection: Given a goal with a self type such as `<Ty as Trait>::Assoc`,
493+ /// we require that the bound `Ty: Trait` can be proven using either a nested alias
494+ /// bound candidate, or a param-env candidate.
495+ ///
496+ /// * Opaque: The param-env must be in `Reveal::UserFacing` mode. Otherwise,
497+ /// the goal should be proven by using the hidden type instead.
498+ #[ instrument( level = "debug" , skip( self ) , ret) ]
499+ pub ( super ) fn validate_alias_bound_self_from_param_env < G : GoalKind < ' tcx > > (
500+ & mut self ,
501+ goal : Goal < ' tcx , G > ,
502+ ) -> QueryResult < ' tcx > {
503+ match * goal. predicate . self_ty ( ) . kind ( ) {
504+ ty:: Alias ( ty:: Projection , projection_ty) => {
505+ let mut param_env_candidates = vec ! [ ] ;
506+ let self_trait_ref = projection_ty. trait_ref ( self . tcx ( ) ) ;
507+
508+ if self_trait_ref. self_ty ( ) . is_ty_var ( ) {
509+ return self
510+ . evaluate_added_goals_and_make_canonical_response ( Certainty :: AMBIGUOUS ) ;
511+ }
512+
513+ let trait_goal: Goal < ' _ , ty:: TraitPredicate < ' tcx > > = goal. with (
514+ self . tcx ( ) ,
515+ ty:: TraitPredicate {
516+ trait_ref : self_trait_ref,
517+ constness : ty:: BoundConstness :: NotConst ,
518+ polarity : ty:: ImplPolarity :: Positive ,
519+ } ,
520+ ) ;
521+
522+ self . assemble_param_env_candidates ( trait_goal, & mut param_env_candidates) ;
523+ // FIXME: We probably need some sort of recursion depth check here.
524+ // Can't come up with an example yet, though, and the worst case
525+ // we can have is a compiler stack overflow...
526+ self . assemble_alias_bound_candidates ( trait_goal, & mut param_env_candidates) ;
527+
528+ // FIXME: We must also consider alias-bound candidates for a peculiar
529+ // class of built-in candidates that I'll call "defaulted" built-ins.
530+ //
531+ // For example, we always know that `T: Pointee` is implemented, but
532+ // we do not always know what `<T as Pointee>::Metadata` actually is,
533+ // similar to if we had a user-defined impl with a `default type ...`.
534+ // For these traits, since we're not able to always normalize their
535+ // associated types to a concrete type, we must consider their alias bounds
536+ // instead, so we can prove bounds such as `<T as Pointee>::Metadata: Copy`.
537+ self . assemble_alias_bound_candidates_for_builtin_impl_default_items (
538+ trait_goal,
539+ & mut param_env_candidates,
540+ ) ;
541+
542+ self . merge_candidates ( param_env_candidates)
543+ }
544+ ty:: Alias ( ty:: Opaque , _opaque_ty) => match goal. param_env . reveal ( ) {
545+ Reveal :: UserFacing => {
546+ self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
547+ }
548+ Reveal :: All => return Err ( NoSolution ) ,
549+ } ,
550+ _ => bug ! ( "only expected to be called on alias tys" ) ,
551+ }
552+ }
553+
554+ /// Assemble a subset of builtin impl candidates for a class of candidates called
555+ /// "defaulted" built-in traits.
556+ ///
557+ /// For example, we always know that `T: Pointee` is implemented, but we do not
558+ /// always know what `<T as Pointee>::Metadata` actually is! See the comment in
559+ /// [`EvalCtxt::validate_alias_bound_self_from_param_env`] for more detail.
560+ #[ instrument( level = "debug" , skip_all) ]
561+ fn assemble_alias_bound_candidates_for_builtin_impl_default_items < G : GoalKind < ' tcx > > (
562+ & mut self ,
563+ goal : Goal < ' tcx , G > ,
564+ candidates : & mut Vec < Candidate < ' tcx > > ,
565+ ) {
566+ let lang_items = self . tcx ( ) . lang_items ( ) ;
567+ let trait_def_id = goal. predicate . trait_def_id ( self . tcx ( ) ) ;
568+
569+ // You probably shouldn't add anything to this list unless you
570+ // know what you're doing.
571+ let result = if lang_items. pointee_trait ( ) == Some ( trait_def_id) {
572+ G :: consider_builtin_pointee_candidate ( self , goal)
573+ } else if lang_items. discriminant_kind_trait ( ) == Some ( trait_def_id) {
574+ G :: consider_builtin_discriminant_kind_candidate ( self , goal)
575+ } else {
576+ Err ( NoSolution )
577+ } ;
578+
579+ match result {
580+ Ok ( result) => {
581+ candidates. push ( Candidate { source : CandidateSource :: BuiltinImpl , result } )
582+ }
583+ Err ( NoSolution ) => ( ) ,
584+ }
585+ }
586+
475587 #[ instrument( level = "debug" , skip_all) ]
476588 fn assemble_object_bound_candidates < G : GoalKind < ' tcx > > (
477589 & mut self ,
0 commit comments