@@ -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+ then : 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_opaques ( 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) ;
@@ -484,8 +496,9 @@ where
484496 if cx. impl_is_default ( impl_def_id) {
485497 return ;
486498 }
487-
488- match G :: consider_impl_candidate ( self , goal, impl_def_id) {
499+ match G :: consider_impl_candidate ( self , goal, impl_def_id, |ecx, certainty| {
500+ ecx. evaluate_added_goals_and_make_canonical_response ( certainty)
501+ } ) {
489502 Ok ( candidate) => candidates. push ( candidate) ,
490503 Err ( NoSolution ) => ( ) ,
491504 }
@@ -943,6 +956,116 @@ where
943956 }
944957 }
945958
959+ /// If the self type is the hidden type of an opaque, try to assemble
960+ /// candidates for it by consider its item bounds and by using blanket
961+ /// impls. This is used to incompletely guide type inference when handling
962+ /// non-defining uses in the defining scope.
963+ ///
964+ /// We otherwise just fail fail with ambiguity. Even if we're using an
965+ /// opaque type item bound or a blank impls, we still force its certainty
966+ /// to be `Maybe` so that we properly prove this goal later.
967+ ///
968+ /// See <https://github.com/rust-lang/trait-system-refactor-initiative/issues/182>
969+ /// for why this is necessary.
970+ fn try_assemble_bounds_via_registered_opaques < G : GoalKind < D > > (
971+ & mut self ,
972+ goal : Goal < I , G > ,
973+ assemble_from : AssembleCandidatesFrom ,
974+ candidates : & mut Vec < Candidate < I > > ,
975+ ) {
976+ let self_ty = goal. predicate . self_ty ( ) ;
977+ // If the self type is sub unified with any opaque type, we
978+ // also look at blanket impls for it.
979+ let mut assemble_blanket_impls = false ;
980+ for alias_ty in self . opaques_with_sub_unified_hidden_type ( self_ty) {
981+ assemble_blanket_impls = true ;
982+ debug ! ( "self ty is sub unified with {alias_ty:?}" ) ;
983+
984+ struct ReplaceOpaque < I : Interner > {
985+ cx : I ,
986+ alias_ty : ty:: AliasTy < I > ,
987+ self_ty : I :: Ty ,
988+ }
989+ impl < I : Interner > TypeFolder < I > for ReplaceOpaque < I > {
990+ fn cx ( & self ) -> I {
991+ self . cx
992+ }
993+ fn fold_ty ( & mut self , ty : I :: Ty ) -> I :: Ty {
994+ if let ty:: Alias ( ty:: Opaque , alias_ty) = ty. kind ( ) {
995+ if alias_ty == self . alias_ty {
996+ return self . self_ty ;
997+ }
998+ }
999+ ty. super_fold_with ( self )
1000+ }
1001+ }
1002+
1003+ // We look at all item-bounds of the opaque, replacing the
1004+ // opaque with the current self type before considering
1005+ // them as a candidate. Imagine e've got `?x: Trait<?y>`
1006+ // and `?x` has been sub-unified with the hidden type of
1007+ // `impl Trait<u32>`, We take the item bound `opaque: Trait<u32>`
1008+ // and replace all occurrences of `opaque` with `?x`. This results
1009+ // in a `?x: Trait<u32>` alias-bound candidate.
1010+ for item_bound in self
1011+ . cx ( )
1012+ . item_self_bounds ( alias_ty. def_id )
1013+ . iter_instantiated ( self . cx ( ) , alias_ty. args )
1014+ {
1015+ let assumption =
1016+ item_bound. fold_with ( & mut ReplaceOpaque { cx : self . cx ( ) , alias_ty, self_ty } ) ;
1017+ candidates. extend ( G :: probe_and_match_goal_against_assumption (
1018+ self ,
1019+ CandidateSource :: AliasBound ,
1020+ goal,
1021+ assumption,
1022+ |ecx| {
1023+ // We want to reprove this goal once we've inferred the
1024+ // hidden type, so we force the certainty to `Maybe`.
1025+ ecx. evaluate_added_goals_and_make_canonical_response ( Certainty :: AMBIGUOUS )
1026+ } ,
1027+ ) ) ;
1028+ }
1029+ }
1030+
1031+ // We also need to consider blanket impls for not-yet-defined opaque types.
1032+ //
1033+ // See tests/ui/impl-trait/non-defining-uses/use-blanket-impl.rs for an example.
1034+ if assemble_blanket_impls && assemble_from. should_assemble_impl_candidates ( ) {
1035+ let cx = self . cx ( ) ;
1036+ cx. for_each_blanket_impl ( goal. predicate . trait_def_id ( cx) , |impl_def_id| {
1037+ // For every `default impl`, there's always a non-default `impl`
1038+ // that will *also* apply. There's no reason to register a candidate
1039+ // for this impl, since it is *not* proof that the trait goal holds.
1040+ if cx. impl_is_default ( impl_def_id) {
1041+ return ;
1042+ }
1043+
1044+ match G :: consider_impl_candidate ( self , goal, impl_def_id, |ecx, certainty| {
1045+ if ecx. shallow_resolve ( self_ty) . is_ty_var ( ) {
1046+ // We force the certainty of impl candidates to be `Maybe`.
1047+ let certainty = certainty. and ( Certainty :: AMBIGUOUS ) ;
1048+ ecx. evaluate_added_goals_and_make_canonical_response ( certainty)
1049+ } else {
1050+ // We don't want to use impls if they constrain the opaque.
1051+ //
1052+ // FIXME(trait-system-refactor-initiative#229): This isn't
1053+ // perfect yet as it still allows us to incorrectly constrain
1054+ // other inference variables.
1055+ Err ( NoSolution )
1056+ }
1057+ } ) {
1058+ Ok ( candidate) => candidates. push ( candidate) ,
1059+ Err ( NoSolution ) => ( ) ,
1060+ }
1061+ } ) ;
1062+ }
1063+
1064+ if candidates. is_empty ( ) {
1065+ candidates. extend ( self . forced_ambiguity ( MaybeCause :: Ambiguity ) ) ;
1066+ }
1067+ }
1068+
9461069 /// Assemble and merge candidates for goals which are related to an underlying trait
9471070 /// goal. Right now, this is normalizes-to and host effect goals.
9481071 ///
0 commit comments