@@ -8,6 +8,7 @@ use rustc_data_structures::fx::FxIndexSet;
8
8
use rustc_hir:: def_id:: DefId ;
9
9
use rustc_infer:: traits:: query:: NoSolution ;
10
10
use rustc_infer:: traits:: util:: elaborate;
11
+ use rustc_infer:: traits:: Reveal ;
11
12
use rustc_middle:: traits:: solve:: { CanonicalResponse , Certainty , Goal , MaybeCause , QueryResult } ;
12
13
use rustc_middle:: ty:: fast_reject:: TreatProjections ;
13
14
use rustc_middle:: ty:: TypeFoldable ;
@@ -87,7 +88,9 @@ pub(super) enum CandidateSource {
87
88
}
88
89
89
90
/// 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
+ {
91
94
fn self_ty ( self ) -> Ty < ' tcx > ;
92
95
93
96
fn trait_ref ( self , tcx : TyCtxt < ' tcx > ) -> ty:: TraitRef < ' tcx > ;
@@ -96,6 +99,17 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<TyCtxt<'tcx>> + Copy + Eq {
96
99
97
100
fn trait_def_id ( self , tcx : TyCtxt < ' tcx > ) -> DefId ;
98
101
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
+
99
113
// Consider a clause, which consists of a "assumption" and some "requirements",
100
114
// to satisfy a goal. If the requirements hold, then attempt to satisfy our
101
115
// goal by equating it with the assumption.
@@ -104,7 +118,26 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<TyCtxt<'tcx>> + Copy + Eq {
104
118
goal : Goal < ' tcx , Self > ,
105
119
assumption : ty:: Predicate < ' tcx > ,
106
120
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
+ }
108
141
109
142
// Consider a clause specifically for a `dyn Trait` self type. This requires
110
143
// 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 {
113
146
ecx : & mut EvalCtxt < ' _ , ' tcx > ,
114
147
goal : Goal < ' tcx , Self > ,
115
148
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
+ }
117
168
118
169
fn consider_impl_candidate (
119
170
ecx : & mut EvalCtxt < ' _ , ' tcx > ,
@@ -463,7 +514,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
463
514
464
515
for assumption in self . tcx ( ) . item_bounds ( alias_ty. def_id ) . subst ( self . tcx ( ) , alias_ty. substs )
465
516
{
466
- match G :: consider_implied_clause ( self , goal, assumption, [ ] ) {
517
+ match G :: consider_alias_bound_candidate ( self , goal, assumption) {
467
518
Ok ( result) => {
468
519
candidates. push ( Candidate { source : CandidateSource :: AliasBound , result } )
469
520
}
@@ -472,6 +523,105 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
472
523
}
473
524
}
474
525
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
+
475
625
#[ instrument( level = "debug" , skip_all) ]
476
626
fn assemble_object_bound_candidates < G : GoalKind < ' tcx > > (
477
627
& mut self ,
0 commit comments