@@ -313,6 +313,18 @@ pub trait TypeErrCtxtExt<'tcx> {
313
313
predicate : ty:: Predicate < ' tcx > ,
314
314
call_hir_id : HirId ,
315
315
) ;
316
+
317
+ fn look_for_iterator_item_mistakes (
318
+ & self ,
319
+ assocs_in_this_method : & [ Option < ( Span , ( DefId , Ty < ' tcx > ) ) > ] ,
320
+ typeck_results : & TypeckResults < ' tcx > ,
321
+ type_diffs : & [ TypeError < ' tcx > ] ,
322
+ param_env : ty:: ParamEnv < ' tcx > ,
323
+ path_segment : & hir:: PathSegment < ' _ > ,
324
+ args : & [ hir:: Expr < ' _ > ] ,
325
+ err : & mut Diagnostic ,
326
+ ) ;
327
+
316
328
fn point_at_chain (
317
329
& self ,
318
330
expr : & hir:: Expr < ' _ > ,
@@ -321,6 +333,7 @@ pub trait TypeErrCtxtExt<'tcx> {
321
333
param_env : ty:: ParamEnv < ' tcx > ,
322
334
err : & mut Diagnostic ,
323
335
) ;
336
+
324
337
fn probe_assoc_types_at_expr (
325
338
& self ,
326
339
type_diffs : & [ TypeError < ' tcx > ] ,
@@ -3612,6 +3625,109 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
3612
3625
}
3613
3626
}
3614
3627
3628
+ fn look_for_iterator_item_mistakes (
3629
+ & self ,
3630
+ assocs_in_this_method : & [ Option < ( Span , ( DefId , Ty < ' tcx > ) ) > ] ,
3631
+ typeck_results : & TypeckResults < ' tcx > ,
3632
+ type_diffs : & [ TypeError < ' tcx > ] ,
3633
+ param_env : ty:: ParamEnv < ' tcx > ,
3634
+ path_segment : & hir:: PathSegment < ' _ > ,
3635
+ args : & [ hir:: Expr < ' _ > ] ,
3636
+ err : & mut Diagnostic ,
3637
+ ) {
3638
+ let tcx = self . tcx ;
3639
+ // Special case for iterator chains, we look at potential failures of `Iterator::Item`
3640
+ // not being `: Clone` and `Iterator::map` calls with spurious trailing `;`.
3641
+ for entry in assocs_in_this_method {
3642
+ let Some ( ( _span, ( def_id, ty) ) ) = entry else {
3643
+ continue ;
3644
+ } ;
3645
+ for diff in type_diffs {
3646
+ let Sorts ( expected_found) = diff else {
3647
+ continue ;
3648
+ } ;
3649
+ if tcx. is_diagnostic_item ( sym:: IteratorItem , * def_id)
3650
+ && path_segment. ident . name == sym:: map
3651
+ && self . can_eq ( param_env, expected_found. found , * ty)
3652
+ && let [ arg] = args
3653
+ && let hir:: ExprKind :: Closure ( closure) = arg. kind
3654
+ {
3655
+ let body = tcx. hir ( ) . body ( closure. body ) ;
3656
+ if let hir:: ExprKind :: Block ( block, None ) = body. value . kind
3657
+ && let None = block. expr
3658
+ && let [ .., stmt] = block. stmts
3659
+ && let hir:: StmtKind :: Semi ( expr) = stmt. kind
3660
+ // FIXME: actually check the expected vs found types, but right now
3661
+ // the expected is a projection that we need to resolve.
3662
+ // && let Some(tail_ty) = typeck_results.expr_ty_opt(expr)
3663
+ && expected_found. found . is_unit ( )
3664
+ {
3665
+ err. span_suggestion_verbose (
3666
+ expr. span . shrink_to_hi ( ) . with_hi ( stmt. span . hi ( ) ) ,
3667
+ "consider removing this semicolon" ,
3668
+ String :: new ( ) ,
3669
+ Applicability :: MachineApplicable ,
3670
+ ) ;
3671
+ }
3672
+ let expr = if let hir:: ExprKind :: Block ( block, None ) = body. value . kind
3673
+ && let Some ( expr) = block. expr
3674
+ {
3675
+ expr
3676
+ } else {
3677
+ body. value
3678
+ } ;
3679
+ if let hir:: ExprKind :: MethodCall ( path_segment, rcvr, [ ] , span) = expr. kind
3680
+ && path_segment. ident . name == sym:: clone
3681
+ && let Some ( expr_ty) = typeck_results. expr_ty_opt ( expr)
3682
+ && let Some ( rcvr_ty) = typeck_results. expr_ty_opt ( rcvr)
3683
+ && self . can_eq ( param_env, expr_ty, rcvr_ty)
3684
+ && let ty:: Ref ( _, ty, _) = expr_ty. kind ( )
3685
+ {
3686
+ err. span_label (
3687
+ span,
3688
+ format ! (
3689
+ "this method call is cloning the reference `{expr_ty}`, not \
3690
+ `{ty}` which doesn't implement `Clone`",
3691
+ ) ,
3692
+ ) ;
3693
+ let ty:: Param ( ..) = ty. kind ( ) else {
3694
+ continue ;
3695
+ } ;
3696
+ let hir = tcx. hir ( ) ;
3697
+ let node = hir. get_by_def_id ( hir. get_parent_item ( expr. hir_id ) . def_id ) ;
3698
+
3699
+ let pred = ty:: Binder :: dummy ( ty:: TraitPredicate {
3700
+ trait_ref : ty:: TraitRef :: from_lang_item (
3701
+ tcx,
3702
+ LangItem :: Clone ,
3703
+ span,
3704
+ [ * ty] ,
3705
+ ) ,
3706
+ polarity : ty:: ImplPolarity :: Positive ,
3707
+ } ) ;
3708
+ let Some ( generics) = node. generics ( ) else {
3709
+ continue ;
3710
+ } ;
3711
+ let Some ( body_id) = node. body_id ( ) else {
3712
+ continue ;
3713
+ } ;
3714
+ suggest_restriction (
3715
+ tcx,
3716
+ hir. body_owner_def_id ( body_id) ,
3717
+ & generics,
3718
+ & format ! ( "type parameter `{ty}`" ) ,
3719
+ err,
3720
+ node. fn_sig ( ) ,
3721
+ None ,
3722
+ pred,
3723
+ None ,
3724
+ ) ;
3725
+ }
3726
+ }
3727
+ }
3728
+ }
3729
+ }
3730
+
3615
3731
fn point_at_chain (
3616
3732
& self ,
3617
3733
expr : & hir:: Expr < ' _ > ,
@@ -3631,13 +3747,22 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
3631
3747
let mut prev_ty = self . resolve_vars_if_possible (
3632
3748
typeck_results. expr_ty_adjusted_opt ( expr) . unwrap_or ( Ty :: new_misc_error ( tcx) ) ,
3633
3749
) ;
3634
- while let hir:: ExprKind :: MethodCall ( _path_segment , rcvr_expr, _args , span) = expr. kind {
3750
+ while let hir:: ExprKind :: MethodCall ( path_segment , rcvr_expr, args , span) = expr. kind {
3635
3751
// Point at every method call in the chain with the resulting type.
3636
3752
// vec![1, 2, 3].iter().map(mapper).sum<i32>()
3637
3753
// ^^^^^^ ^^^^^^^^^^^
3638
3754
expr = rcvr_expr;
3639
3755
let assocs_in_this_method =
3640
3756
self . probe_assoc_types_at_expr ( & type_diffs, span, prev_ty, expr. hir_id , param_env) ;
3757
+ self . look_for_iterator_item_mistakes (
3758
+ & assocs_in_this_method,
3759
+ typeck_results,
3760
+ & type_diffs,
3761
+ param_env,
3762
+ path_segment,
3763
+ args,
3764
+ err,
3765
+ ) ;
3641
3766
assocs. push ( assocs_in_this_method) ;
3642
3767
prev_ty = self . resolve_vars_if_possible (
3643
3768
typeck_results. expr_ty_adjusted_opt ( expr) . unwrap_or ( Ty :: new_misc_error ( tcx) ) ,
0 commit comments