@@ -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,90 @@ 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
+ }
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
+ }
269
346
}
270
347
271
348
impl < ' tcx > ProofTreeVisitor < ' tcx > for BestObligation < ' tcx > {
@@ -277,11 +354,19 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
277
354
278
355
#[ instrument( level = "trace" , skip( self , goal) , fields( goal = ?goal. goal( ) ) ) ]
279
356
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 ( ) ;
282
364
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 ( ) ) ,
285
370
} ;
286
371
287
372
// Don't walk into impls that have `do_not_recommend`.
@@ -291,13 +376,12 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
291
376
} = candidate. kind ( )
292
377
&& goal. infcx ( ) . tcx . do_not_recommend_impl ( impl_def_id)
293
378
{
379
+ trace ! ( "#[do_not_recommend] -> exit" ) ;
294
380
return ControlFlow :: Break ( self . obligation . clone ( ) ) ;
295
381
}
296
382
297
- let tcx = goal. infcx ( ) . tcx ;
298
383
// FIXME: Also, what about considering >1 layer up the stack? May be necessary
299
384
// for normalizes-to.
300
- let pred_kind = goal. goal ( ) . predicate . kind ( ) ;
301
385
let child_mode = match pred_kind. skip_binder ( ) {
302
386
ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Trait ( pred) ) => {
303
387
ChildMode :: Trait ( pred_kind. rebind ( pred) )
@@ -390,12 +474,6 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
390
474
}
391
475
}
392
476
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
477
self . with_derived_obligation ( obligation, |this| nested_goal. visit_with ( this) ) ?;
400
478
}
401
479
0 commit comments