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::DeepRejectCtxt;
use rustc_middle::ty::fast_reject::{simplify_type, TreatParams}; 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::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::{self, GenericArgKind, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::ty::{IsSuggestable, ToPolyTraitRef};
use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Symbol; use rustc_span::Symbol;
use rustc_span::{edit_distance, source_map, ExpnKind, FileName, MacroKind, Span}; 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 derives = Vec::<(String, Span, Symbol)>::new();
let mut traits = Vec::new(); let mut traits = Vec::new();
for (pred, _, _) in unsatisfied_predicates { 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() { let adt = match trait_pred.self_ty().ty_adt_def() {
Some(adt) if adt.did().is_local() => adt, Some(adt) if adt.did().is_local() => adt,
_ => continue, _ => continue,
@ -2085,22 +2089,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
| sym::Hash | sym::Hash
| sym::Debug => true, | sym::Debug => true,
_ => false, _ => 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 { if can_derive {
let self_name = trait_pred.self_ty().to_string(); let self_name = trait_pred.self_ty().to_string();
let self_span = self.tcx.def_span(adt.did()); 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
for super_trait in supertraits(self.tcx, poly_trait_ref.to_poly_trait_ref()) supertraits(self.tcx, ty::Binder::dummy(trait_pred.trait_ref))
{ {
if let Some(parent_diagnostic_name) = if let Some(parent_diagnostic_name) =
self.tcx.get_diagnostic_name(super_trait.def_id()) self.tcx.get_diagnostic_name(super_trait.def_id())
{ {
derives.push(( derives.push((self_name.clone(), self_span, parent_diagnostic_name));
self_name.clone(),
self_span,
parent_diagnostic_name,
));
}
} }
} }
derives.push((self_name, self_span, 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( self.lookup_op_method(
lhs_ty, lhs_ty,
Some((rhs_expr, rhs_ty)), Some((rhs_expr, rhs_ty)),
@ -416,6 +416,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected, expected,
) )
.is_ok() .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 // 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); suggest_deref_binop(*lhs_deref_ty);
} }
} else if self.suggest_fn_call(&mut err, lhs_expr, lhs_ty, |lhs_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| { }) || 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( }) || self.suggest_two_fn_call(
&mut err, &mut err,
rhs_expr, rhs_expr,
rhs_ty, rhs_ty,
lhs_expr, lhs_expr,
lhs_ty, 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 // Cool
} }

View File

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