Skip to content

Commit 747075d

Browse files
committed
Auto merge of rust-lang#98462 - cjgillot:no-apit-hrtb-beta, r=Mark-Simulacrum
[beta] Fail gracefully when encountering an HRTB in APIT. Backport of rust-lang#97683 The diagnostic is a bit worse, but still better than an ICE. r? `@ehuss`
2 parents d8ffc1f + a081507 commit 747075d

File tree

4 files changed

+82
-8
lines changed

4 files changed

+82
-8
lines changed

compiler/rustc_hir/src/hir.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -721,7 +721,7 @@ impl<'hir> WherePredicate<'hir> {
721721
}
722722
}
723723

724-
#[derive(Debug, HashStable_Generic, PartialEq, Eq)]
724+
#[derive(Copy, Clone, Debug, HashStable_Generic, PartialEq, Eq)]
725725
pub enum PredicateOrigin {
726726
WhereClause,
727727
GenericParam,

compiler/rustc_resolve/src/late/lifetimes.rs

+65-7
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,13 @@ enum Scope<'a> {
230230
/// In some cases not allowing late bounds allows us to avoid ICEs.
231231
/// This is almost ways set to true.
232232
allow_late_bound: bool,
233+
234+
/// If this binder comes from a where clause, specify how it was created.
235+
/// This is used to diagnose inaccessible lifetimes in APIT:
236+
/// ```ignore (illustrative)
237+
/// fn foo(x: impl for<'a> Trait<'a, Assoc = impl Copy + 'a>) {}
238+
/// ```
239+
where_bound_origin: Option<hir::PredicateOrigin>,
233240
},
234241

