@@ -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
+ finalize : 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_opaque ( 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) ;
@@ -485,7 +497,9 @@ where
485
497
return ;
486
498
}
487
499
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
+ } ) {
489
503
Ok ( candidate) => candidates. push ( candidate) ,
490
504
Err ( NoSolution ) => ( ) ,
491
505
}
@@ -943,6 +957,110 @@ where
943
957
}
944
958
}
945
959
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
+
946
1064
/// Assemble and merge candidates for goals which are related to an underlying trait
947
1065
/// goal. Right now, this is normalizes-to and host effect goals.
948
1066
///
0 commit comments