Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not ICE when suggesting dereferencing closure arg #126884

Merged
merged 1 commit into from
Jun 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions compiler/rustc_borrowck/src/diagnostics/region_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1152,7 +1152,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
// 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 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()
} else if param.index == closure_param.index {
closure_ty.into()
Expand All @@ -1169,7 +1171,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
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(
tcx.hir().body(*body).value.peel_blocks().span.shrink_to_lo(),
"dereference the return value",
Expand Down
19 changes: 19 additions & 0 deletions tests/ui/regions/account-for-lifetimes-in-closure-suggestion.rs
Original file line number Diff line number Diff line change
@@ -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() {}
Original file line number Diff line number Diff line change
@@ -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

Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
//@ known-bug: rust-lang/rust#124563

// #124563
use std::marker::PhantomData;

pub trait Trait {}
Expand All @@ -17,11 +16,11 @@ where
T: Trait,
{
type Trait = T;
type Bar = BarImpl<'a, 'b, T>;
type Bar = BarImpl<'a, 'b, T>; //~ ERROR lifetime bound not satisfied

fn foo(&mut self) {
self.enter_scope(|ctx| {
BarImpl(ctx);
self.enter_scope(|ctx| { //~ ERROR lifetime may not live long enough
BarImpl(ctx); //~ ERROR lifetime may not live long enough
});
}
}
Expand All @@ -44,3 +43,5 @@ where
{
type Foo = FooImpl<'a, 'b, T>;
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -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 changes: 17 additions & 0 deletions tests/ui/regions/regions-escape-method.fixed
Original file line number Diff line number Diff line change
@@ -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
}
1 change: 1 addition & 0 deletions tests/ui/regions/regions-escape-method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// 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;

Expand Down
7 changes: 6 additions & 1 deletion tests/ui/regions/regions-escape-method.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
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)
| -- ^ returning this value requires that `'1` must outlive `'2`
| ||
| |return type of closure is &'2 i32
| has type `&'1 i32`
|
help: dereference the return value
|
LL | s.f(|p| *p)
| +

error: aborting due to 1 previous error

Loading