1
Fork 0

Suggest dereferncing when possible in E0277, fix #87437

This commit is contained in:
Esteban Kuber 2022-03-26 23:01:29 +00:00
parent ac8cbbd200
commit 883b93c7b7
7 changed files with 121 additions and 41 deletions

View file

@ -1,6 +1,6 @@
use super::{ use super::{
EvaluationResult, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation, DerivedObligationCause, EvaluationResult, ImplDerivedObligationCause, Obligation,
SelectionContext, ObligationCause, ObligationCauseCode, PredicateObligation, SelectionContext,
}; };
use crate::autoderef::Autoderef; use crate::autoderef::Autoderef;
@ -496,24 +496,38 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
trait_pred: ty::PolyTraitPredicate<'tcx>, trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> bool { ) -> bool {
// It only make sense when suggesting dereferences for arguments // It only make sense when suggesting dereferences for arguments
let code = if let ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } = let ObligationCauseCode::FunctionArgumentObligation { .. } = obligation.cause.code() else {
obligation.cause.code()
{
parent_code.clone()
} else {
return false; return false;
}; };
let param_env = obligation.param_env; let param_env = obligation.param_env;
let body_id = obligation.cause.body_id; let body_id = obligation.cause.body_id;
let span = obligation.cause.span; let span = obligation.cause.span;
let real_trait_pred = match &*code { let mut real_trait_pred = trait_pred;
ObligationCauseCode::ImplDerivedObligation(cause) => cause.derived.parent_trait_pred, let mut code = obligation.cause.code();
ObligationCauseCode::DerivedObligation(cause) loop {
| ObligationCauseCode::BuiltinDerivedObligation(cause) => cause.parent_trait_pred, match &code {
_ => trait_pred, ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => {
code = &parent_code;
}
ObligationCauseCode::ImplDerivedObligation(box ImplDerivedObligationCause {
derived: DerivedObligationCause { parent_code, parent_trait_pred },
..
})
| ObligationCauseCode::BuiltinDerivedObligation(DerivedObligationCause {
parent_code,
parent_trait_pred,
})
| ObligationCauseCode::DerivedObligation(DerivedObligationCause {
parent_code,
parent_trait_pred,
}) => {
code = &parent_code;
real_trait_pred = *parent_trait_pred;
}
_ => break,
}; };
let Some(real_ty) = real_trait_pred.self_ty().no_bound_vars() else { let Some(real_ty) = real_trait_pred.self_ty().no_bound_vars() else {
return false; continue;
}; };
if let ty::Ref(region, base_ty, mutbl) = *real_ty.kind() { if let ty::Ref(region, base_ty, mutbl) = *real_ty.kind() {
@ -533,7 +547,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
let derefs = "*".repeat(steps); let derefs = "*".repeat(steps);
err.span_suggestion( err.span_suggestion(
span, span,
"consider adding dereference here", "consider dereferencing here",
format!("&{}{}", derefs, &src[1..]), format!("&{}{}", derefs, &src[1..]),
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
@ -541,6 +555,20 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
} }
} }
} }
} else if real_trait_pred != trait_pred {
// This branch addresses #87437.
let obligation =
self.mk_trait_obligation_with_new_self_ty(param_env, real_trait_pred, base_ty);
if self.predicate_may_hold(&obligation) {
err.span_suggestion_verbose(
span.shrink_to_lo(),
"consider dereferencing here",
"*".to_string(),
Applicability::MachineApplicable,
);
return true;
}
}
} }
} }
false false

View file

@ -5,7 +5,7 @@ LL | let _errors = TcpListener::bind(&bad);
| ----------------- ^^^^ | ----------------- ^^^^
| | | | | |
| | the trait `ToSocketAddrs` is not implemented for `NoToSocketAddrs` | | the trait `ToSocketAddrs` is not implemented for `NoToSocketAddrs`
| | help: consider adding dereference here: `&*bad` | | help: consider dereferencing here: `&*bad`
| required by a bound introduced by this call | required by a bound introduced by this call
| |
= note: required because of the requirements on the impl of `ToSocketAddrs` for `&NoToSocketAddrs` = note: required because of the requirements on the impl of `ToSocketAddrs` for `&NoToSocketAddrs`

View file

@ -5,7 +5,7 @@ LL | takes_type_parameter(&string); // Error
| -------------------- ^^^^^^^ | -------------------- ^^^^^^^
| | | | | |
| | the trait `SomeTrait` is not implemented for `&String` | | the trait `SomeTrait` is not implemented for `&String`
| | help: consider adding dereference here: `&*string` | | help: consider dereferencing here: `&*string`
| required by a bound introduced by this call | required by a bound introduced by this call
| |
note: required by a bound in `takes_type_parameter` note: required by a bound in `takes_type_parameter`

View file

@ -5,7 +5,7 @@ LL | foo(&baz);
| --- ^^^^ | --- ^^^^
| | | | | |
| | the trait `Happy` is not implemented for `&Baz` | | the trait `Happy` is not implemented for `&Baz`
| | help: consider adding dereference here: `&***baz` | | help: consider dereferencing here: `&***baz`
| required by a bound introduced by this call | required by a bound introduced by this call
| |
note: required by a bound in `foo` note: required by a bound in `foo`

View file

@ -0,0 +1,14 @@
// run-rustfix
fn get_vowel_count(string: &str) -> usize {
string
.chars()
.filter(|c| "aeiou".contains(*c))
//~^ ERROR expected a `Fn<(char,)>` closure, found `char`
.count()
}
fn main() {
let _ = get_vowel_count("asdf");
}

View file

@ -0,0 +1,14 @@
// run-rustfix
fn get_vowel_count(string: &str) -> usize {
string
.chars()
.filter(|c| "aeiou".contains(c))
//~^ ERROR expected a `Fn<(char,)>` closure, found `char`
.count()
}
fn main() {
let _ = get_vowel_count("asdf");
}

View file

@ -0,0 +1,24 @@
error[E0277]: expected a `Fn<(char,)>` closure, found `char`
--> $DIR/root-obligation.rs:6:38
|
LL | .filter(|c| "aeiou".contains(c))
| -------- ^ expected an `Fn<(char,)>` closure, found `char`
| |
| required by a bound introduced by this call
|
= help: the trait `Fn<(char,)>` is not implemented for `char`
= note: required because of the requirements on the impl of `FnOnce<(char,)>` for `&char`
= note: required because of the requirements on the impl of `Pattern<'_>` for `&char`
note: required by a bound in `core::str::<impl str>::contains`
--> $SRC_DIR/core/src/str/mod.rs:LL:COL
|
LL | pub fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
| ^^^^^^^^^^^ required by this bound in `core::str::<impl str>::contains`
help: consider dereferencing here
|
LL | .filter(|c| "aeiou".contains(*c))
| +
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.