Fix a bad binop error when we need a call

This commit is contained in:
Michael Goulet 2023-04-27 01:32:44 +00:00
parent 015acc2611
commit 3125979b78
3 changed files with 39 additions and 21 deletions

View File

@ -27,8 +27,8 @@ use rustc_middle::traits::util::supertraits;
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
use rustc_middle::ty::print::{with_crate_prefix, with_forced_trimmed_paths};
use rustc_middle::ty::IsSuggestable;
use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::ty::{IsSuggestable, ToPolyTraitRef};
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Symbol;
use rustc_span::{edit_distance, source_map, ExpnKind, FileName, MacroKind, Span};
@ -2068,7 +2068,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut derives = Vec::<(String, Span, Symbol)>::new();
let mut traits = Vec::new();
for (pred, _, _) in unsatisfied_predicates {
let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = pred.kind().skip_binder() else { continue };
let Some(ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred))) =
pred.kind().no_bound_vars()
else {
continue
};
let adt = match trait_pred.self_ty().ty_adt_def() {
Some(adt) if adt.did().is_local() => adt,
_ => continue,
@ -2085,22 +2089,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
| sym::Hash
| sym::Debug => true,
_ => false,
} && match trait_pred.trait_ref.substs.as_slice() {
// Only suggest deriving if lhs == rhs...
[lhs, rhs] => {
if let Some(lhs) = lhs.as_type()
&& let Some(rhs) = rhs.as_type()
{
self.can_eq(self.param_env, lhs, rhs)
} else {
false
}
},
// Unary ops can always be derived
[_] => true,
_ => false,
};
if can_derive {
let self_name = trait_pred.self_ty().to_string();
let self_span = self.tcx.def_span(adt.did());
if let Some(poly_trait_ref) = pred.to_opt_poly_trait_pred() {
for super_trait in supertraits(self.tcx, poly_trait_ref.to_poly_trait_ref())
for super_trait in
supertraits(self.tcx, ty::Binder::dummy(trait_pred.trait_ref))
{
if let Some(parent_diagnostic_name) =
self.tcx.get_diagnostic_name(super_trait.def_id())
{
if let Some(parent_diagnostic_name) =
self.tcx.get_diagnostic_name(super_trait.def_id())
{
derives.push((
self_name.clone(),
self_span,
parent_diagnostic_name,
));
}
derives.push((self_name.clone(), self_span, parent_diagnostic_name));
}
}
derives.push((self_name, self_span, diagnostic_name));

View File

@ -408,7 +408,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
};
let is_compatible = |lhs_ty, rhs_ty| {
let is_compatible_after_call = |lhs_ty, rhs_ty| {
self.lookup_op_method(
lhs_ty,
Some((rhs_expr, rhs_ty)),
@ -416,6 +416,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected,
)
.is_ok()
// Suggest calling even if, after calling, the types don't
// implement the operator, since it'll lead to better
// diagnostics later.
|| self.can_eq(self.param_env, lhs_ty, rhs_ty)
};
// We should suggest `a + b` => `*a + b` if `a` is copy, and suggest
@ -436,16 +440,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
suggest_deref_binop(*lhs_deref_ty);
}
} else if self.suggest_fn_call(&mut err, lhs_expr, lhs_ty, |lhs_ty| {
is_compatible(lhs_ty, rhs_ty)
is_compatible_after_call(lhs_ty, rhs_ty)
}) || self.suggest_fn_call(&mut err, rhs_expr, rhs_ty, |rhs_ty| {
is_compatible(lhs_ty, rhs_ty)
is_compatible_after_call(lhs_ty, rhs_ty)
}) || self.suggest_two_fn_call(
&mut err,
rhs_expr,
rhs_ty,
lhs_expr,
lhs_ty,
|lhs_ty, rhs_ty| is_compatible(lhs_ty, rhs_ty),
|lhs_ty, rhs_ty| is_compatible_after_call(lhs_ty, rhs_ty),
) {
// Cool
}

View File

@ -11,11 +11,12 @@ note: an implementation of `PartialEq<fn(()) -> A {A::Value}>` might be missing
|
LL | enum A {
| ^^^^^^ must implement `PartialEq<fn(()) -> A {A::Value}>`
help: consider annotating `A` with `#[derive(PartialEq)]`
|
LL + #[derive(PartialEq)]
LL | enum A {
note: the trait `PartialEq` must be implemented
--> $SRC_DIR/core/src/cmp.rs:LL:COL
help: use parentheses to construct this tuple variant
|
LL | a == A::Value(/* () */);
| ++++++++++
error: aborting due to previous error