@@ -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,90 @@ 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+ }
293+
294+ /// It is likely that `NormalizesTo` failed without any applicable candidates
295+ /// because the alias is not well-formed.
296+ ///
297+ /// As we only enter `RigidAlias` candidates if the trait bound of the associated type
298+ /// holds, we discard these candidates in `non_trivial_candidates` and always manually
299+ /// check this here.
300+ fn detect_non_well_formed_assoc_item (
301+ & mut self ,
302+ goal : & inspect:: InspectGoal < ' _ , ' tcx > ,
303+ alias : ty:: AliasTerm < ' tcx > ,
304+ ) -> ControlFlow < PredicateObligation < ' tcx > > {
305+ let tcx = goal. infcx ( ) . tcx ;
306+ let obligation = Obligation :: new (
307+ tcx,
308+ self . obligation . cause . clone ( ) ,
309+ goal. goal ( ) . param_env ,
310+ alias. trait_ref ( tcx) ,
311+ ) ;
312+ self . with_derived_obligation ( obligation, |this| {
313+ goal. infcx ( ) . visit_proof_tree_at_depth (
314+ goal. goal ( ) . with ( tcx, alias. trait_ref ( tcx) ) ,
315+ goal. depth ( ) + 1 ,
316+ this,
317+ )
318+ } )
319+ }
320+
321+ /// If we have no candidates, then it's likely that there is a
322+ /// non-well-formed alias in the goal.
323+ fn detect_error_from_empty_candidates (
324+ & mut self ,
325+ goal : & inspect:: InspectGoal < ' _ , ' tcx > ,
326+ ) -> ControlFlow < PredicateObligation < ' tcx > > {
327+ let tcx = goal. infcx ( ) . tcx ;
328+ let pred_kind = goal. goal ( ) . predicate . kind ( ) ;
329+
330+ match pred_kind. no_bound_vars ( ) {
331+ Some ( ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Trait ( pred) ) ) => {
332+ self . detect_error_in_self_ty_normalization ( goal, pred. self_ty ( ) ) ?;
333+ }
334+ Some ( ty:: PredicateKind :: NormalizesTo ( pred) )
335+ if let ty:: AliasTermKind :: ProjectionTy | ty:: AliasTermKind :: ProjectionConst =
336+ pred. alias . kind ( tcx) =>
337+ {
338+ self . detect_error_in_self_ty_normalization ( goal, pred. alias . self_ty ( ) ) ?;
339+ self . detect_non_well_formed_assoc_item ( goal, pred. alias ) ?;
340+ }
341+ Some ( _) | None => { }
342+ }
343+
344+ ControlFlow :: Break ( self . obligation . clone ( ) )
345+ }
269346}
270347
271348impl < ' tcx > ProofTreeVisitor < ' tcx > for BestObligation < ' tcx > {
@@ -277,11 +354,19 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
277354
278355 #[ instrument( level = "trace" , skip( self , goal) , fields( goal = ?goal. goal( ) ) ) ]
279356 fn visit_goal ( & mut self , goal : & inspect:: InspectGoal < ' _ , ' tcx > ) -> Self :: Result {
280- let candidates = self . non_trivial_candidates ( goal) ;
281- trace ! ( candidates = ?candidates. iter( ) . map( |c| c. kind( ) ) . collect:: <Vec <_>>( ) ) ;
357+ let tcx = goal. infcx ( ) . tcx ;
358+ // Skip goals that aren't the *reason* for our goal's failure.
359+ match ( self . consider_ambiguities , goal. result ( ) ) {
360+ ( true , Ok ( Certainty :: Maybe ( MaybeCause :: Ambiguity ) ) ) | ( false , Err ( _) ) => { }
361+ _ => return ControlFlow :: Continue ( ( ) ) ,
362+ }
363+ let pred_kind = goal. goal ( ) . predicate . kind ( ) ;
282364
283- let [ candidate] = candidates. as_slice ( ) else {
284- return ControlFlow :: Break ( self . obligation . clone ( ) ) ;
365+ let candidates = self . non_trivial_candidates ( goal) ;
366+ let candidate = match candidates. as_slice ( ) {
367+ [ candidate] => candidate,
368+ [ ] => return self . detect_error_from_empty_candidates ( goal) ,
369+ _ => return ControlFlow :: Break ( self . obligation . clone ( ) ) ,
285370 } ;
286371
287372 // Don't walk into impls that have `do_not_recommend`.
@@ -291,13 +376,12 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
291376 } = candidate. kind ( )
292377 && goal. infcx ( ) . tcx . do_not_recommend_impl ( impl_def_id)
293378 {
379+ trace ! ( "#[do_not_recommend] -> exit" ) ;
294380 return ControlFlow :: Break ( self . obligation . clone ( ) ) ;
295381 }
296382
297- let tcx = goal. infcx ( ) . tcx ;
298383 // FIXME: Also, what about considering >1 layer up the stack? May be necessary
299384 // for normalizes-to.
300- let pred_kind = goal. goal ( ) . predicate . kind ( ) ;
301385 let child_mode = match pred_kind. skip_binder ( ) {
302386 ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Trait ( pred) ) => {
303387 ChildMode :: Trait ( pred_kind. rebind ( pred) )
@@ -390,12 +474,6 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
390474 }
391475 }
392476
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-
399477 self . with_derived_obligation ( obligation, |this| nested_goal. visit_with ( this) ) ?;
400478 }
401479
0 commit comments