@@ -8,6 +8,7 @@ use crate::{PathResult, PathSource, Segment};
88use rustc_ast:: util:: lev_distance:: find_best_match_for_name;
99use rustc_ast:: visit:: FnKind ;
1010use rustc_ast:: { self as ast, Expr , ExprKind , Item , ItemKind , NodeId , Path , Ty , TyKind } ;
11+ use rustc_ast_pretty:: pprust:: path_segment_to_string;
1112use rustc_data_structures:: fx:: FxHashSet ;
1213use rustc_errors:: { pluralize, struct_span_err, Applicability , DiagnosticBuilder } ;
1314use rustc_hir as hir;
@@ -497,6 +498,9 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
497498 }
498499 }
499500 }
501+
502+ fallback |= self . restrict_assoc_type_in_where_clause ( span, & mut err) ;
503+
500504 if !self . r . add_typo_suggestion ( & mut err, typo_sugg, ident_span) {
501505 fallback = true ;
502506 match self . diagnostic_metadata . current_let_binding {
@@ -521,6 +525,120 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
521525 ( err, candidates)
522526 }
523527
528+ /// Given `where <T as Bar>::Baz: String`, suggest `where T: Bar<Baz = String>`.
529+ fn restrict_assoc_type_in_where_clause (
530+ & mut self ,
531+ span : Span ,
532+ err : & mut DiagnosticBuilder < ' _ > ,
533+ ) -> bool {
534+ // Detect that we are actually in a `where` predicate.
535+ let ( bounded_ty, bounds, where_span) =
536+ if let Some ( ast:: WherePredicate :: BoundPredicate ( ast:: WhereBoundPredicate {
537+ bounded_ty,
538+ bound_generic_params,
539+ bounds,
540+ span,
541+ } ) ) = self . diagnostic_metadata . current_where_predicate
542+ {
543+ if !bound_generic_params. is_empty ( ) {
544+ return false ;
545+ }
546+ ( bounded_ty, bounds, span)
547+ } else {
548+ return false ;
549+ } ;
550+
551+ // Confirm that the target is an associated type.
552+ let ( ty, position, path) = if let ast:: TyKind :: Path (
553+ Some ( ast:: QSelf { ty, position, .. } ) ,
554+ path,
555+ ) = & bounded_ty. kind
556+ {
557+ // use this to verify that ident is a type param.
558+ let partial_res = if let Ok ( Some ( partial_res) ) = self . resolve_qpath_anywhere (
559+ bounded_ty. id ,
560+ None ,
561+ & Segment :: from_path ( path) ,
562+ Namespace :: TypeNS ,
563+ span,
564+ true ,
565+ CrateLint :: No ,
566+ ) {
567+ partial_res
568+ } else {
569+ return false ;
570+ } ;
571+ if !( matches ! (
572+ partial_res. base_res( ) ,
573+ hir:: def:: Res :: Def ( hir:: def:: DefKind :: AssocTy , _)
574+ ) && partial_res. unresolved_segments ( ) == 0 )
575+ {
576+ return false ;
577+ }
578+ ( ty, position, path)
579+ } else {
580+ return false ;
581+ } ;
582+
583+ if let ast:: TyKind :: Path ( None , type_param_path) = & ty. kind {
584+ // Confirm that the `SelfTy` is a type parameter.
585+ let partial_res = if let Ok ( Some ( partial_res) ) = self . resolve_qpath_anywhere (
586+ bounded_ty. id ,
587+ None ,
588+ & Segment :: from_path ( type_param_path) ,
589+ Namespace :: TypeNS ,
590+ span,
591+ true ,
592+ CrateLint :: No ,
593+ ) {
594+ partial_res
595+ } else {
596+ return false ;
597+ } ;
598+ if !( matches ! (
599+ partial_res. base_res( ) ,
600+ hir:: def:: Res :: Def ( hir:: def:: DefKind :: TyParam , _)
601+ ) && partial_res. unresolved_segments ( ) == 0 )
602+ {
603+ return false ;
604+ }
605+ if let (
606+ [ ast:: PathSegment { ident, args : None , .. } ] ,
607+ [ ast:: GenericBound :: Trait ( poly_trait_ref, ast:: TraitBoundModifier :: None ) ] ,
608+ ) = ( & type_param_path. segments [ ..] , & bounds[ ..] )
609+ {
610+ if let [ ast:: PathSegment { ident : bound_ident, args : None , .. } ] =
611+ & poly_trait_ref. trait_ref . path . segments [ ..]
612+ {
613+ if bound_ident. span == span {
614+ err. span_suggestion_verbose (
615+ * where_span,
616+ & format ! ( "constrain the associated type to `{}`" , bound_ident) ,
617+ format ! (
618+ "{}: {}<{} = {}>" ,
619+ ident,
620+ path. segments[ ..* position]
621+ . iter( )
622+ . map( |segment| path_segment_to_string( segment) )
623+ . collect:: <Vec <_>>( )
624+ . join( "::" ) ,
625+ path. segments[ * position..]
626+ . iter( )
627+ . map( |segment| path_segment_to_string( segment) )
628+ . collect:: <Vec <_>>( )
629+ . join( "::" ) ,
630+ bound_ident,
631+ ) ,
632+ Applicability :: MaybeIncorrect ,
633+ ) ;
634+ }
635+ return true ;
636+ }
637+ }
638+ }
639+ false
640+ }
641+
524642 /// Check if the source is call expression and the first argument is `self`. If true,
525643 /// return the span of whole call and the span for all arguments expect the first one (`self`).
526644 fn call_has_self_arg ( & self , source : PathSource < ' _ > ) -> Option < ( Span , Option < Span > ) > {
0 commit comments