@@ -8,6 +8,7 @@ use crate::{PathResult, PathSource, Segment};
8
8
use rustc_ast:: util:: lev_distance:: find_best_match_for_name;
9
9
use rustc_ast:: visit:: FnKind ;
10
10
use rustc_ast:: { self as ast, Expr , ExprKind , Item , ItemKind , NodeId , Path , Ty , TyKind } ;
11
+ use rustc_ast_pretty:: pprust:: path_segment_to_string;
11
12
use rustc_data_structures:: fx:: FxHashSet ;
12
13
use rustc_errors:: { pluralize, struct_span_err, Applicability , DiagnosticBuilder } ;
13
14
use rustc_hir as hir;
@@ -497,6 +498,9 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
497
498
}
498
499
}
499
500
}
501
+
502
+ fallback |= self . restrict_assoc_type_in_where_clause ( span, & mut err) ;
503
+
500
504
if !self . r . add_typo_suggestion ( & mut err, typo_sugg, ident_span) {
501
505
fallback = true ;
502
506
match self . diagnostic_metadata . current_let_binding {
@@ -521,6 +525,120 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
521
525
( err, candidates)
522
526
}
523
527
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
+
524
642
/// Check if the source is call expression and the first argument is `self`. If true,
525
643
/// return the span of whole call and the span for all arguments expect the first one (`self`).
526
644
fn call_has_self_arg ( & self , source : PathSource < ' _ > ) -> Option < ( Span , Option < Span > ) > {
0 commit comments