@@ -2093,6 +2093,98 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
20932093 ) ;
20942094 }
20952095 }
2096+
2097+ if let ( Some ( body_id) , Some ( ty:: subst:: GenericArgKind :: Type ( _) ) ) =
2098+ ( body_id, subst. map ( |subst| subst. unpack ( ) ) )
2099+ {
2100+ struct FindExprBySpan < ' hir > {
2101+ span : Span ,
2102+ result : Option < & ' hir hir:: Expr < ' hir > > ,
2103+ }
2104+
2105+ impl < ' v > hir:: intravisit:: Visitor < ' v > for FindExprBySpan < ' v > {
2106+ fn visit_expr ( & mut self , ex : & ' v hir:: Expr < ' v > ) {
2107+ if self . span == ex. span {
2108+ self . result = Some ( ex) ;
2109+ } else {
2110+ hir:: intravisit:: walk_expr ( self , ex) ;
2111+ }
2112+ }
2113+ }
2114+
2115+ let mut expr_finder = FindExprBySpan { span, result : None } ;
2116+
2117+ expr_finder. visit_expr ( & self . tcx . hir ( ) . body ( body_id) . value ) ;
2118+
2119+ if let Some ( hir:: Expr {
2120+ kind : hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( None , path) ) , .. }
2121+ ) = expr_finder. result
2122+ && let [
2123+ ..,
2124+ trait_path_segment @ hir:: PathSegment {
2125+ res : Some ( rustc_hir:: def:: Res :: Def ( rustc_hir:: def:: DefKind :: Trait , trait_id) ) ,
2126+ ..
2127+ } ,
2128+ hir:: PathSegment {
2129+ ident : assoc_item_name,
2130+ res : Some ( rustc_hir:: def:: Res :: Def ( _, item_id) ) ,
2131+ ..
2132+ }
2133+ ] = path. segments
2134+ && data. trait_ref . def_id == * trait_id
2135+ && self . tcx . trait_of_item ( item_id) == Some ( * trait_id)
2136+ && !self . is_tainted_by_errors ( )
2137+ {
2138+ let ( verb, noun) = match self . tcx . associated_item ( item_id) . kind {
2139+ ty:: AssocKind :: Const => ( "refer to the" , "constant" ) ,
2140+ ty:: AssocKind :: Fn => ( "call" , "function" ) ,
2141+ ty:: AssocKind :: Type => ( "refer to the" , "type" ) , // this is already covered by E0223, but this single match arm doesn't hurt here
2142+ } ;
2143+
2144+ // Replace the more general E0283 with a more specific error
2145+ err. cancel ( ) ;
2146+ err = self . tcx . sess . struct_span_err_with_code (
2147+ span,
2148+ & format ! (
2149+ "cannot {verb} associated {noun} on trait without specifying the corresponding `impl` type" ,
2150+ ) ,
2151+ rustc_errors:: error_code!( E0789 ) ,
2152+ ) ;
2153+
2154+ if let Some ( local_def_id) = data. trait_ref . def_id . as_local ( )
2155+ && let Some ( hir:: Node :: Item ( hir:: Item { ident : trait_name, kind : hir:: ItemKind :: Trait ( _, _, _, _, trait_item_refs) , .. } ) ) = self . tcx . hir ( ) . find_by_def_id ( local_def_id)
2156+ && let Some ( method_ref) = trait_item_refs. iter ( ) . find ( |item_ref| item_ref. ident == * assoc_item_name) {
2157+ err. span_label ( method_ref. span , format ! ( "`{}::{}` defined here" , trait_name, assoc_item_name) ) ;
2158+ }
2159+
2160+ err. span_label ( span, format ! ( "cannot {verb} associated {noun} of trait" ) ) ;
2161+
2162+ let trait_impls = self . tcx . trait_impls_of ( data. trait_ref . def_id ) ;
2163+
2164+ if trait_impls. blanket_impls ( ) . is_empty ( )
2165+ && let Some ( ( impl_ty, _) ) = trait_impls. non_blanket_impls ( ) . iter ( ) . next ( )
2166+ && let Some ( impl_def_id) = impl_ty. def ( ) {
2167+ let message = if trait_impls. non_blanket_impls ( ) . len ( ) == 1 {
2168+ "use the fully-qualified path to the only available implementation" . to_string ( )
2169+ } else {
2170+ format ! (
2171+ "use a fully-qualified path to a specific available implementation ({} found)" ,
2172+ trait_impls. non_blanket_impls( ) . len( )
2173+ )
2174+ } ;
2175+
2176+ err. multipart_suggestion (
2177+ message,
2178+ vec ! [
2179+ ( trait_path_segment. ident. span. shrink_to_lo( ) , format!( "<{} as " , self . tcx. def_path( impl_def_id) . to_string_no_crate_verbose( ) ) ) ,
2180+ ( trait_path_segment. ident. span. shrink_to_hi( ) , format!( ">" ) )
2181+ ] ,
2182+ Applicability :: MaybeIncorrect
2183+ ) ;
2184+ }
2185+ }
2186+ } ;
2187+
20962188 err
20972189 }
20982190
0 commit comments