@@ -2093,6 +2093,98 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
2093
2093
) ;
2094
2094
}
2095
2095
}
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
+
2096
2188
err
2097
2189
}
2098
2190
0 commit comments