@@ -7,7 +7,7 @@ use rustc_infer::traits::{
7
7
PredicateObligation , SelectionError ,
8
8
} ;
9
9
use rustc_middle:: ty:: error:: { ExpectedFound , TypeError } ;
10
- use rustc_middle:: ty:: { self , TyCtxt } ;
10
+ use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
11
11
use rustc_middle:: { bug, span_bug} ;
12
12
use rustc_next_trait_solver:: solve:: { GenerateProofTree , SolverDelegateEvalExt as _} ;
13
13
use rustc_type_ir:: solve:: { Goal , NoSolution } ;
@@ -139,6 +139,7 @@ pub(super) fn fulfillment_error_for_overflow<'tcx>(
139
139
}
140
140
}
141
141
142
+ #[ instrument( level = "debug" , skip( infcx) , ret) ]
142
143
fn find_best_leaf_obligation < ' tcx > (
143
144
infcx : & InferCtxt < ' tcx > ,
144
145
obligation : & PredicateObligation < ' tcx > ,
@@ -197,6 +198,9 @@ impl<'tcx> BestObligation<'tcx> {
197
198
candidates. retain ( |candidate| candidate. result ( ) . is_ok ( ) ) ;
198
199
}
199
200
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 { .. } ) ) ;
200
204
// If we have >1 candidate, one may still be due to "boring" reasons, like
201
205
// an alias-relate that failed to hold when deeply evaluated. We really
202
206
// don't care about reasons like this.
@@ -211,23 +215,12 @@ impl<'tcx> BestObligation<'tcx> {
211
215
| GoalSource :: AliasBoundConstCondition
212
216
| GoalSource :: InstantiateHigherRanked
213
217
| 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 ( )
219
219
} ,
220
220
)
221
221
} )
222
222
} ) ;
223
223
}
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
- }
231
224
}
232
225
}
233
226
@@ -266,6 +259,37 @@ impl<'tcx> BestObligation<'tcx> {
266
259
267
260
ControlFlow :: Break ( self . obligation . clone ( ) )
268
261
}
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
+ }
269
293
}
270
294
271
295
impl < ' tcx > ProofTreeVisitor < ' tcx > for BestObligation < ' tcx > {
@@ -277,11 +301,51 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
277
301
278
302
#[ instrument( level = "trace" , skip( self , goal) , fields( goal = ?goal. goal( ) ) ) ]
279
303
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
+
280
312
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
+ Some ( ty:: PredicateKind :: NormalizesTo ( pred) )
320
+ if let ty:: AliasTermKind :: ProjectionTy
321
+ | ty:: AliasTermKind :: ProjectionConst = pred. alias . kind ( tcx) =>
322
+ {
323
+ self . detect_error_in_self_ty_normalization ( goal, pred. alias . self_ty ( ) ) ?;
324
+ // It is likely that `NormalizesTo` failed because the alias is not well-formed.
325
+ // As we only enter `RigidAlias` candidates if the trait bound of the associated type
326
+ // holds, we discard these candidates in `non_trivial_candidates` and always manually
327
+ // check this here.
328
+ let obligation = Obligation :: new (
329
+ tcx,
330
+ self . obligation . cause . clone ( ) ,
331
+ goal. goal ( ) . param_env ,
332
+ pred. alias . trait_ref ( tcx) ,
333
+ ) ;
334
+ self . with_derived_obligation ( obligation, |this| {
335
+ goal. infcx ( ) . visit_proof_tree_at_depth (
336
+ goal. goal ( ) . with ( tcx, pred. alias . trait_ref ( tcx) ) ,
337
+ goal. depth ( ) + 1 ,
338
+ this,
339
+ )
340
+ } ) ?;
341
+ }
342
+ Some ( _) | None => { }
343
+ }
282
344
283
- let [ candidate] = candidates. as_slice ( ) else {
284
- return ControlFlow :: Break ( self . obligation . clone ( ) ) ;
345
+ return ControlFlow :: Break ( self . obligation . clone ( ) ) ;
346
+ }
347
+ [ candidate] => candidate,
348
+ _ => return ControlFlow :: Break ( self . obligation . clone ( ) ) ,
285
349
} ;
286
350
287
351
// Don't walk into impls that have `do_not_recommend`.
@@ -291,13 +355,12 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
291
355
} = candidate. kind ( )
292
356
&& goal. infcx ( ) . tcx . do_not_recommend_impl ( impl_def_id)
293
357
{
358
+ trace ! ( "#[do_not_recommend] -> exit" ) ;
294
359
return ControlFlow :: Break ( self . obligation . clone ( ) ) ;
295
360
}
296
361
297
- let tcx = goal. infcx ( ) . tcx ;
298
362
// FIXME: Also, what about considering >1 layer up the stack? May be necessary
299
363
// for normalizes-to.
300
- let pred_kind = goal. goal ( ) . predicate . kind ( ) ;
301
364
let child_mode = match pred_kind. skip_binder ( ) {
302
365
ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Trait ( pred) ) => {
303
366
ChildMode :: Trait ( pred_kind. rebind ( pred) )
@@ -390,12 +453,6 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
390
453
}
391
454
}
392
455
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
-
399
456
self . with_derived_obligation ( obligation, |this| nested_goal. visit_with ( this) ) ?;
400
457
}
401
458
0 commit comments