@@ -11,8 +11,9 @@ use rustc_type_ir::lang_items::SolverTraitLangItem;
1111use rustc_type_ir:: search_graph:: CandidateHeadUsages ;
1212use rustc_type_ir:: solve:: SizedTraitKind ;
1313use rustc_type_ir:: {
14- self as ty, Interner , TypeFlags , TypeFoldable , TypeSuperVisitable , TypeVisitable ,
15- TypeVisitableExt as _, TypeVisitor , TypingMode , Upcast as _, elaborate,
14+ self as ty, Interner , TypeFlags , TypeFoldable , TypeFolder , TypeSuperFoldable ,
15+ TypeSuperVisitable , TypeVisitable , TypeVisitableExt , TypeVisitor , TypingMode , Upcast ,
16+ elaborate,
1617} ;
1718use tracing:: { debug, instrument} ;
1819
@@ -187,6 +188,7 @@ where
187188 ecx : & mut EvalCtxt < ' _ , D > ,
188189 goal : Goal < I , Self > ,
189190 impl_def_id : I :: ImplId ,
191+ finalize : impl FnOnce ( & mut EvalCtxt < ' _ , D > , Certainty ) -> QueryResult < I > ,
190192 ) -> Result < Candidate < I > , NoSolution > ;
191193
192194 /// If the predicate contained an error, we want to avoid emitting unnecessary trait
@@ -365,6 +367,15 @@ pub(super) enum AssembleCandidatesFrom {
365367 EnvAndBounds ,
366368}
367369
370+ impl AssembleCandidatesFrom {
371+ fn should_assemble_impl_candidates ( & self ) -> bool {
372+ match self {
373+ AssembleCandidatesFrom :: All => true ,
374+ AssembleCandidatesFrom :: EnvAndBounds => false ,
375+ }
376+ }
377+ }
378+
368379/// This is currently used to track the [CandidateHeadUsages] of all failed `ParamEnv`
369380/// candidates. This is then used to ignore their head usages in case there's another
370381/// always applicable `ParamEnv` candidate. Look at how `param_env_head_usages` is
@@ -397,14 +408,15 @@ where
397408 return ( candidates, failed_candidate_info) ;
398409 } ;
399410
411+ let goal: Goal < I , G > = goal
412+ . with ( self . cx ( ) , goal. predicate . with_replaced_self_ty ( self . cx ( ) , normalized_self_ty) ) ;
413+
400414 if normalized_self_ty. is_ty_var ( ) {
401415 debug ! ( "self type has been normalized to infer" ) ;
402- candidates . extend ( self . forced_ambiguity ( MaybeCause :: Ambiguity ) ) ;
416+ self . try_assemble_bounds_via_registered_opaque ( goal , assemble_from , & mut candidates ) ;
403417 return ( candidates, failed_candidate_info) ;
404418 }
405419
406- let goal: Goal < I , G > = goal
407- . with ( self . cx ( ) , goal. predicate . with_replaced_self_ty ( self . cx ( ) , normalized_self_ty) ) ;
408420 // Vars that show up in the rest of the goal substs may have been constrained by
409421 // normalizing the self type as well, since type variables are not uniquified.
410422 let goal = self . resolve_vars_if_possible ( goal) ;
@@ -485,7 +497,9 @@ where
485497 return ;
486498 }
487499
488- match G :: consider_impl_candidate ( self , goal, impl_def_id) {
500+ match G :: consider_impl_candidate ( self , goal, impl_def_id, |ecx, certainty| {
501+ ecx. evaluate_added_goals_and_make_canonical_response ( certainty)
502+ } ) {
489503 Ok ( candidate) => candidates. push ( candidate) ,
490504 Err ( NoSolution ) => ( ) ,
491505 }
@@ -943,6 +957,110 @@ where
943957 }
944958 }
945959
960+ /// If the self type is the hidden type of an opaque, try to assemble
961+ /// candidates for it by consider its item bounds and by using blanket
962+ /// impls. This is used to incompletely guide type inference when handling
963+ /// non-defining uses in the defining scope.
964+ ///
965+ /// We otherwise just fail fail with ambiguity. Even if we're using an
966+ /// opaque type item bound or a blank impls, we still force its certainty
967+ /// to be `Maybe` so that we properly prove this goal later.
968+ ///
969+ /// See <https://github.com/rust-lang/trait-system-refactor-initiative/issues/182>
970+ /// for why this is necessary.
971+ fn try_assemble_bounds_via_registered_opaque < G : GoalKind < D > > (
972+ & mut self ,
973+ goal : Goal < I , G > ,
974+ assemble_from : AssembleCandidatesFrom ,
975+ candidates : & mut Vec < Candidate < I > > ,
976+ ) {
977+ let self_ty = goal. predicate . self_ty ( ) ;
978+ let mut is_hidden_type_of_alias = false ;
979+ for alias_ty in self . find_sup_as_registered_opaque ( self_ty) {
980+ debug ! ( "self ty is sub unified with {alias_ty:?}" ) ;
981+ is_hidden_type_of_alias = true ;
982+
983+ struct ReplaceOpaque < I : Interner > {
984+ cx : I ,
985+ alias_ty : ty:: AliasTy < I > ,
986+ self_ty : I :: Ty ,
987+ }
988+ impl < I : Interner > TypeFolder < I > for ReplaceOpaque < I > {
989+ fn cx ( & self ) -> I {
990+ self . cx
991+ }
992+ fn fold_ty ( & mut self , ty : I :: Ty ) -> I :: Ty {
993+ if let ty:: Alias ( ty:: Opaque , alias_ty) = ty. kind ( ) {
994+ if alias_ty == self . alias_ty {
995+ return self . self_ty ;
996+ }
997+ }
998+ ty. super_fold_with ( self )
999+ }
1000+ }
1001+
1002+ // We look at all item-bounds of the opaque, replacing the
1003+ // opaque with the current self type before considering
1004+ // them as a candidate. Imagine e've got `?x: Trait<?y>`
1005+ // and `?x` has been sub-unified with the hidden type of
1006+ // `impl Trait<u32>`, We take the item bound `opaque: Trait<u32>`
1007+ // and replace all occurances of `opaque` with `?x`. This results
1008+ // in a `?x: Trait<u32>` alias-bound candidate.
1009+ for item_bound in self
1010+ . cx ( )
1011+ . item_self_bounds ( alias_ty. def_id )
1012+ . iter_instantiated ( self . cx ( ) , alias_ty. args )
1013+ {
1014+ let assumption =
1015+ item_bound. fold_with ( & mut ReplaceOpaque { cx : self . cx ( ) , alias_ty, self_ty } ) ;
1016+ // We want to reprove this goal once we've inferred the hidden type,
1017+ // so we force the certainty to `Maybe`.
1018+ candidates. extend ( G :: probe_and_match_goal_against_assumption (
1019+ self ,
1020+ CandidateSource :: AliasBound ,
1021+ goal,
1022+ assumption,
1023+ |ecx| {
1024+ ecx. evaluate_added_goals_and_make_canonical_response ( Certainty :: AMBIGUOUS )
1025+ } ,
1026+ ) ) ;
1027+ }
1028+ }
1029+
1030+ // We also need to consider blanket impls for not-yet-defined opaque types.
1031+ //
1032+ // See tests/ui/impl-trait/non-defining-uses/use-blanket-impl.rs for an example.
1033+ if is_hidden_type_of_alias && assemble_from. should_assemble_impl_candidates ( ) {
1034+ let cx = self . cx ( ) ;
1035+ cx. for_each_blanket_impl ( goal. predicate . trait_def_id ( cx) , |impl_def_id| {
1036+ // For every `default impl`, there's always a non-default `impl`
1037+ // that will *also* apply. There's no reason to register a candidate
1038+ // for this impl, since it is *not* proof that the trait goal holds.
1039+ if cx. impl_is_default ( impl_def_id) {
1040+ return ;
1041+ }
1042+
1043+ // We force the certainty of impl candidates to be `Maybe`.
1044+ match G :: consider_impl_candidate ( self , goal, impl_def_id, |ecx, certainty| {
1045+ if ecx. shallow_resolve ( self_ty) . is_ty_var ( ) {
1046+ ecx. evaluate_added_goals_and_make_canonical_response (
1047+ certainty. and ( Certainty :: AMBIGUOUS ) ,
1048+ )
1049+ } else {
1050+ Err ( NoSolution )
1051+ }
1052+ } ) {
1053+ Ok ( candidate) => candidates. push ( candidate) ,
1054+ Err ( NoSolution ) => ( ) ,
1055+ }
1056+ } ) ;
1057+ }
1058+
1059+ if candidates. is_empty ( ) {
1060+ candidates. extend ( self . forced_ambiguity ( MaybeCause :: Ambiguity ) ) ;
1061+ }
1062+ }
1063+
9461064 /// Assemble and merge candidates for goals which are related to an underlying trait
9471065 /// goal. Right now, this is normalizes-to and host effect goals.
9481066 ///
0 commit comments