Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unify binop errors wording #60497

Closed
estebank opened this issue May 3, 2019 · 7 comments · Fixed by #67189
Closed

Unify binop errors wording #60497

estebank opened this issue May 3, 2019 · 7 comments · Fixed by #67189
Assignees
Labels
A-diagnostics Area: Messages for errors, warnings, and lints C-enhancement Category: An issue proposing an enhancement or a PR with one. E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. E-mentor Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion. F-on_unimplemented Error messages that can be tackled with `#[rustc_on_unimplemented]` T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@estebank
Copy link
Contributor

estebank commented May 3, 2019

The following two errors are actually the same problem but have different output because they are handled in different parts of the compiler. We should unify the output to have similar, if not the same, text.

error[E0277]: cannot add `std::option::Option<i8>` to `i8`
 --> src/main.rs:5:13
  |
5 | let sum = x + y;
  |             ^ no implementation for `i8 + std::option::Option<i8>`
  |
  = help: the trait `std::ops::Add<std::option::Option<i8>>` is not implemented for `i8`
error[E0369]: binary operation `+` cannot be applied to type `std::option::Option<i8>`
 --> src/main.rs:5:13
  |
5 | let sum = y + x;
  |           - ^ - i8
  |           |
  |           std::option::Option<i8>
  |
  = note: an implementation of `std::ops::Add` might be missing for `std::option::Option<i8>`

This issue has been assigned to @LeSeulArtichaut via this comment.

@estebank estebank added the A-diagnostics Area: Messages for errors, warnings, and lints label May 3, 2019
@jonas-schievink jonas-schievink added C-enhancement Category: An issue proposing an enhancement or a PR with one. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels May 3, 2019
@Lonami
Copy link
Contributor

Lonami commented May 3, 2019

How should one go about implementing this? Somehow sorting the operator order to pick consistently? Or better to always show the two hints for both orderings?

@estebank
Copy link
Contributor Author

estebank commented May 3, 2019

We could do it by picking and matching wording from both errors to make them consistent with each other. The E0277 one can be updated by changing the rustc_on_unimplemented text for the trait, while E0369 can be updated by changing the following code:

IsAssign::No => {
let mut err = struct_span_err!(self.tcx.sess, op.span, E0369,
"binary operation `{}` cannot be applied to type `{}`",
op.node.as_str(),
lhs_ty);
let mut involves_fn = false;
if !lhs_expr.span.eq(&rhs_expr.span) {
involves_fn |= self.add_type_neq_err_label(
&mut err,
lhs_expr.span,
lhs_ty,
rhs_ty,
op,
is_assign
);
involves_fn |= self.add_type_neq_err_label(
&mut err,
rhs_expr.span,
rhs_ty,
lhs_ty,
op,
is_assign
);
}
let mut suggested_deref = false;
if let Ref(_, mut rty, _) = lhs_ty.sty {
if {
self.infcx.type_is_copy_modulo_regions(self.param_env,
rty,
lhs_expr.span) &&
self.lookup_op_method(rty,
&[rhs_ty],
Op::Binary(op, is_assign))
.is_ok()
} {
if let Ok(lstring) = source_map.span_to_snippet(lhs_expr.span) {
while let Ref(_, rty_inner, _) = rty.sty {
rty = rty_inner;
}
let msg = &format!(
"`{}` can be used on '{}', you can \
dereference `{2}`: `*{2}`",
op.node.as_str(),
rty,
lstring
);
err.help(msg);
suggested_deref = true;
}
}
}
let missing_trait = match op.node {
hir::BinOpKind::Add => Some("std::ops::Add"),
hir::BinOpKind::Sub => Some("std::ops::Sub"),
hir::BinOpKind::Mul => Some("std::ops::Mul"),
hir::BinOpKind::Div => Some("std::ops::Div"),
hir::BinOpKind::Rem => Some("std::ops::Rem"),
hir::BinOpKind::BitAnd => Some("std::ops::BitAnd"),
hir::BinOpKind::BitXor => Some("std::ops::BitXor"),
hir::BinOpKind::BitOr => Some("std::ops::BitOr"),
hir::BinOpKind::Shl => Some("std::ops::Shl"),
hir::BinOpKind::Shr => Some("std::ops::Shr"),
hir::BinOpKind::Eq |
hir::BinOpKind::Ne => Some("std::cmp::PartialEq"),
hir::BinOpKind::Lt |
hir::BinOpKind::Le |
hir::BinOpKind::Gt |
hir::BinOpKind::Ge => Some("std::cmp::PartialOrd"),
_ => None
};
if let Some(missing_trait) = missing_trait {
if op.node == hir::BinOpKind::Add &&
self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty,
rhs_ty, &mut err, false, op) {
// This has nothing here because it means we did string
// concatenation (e.g., "Hello " + "World!"). This means
// we don't want the note in the else clause to be emitted
} else if let ty::Param(_) = lhs_ty.sty {
// FIXME: point to span of param
err.note(&format!(
"`{}` might need a bound for `{}`",
lhs_ty, missing_trait
));
} else if !suggested_deref && !involves_fn {
err.note(&format!(
"an implementation of `{}` might \
be missing for `{}`",
missing_trait, lhs_ty
));
}
}
err.emit();

