@@ -11,8 +11,9 @@ use rustc_type_ir::lang_items::SolverTraitLangItem;
11
11
use rustc_type_ir:: search_graph:: CandidateHeadUsages ;
12
12
use rustc_type_ir:: solve:: SizedTraitKind ;
13
13
use 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,
16
17
} ;
17
18
use tracing:: { debug, instrument} ;
18
19
@@ -187,6 +188,7 @@ where
187
188
ecx : & mut EvalCtxt < ' _ , D > ,
188
189
goal : Goal < I , Self > ,
189
190
impl_def_id : I :: ImplId ,
191
+ then : impl FnOnce ( & mut EvalCtxt < ' _ , D > , Certainty ) -> QueryResult < I > ,
190
192
) -> Result < Candidate < I > , NoSolution > ;
191
193
192
194
/// If the predicate contained an error, we want to avoid emitting unnecessary trait
@@ -365,6 +367,15 @@ pub(super) enum AssembleCandidatesFrom {
365
367
EnvAndBounds ,
366
368
}
367
369
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
+
368
379
/// This is currently used to track the [CandidateHeadUsages] of all failed `ParamEnv`
369
380
/// candidates. This is then used to ignore their head usages in case there's another
370
381
/// always applicable `ParamEnv` candidate. Look at how `param_env_head_usages` is
@@ -397,14 +408,15 @@ where
397
408
return ( candidates, failed_candidate_info) ;
398
409
} ;
399
410
411
+ let goal: Goal < I , G > = goal
412
+ . with ( self . cx ( ) , goal. predicate . with_replaced_self_ty ( self . cx ( ) , normalized_self_ty) ) ;
413
+
400
414
if normalized_self_ty. is_ty_var ( ) {
401
415
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 ) ;
403
417
return ( candidates, failed_candidate_info) ;
404
418
}
405
419
406
- let goal: Goal < I , G > = goal
407
- . with ( self . cx ( ) , goal. predicate . with_replaced_self_ty ( self . cx ( ) , normalized_self_ty) ) ;
408
420
// Vars that show up in the rest of the goal substs may have been constrained by
409
421
// normalizing the self type as well, since type variables are not uniquified.
410
422
let goal = self . resolve_vars_if_possible ( goal) ;
@@ -484,8 +496,9 @@ where
484
496
if cx. impl_is_default ( impl_def_id) {
485
497
return ;
486
498
}
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
+ } ) {
489
502
Ok ( candidate) => candidates. push ( candidate) ,
490
503
Err ( NoSolution ) => ( ) ,
491
504
}
@@ -943,6 +956,116 @@ where
943
956
}
944
957
}
945
958
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
+
946
1069
/// Assemble and merge candidates for goals which are related to an underlying trait
947
1070
/// goal. Right now, this is normalizes-to and host effect goals.
948
1071
///
0 commit comments