@@ -4,11 +4,10 @@ use super::{
4
4
} ;
5
5
6
6
use crate :: autoderef:: Autoderef ;
7
- use crate :: infer:: type_variable:: { TypeVariableOrigin , TypeVariableOriginKind } ;
8
7
use crate :: infer:: { InferCtxt , InferOk } ;
9
8
use crate :: traits:: { self , normalize_projection_type} ;
10
9
11
- use rustc_data_structures:: fx:: FxHashSet ;
10
+ use rustc_data_structures:: fx:: FxHashMap ;
12
11
use rustc_data_structures:: stack:: ensure_sufficient_stack;
13
12
use rustc_errors:: { error_code, struct_span_err, Applicability , DiagnosticBuilder , Style } ;
14
13
use rustc_hir as hir;
@@ -336,64 +335,80 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
336
335
data : ty:: TraitPredicate < ' tcx > ,
337
336
self_ty : Ty < ' tcx > ,
338
337
) -> Vec < String > {
339
- let mut turbofish_suggestions = FxHashSet :: default ( ) ;
338
+ let mut turbofish_suggestions = FxHashMap :: default ( ) ;
340
339
self . tcx . for_each_relevant_impl ( data. trait_ref . def_id , self_ty, |impl_def_id| {
341
- let param_env = ty:: ParamEnv :: empty ( ) ;
342
- let param_env = param_env. subst ( self . tcx , data. trait_ref . substs ) ;
343
- let ty = self . next_ty_var ( TypeVariableOrigin {
344
- kind : TypeVariableOriginKind :: NormalizeProjectionType ,
345
- span : DUMMY_SP ,
346
- } ) ;
347
-
348
- let impl_substs = self . fresh_substs_for_item ( obligation. cause . span , impl_def_id) ;
349
- let trait_ref = self . tcx . impl_trait_ref ( impl_def_id) . unwrap ( ) ;
350
- let trait_ref = trait_ref. subst ( self . tcx , impl_substs) ;
351
-
352
- // Require the type the impl is implemented on to match
353
- // our type, and ignore the impl if there was a mismatch.
354
- let cause = traits:: ObligationCause :: dummy ( ) ;
355
- let eq_result = self . at ( & cause, param_env) . eq ( trait_ref. self_ty ( ) , ty) ;
356
- if let Ok ( InferOk { value : ( ) , obligations } ) = eq_result {
357
- // FIXME: ignoring `obligations` might cause false positives.
358
- drop ( obligations) ;
359
-
360
- let can_impl = match self . evaluate_obligation ( & Obligation :: new (
361
- cause,
362
- obligation. param_env ,
363
- trait_ref. without_const ( ) . to_predicate ( self . tcx ) ,
364
- ) ) {
365
- Ok ( eval_result) => eval_result. may_apply ( ) ,
366
- Err ( traits:: OverflowError ) => true , // overflow doesn't mean yes *or* no
367
- } ;
368
- if can_impl
369
- && data. trait_ref . substs . iter ( ) . zip ( trait_ref. substs . iter ( ) ) . all ( |( l, r) | {
370
- // FIXME: ideally we would use `can_coerce` here instead, but `typeck`
371
- // comes *after* in the dependency graph.
372
- match ( l. unpack ( ) , r. unpack ( ) ) {
373
- ( GenericArgKind :: Type ( left_ty) , GenericArgKind :: Type ( right_ty) ) => {
374
- match ( & left_ty. peel_refs ( ) . kind ( ) , & right_ty. peel_refs ( ) . kind ( ) ) {
375
- ( Infer ( _) , _) | ( _, Infer ( _) ) => true ,
376
- ( left_kind, right_kind) => left_kind == right_kind,
377
- }
378
- }
379
- ( GenericArgKind :: Lifetime ( _) , GenericArgKind :: Lifetime ( _) )
380
- | ( GenericArgKind :: Const ( _) , GenericArgKind :: Const ( _) ) => true ,
381
- _ => false ,
340
+ self . probe ( |_| {
341
+ let impl_substs = self . fresh_substs_for_item ( DUMMY_SP , impl_def_id) ;
342
+ let trait_ref = self . tcx . impl_trait_ref ( impl_def_id) . unwrap ( ) ;
343
+ let trait_ref = trait_ref. subst ( self . tcx , impl_substs) ;
344
+
345
+ // Require the type the impl is implemented on to match
346
+ // our type, and ignore the impl if there was a mismatch.
347
+ let cause = traits:: ObligationCause :: dummy ( ) ;
348
+ let eq_result =
349
+ self . at ( & cause, obligation. param_env ) . eq ( trait_ref. self_ty ( ) , self_ty) ;
350
+ if let Ok ( InferOk { value : ( ) , obligations : _ } ) = eq_result {
351
+ if let Ok ( eval_result) = self . evaluate_obligation ( & Obligation :: new (
352
+ cause. clone ( ) ,
353
+ obligation. param_env ,
354
+ trait_ref. without_const ( ) . to_predicate ( self . tcx ) ,
355
+ ) ) {
356
+ // FIXME: We will also suggest cases where `eval_result` is
357
+ // `EvaluatedToAmbig`, we just put them at the end of the sugg list.
358
+ // Ideally we would only suggest types that would always apply cleanly.
359
+ // This means that for `collect` we will suggest `PathBuf` as a valid type
360
+ // whereas that `impl` has an extra requirement `T: AsRef<Path>` which we
361
+ // don't evaluate.
362
+ if eval_result. may_apply ( )
363
+ && data. trait_ref . substs . iter ( ) . zip ( trait_ref. substs . iter ( ) ) . all (
364
+ // Here we'll have something like `[_, i32]` coming from our code
365
+ // and `[Vec<_>, _]` from the probe. For cases with
366
+ // inference variables we are left with ambiguous cases due to
367
+ // trait bounds we couldn't evaluate, but we *can* filter out cases
368
+ // like `[std::string::String, char]`, where we can `collect` a
369
+ // `String` only if we have an `IntoIterator<Item = char>`, which
370
+ // won't match the `i32` we have.
371
+ |( l, r) | {
372
+ // FIXME: ideally we would use `can_coerce` here instead, but `typeck`
373
+ // comes *after* in the dependency graph.
374
+ match ( l. unpack ( ) , r. unpack ( ) ) {
375
+ (
376
+ GenericArgKind :: Type ( left_ty) ,
377
+ GenericArgKind :: Type ( right_ty) ,
378
+ ) => match (
379
+ & left_ty. peel_refs ( ) . kind ( ) ,
380
+ & right_ty. peel_refs ( ) . kind ( ) ,
381
+ ) {
382
+ ( Infer ( _) , _) | ( _, Infer ( _) ) => true ,
383
+ ( left_kind, right_kind) => left_kind == right_kind,
384
+ } ,
385
+ (
386
+ GenericArgKind :: Lifetime ( _) ,
387
+ GenericArgKind :: Lifetime ( _) ,
388
+ )
389
+ | ( GenericArgKind :: Const ( _) , GenericArgKind :: Const ( _) ) => {
390
+ true
391
+ }
392
+ _ => false ,
393
+ }
394
+ } ,
395
+ )
396
+ && !matches ! ( trait_ref. self_ty( ) . kind( ) , ty:: Infer ( _) )
397
+ {
398
+ turbofish_suggestions. insert ( trait_ref. self_ty ( ) , eval_result) ;
382
399
}
383
- } )
384
- && !matches ! ( trait_ref. self_ty( ) . kind( ) , ty:: Infer ( _) )
385
- {
386
- turbofish_suggestions. insert ( trait_ref. self_ty ( ) ) ;
400
+ } ;
387
401
}
388
- }
402
+ } )
389
403
} ) ;
390
404
// Sort types by always suggesting `Vec<_>` and `String` first, as they are the
391
- // most likely desired types.
405
+ // most likely desired types. Otherwise sort first by `EvaluationResult` and then by their
406
+ // string representation.
392
407
let mut turbofish_suggestions = turbofish_suggestions. into_iter ( ) . collect :: < Vec < _ > > ( ) ;
393
408
turbofish_suggestions. sort_by ( |left, right| {
394
409
let vec_type = self . tcx . get_diagnostic_item ( sym:: vec_type) ;
395
410
let string_type = self . tcx . get_diagnostic_item ( sym:: string_type) ;
396
- match ( & left. kind ( ) , & right. kind ( ) ) {
411
+ match ( & left. 0 . kind ( ) , & right. 0 . kind ( ) ) {
397
412
(
398
413
ty:: Adt ( ty:: AdtDef { did : left, .. } , _) ,
399
414
ty:: Adt ( ty:: AdtDef { did : right, .. } , _) ,
@@ -416,10 +431,19 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
416
431
{
417
432
Ordering :: Greater
418
433
}
419
- _ => left. cmp ( right) ,
434
+ _ => {
435
+ // We give preferential place in the suggestion list to types that will apply
436
+ // without doubt, to push types with abiguities (may or may not apply depending
437
+ // on other obligations we don't have access to here) later in the sugg list.
438
+ if left. 1 == right. 1 {
439
+ left. 0 . to_string ( ) . cmp ( & right. 0 . to_string ( ) )
440
+ } else {
441
+ left. 1 . cmp ( & right. 1 )
442
+ }
443
+ }
420
444
}
421
445
} ) ;
422
- turbofish_suggestions. into_iter ( ) . map ( |ty | ty. to_string ( ) ) . collect ( )
446
+ turbofish_suggestions. into_iter ( ) . map ( |( ty , _ ) | ty. to_string ( ) ) . collect ( )
423
447
}
424
448
425
449
fn suggest_restricting_param_bound (
0 commit comments