@@ -4,11 +4,10 @@ use super::{
44} ;
55
66use crate :: autoderef:: Autoderef ;
7- use crate :: infer:: type_variable:: { TypeVariableOrigin , TypeVariableOriginKind } ;
87use crate :: infer:: { InferCtxt , InferOk } ;
98use crate :: traits:: { self , normalize_projection_type} ;
109
11- use rustc_data_structures:: fx:: FxHashSet ;
10+ use rustc_data_structures:: fx:: FxHashMap ;
1211use rustc_data_structures:: stack:: ensure_sufficient_stack;
1312use rustc_errors:: { error_code, struct_span_err, Applicability , DiagnosticBuilder , Style } ;
1413use rustc_hir as hir;
@@ -336,64 +335,80 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
336335 data : ty:: TraitPredicate < ' tcx > ,
337336 self_ty : Ty < ' tcx > ,
338337 ) -> Vec < String > {
339- let mut turbofish_suggestions = FxHashSet :: default ( ) ;
338+ let mut turbofish_suggestions = FxHashMap :: default ( ) ;
340339 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) ;
382399 }
383- } )
384- && !matches ! ( trait_ref. self_ty( ) . kind( ) , ty:: Infer ( _) )
385- {
386- turbofish_suggestions. insert ( trait_ref. self_ty ( ) ) ;
400+ } ;
387401 }
388- }
402+ } )
389403 } ) ;
390404 // 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.
392407 let mut turbofish_suggestions = turbofish_suggestions. into_iter ( ) . collect :: < Vec < _ > > ( ) ;
393408 turbofish_suggestions. sort_by ( |left, right| {
394409 let vec_type = self . tcx . get_diagnostic_item ( sym:: vec_type) ;
395410 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 ( ) ) {
397412 (
398413 ty:: Adt ( ty:: AdtDef { did : left, .. } , _) ,
399414 ty:: Adt ( ty:: AdtDef { did : right, .. } , _) ,
@@ -416,10 +431,19 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
416431 {
417432 Ordering :: Greater
418433 }
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+ }
420444 }
421445 } ) ;
422- turbofish_suggestions. into_iter ( ) . map ( |ty | ty. to_string ( ) ) . collect ( )
446+ turbofish_suggestions. into_iter ( ) . map ( |( ty , _ ) | ty. to_string ( ) ) . collect ( )
423447 }
424448
425449 fn suggest_restricting_param_bound (
0 commit comments