@@ -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 > ;
@@ -106,6 +109,16 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<TyCtxt<'tcx>> + Copy + Eq {
106
109
requirements : impl IntoIterator < Item = Goal < ' tcx , ty:: Predicate < ' tcx > > > ,
107
110
) -> QueryResult < ' tcx > ;
108
111
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
+
109
122
// Consider a clause specifically for a `dyn Trait` self type. This requires
110
123
// additionally checking all of the supertraits and object bounds to hold,
111
124
// since they're not implied by the well-formedness of the object type.
@@ -463,7 +476,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
463
476
464
477
for assumption in self . tcx ( ) . item_bounds ( alias_ty. def_id ) . subst ( self . tcx ( ) , alias_ty. substs )
465
478
{
466
- match G :: consider_implied_clause ( self , goal, assumption, [ ] ) {
479
+ match G :: consider_alias_bound_candidate ( self , goal, assumption) {
467
480
Ok ( result) => {
468
481
candidates. push ( Candidate { source : CandidateSource :: AliasBound , result } )
469
482
}
@@ -472,6 +485,105 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
472
485
}
473
486
}
474
487
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
+
475
587
#[ instrument( level = "debug" , skip_all) ]
476
588
fn assemble_object_bound_candidates < G : GoalKind < ' tcx > > (
477
589
& mut self ,
0 commit comments