Rollup merge of #133130 - dianne:fix-133118, r=compiler-errors
`suggest_borrow_generic_arg`: instantiate clauses properly This simplifies and fixes the way `suggest_borrow_generic_arg` instantiates callees' predicates when testing them to see if a moved argument can instead be borrowed. Previously, it would ICE if the moved argument's type included a region variable, since it was getting passed to a call of `EarlyBinder::instantiate`. This makes the instantiation much more straightforward, which also fixes the ICE. Fixes #133118 This also modifies `tests/ui/moves/moved-value-on-as-ref-arg.rs` to have more useful bounds on the tests for suggestions to borrow `Borrow` and `BorrowMut` arguments. With its old tautological `T: BorrowMut<T>` bound, this fix would make it suggest a shared borrow for that argument.
This commit is contained in:
commit
fc4f71db68
5 changed files with 60 additions and 20 deletions
|
@ -27,7 +27,7 @@ use rustc_middle::mir::{
|
||||||
};
|
};
|
||||||
use rustc_middle::ty::print::PrintTraitRefExt as _;
|
use rustc_middle::ty::print::PrintTraitRefExt as _;
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, ClauseKind, PredicateKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, Upcast,
|
self, PredicateKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, Upcast,
|
||||||
suggest_constraining_type_params,
|
suggest_constraining_type_params,
|
||||||
};
|
};
|
||||||
use rustc_middle::util::CallKind;
|
use rustc_middle::util::CallKind;
|
||||||
|
@ -649,11 +649,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
) -> Option<ty::Mutability> {
|
) -> Option<ty::Mutability> {
|
||||||
let tcx = self.infcx.tcx;
|
let tcx = self.infcx.tcx;
|
||||||
let sig = tcx.fn_sig(callee_did).instantiate_identity().skip_binder();
|
let sig = tcx.fn_sig(callee_did).instantiate_identity().skip_binder();
|
||||||
let clauses = tcx.predicates_of(callee_did).instantiate_identity(self.infcx.tcx).predicates;
|
let clauses = tcx.predicates_of(callee_did);
|
||||||
|
|
||||||
// First, is there at least one method on one of `param`'s trait bounds?
|
// First, is there at least one method on one of `param`'s trait bounds?
|
||||||
// This keeps us from suggesting borrowing the argument to `mem::drop`, e.g.
|
// This keeps us from suggesting borrowing the argument to `mem::drop`, e.g.
|
||||||
if !clauses.iter().any(|clause| {
|
if !clauses.instantiate_identity(tcx).predicates.iter().any(|clause| {
|
||||||
clause.as_trait_clause().is_some_and(|tc| {
|
clause.as_trait_clause().is_some_and(|tc| {
|
||||||
tc.self_ty().skip_binder().is_param(param.index)
|
tc.self_ty().skip_binder().is_param(param.index)
|
||||||
&& tc.polarity() == ty::PredicatePolarity::Positive
|
&& tc.polarity() == ty::PredicatePolarity::Positive
|
||||||
|
@ -700,23 +700,17 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test the callee's predicates, substituting a reference in for the self ty
|
// Test the callee's predicates, substituting in `ref_ty` for the moved argument type.
|
||||||
// in bounds on `param`.
|
clauses.instantiate(tcx, new_args).predicates.iter().all(|&(mut clause)| {
|
||||||
clauses.iter().all(|&clause| {
|
// Normalize before testing to see through type aliases and projections.
|
||||||
let clause_for_ref = clause.kind().map_bound(|kind| match kind {
|
if let Ok(normalized) = tcx.try_normalize_erasing_regions(self.param_env, clause) {
|
||||||
ClauseKind::Trait(c) if c.self_ty().is_param(param.index) => {
|
clause = normalized;
|
||||||
ClauseKind::Trait(c.with_self_ty(tcx, ref_ty))
|
}
|
||||||
}
|
|
||||||
ClauseKind::Projection(c) if c.self_ty().is_param(param.index) => {
|
|
||||||
ClauseKind::Projection(c.with_self_ty(tcx, ref_ty))
|
|
||||||
}
|
|
||||||
_ => kind,
|
|
||||||
});
|
|
||||||
self.infcx.predicate_must_hold_modulo_regions(&Obligation::new(
|
self.infcx.predicate_must_hold_modulo_regions(&Obligation::new(
|
||||||
tcx,
|
tcx,
|
||||||
ObligationCause::dummy(),
|
ObligationCause::dummy(),
|
||||||
self.param_env,
|
self.param_env,
|
||||||
ty::EarlyBinder::bind(clause_for_ref).instantiate(tcx, generic_args),
|
clause,
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
}) {
|
}) {
|
||||||
|
|
|
@ -18,8 +18,8 @@ impl AsMut<Bar> for Bar {
|
||||||
|
|
||||||
fn foo<T: AsRef<Bar>>(_: T) {}
|
fn foo<T: AsRef<Bar>>(_: T) {}
|
||||||
fn qux<T: AsMut<Bar>>(_: T) {}
|
fn qux<T: AsMut<Bar>>(_: T) {}
|
||||||
fn bat<T: Borrow<T>>(_: T) {}
|
fn bat<T: Borrow<Bar>>(_: T) {}
|
||||||
fn baz<T: BorrowMut<T>>(_: T) {}
|
fn baz<T: BorrowMut<Bar>>(_: T) {}
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
let bar = Bar;
|
let bar = Bar;
|
||||||
|
|
|
@ -18,8 +18,8 @@ impl AsMut<Bar> for Bar {
|
||||||
|
|
||||||
fn foo<T: AsRef<Bar>>(_: T) {}
|
fn foo<T: AsRef<Bar>>(_: T) {}
|
||||||
fn qux<T: AsMut<Bar>>(_: T) {}
|
fn qux<T: AsMut<Bar>>(_: T) {}
|
||||||
fn bat<T: Borrow<T>>(_: T) {}
|
fn bat<T: Borrow<Bar>>(_: T) {}
|
||||||
fn baz<T: BorrowMut<T>>(_: T) {}
|
fn baz<T: BorrowMut<Bar>>(_: T) {}
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
let bar = Bar;
|
let bar = Bar;
|
||||||
|
|
25
tests/ui/moves/region-var-in-moved-ty-issue-133118.rs
Normal file
25
tests/ui/moves/region-var-in-moved-ty-issue-133118.rs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
//! regression test for #133118
|
||||||
|
|
||||||
|
pub trait Alpha {
|
||||||
|
fn y(self) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Beta {
|
||||||
|
type Gamma;
|
||||||
|
fn gamma(&self) -> Self::Gamma;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn a<T: Alpha>(_x: T) -> usize {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn x<B>(beta: &B) -> usize
|
||||||
|
where
|
||||||
|
for<'a> &'a B: Beta,
|
||||||
|
for<'a> <&'a B as Beta>::Gamma: Alpha,
|
||||||
|
{
|
||||||
|
let g1 = beta.gamma();
|
||||||
|
a(g1) + a(g1) //~ ERROR use of moved value: `g1` [E0382]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() {}
|
21
tests/ui/moves/region-var-in-moved-ty-issue-133118.stderr
Normal file
21
tests/ui/moves/region-var-in-moved-ty-issue-133118.stderr
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
error[E0382]: use of moved value: `g1`
|
||||||
|
--> $DIR/region-var-in-moved-ty-issue-133118.rs:22:15
|
||||||
|
|
|
||||||
|
LL | let g1 = beta.gamma();
|
||||||
|
| -- move occurs because `g1` has type `<&B as Beta>::Gamma`, which does not implement the `Copy` trait
|
||||||
|
LL | a(g1) + a(g1)
|
||||||
|
| -- ^^ value used here after move
|
||||||
|
| |
|
||||||
|
| value moved here
|
||||||
|
|
|
||||||
|
note: consider changing this parameter type in function `a` to borrow instead if owning the value isn't necessary
|
||||||
|
--> $DIR/region-var-in-moved-ty-issue-133118.rs:12:24
|
||||||
|
|
|
||||||
|
LL | pub fn a<T: Alpha>(_x: T) -> usize {
|
||||||
|
| - ^ this parameter takes ownership of the value
|
||||||
|
| |
|
||||||
|
| in this function
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0382`.
|
Loading…
Add table
Reference in a new issue