Do not ICE when suggesting dereferencing closure arg
Account for `for` lifetimes when constructing closure to see if dereferencing the return value would be valid. Fix #125634, fix #124563.
This commit is contained in:
parent
33422e72c8
commit
a2298a6f19
@ -1152,7 +1152,9 @@ fn suggest_deref_closure_return(&self, diag: &mut Diag<'_>) {
|
|||||||
// Get the arguments for the found method, only specifying that `Self` is the receiver type.
|
// Get the arguments for the found method, only specifying that `Self` is the receiver type.
|
||||||
let Some(possible_rcvr_ty) = typeck_results.node_type_opt(rcvr.hir_id) else { return };
|
let Some(possible_rcvr_ty) = typeck_results.node_type_opt(rcvr.hir_id) else { return };
|
||||||
let args = GenericArgs::for_item(tcx, method_def_id, |param, _| {
|
let args = GenericArgs::for_item(tcx, method_def_id, |param, _| {
|
||||||
if param.index == 0 {
|
if let ty::GenericParamDefKind::Lifetime = param.kind {
|
||||||
|
tcx.lifetimes.re_erased.into()
|
||||||
|
} else if param.index == 0 && param.name == kw::SelfUpper {
|
||||||
possible_rcvr_ty.into()
|
possible_rcvr_ty.into()
|
||||||
} else if param.index == closure_param.index {
|
} else if param.index == closure_param.index {
|
||||||
closure_ty.into()
|
closure_ty.into()
|
||||||
@ -1169,7 +1171,7 @@ fn suggest_deref_closure_return(&self, diag: &mut Diag<'_>) {
|
|||||||
Obligation::misc(tcx, span, self.mir_def_id(), self.param_env, pred)
|
Obligation::misc(tcx, span, self.mir_def_id(), self.param_env, pred)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if ocx.select_all_or_error().is_empty() {
|
if ocx.select_all_or_error().is_empty() && count > 0 {
|
||||||
diag.span_suggestion_verbose(
|
diag.span_suggestion_verbose(
|
||||||
tcx.hir().body(*body).value.peel_blocks().span.shrink_to_lo(),
|
tcx.hir().body(*body).value.peel_blocks().span.shrink_to_lo(),
|
||||||
"dereference the return value",
|
"dereference the return value",
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
// #125634
|
||||||
|
struct Thing;
|
||||||
|
|
||||||
|
// Invariant in 'a, Covariant in 'b
|
||||||
|
struct TwoThings<'a, 'b>(*mut &'a (), &'b mut ());
|
||||||
|
|
||||||
|
impl Thing {
|
||||||
|
fn enter_scope<'a>(self, _scope: impl for<'b> FnOnce(TwoThings<'a, 'b>)) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo() {
|
||||||
|
Thing.enter_scope(|ctx| {
|
||||||
|
SameLifetime(ctx); //~ ERROR lifetime may not live long enough
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SameLifetime<'a>(TwoThings<'a, 'a>);
|
||||||
|
|
||||||
|
fn main() {}
|
@ -0,0 +1,17 @@
|
|||||||
|
error: lifetime may not live long enough
|
||||||
|
--> $DIR/account-for-lifetimes-in-closure-suggestion.rs:13:22
|
||||||
|
|
|
||||||
|
LL | Thing.enter_scope(|ctx| {
|
||||||
|
| ---
|
||||||
|
| |
|
||||||
|
| has type `TwoThings<'_, '1>`
|
||||||
|
| has type `TwoThings<'2, '_>`
|
||||||
|
LL | SameLifetime(ctx);
|
||||||
|
| ^^^ this usage requires that `'1` must outlive `'2`
|
||||||
|
|
|
||||||
|
= note: requirement occurs because of the type `TwoThings<'_, '_>`, which makes the generic argument `'_` invariant
|
||||||
|
= note: the struct `TwoThings<'a, 'b>` is invariant over the parameter `'a`
|
||||||
|
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
@ -1,5 +1,4 @@
|
|||||||
//@ known-bug: rust-lang/rust#124563
|
// #124563
|
||||||
|
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
pub trait Trait {}
|
pub trait Trait {}
|
||||||
@ -17,11 +16,11 @@ impl<'a, 'b, T> Foo for FooImpl<'a, 'b, T>
|
|||||||
T: Trait,
|
T: Trait,
|
||||||
{
|
{
|
||||||
type Trait = T;
|
type Trait = T;
|
||||||
type Bar = BarImpl<'a, 'b, T>;
|
type Bar = BarImpl<'a, 'b, T>; //~ ERROR lifetime bound not satisfied
|
||||||
|
|
||||||
fn foo(&mut self) {
|
fn foo(&mut self) {
|
||||||
self.enter_scope(|ctx| {
|
self.enter_scope(|ctx| { //~ ERROR lifetime may not live long enough
|
||||||
BarImpl(ctx);
|
BarImpl(ctx); //~ ERROR lifetime may not live long enough
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -44,3 +43,5 @@ impl<'a, 'b, T> Bar for BarImpl<'a, 'b, T>
|
|||||||
{
|
{
|
||||||
type Foo = FooImpl<'a, 'b, T>;
|
type Foo = FooImpl<'a, 'b, T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
@ -0,0 +1,49 @@
|
|||||||
|
error[E0478]: lifetime bound not satisfied
|
||||||
|
--> $DIR/lifetime-not-long-enough-suggestion-regression-test-124563.rs:19:16
|
||||||
|
|
|
||||||
|
LL | type Bar = BarImpl<'a, 'b, T>;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: lifetime parameter instantiated with the lifetime `'a` as defined here
|
||||||
|
--> $DIR/lifetime-not-long-enough-suggestion-regression-test-124563.rs:14:6
|
||||||
|
|
|
||||||
|
LL | impl<'a, 'b, T> Foo for FooImpl<'a, 'b, T>
|
||||||
|
| ^^
|
||||||
|
note: but lifetime parameter must outlive the lifetime `'b` as defined here
|
||||||
|
--> $DIR/lifetime-not-long-enough-suggestion-regression-test-124563.rs:14:10
|
||||||
|
|
|
||||||
|
LL | impl<'a, 'b, T> Foo for FooImpl<'a, 'b, T>
|
||||||
|
| ^^
|
||||||
|
|
||||||
|
error: lifetime may not live long enough
|
||||||
|
--> $DIR/lifetime-not-long-enough-suggestion-regression-test-124563.rs:23:21
|
||||||
|
|
|
||||||
|
LL | self.enter_scope(|ctx| {
|
||||||
|
| ---
|
||||||
|
| |
|
||||||
|
| has type `&'1 mut FooImpl<'_, '_, T>`
|
||||||
|
| has type `&mut FooImpl<'2, '_, T>`
|
||||||
|
LL | BarImpl(ctx);
|
||||||
|
| ^^^ this usage requires that `'1` must outlive `'2`
|
||||||
|
|
||||||
|
error: lifetime may not live long enough
|
||||||
|
--> $DIR/lifetime-not-long-enough-suggestion-regression-test-124563.rs:22:9
|
||||||
|
|
|
||||||
|
LL | impl<'a, 'b, T> Foo for FooImpl<'a, 'b, T>
|
||||||
|
| -- -- lifetime `'b` defined here
|
||||||
|
| |
|
||||||
|
| lifetime `'a` defined here
|
||||||
|
...
|
||||||
|
LL | / self.enter_scope(|ctx| {
|
||||||
|
LL | | BarImpl(ctx);
|
||||||
|
LL | | });
|
||||||
|
| |__________^ argument requires that `'a` must outlive `'b`
|
||||||
|
|
|
||||||
|
= help: consider adding the following bound: `'a: 'b`
|
||||||
|
= note: requirement occurs because of a mutable reference to `FooImpl<'_, '_, T>`
|
||||||
|
= note: mutable references are invariant over their type parameter
|
||||||
|
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0478`.
|
17
tests/ui/regions/regions-escape-method.fixed
Normal file
17
tests/ui/regions/regions-escape-method.fixed
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Test a method call where the parameter `B` would (illegally) be
|
||||||
|
// inferred to a region bound in the method argument. If this program
|
||||||
|
// were accepted, then the closure passed to `s.f` could escape its
|
||||||
|
// argument.
|
||||||
|
//@ run-rustfix
|
||||||
|
|
||||||
|
struct S;
|
||||||
|
|
||||||
|
impl S {
|
||||||
|
fn f<B, F>(&self, _: F) where F: FnOnce(&i32) -> B {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let s = S;
|
||||||
|
s.f(|p| *p) //~ ERROR lifetime may not live long enough
|
||||||
|
}
|
@ -2,6 +2,7 @@
|
|||||||
// inferred to a region bound in the method argument. If this program
|
// inferred to a region bound in the method argument. If this program
|
||||||
// were accepted, then the closure passed to `s.f` could escape its
|
// were accepted, then the closure passed to `s.f` could escape its
|
||||||
// argument.
|
// argument.
|
||||||
|
//@ run-rustfix
|
||||||
|
|
||||||
struct S;
|
struct S;
|
||||||
|
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
error: lifetime may not live long enough
|
error: lifetime may not live long enough
|
||||||
--> $DIR/regions-escape-method.rs:15:13
|
--> $DIR/regions-escape-method.rs:16:13
|
||||||
|
|
|
|
||||||
LL | s.f(|p| p)
|
LL | s.f(|p| p)
|
||||||
| -- ^ returning this value requires that `'1` must outlive `'2`
|
| -- ^ returning this value requires that `'1` must outlive `'2`
|
||||||
| ||
|
| ||
|
||||||
| |return type of closure is &'2 i32
|
| |return type of closure is &'2 i32
|
||||||
| has type `&'1 i32`
|
| has type `&'1 i32`
|
||||||
|
|
|
||||||
|
help: dereference the return value
|
||||||
|
|
|
||||||
|
LL | s.f(|p| *p)
|
||||||
|
| +
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user