235242
/// Lifetimes introduced by a fn are scoped to the call-site for that fn,
@@ -301,8 +308,9 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
301308
opaque_type_parent,
302309
scope_type,
303310
hir_id,
304-
s: _,
305311
allow_late_bound,
312+
where_bound_origin,
313+
s: _,
306314
} => f
307315
.debug_struct("Binder")
308316
.field("lifetimes", lifetimes)
@@ -311,8 +319,9 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
311319
.field("opaque_type_parent", opaque_type_parent)
312320
.field("scope_type", scope_type)
313321
.field("hir_id", hir_id)
314-
.field("s", &"..")
315322
.field("allow_late_bound", allow_late_bound)
323+
.field("where_bound_origin", where_bound_origin)
324+
.field("s", &"..")
316325
.finish(),
317326
Scope::Body { id, s: _ } => {
318327
f.debug_struct("Body").field("id", id).field("s", &"..").finish()
@@ -701,6 +710,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
701710
opaque_type_parent: false,
702711
scope_type: BinderScopeType::Normal,
703712
allow_late_bound: true,
713+
where_bound_origin: None,
704714
};
705715
self.with(scope, move |_old_scope, this| {
706716
intravisit::walk_fn(this, fk, fd, b, s, hir_id)
@@ -829,6 +839,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
829839
scope_type: BinderScopeType::Normal,
830840
s: ROOT_SCOPE,
831841
allow_late_bound: false,
842+
where_bound_origin: None,
832843
};
833844
self.with(scope, |old_scope, this| {
834845
this.check_lifetime_params(old_scope, &generics.params);
@@ -896,6 +907,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
896907
opaque_type_parent: false,
897908
scope_type: BinderScopeType::Normal,
898909
allow_late_bound: true,
910+
where_bound_origin: None,
899911
};
900912
self.with(scope, |old_scope, this| {
901913
// a bare fn has no bounds, so everything
@@ -1091,6 +1103,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
10911103
opaque_type_parent: false,
10921104
scope_type: BinderScopeType::Normal,
10931105
allow_late_bound: false,
1106+
where_bound_origin: None,
10941107
};
10951108
this.with(scope, |_old_scope, this| {
10961109
this.visit_generics(generics);
@@ -1112,6 +1125,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
11121125
opaque_type_parent: false,
11131126
scope_type: BinderScopeType::Normal,
11141127
allow_late_bound: false,
1128+
where_bound_origin: None,
11151129
};
11161130
self.with(scope, |_old_scope, this| {
11171131
let scope = Scope::TraitRefBoundary { s: this.scope };
@@ -1172,6 +1186,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
11721186
opaque_type_parent: true,
11731187
scope_type: BinderScopeType::Normal,
11741188
allow_late_bound: false,
1189+
where_bound_origin: None,
11751190
};
11761191
self.with(scope, |old_scope, this| {
11771192
this.check_lifetime_params(old_scope, &generics.params);
@@ -1242,6 +1257,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
12421257
opaque_type_parent: true,
12431258
scope_type: BinderScopeType::Normal,
12441259
allow_late_bound: true,
1260+
where_bound_origin: None,
12451261
};
12461262
self.with(scope, |old_scope, this| {
12471263
this.check_lifetime_params(old_scope, &generics.params);
@@ -1356,6 +1372,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
13561372
ref bounded_ty,
13571373
bounds,
13581374
ref bound_generic_params,
1375+
origin,
13591376
..
13601377
}) => {
13611378
let (lifetimes, binders): (FxIndexMap<hir::ParamName, Region>, Vec<_>) =
@@ -1387,6 +1404,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
13871404
opaque_type_parent: false,
13881405
scope_type: BinderScopeType::Normal,
13891406
allow_late_bound: true,
1407+
where_bound_origin: Some(origin),
13901408
};
13911409
this.with(scope, |old_scope, this| {
13921410
this.check_lifetime_params(old_scope, &bound_generic_params);
@@ -1461,6 +1479,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
14611479
opaque_type_parent: false,
14621480
scope_type,
14631481
allow_late_bound: true,
1482+
where_bound_origin: None,
14641483
};
14651484
self.with(scope, |_, this| {
14661485
intravisit::walk_param_bound(this, bound);
@@ -1514,6 +1533,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
15141533
opaque_type_parent: false,
15151534
scope_type,
15161535
allow_late_bound: true,
1536+
where_bound_origin: None,
15171537
};
15181538
self.with(scope, |old_scope, this| {
15191539
this.check_lifetime_params(old_scope, &trait_ref.bound_generic_params);
@@ -2207,6 +2227,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
22072227
track_lifetime_uses: false,
22082228
scope_type: BinderScopeType::Normal,
22092229
allow_late_bound: true,
2230+
where_bound_origin: None,
22102231
};
22112232
self.with(scope, move |old_scope, this| {
22122233
this.check_lifetime_params(old_scope, &generics.params);
@@ -2321,12 +2342,49 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
23212342
}
23222343

23232344
self.insert_lifetime(lifetime_ref, def);
2324-
} else {
2325-
self.tcx.sess.delay_span_bug(
2326-
lifetime_ref.span,
2327-
&format!("Could not resolve {:?} in scope {:#?}", lifetime_ref, self.scope,),
2328-
);
2345+
return;
2346+
}
2347+
2348+
// We may fail to resolve higher-ranked lifetimes that are mentionned by APIT.
2349+
// AST-based resolution does not care for impl-trait desugaring, which are the
2350+
// responibility of lowering. This may create a mismatch between the resolution
2351+
// AST found (`region_def_id`) which points to HRTB, and what HIR allows.
2352+
// ```
2353+
// fn foo(x: impl for<'a> Trait<'a, Assoc = impl Copy + 'a>) {}
2354+
// ```
2355+
//
2356+
// In such case, walk back the binders to diagnose it properly.
2357+
let mut scope = self.scope;
2358+
loop {
2359+
match *scope {
2360+
Scope::Binder {
2361+
where_bound_origin: Some(hir::PredicateOrigin::ImplTrait), ..
2362+
} => {
2363+
self.tcx
2364+
.sess
2365+
.struct_span_err(
2366+
lifetime_ref.span,
2367+
"`impl Trait` can only mention lifetimes bound at the fn or impl level",
2368+
)
2369+
.emit();
2370+
return;
2371+
}
2372+
Scope::Root => break,
2373+
Scope::Binder { s, .. }
2374+
| Scope::Body { s, .. }
2375+
| Scope::Elision { s, .. }
2376+
| Scope::ObjectLifetimeDefault { s, .. }
2377+
| Scope::Supertrait { s, .. }
2378+
| Scope::TraitRefBoundary { s, .. } => {
2379+
scope = s;
2380+
}
2381+
}
23292382
}
2383+
2384+
self.tcx.sess.delay_span_bug(
2385+
lifetime_ref.span,
2386+
&format!("Could not resolve {:?} in scope {:#?}", lifetime_ref, self.scope,),
2387+
);
23302388
}
23312389

23322390
fn visit_segment_args(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
trait Trait<'a> {
2+
type Assoc;
3+
}
4+
5+
fn test_argument_position(x: impl for<'a> Trait<'a, Assoc = impl Copy + 'a>) {}
6+
//~^ ERROR `impl Trait` can only mention lifetimes bound at the fn or impl level
7+
8+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: `impl Trait` can only mention lifetimes bound at the fn or impl level
2+
--> $DIR/universal_wrong_hrtb.rs:5:73
3+
|
4+
LL | fn test_argument_position(x: impl for<'a> Trait<'a, Assoc = impl Copy + 'a>) {}
5+
| ^^
6+
7+
error: aborting due to previous error
8+

0 commit comments

Comments
 (0)