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:
Jacob Pratt 2024-11-17 22:30:49 -05:00 committed by GitHub
commit fc4f71db68
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 60 additions and 20 deletions

View File

@ -27,7 +27,7 @@ use rustc_middle::mir::{
};
use rustc_middle::ty::print::PrintTraitRefExt as _;
use rustc_middle::ty::{
self, ClauseKind, PredicateKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, Upcast,
self, PredicateKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, Upcast,
suggest_constraining_type_params,
};
use rustc_middle::util::CallKind;
@ -649,11 +649,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
) -> Option<ty::Mutability> {
let tcx = self.infcx.tcx;
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?
// 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| {
tc.self_ty().skip_binder().is_param(param.index)
&& tc.polarity() == ty::PredicatePolarity::Positive
@ -700,23 +700,17 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
return false;
}
// Test the callee's predicates, substituting a reference in for the self ty
// in bounds on `param`.
clauses.iter().all(|&clause| {
let clause_for_ref = clause.kind().map_bound(|kind| match kind {
ClauseKind::Trait(c) if c.self_ty().is_param(param.index) => {
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,
});
// Test the callee's predicates, substituting in `ref_ty` for the moved argument type.
clauses.instantiate(tcx, new_args).predicates.iter().all(|&(mut clause)| {
// Normalize before testing to see through type aliases and projections.
if let Ok(normalized) = tcx.try_normalize_erasing_regions(self.param_env, clause) {
clause = normalized;
}
self.infcx.predicate_must_hold_modulo_regions(&Obligation::new(
tcx,
ObligationCause::dummy(),
self.param_env,
ty::EarlyBinder::bind(clause_for_ref).instantiate(tcx, generic_args),
clause,
))
})
}) {

View File

@ -18,8 +18,8 @@ impl AsMut<Bar> for Bar {
fn foo<T: AsRef<Bar>>(_: T) {}
fn qux<T: AsMut<Bar>>(_: T) {}
fn bat<T: Borrow<T>>(_: T) {}
fn baz<T: BorrowMut<T>>(_: T) {}
fn bat<T: Borrow<Bar>>(_: T) {}
fn baz<T: BorrowMut<Bar>>(_: T) {}
pub fn main() {
let bar = Bar;

View File

@ -18,8 +18,8 @@ impl AsMut<Bar> for Bar {
fn foo<T: AsRef<Bar>>(_: T) {}
fn qux<T: AsMut<Bar>>(_: T) {}
fn bat<T: Borrow<T>>(_: T) {}
fn baz<T: BorrowMut<T>>(_: T) {}
fn bat<T: Borrow<Bar>>(_: T) {}
fn baz<T: BorrowMut<Bar>>(_: T) {}
pub fn main() {
let bar = Bar;

View 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() {}

View 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`.