@@ -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 > ;
@@ -96,6 +99,17 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<TyCtxt<'tcx>> + Copy + Eq {
9699
97100 fn trait_def_id ( self , tcx : TyCtxt < ' tcx > ) -> DefId ;
98101
102+ // Try equating an assumption predicate against a goal's predicate. If it
103+ // holds, then execute the `then` callback, which should do any additional
104+ // work, then produce a response (typically by executing
105+ // [`EvalCtxt::evaluate_added_goals_and_make_canonical_response`]).
106+ fn probe_and_match_goal_against_assumption (
107+ ecx : & mut EvalCtxt < ' _ , ' tcx > ,
108+ goal : Goal < ' tcx , Self > ,
109+ assumption : ty:: Predicate < ' tcx > ,
110+ then : impl FnOnce ( & mut EvalCtxt < ' _ , ' tcx > ) -> QueryResult < ' tcx > ,
111+ ) -> QueryResult < ' tcx > ;
112+
99113 // Consider a clause, which consists of a "assumption" and some "requirements",
100114 // to satisfy a goal. If the requirements hold, then attempt to satisfy our
101115 // goal by equating it with the assumption.
@@ -104,7 +118,26 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<TyCtxt<'tcx>> + Copy + Eq {
104118 goal : Goal < ' tcx , Self > ,
105119 assumption : ty:: Predicate < ' tcx > ,
106120 requirements : impl IntoIterator < Item = Goal < ' tcx , ty:: Predicate < ' tcx > > > ,
107- ) -> QueryResult < ' tcx > ;
121+ ) -> QueryResult < ' tcx > {
122+ Self :: probe_and_match_goal_against_assumption ( ecx, goal, assumption, |ecx| {
123+ ecx. add_goals ( requirements) ;
124+ ecx. evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
125+ } )
126+ }
127+
128+ /// Consider a bound originating from the item bounds of an alias. For this we
129+ /// require that the well-formed requirements of the self type of the goal
130+ /// are "satisfied from the param-env".
131+ /// See [`EvalCtxt::validate_alias_bound_self_from_param_env`].
132+ fn consider_alias_bound_candidate (
133+ ecx : & mut EvalCtxt < ' _ , ' tcx > ,
134+ goal : Goal < ' tcx , Self > ,
135+ assumption : ty:: Predicate < ' tcx > ,
136+ ) -> QueryResult < ' tcx > {
137+ Self :: probe_and_match_goal_against_assumption ( ecx, goal, assumption, |ecx| {
138+ ecx. validate_alias_bound_self_from_param_env ( goal)
139+ } )
140+ }
108141
109142 // Consider a clause specifically for a `dyn Trait` self type. This requires
110143 // additionally checking all of the supertraits and object bounds to hold,
@@ -113,7 +146,25 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<TyCtxt<'tcx>> + Copy + Eq {
113146 ecx : & mut EvalCtxt < ' _ , ' tcx > ,
114147 goal : Goal < ' tcx , Self > ,
115148 assumption : ty:: Predicate < ' tcx > ,
116- ) -> QueryResult < ' tcx > ;
149+ ) -> QueryResult < ' tcx > {
150+ Self :: probe_and_match_goal_against_assumption ( ecx, goal, assumption, |ecx| {
151+ let tcx = ecx. tcx ( ) ;
152+ let ty:: Dynamic ( bounds, _, _) = * goal. predicate . self_ty ( ) . kind ( ) else {
153+ bug ! ( "expected object type in `consider_object_bound_candidate`" ) ;
154+ } ;
155+ ecx. add_goals (
156+ structural_traits:: predicates_for_object_candidate (
157+ & ecx,
158+ goal. param_env ,
159+ goal. predicate . trait_ref ( tcx) ,
160+ bounds,
161+ )
162+ . into_iter ( )
163+ . map ( |pred| goal. with ( tcx, pred) ) ,
164+ ) ;
165+ ecx. evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
166+ } )
167+ }
117168
118169 fn consider_impl_candidate (
119170 ecx : & mut EvalCtxt < ' _ , ' tcx > ,
@@ -463,7 +514,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
463514
464515 for assumption in self . tcx ( ) . item_bounds ( alias_ty. def_id ) . subst ( self . tcx ( ) , alias_ty. substs )
465516 {
466- match G :: consider_implied_clause ( self , goal, assumption, [ ] ) {
517+ match G :: consider_alias_bound_candidate ( self , goal, assumption) {
467518 Ok ( result) => {
468519 candidates. push ( Candidate { source : CandidateSource :: AliasBound , result } )
469520 }
@@ -472,6 +523,105 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
472523 }
473524 }
474525
526+ /// Check that we are allowed to use an alias bound originating from the self
527+ /// type of this goal. This means something different depending on the self type's
528+ /// alias kind.
529+ ///
530+ /// * Projection: Given a goal with a self type such as `<Ty as Trait>::Assoc`,
531+ /// we require that the bound `Ty: Trait` can be proven using either a nested alias
532+ /// bound candidate, or a param-env candidate.
533+ ///
534+ /// * Opaque: The param-env must be in `Reveal::UserFacing` mode. Otherwise,
535+ /// the goal should be proven by using the hidden type instead.
536+ #[ instrument( level = "debug" , skip( self ) , ret) ]
537+ pub ( super ) fn validate_alias_bound_self_from_param_env < G : GoalKind < ' tcx > > (
538+ & mut self ,
539+ goal : Goal < ' tcx , G > ,
540+ ) -> QueryResult < ' tcx > {
541+ match * goal. predicate . self_ty ( ) . kind ( ) {
542+ ty:: Alias ( ty:: Projection , projection_ty) => {
543+ let mut param_env_candidates = vec ! [ ] ;
544+ let self_trait_ref = projection_ty. trait_ref ( self . tcx ( ) ) ;
545+
546+ if self_trait_ref. self_ty ( ) . is_ty_var ( ) {
547+ return self
548+ . evaluate_added_goals_and_make_canonical_response ( Certainty :: AMBIGUOUS ) ;
549+ }
550+
551+ let trait_goal: Goal < ' _ , ty:: TraitPredicate < ' tcx > > = goal. with (
552+ self . tcx ( ) ,
553+ ty:: TraitPredicate {
554+ trait_ref : self_trait_ref,
555+ constness : ty:: BoundConstness :: NotConst ,
556+ polarity : ty:: ImplPolarity :: Positive ,
557+ } ,
558+ ) ;
559+
560+ self . assemble_param_env_candidates ( trait_goal, & mut param_env_candidates) ;
561+ // FIXME: We probably need some sort of recursion depth check here.
562+ // Can't come up with an example yet, though, and the worst case
563+ // we can have is a compiler stack overflow...
564+ self . assemble_alias_bound_candidates ( trait_goal, & mut param_env_candidates) ;
565+
566+ // FIXME: We must also consider alias-bound candidates for a peculiar
567+ // class of built-in candidates that I'll call "defaulted" built-ins.
568+ //
569+ // For example, we always know that `T: Pointee` is implemented, but
570+ // we do not always know what `<T as Pointee>::Metadata` actually is,
571+ // similar to if we had a user-defined impl with a `default type ...`.
572+ // For these traits, since we're not able to always normalize their
573+ // associated types to a concrete type, we must consider their alias bounds
574+ // instead, so we can prove bounds such as `<T as Pointee>::Metadata: Copy`.
575+ self . assemble_alias_bound_candidates_for_builtin_impl_default_items (
576+ trait_goal,
577+ & mut param_env_candidates,
578+ ) ;
579+
580+ self . merge_candidates ( param_env_candidates)
581+ }
582+ ty:: Alias ( ty:: Opaque , _opaque_ty) => match goal. param_env . reveal ( ) {
583+ Reveal :: UserFacing => {
584+ self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
585+ }
586+ Reveal :: All => return Err ( NoSolution ) ,
587+ } ,
588+ _ => bug ! ( "only expected to be called on alias tys" ) ,
589+ }
590+ }
591+
592+ /// Assemble a subset of builtin impl candidates for a class of candidates called
593+ /// "defaulted" built-in traits.
594+ ///
595+ /// For example, we always know that `T: Pointee` is implemented, but we do not
596+ /// always know what `<T as Pointee>::Metadata` actually is! See the comment in
597+ /// [`EvalCtxt::validate_alias_bound_self_from_param_env`] for more detail.
598+ #[ instrument( level = "debug" , skip_all) ]
599+ fn assemble_alias_bound_candidates_for_builtin_impl_default_items < G : GoalKind < ' tcx > > (
600+ & mut self ,
601+ goal : Goal < ' tcx , G > ,
602+ candidates : & mut Vec < Candidate < ' tcx > > ,
603+ ) {
604+ let lang_items = self . tcx ( ) . lang_items ( ) ;
605+ let trait_def_id = goal. predicate . trait_def_id ( self . tcx ( ) ) ;
606+
607+ // You probably shouldn't add anything to this list unless you
608+ // know what you're doing.
609+ let result = if lang_items. pointee_trait ( ) == Some ( trait_def_id) {
610+ G :: consider_builtin_pointee_candidate ( self , goal)
611+ } else if lang_items. discriminant_kind_trait ( ) == Some ( trait_def_id) {
612+ G :: consider_builtin_discriminant_kind_candidate ( self , goal)
613+ } else {
614+ Err ( NoSolution )
615+ } ;
616+
617+ match result {
618+ Ok ( result) => {
619+ candidates. push ( Candidate { source : CandidateSource :: BuiltinImpl , result } )
620+ }
621+ Err ( NoSolution ) => ( ) ,
622+ }
623+ }
624+
475625 #[ instrument( level = "debug" , skip_all) ]
476626 fn assemble_object_bound_candidates < G : GoalKind < ' tcx > > (
477627 & mut self ,
0 commit comments