@@ -7,7 +7,7 @@ use rustc_infer::traits::{
77 PredicateObligation , SelectionError ,
88} ;
99use rustc_middle:: ty:: error:: { ExpectedFound , TypeError } ;
10- use rustc_middle:: ty:: { self , TyCtxt } ;
10+ use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
1111use rustc_middle:: { bug, span_bug} ;
1212use rustc_next_trait_solver:: solve:: { GenerateProofTree , SolverDelegateEvalExt as _} ;
1313use rustc_type_ir:: solve:: { Goal , NoSolution } ;
@@ -139,6 +139,7 @@ pub(super) fn fulfillment_error_for_overflow<'tcx>(
139139 }
140140}
141141
142+ #[ instrument( level = "debug" , skip( infcx) , ret) ]
142143fn find_best_leaf_obligation < ' tcx > (
143144 infcx : & InferCtxt < ' tcx > ,
144145 obligation : & PredicateObligation < ' tcx > ,
@@ -197,6 +198,9 @@ impl<'tcx> BestObligation<'tcx> {
197198 candidates. retain ( |candidate| candidate. result ( ) . is_ok ( ) ) ;
198199 }
199200 false => {
201+ // We always handle rigid alias candidates separately as we may not add them for
202+ // aliases whose trait bound doesn't hold.
203+ candidates. retain ( |c| !matches ! ( c. kind( ) , inspect:: ProbeKind :: RigidAlias { .. } ) ) ;
200204 // If we have >1 candidate, one may still be due to "boring" reasons, like
201205 // an alias-relate that failed to hold when deeply evaluated. We really
202206 // don't care about reasons like this.
@@ -211,23 +215,12 @@ impl<'tcx> BestObligation<'tcx> {
211215 | GoalSource :: AliasBoundConstCondition
212216 | GoalSource :: InstantiateHigherRanked
213217 | GoalSource :: AliasWellFormed
214- ) && match ( self . consider_ambiguities , nested_goal. result ( ) ) {
215- ( true , Ok ( Certainty :: Maybe ( MaybeCause :: Ambiguity ) ) )
216- | ( false , Err ( _) ) => true ,
217- _ => false ,
218- }
218+ ) && nested_goal. result ( ) . is_err ( )
219219 } ,
220220 )
221221 } )
222222 } ) ;
223223 }
224-
225- // Prefer a non-rigid candidate if there is one.
226- if candidates. len ( ) > 1 {
227- candidates. retain ( |candidate| {
228- !matches ! ( candidate. kind( ) , inspect:: ProbeKind :: RigidAlias { .. } )
229- } ) ;
230- }
231224 }
232225 }
233226
@@ -266,6 +259,37 @@ impl<'tcx> BestObligation<'tcx> {
266259
267260 ControlFlow :: Break ( self . obligation . clone ( ) )
268261 }
262+
263+ /// If a normalization of an associated item or a trait goal fails without trying any
264+ /// candidates it's likely that normalizing its self type failed. We manually detect
265+ /// such cases here.
266+ fn detect_error_in_self_ty_normalization (
267+ & mut self ,
268+ goal : & inspect:: InspectGoal < ' _ , ' tcx > ,
269+ self_ty : Ty < ' tcx > ,
270+ ) -> ControlFlow < PredicateObligation < ' tcx > > {
271+ assert ! ( !self . consider_ambiguities) ;
272+ let tcx = goal. infcx ( ) . tcx ;
273+ if let ty:: Alias ( ..) = self_ty. kind ( ) {
274+ let infer_term = goal. infcx ( ) . next_ty_var ( self . obligation . cause . span ) ;
275+ let pred = ty:: PredicateKind :: AliasRelate (
276+ self_ty. into ( ) ,
277+ infer_term. into ( ) ,
278+ ty:: AliasRelationDirection :: Equate ,
279+ ) ;
280+ let obligation =
281+ Obligation :: new ( tcx, self . obligation . cause . clone ( ) , goal. goal ( ) . param_env , pred) ;
282+ self . with_derived_obligation ( obligation, |this| {
283+ goal. infcx ( ) . visit_proof_tree_at_depth (
284+ goal. goal ( ) . with ( tcx, pred) ,
285+ goal. depth ( ) + 1 ,
286+ this,
287+ )
288+ } )
289+ } else {
290+ ControlFlow :: Continue ( ( ) )
291+ }
292+ }
269293}
270294
271295impl < ' tcx > ProofTreeVisitor < ' tcx > for BestObligation < ' tcx > {
@@ -277,11 +301,55 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
277301
278302 #[ instrument( level = "trace" , skip( self , goal) , fields( goal = ?goal. goal( ) ) ) ]
279303 fn visit_goal ( & mut self , goal : & inspect:: InspectGoal < ' _ , ' tcx > ) -> Self :: Result {
304+ let tcx = goal. infcx ( ) . tcx ;
305+ // Skip goals that aren't the *reason* for our goal's failure.
306+ match ( self . consider_ambiguities , goal. result ( ) ) {
307+ ( true , Ok ( Certainty :: Maybe ( MaybeCause :: Ambiguity ) ) ) | ( false , Err ( _) ) => { }
308+ _ => return ControlFlow :: Continue ( ( ) ) ,
309+ }
310+ let pred_kind = goal. goal ( ) . predicate . kind ( ) ;
311+
280312 let candidates = self . non_trivial_candidates ( goal) ;
281- trace ! ( candidates = ?candidates. iter( ) . map( |c| c. kind( ) ) . collect:: <Vec <_>>( ) ) ;
313+ let candidate = match candidates. as_slice ( ) {
314+ [ ] => {
315+ match pred_kind. no_bound_vars ( ) {
316+ Some ( ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Trait ( pred) ) ) => {
317+ self . detect_error_in_self_ty_normalization ( goal, pred. self_ty ( ) ) ?;
318+ }
319+ // It is likely that `NormalizesTo` failed because the alias is not well-formed.
320+ // As we only enter `RigidAlias` candidates if the trait bound of the associated type
321+ // holds, we discard these candidates in `non_trivial_candidates` and always manually
322+ // check this here.
323+ Some ( ty:: PredicateKind :: NormalizesTo ( pred) )
324+ if let ty:: AliasTermKind :: ProjectionTy
325+ | ty:: AliasTermKind :: ProjectionConst = pred. alias . kind ( tcx) =>
326+ {
327+ self . detect_error_in_self_ty_normalization ( goal, pred. alias . self_ty ( ) ) ?;
328+ // It is likely that `NormalizesTo` failed because the alias is not well-formed.
329+ // As we only enter `RigidAlias` candidates if the trait bound of the associated type
330+ // holds, we discard these candidates in `non_trivial_candidates` and always manually
331+ // check this here.
332+ let obligation = Obligation :: new (
333+ tcx,
334+ self . obligation . cause . clone ( ) ,
335+ goal. goal ( ) . param_env ,
336+ pred. alias . trait_ref ( tcx) ,
337+ ) ;
338+ self . with_derived_obligation ( obligation, |this| {
339+ goal. infcx ( ) . visit_proof_tree_at_depth (
340+ goal. goal ( ) . with ( tcx, pred. alias . trait_ref ( tcx) ) ,
341+ goal. depth ( ) + 1 ,
342+ this,
343+ )
344+ } ) ?;
345+ }
346+ Some ( _) | None => { }
347+ }
282348
283- let [ candidate] = candidates. as_slice ( ) else {
284- return ControlFlow :: Break ( self . obligation . clone ( ) ) ;
349+ return ControlFlow :: Break ( self . obligation . clone ( ) ) ;
350+ }
351+ [ candidate] => candidate,
352+ _ => return ControlFlow :: Break ( self . obligation . clone ( ) ) ,
285353 } ;
286354
287355 // Don't walk into impls that have `do_not_recommend`.
@@ -291,13 +359,12 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
291359 } = candidate. kind ( )
292360 && goal. infcx ( ) . tcx . do_not_recommend_impl ( impl_def_id)
293361 {
362+ trace ! ( "#[do_not_recommend] -> exit" ) ;
294363 return ControlFlow :: Break ( self . obligation . clone ( ) ) ;
295364 }
296365
297- let tcx = goal. infcx ( ) . tcx ;
298366 // FIXME: Also, what about considering >1 layer up the stack? May be necessary
299367 // for normalizes-to.
300- let pred_kind = goal. goal ( ) . predicate . kind ( ) ;
301368 let child_mode = match pred_kind. skip_binder ( ) {
302369 ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Trait ( pred) ) => {
303370 ChildMode :: Trait ( pred_kind. rebind ( pred) )
@@ -390,12 +457,6 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
390457 }
391458 }
392459
393- // Skip nested goals that aren't the *reason* for our goal's failure.
394- match ( self . consider_ambiguities , nested_goal. result ( ) ) {
395- ( true , Ok ( Certainty :: Maybe ( MaybeCause :: Ambiguity ) ) ) | ( false , Err ( _) ) => { }
396- _ => continue ,
397- }
398-
399460 self . with_derived_obligation ( obligation, |this| nested_goal. visit_with ( this) ) ?;
400461 }
401462
0 commit comments