@@ -4,15 +4,19 @@ use rustc_errors::MultiSpan;
4
4
use rustc_errors:: { Applicability , Diagnostic , DiagnosticBuilder , ErrorGuaranteed } ;
5
5
use rustc_hir as hir;
6
6
use rustc_hir:: def:: CtorKind ;
7
+ use rustc_hir:: intravisit:: Visitor ;
7
8
use rustc_hir:: lang_items:: LangItem ;
8
9
use rustc_hir:: { is_range_literal, Node } ;
9
10
use rustc_infer:: infer:: InferOk ;
10
11
use rustc_middle:: lint:: in_external_macro;
11
12
use rustc_middle:: middle:: stability:: EvalResult ;
12
13
use rustc_middle:: ty:: adjustment:: AllowTwoPhase ;
13
14
use rustc_middle:: ty:: error:: { ExpectedFound , TypeError } ;
14
- use rustc_middle:: ty:: print:: with_no_trimmed_paths;
15
- use rustc_middle:: ty:: { self , Article , AssocItem , Ty , TypeAndMut } ;
15
+ use rustc_middle:: ty:: fold:: TypeFolder ;
16
+ use rustc_middle:: ty:: print:: { with_forced_trimmed_paths, with_no_trimmed_paths} ;
17
+ use rustc_middle:: ty:: {
18
+ self , Article , AssocItem , Ty , TyCtxt , TypeAndMut , TypeSuperFoldable , TypeVisitable ,
19
+ } ;
16
20
use rustc_span:: symbol:: { sym, Symbol } ;
17
21
use rustc_span:: { BytePos , Span } ;
18
22
use rustc_trait_selection:: infer:: InferCtxtExt as _;
@@ -53,7 +57,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
53
57
|| self . suggest_block_to_brackets_peeling_refs ( err, expr, expr_ty, expected)
54
58
|| self . suggest_copied_or_cloned ( err, expr, expr_ty, expected)
55
59
|| self . suggest_into ( err, expr, expr_ty, expected)
56
- || self . suggest_floating_point_literal ( err, expr, expected) ;
60
+ || self . suggest_floating_point_literal ( err, expr, expected)
61
+ || self . point_inference_types ( err, expr) ;
57
62
}
58
63
59
64
pub fn emit_coerce_suggestions (
@@ -205,6 +210,157 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
205
210
( expected, Some ( err) )
206
211
}
207
212
213
+ fn point_inference_types ( & self , err : & mut Diagnostic , expr : & hir:: Expr < ' _ > ) -> bool {
214
+ let tcx = self . tcx ;
215
+ let map = self . tcx . hir ( ) ;
216
+
217
+ // Hack to make equality checks on types with inference variables and regions useful.
218
+ struct TypeEraser < ' tcx > {
219
+ tcx : TyCtxt < ' tcx > ,
220
+ }
221
+ impl < ' tcx > TypeFolder < ' tcx > for TypeEraser < ' tcx > {
222
+ fn tcx < ' b > ( & ' b self ) -> TyCtxt < ' tcx > {
223
+ self . tcx
224
+ }
225
+ fn fold_region ( & mut self , _r : ty:: Region < ' tcx > ) -> ty:: Region < ' tcx > {
226
+ self . tcx ( ) . lifetimes . re_erased
227
+ }
228
+ fn fold_ty ( & mut self , t : Ty < ' tcx > ) -> Ty < ' tcx > {
229
+ if !t. needs_infer ( ) && !t. has_erasable_regions ( ) {
230
+ return t;
231
+ }
232
+ match * t. kind ( ) {
233
+ ty:: Infer ( ty:: TyVar ( _) | ty:: FreshTy ( _) ) => {
234
+ self . tcx . mk_ty_infer ( ty:: TyVar ( ty:: TyVid :: from_u32 ( 0 ) ) )
235
+ }
236
+ ty:: Infer ( ty:: IntVar ( _) | ty:: FreshIntTy ( _) ) => {
237
+ self . tcx . mk_ty_infer ( ty:: IntVar ( ty:: IntVid { index : 0 } ) )
238
+ }
239
+ ty:: Infer ( ty:: FloatVar ( _) | ty:: FreshFloatTy ( _) ) => {
240
+ self . tcx . mk_ty_infer ( ty:: FloatVar ( ty:: FloatVid { index : 0 } ) )
241
+ }
242
+ _ => t. super_fold_with ( self ) ,
243
+ }
244
+ }
245
+ fn fold_const ( & mut self , ct : ty:: Const < ' tcx > ) -> ty:: Const < ' tcx > {
246
+ ct. super_fold_with ( self )
247
+ }
248
+ }
249
+
250
+ let hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( None , p) ) = expr. kind else { return false ; } ;
251
+ let [ hir:: PathSegment { ident, args : None , .. } ] = p. segments else { return false ; } ;
252
+ let hir:: def:: Res :: Local ( hir_id) = p. res else { return false ; } ;
253
+ let Some ( node) = map. find ( hir_id) else { return false ; } ;
254
+ let hir:: Node :: Pat ( pat) = node else { return false ; } ;
255
+ let parent = map. get_parent_node ( pat. hir_id ) ;
256
+ let Some ( hir:: Node :: Local ( hir:: Local {
257
+ ty : None ,
258
+ init : Some ( init) ,
259
+ ..
260
+ } ) ) = map. find ( parent) else { return false ; } ;
261
+
262
+ let ty = self . node_ty ( init. hir_id ) ;
263
+ if ty. is_closure ( ) || init. span . overlaps ( expr. span ) {
264
+ return false ;
265
+ }
266
+ let mut span_labels = vec ! [ (
267
+ init. span,
268
+ with_forced_trimmed_paths!( format!(
269
+ "here the type of `{ident}` is inferred to be `{ty}`" ,
270
+ ) ) ,
271
+ ) ] ;
272
+
273
+ // Locate all the usages of the relevant binding.
274
+ struct FindExprs < ' hir > {
275
+ hir_id : hir:: HirId ,
276
+ uses : Vec < & ' hir hir:: Expr < ' hir > > ,
277
+ }
278
+ impl < ' v > Visitor < ' v > for FindExprs < ' v > {
279
+ fn visit_expr ( & mut self , ex : & ' v hir:: Expr < ' v > ) {
280
+ if let hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( None , path) ) = ex. kind
281
+ && let hir:: def:: Res :: Local ( hir_id) = path. res
282
+ && hir_id == self . hir_id
283
+ {
284
+ self . uses . push ( ex) ;
285
+ }
286
+ hir:: intravisit:: walk_expr ( self , ex) ;
287
+ }
288
+ }
289
+
290
+ let mut expr_finder = FindExprs { hir_id, uses : vec ! [ ] } ;
291
+ let id = map. get_parent_item ( hir_id) ;
292
+ let hir_id: hir:: HirId = id. into ( ) ;
293
+
294
+ if let Some ( node) = map. find ( hir_id) && let Some ( body_id) = node. body_id ( ) {
295
+ let body = map. body ( body_id) ;
296
+ expr_finder. visit_expr ( body. value ) ;
297
+ let mut eraser = TypeEraser { tcx } ;
298
+ let mut prev = eraser. fold_ty ( ty) ;
299
+
300
+ for ex in expr_finder. uses {
301
+ if ex. span . overlaps ( expr. span ) { break ; }
302
+ let parent = map. get_parent_node ( ex. hir_id ) ;
303
+ if let Some ( hir:: Node :: Expr ( expr) )
304
+ | Some ( hir:: Node :: Stmt ( hir:: Stmt {
305
+ kind : hir:: StmtKind :: Expr ( expr) | hir:: StmtKind :: Semi ( expr) ,
306
+ ..
307
+ } ) ) = & map. find ( parent)
308
+ && let hir:: ExprKind :: MethodCall ( s, rcvr, args, span) = expr. kind
309
+ && rcvr. hir_id == ex. hir_id
310
+ {
311
+ let ty = if let Ok ( m) = self . lookup_method ( ty, s, span, expr, rcvr, args) {
312
+ // We get the self type from `lookup_method` because the `rcvr` node
313
+ // type will not have had any adjustments from the fn arguments.
314
+ let ty = m. sig . inputs_and_output [ 0 ] ;
315
+ match ty. kind ( ) {
316
+ // Remove one layer of references to account for `&mut self` and
317
+ // `&self`, so that we can compare it against the binding.
318
+ ty:: Ref ( _, ty, _) => * ty,
319
+ _ => ty,
320
+ }
321
+ } else {
322
+ self . node_ty ( rcvr. hir_id )
323
+ } ;
324
+ let ty = eraser. fold_ty ( ty) ;
325
+ if ty. references_error ( ) {
326
+ break ;
327
+ }
328
+ if ty != prev {
329
+ span_labels. push ( (
330
+ s. ident . span ,
331
+ with_forced_trimmed_paths ! ( format!(
332
+ "here the type of `{ident}` is inferred to be `{ty}`" ,
333
+ ) ) ,
334
+ ) ) ;
335
+ prev = ty;
336
+ }
337
+ } else {
338
+ let ty = eraser. fold_ty ( self . node_ty ( ex. hir_id ) ) ;
339
+ if ty. references_error ( ) {
340
+ break ;
341
+ }
342
+ if ty != prev {
343
+ span_labels. push ( (
344
+ ex. span ,
345
+ with_forced_trimmed_paths ! ( format!(
346
+ "here the type of `{ident}` is inferred to be `{ty}`" ,
347
+ ) ) ,
348
+ ) ) ;
349
+ }
350
+ prev = ty;
351
+ }
352
+ if ex. hir_id == expr. hir_id {
353
+ // Stop showing spans after the error type was emitted.
354
+ break ;
355
+ }
356
+ }
357
+ }
358
+ for ( sp, label) in span_labels {
359
+ err. span_label ( sp, & label) ;
360
+ }
361
+ true
362
+ }
363
+
208
364
fn annotate_expected_due_to_let_ty (
209
365
& self ,
210
366
err : & mut Diagnostic ,
0 commit comments