I think in the end E0369 should mimic E0277 and not worry about adding the type labels to E0277.

@JohnTitor
Copy link
Member

I'll work on this but I don't catch better wording. One of options is to change E0369 cannot be applied to type {} to cannot be applied to type {} and {}, is this reasonable? And should we also unify note/help wording?

@estebank estebank added the F-on_unimplemented Error messages that can be tackled with `#[rustc_on_unimplemented]` label Aug 4, 2019
@varkor varkor added E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. E-mentor Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion. labels Sep 24, 2019
@LeSeulArtichaut
Copy link
Contributor

@rustbot claim

@rustbot rustbot self-assigned this Dec 6, 2019
@estebank
Copy link
Contributor Author

estebank commented Dec 6, 2019

@JohnTitor I believe that doing the following should be enough to close this ticket:

error[E0277]: cannot add `std::option::Option<i8>` to `i8`
 --> src/main.rs:5:13
  |
5 | let sum = x + y;
  |             ^ no implementation for `i8 + std::option::Option<i8>`
  |
  = help: the trait `std::ops::Add<std::option::Option<i8>>` is not implemented for `i8`

error[E0369]: cannot add `i8` to `std::option::Option<i8>`
 --> src/main.rs:5:13
  |
5 | let sum = y + x;
  |           - ^ - i8
  |           | |
  |           | no implementation for `std::option::Option<i8> + i8`
  |           std::option::Option<i8>
  |
  = note: an implementation of `std::ops::Add<i8>` might be missing for `std::option::Option<i8>`

The note suggesting implementing Add<i8> should only be emitted if Option<i8> were local to the current crate, which it isn't, so in this case it shouldn't be emitted.

@LeSeulArtichaut feel free to reach out if you need help with this.

@LeSeulArtichaut
Copy link
Contributor

LeSeulArtichaut commented Dec 7, 2019

@estebank I don't know what to do with the comparaison operations. For example, this gives me E0308, and I haven't figured out a case with comparaison operators where E0369 is emitted. Am I missing something?

@estebank
Copy link
Contributor Author

estebank commented Dec 10, 2019

@LeSeulArtichaut it is ok if you only tackle a subset of all the binops, we can get back to == and other bool binops friends later.

These go through different parts of typeck, which is why they produce different results.

@bors bors closed this as completed in eac5fb8 Dec 19, 2019
Centril added a commit to Centril/rust that referenced this issue Feb 18, 2020
…, r=estebank

Do not emit note suggesting to implement operation trait to foreign type

When a binary operation isn't valid, you will get a lint proposing to add a trait implementation to make the operation possible. However, this cannot be done for foreign types, such as types from `core` or `std`.

For example:
```
= note: an implementation of `std::ops::Add` might be missing for `std::option::Option<i8>`
```
As mentioned in rust-lang#60497 (comment):
> The note suggesting implementing Add<i8> should only be emitted if Option<i8> were local to the current crate, which it isn't, so in this case it shouldn't be emitted.

(I will use the CI to check tests for me, or my computer will just burn... and running IDEs is not possible on a pile of ashes)

r? @estebank
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints C-enhancement Category: An issue proposing an enhancement or a PR with one. E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. E-mentor Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion. F-on_unimplemented Error messages that can be tackled with `#[rustc_on_unimplemented]` T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants