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