Skip to content

Commit a8e9638

Browse files
committed
erase regions in cause code when giving suggestion
1 parent fb505a7 commit a8e9638

File tree

3 files changed

+107
-1
lines changed

3 files changed

+107
-1
lines changed

compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1499,7 +1499,35 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
14991499
};
15001500

15011501
if let ObligationCauseCode::ImplDerived(cause) = &*code {
1502-
try_borrowing(cause.derived.parent_trait_pred, &[])
1502+
// Parent trait predicate may contain regions that's already popped since `cause`
1503+
// in `Obligation` is ignored by folders/visitors.
1504+
// We can erase them since evaluation later doesn't care about regions anyway.
1505+
struct PoppedRegionEraser<'a, 'tcx> {
1506+
infcx: &'a InferCtxt<'tcx>,
1507+
}
1508+
impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for PoppedRegionEraser<'a, 'tcx> {
1509+
fn cx(&self) -> TyCtxt<'tcx> {
1510+
self.infcx.tcx
1511+
}
1512+
1513+
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
1514+
if ty.has_infer_regions() { ty.super_fold_with(self) } else { ty }
1515+
}
1516+
1517+
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
1518+
if let ty::ReVar(vid) = r.kind()
1519+
&& vid.index() >= self.infcx.num_region_vars()
1520+
{
1521+
self.infcx.tcx.lifetimes.re_erased
1522+
} else {
1523+
r
1524+
}
1525+
}
1526+
}
1527+
1528+
let parent_trait_pred =
1529+
cause.derived.parent_trait_pred.fold_with(&mut PoppedRegionEraser { infcx: self });
1530+
try_borrowing(parent_trait_pred, &[])
15031531
} else if let ObligationCauseCode::WhereClause(..)
15041532
| ObligationCauseCode::WhereClauseInExpr(..) = code
15051533
{
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//@ compile-flags: -Znext-solver
2+
//@ edition: 2024
3+
//
4+
// A regression test for the ICE variant in trait-system-refactor-initiative#245.
5+
// We'll meet regions that're already popped off when using parent predicate in cause code.
6+
// `cause` in `Obligation` is ignored by folders/visitors.
7+
// In this case, `fudge_inference_if_ok` doesn't fudge a region var in cause code.
8+
//
9+
// The old solver doesn't trigger ICE because regions in the predicate are replaced with
10+
// placeholders when checking generator witness. Besides, the old solver doesn't eagerly
11+
// resolves vars before canonicalizing the predicate in `predicate_must_hold_modulo_regions`.
12+
13+
trait AsyncFn: Send + 'static {
14+
type Fut: Future<Output = ()> + Send;
15+
16+
fn call(&self) -> Self::Fut;
17+
}
18+
19+
async fn wrap_call<P: AsyncFn + ?Sized>(filter: &P) {
20+
filter.call().await;
21+
}
22+
23+
fn get_boxed_fn() -> Box<DynAsyncFnBoxed> {
24+
todo!()
25+
}
26+
27+
async fn cursed_fut() {
28+
wrap_call(get_boxed_fn().as_ref()).await;
29+
}
30+
31+
fn observe_fut_not_send() {
32+
assert_send(cursed_fut());
33+
//~^ ERROR: `dyn AsyncFn<Fut = Pin<Box<dyn Future<Output = ()> + Send>>>` cannot be shared between threads safely [E0277]
34+
}
35+
36+
fn assert_send<T: Send>(t: T) -> T {
37+
t
38+
}
39+
40+
pub type BoxFuture<'a, T> = std::pin::Pin<Box<dyn Future<Output = T> + Send + 'a>>;
41+
type DynAsyncFnBoxed = dyn AsyncFn<Fut = BoxFuture<'static, ()>>;
42+
43+
fn main() {}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
error[E0277]: `dyn AsyncFn<Fut = Pin<Box<dyn Future<Output = ()> + Send>>>` cannot be shared between threads safely
2+
--> $DIR/outdated-region-in-cause-code.rs:32:17
3+
|
4+
LL | assert_send(cursed_fut());
5+
| ----------- ^^^^^^^^^^^^ `dyn AsyncFn<Fut = Pin<Box<dyn Future<Output = ()> + Send>>>` cannot be shared between threads safely
6+
| |
7+
| required by a bound introduced by this call
8+
|
9+
= help: the trait `Sync` is not implemented for `dyn AsyncFn<Fut = Pin<Box<dyn Future<Output = ()> + Send>>>`
10+
= note: required for `&dyn AsyncFn<Fut = Pin<Box<dyn Future<Output = ()> + Send>>>` to implement `Send`
11+
note: required because it's used within this `async` fn body
12+
--> $DIR/outdated-region-in-cause-code.rs:19:53
13+
|
14+
LL | async fn wrap_call<P: AsyncFn + ?Sized>(filter: &P) {
15+
| _____________________________________________________^
16+
LL | | filter.call().await;
17+
LL | | }
18+
| |_^
19+
note: required because it's used within this `async` fn body
20+
--> $DIR/outdated-region-in-cause-code.rs:27:23
21+
|
22+
LL | async fn cursed_fut() {
23+
| _______________________^
24+
LL | | wrap_call(get_boxed_fn().as_ref()).await;
25+
LL | | }
26+
| |_^
27+
note: required by a bound in `assert_send`
28+
--> $DIR/outdated-region-in-cause-code.rs:36:19
29+
|
30+
LL | fn assert_send<T: Send>(t: T) -> T {
31+
| ^^^^ required by this bound in `assert_send`
32+
33+
error: aborting due to 1 previous error
34+
35+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)