Skip to content

Commit 26954f6

Browse files
committed
address review comment
1 parent 6d23ee8 commit 26954f6

File tree

1 file changed

+125
-90
lines changed
  • compiler/rustc_trait_selection/src/traits/error_reporting

1 file changed

+125
-90
lines changed

compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs

+125-90
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)