@@ -313,6 +313,18 @@ pub trait TypeErrCtxtExt<'tcx> {
313313 predicate : ty:: Predicate < ' tcx > ,
314314 call_hir_id : HirId ,
315315 ) ;
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+
316328 fn point_at_chain (
317329 & self ,
318330 expr : & hir:: Expr < ' _ > ,
@@ -321,6 +333,7 @@ pub trait TypeErrCtxtExt<'tcx> {
321333 param_env : ty:: ParamEnv < ' tcx > ,
322334 err : & mut Diagnostic ,
323335 ) ;
336+
324337 fn probe_assoc_types_at_expr (
325338 & self ,
326339 type_diffs : & [ TypeError < ' tcx > ] ,
@@ -3592,6 +3605,109 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
35923605 }
35933606 }
35943607
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+
35953711 fn point_at_chain (
35963712 & self ,
35973713 expr : & hir:: Expr < ' _ > ,
@@ -3618,96 +3734,15 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
36183734 expr = rcvr_expr;
36193735 let assocs_in_this_method =
36203736 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+ ) ;
37113746 assocs. push ( assocs_in_this_method) ;
37123747 prev_ty = self . resolve_vars_if_possible (
37133748 typeck_results. expr_ty_adjusted_opt ( expr) . unwrap_or ( Ty :: new_misc_error ( tcx) ) ,
0 commit comments