suggest both immutable and mutable trait implementations
This commit is contained in:
parent
4da89a180f
commit
0661c2de24
3 changed files with 70 additions and 32 deletions
|
@ -714,22 +714,28 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
let mut_substs = self.tcx.mk_substs_trait(mut_borrowed_found_ty, &[]);
|
let mut_substs = self.tcx.mk_substs_trait(mut_borrowed_found_ty, &[]);
|
||||||
|
|
||||||
// Try to apply the original trait binding obligation by borrowing.
|
// Try to apply the original trait binding obligation by borrowing.
|
||||||
let mut try_borrowing = |new_trait_ref: ty::TraitRef<'tcx>,
|
let mut try_borrowing = |new_imm_trait_ref: ty::TraitRef<'tcx>,
|
||||||
|
new_mut_trait_ref: ty::TraitRef<'tcx>,
|
||||||
expected_trait_ref: ty::TraitRef<'tcx>,
|
expected_trait_ref: ty::TraitRef<'tcx>,
|
||||||
mtbl: bool,
|
|
||||||
blacklist: &[DefId]|
|
blacklist: &[DefId]|
|
||||||
-> bool {
|
-> bool {
|
||||||
if blacklist.contains(&expected_trait_ref.def_id) {
|
if blacklist.contains(&expected_trait_ref.def_id) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let new_obligation = Obligation::new(
|
let imm_result = self.predicate_must_hold_modulo_regions(&Obligation::new(
|
||||||
ObligationCause::dummy(),
|
ObligationCause::dummy(),
|
||||||
param_env,
|
param_env,
|
||||||
ty::Binder::dummy(new_trait_ref).without_const().to_predicate(self.tcx),
|
ty::Binder::dummy(new_imm_trait_ref).without_const().to_predicate(self.tcx),
|
||||||
);
|
));
|
||||||
|
|
||||||
if self.predicate_must_hold_modulo_regions(&new_obligation) {
|
let mut_result = self.predicate_must_hold_modulo_regions(&Obligation::new(
|
||||||
|
ObligationCause::dummy(),
|
||||||
|
param_env,
|
||||||
|
ty::Binder::dummy(new_mut_trait_ref).without_const().to_predicate(self.tcx),
|
||||||
|
));
|
||||||
|
|
||||||
|
if imm_result || mut_result {
|
||||||
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
|
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
|
||||||
// We have a very specific type of error, where just borrowing this argument
|
// We have a very specific type of error, where just borrowing this argument
|
||||||
// might solve the problem. In cases like this, the important part is the
|
// might solve the problem. In cases like this, the important part is the
|
||||||
|
@ -773,16 +779,25 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
// }
|
// }
|
||||||
// ```
|
// ```
|
||||||
|
|
||||||
|
if imm_result && mut_result {
|
||||||
|
err.span_suggestions(
|
||||||
|
span,
|
||||||
|
"consider borrowing here",
|
||||||
|
[format!("&{}", snippet), format!("&mut {}", snippet)].into_iter(),
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
span,
|
span,
|
||||||
&format!(
|
&format!(
|
||||||
"consider{} borrowing here",
|
"consider{} borrowing here",
|
||||||
if mtbl { " mutably" } else { "" }
|
if mut_result { " mutably" } else { "" }
|
||||||
),
|
),
|
||||||
format!("&{}{}", if mtbl { "mut " } else { "" }, snippet),
|
format!("&{}{}", if mut_result { "mut " } else { "" }, snippet),
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -795,29 +810,16 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
ty::TraitRef::new(obligation.parent_trait_ref.def_id(), imm_substs);
|
ty::TraitRef::new(obligation.parent_trait_ref.def_id(), imm_substs);
|
||||||
let new_mut_trait_ref =
|
let new_mut_trait_ref =
|
||||||
ty::TraitRef::new(obligation.parent_trait_ref.def_id(), mut_substs);
|
ty::TraitRef::new(obligation.parent_trait_ref.def_id(), mut_substs);
|
||||||
if try_borrowing(new_imm_trait_ref, expected_trait_ref, false, &[]) {
|
return try_borrowing(new_imm_trait_ref, new_mut_trait_ref, expected_trait_ref, &[]);
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return try_borrowing(new_mut_trait_ref, expected_trait_ref, true, &[]);
|
|
||||||
}
|
|
||||||
} else if let ObligationCauseCode::BindingObligation(_, _)
|
} else if let ObligationCauseCode::BindingObligation(_, _)
|
||||||
| ObligationCauseCode::ItemObligation(_) = &*code
|
| ObligationCauseCode::ItemObligation(_) = &*code
|
||||||
{
|
{
|
||||||
if try_borrowing(
|
|
||||||
ty::TraitRef::new(trait_ref.def_id, imm_substs),
|
|
||||||
trait_ref,
|
|
||||||
false,
|
|
||||||
&never_suggest_borrow[..],
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return try_borrowing(
|
return try_borrowing(
|
||||||
|
ty::TraitRef::new(trait_ref.def_id, imm_substs),
|
||||||
ty::TraitRef::new(trait_ref.def_id, mut_substs),
|
ty::TraitRef::new(trait_ref.def_id, mut_substs),
|
||||||
trait_ref,
|
trait_ref,
|
||||||
true,
|
|
||||||
&never_suggest_borrow[..],
|
&never_suggest_borrow[..],
|
||||||
);
|
);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
trait Trait {}
|
||||||
|
|
||||||
|
struct S;
|
||||||
|
|
||||||
|
impl Trait for &S {}
|
||||||
|
impl Trait for &mut S {}
|
||||||
|
|
||||||
|
fn foo<X: Trait>(_: X) {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let s = S;
|
||||||
|
foo(s); //~ ERROR the trait bound `S: Trait` is not satisfied
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
error[E0277]: the trait bound `S: Trait` is not satisfied
|
||||||
|
--> $DIR/suggest-both-imm-and-mut-trait-implementation.rs:12:9
|
||||||
|
|
|
||||||
|
LL | foo(s);
|
||||||
|
| --- ^ expected an implementor of trait `Trait`
|
||||||
|
| |
|
||||||
|
| required by a bound introduced by this call
|
||||||
|
|
|
||||||
|
note: required by a bound in `foo`
|
||||||
|
--> $DIR/suggest-both-imm-and-mut-trait-implementation.rs:8:11
|
||||||
|
|
|
||||||
|
LL | fn foo<X: Trait>(_: X) {}
|
||||||
|
| ^^^^^ required by this bound in `foo`
|
||||||
|
help: consider borrowing here
|
||||||
|
|
|
||||||
|
LL | foo(&s);
|
||||||
|
| ~~
|
||||||
|
LL | foo(&mut s);
|
||||||
|
| ~~~~~~
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
Loading…
Add table
Add a link
Reference in a new issue