@@ -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 > ] ,
@@ -3592,6 +3605,109 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
3592
3605
}
3593
3606
}
3594
3607
3608
+ fn look_for_iterator_item_mistakes (
3609
+ & self ,
3610
+ assocs_in_this_method : & [ Option < ( Span , ( DefId , Ty < ' tcx > ) ) > ] ,
3611
+ typeck_results : & TypeckResults < ' tcx > ,
3612
+ type_diffs : & [ TypeError < ' tcx > ] ,
3613
+ param_env : ty:: ParamEnv < ' tcx > ,
3614
+ path_segment : & hir:: PathSegment < ' _ > ,
3615
+ args : & [ hir:: Expr < ' _ > ] ,
3616
+ err : & mut Diagnostic ,
3617
+ ) {
3618
+ let tcx = self . tcx ;
3619
+ // Special case for iterator chains, we look at potential failures of `Iterator::Item`
3620
+ // not being `: Clone` and `Iterator::map` calls with spurious trailing `;`.
3621
+ for entry in assocs_in_this_method {
3622
+ let Some ( ( _span, ( def_id, ty) ) ) = entry else {
3623
+ continue ;
3624
+ } ;
3625
+ for diff in type_diffs {
3626
+ let Sorts ( expected_found) = diff else {
3627
+ continue ;
3628
+ } ;
3629
+ if tcx. is_diagnostic_item ( sym:: IteratorItem , * def_id)
3630
+ && path_segment. ident . name == sym:: map
3631
+ && self . can_eq ( param_env, expected_found. found , * ty)
3632
+ && let [ arg] = args
3633
+ && let hir:: ExprKind :: Closure ( closure) = arg. kind
3634
+ {
3635
+ let body = tcx. hir ( ) . body ( closure. body ) ;
3636
+ if let hir:: ExprKind :: Block ( block, None ) = body. value . kind
3637
+ && let None = block. expr
3638
+ && let [ .., stmt] = block. stmts
3639
+ && let hir:: StmtKind :: Semi ( expr) = stmt. kind
3640
+ // FIXME: actually check the expected vs found types, but right now
3641
+ // the expected is a projection that we need to resolve.
3642
+ // && let Some(tail_ty) = typeck_results.expr_ty_opt(expr)
3643
+ && expected_found. found . is_unit ( )
3644
+ {
3645
+ err. span_suggestion_verbose (
3646
+ expr. span . shrink_to_hi ( ) . with_hi ( stmt. span . hi ( ) ) ,
3647
+ "consider removing this semicolon" ,
3648
+ String :: new ( ) ,
3649
+ Applicability :: MachineApplicable ,
3650
+ ) ;
3651
+ }
3652
+ let expr = if let hir:: ExprKind :: Block ( block, None ) = body. value . kind
3653
+ && let Some ( expr) = block. expr
3654
+ {
3655
+ expr
3656
+ } else {
3657
+ body. value
3658
+ } ;
3659
+ if let hir:: ExprKind :: MethodCall ( path_segment, rcvr, [ ] , span) = expr. kind
3660
+ && path_segment. ident . name == sym:: clone
3661
+ && let Some ( expr_ty) = typeck_results. expr_ty_opt ( expr)
3662
+ && let Some ( rcvr_ty) = typeck_results. expr_ty_opt ( rcvr)
3663
+ && self . can_eq ( param_env, expr_ty, rcvr_ty)
3664
+ && let ty:: Ref ( _, ty, _) = expr_ty. kind ( )
3665
+ {
3666
+ err. span_label (
3667
+ span,
3668
+ format ! (
3669
+ "this method call is cloning the reference `{expr_ty}`, not \
3670
+ `{ty}` which doesn't implement `Clone`",
3671
+ ) ,
3672
+ ) ;
3673
+ let ty:: Param ( ..) = ty. kind ( ) else {
3674
+ continue ;
3675
+ } ;
3676
+ let hir = tcx. hir ( ) ;
3677
+ let node = hir. get_by_def_id ( hir. get_parent_item ( expr. hir_id ) . def_id ) ;
3678
+
3679
+ let pred = ty:: Binder :: dummy ( ty:: TraitPredicate {
3680
+ trait_ref : ty:: TraitRef :: from_lang_item (
3681
+ tcx,
3682
+ LangItem :: Clone ,
3683
+ span,
3684
+ [ * ty] ,
3685
+ ) ,
3686
+ polarity : ty:: ImplPolarity :: Positive ,
3687
+ } ) ;
3688
+ let Some ( generics) = node. generics ( ) else {
3689
+ continue ;
3690
+ } ;
3691
+ let Some ( body_id) = node. body_id ( ) else {
3692
+ continue ;
3693
+ } ;
3694
+ suggest_restriction (
3695
+ tcx,
3696
+ hir. body_owner_def_id ( body_id) ,
3697
+ & generics,
3698
+ & format ! ( "type parameter `{ty}`" ) ,
3699
+ err,
3700
+ node. fn_sig ( ) ,
3701
+ None ,
3702
+ pred,
3703
+ None ,
3704
+ ) ;
3705
+ }
3706
+ }
3707
+ }
3708
+ }
3709
+ }
3710
+
3595
3711
fn point_at_chain (
3596
3712
& self ,
3597
3713
expr : & hir:: Expr < ' _ > ,
@@ -3618,96 +3734,15 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
3618
3734
expr = rcvr_expr;
3619
3735
let assocs_in_this_method =
3620
3736
self . probe_assoc_types_at_expr ( & type_diffs, span, prev_ty, expr. hir_id , param_env) ;
3621
- // Special case for iterator chains, we look at potential failures of `Iterator::Item`
3622
- // not being `: Clone` and `Iterator::map` calls with spurious trailing `;`.
3623
- for entry in & assocs_in_this_method {
3624
- let Some ( ( _span, ( def_id, ty) ) ) = entry else {
3625
- continue ;
3626
- } ;
3627
- for diff in & type_diffs {
3628
- let Sorts ( expected_found) = diff else {
3629
- continue ;
3630
- } ;
3631
- if tcx. is_diagnostic_item ( sym:: IteratorItem , * def_id)
3632
- && path_segment. ident . name == sym:: map
3633
- && self . can_eq ( param_env, expected_found. found , * ty)
3634
- && let [ arg] = args
3635
- && let hir:: ExprKind :: Closure ( closure) = arg. kind
3636
- {
3637
- let body = tcx. hir ( ) . body ( closure. body ) ;
3638
- if let hir:: ExprKind :: Block ( block, None ) = body. value . kind
3639
- && let None = block. expr
3640
- && let [ .., stmt] = block. stmts
3641
- && let hir:: StmtKind :: Semi ( expr) = stmt. kind
3642
- // FIXME: actually check the expected vs found types, but right now
3643
- // the expected is a projection that we need to resolve.
3644
- // && let Some(tail_ty) = typeck_results.expr_ty_opt(expr)
3645
- && expected_found. found . is_unit ( )
3646
- {
3647
- err. span_suggestion_verbose (
3648
- expr. span . shrink_to_hi ( ) . with_hi ( stmt. span . hi ( ) ) ,
3649
- "consider removing this semicolon" ,
3650
- String :: new ( ) ,
3651
- Applicability :: MachineApplicable ,
3652
- ) ;
3653
- }
3654
- let expr = if let hir:: ExprKind :: Block ( block, None ) = body. value . kind
3655
- && let Some ( expr) = block. expr
3656
- {
3657
- expr
3658
- } else {
3659
- body. value
3660
- } ;
3661
- if let hir:: ExprKind :: MethodCall ( path_segment, rcvr, [ ] , span) = expr. kind
3662
- && path_segment. ident . name == sym:: clone
3663
- && let Some ( expr_ty) = typeck_results. expr_ty_opt ( expr)
3664
- && let Some ( rcvr_ty) = typeck_results. expr_ty_opt ( rcvr)
3665
- && self . can_eq ( param_env, expr_ty, rcvr_ty)
3666
- && let ty:: Ref ( _, ty, _) = expr_ty. kind ( )
3667
- {
3668
- err. span_label (
3669
- span,
3670
- format ! (
3671
- "this method call is cloning the reference `{expr_ty}`, not \
3672
- `{ty}` which doesn't implement `Clone`",
3673
- ) ,
3674
- ) ;
3675
- let ty:: Param ( ..) = ty. kind ( ) else {
3676
- continue ;
3677
- } ;
3678
- let hir = tcx. hir ( ) ;
3679
- let node = hir. get_by_def_id ( hir. get_parent_item ( expr. hir_id ) . def_id ) ;
3680
-
3681
- let pred = ty:: Binder :: dummy ( ty:: TraitPredicate {
3682
- trait_ref : ty:: TraitRef :: from_lang_item (
3683
- tcx,
3684
- LangItem :: Clone ,
3685
- span,
3686
- [ * ty] ,
3687
- ) ,
3688
- polarity : ty:: ImplPolarity :: Positive ,
3689
- } ) ;
3690
- let Some ( generics) = node. generics ( ) else {
3691
- continue ;
3692
- } ;
3693
- let Some ( body_id) = node. body_id ( ) else {
3694
- continue ;
3695
- } ;
3696
- suggest_restriction (
3697
- tcx,
3698
- hir. body_owner_def_id ( body_id) ,
3699
- & generics,
3700
- & format ! ( "type parameter `{ty}`" ) ,
3701
- err,
3702
- node. fn_sig ( ) ,
3703
- None ,
3704
- pred,
3705
- None ,
3706
- ) ;
3707
- }
3708
- }
3709
- }
3710
- }
3737
+ self . look_for_iterator_item_mistakes (
3738
+ & assocs_in_this_method,
3739
+ typeck_results,
3740
+ & type_diffs,
3741
+ param_env,
3742
+ path_segment,
3743
+ args,
3744
+ err,
3745
+ ) ;
3711
3746
assocs. push ( assocs_in_this_method) ;
3712
3747
prev_ty = self . resolve_vars_if_possible (
3713
3748
typeck_results. expr_ty_adjusted_opt ( expr) . unwrap_or ( Ty :: new_misc_error ( tcx) ) ,
0 commit comments