Skip to content

Commit f2b3808

Browse files
authored
Rollup merge of #97683 - cjgillot:no-apit-hrtb, r=nagisa
Fail gracefully when encountering an HRTB in APIT. Fixes #96954 ~The first commit will be merged as part of #97415
2 parents 77f0209 + bacd8ad commit f2b3808

File tree

4 files changed

+87
-8
lines changed

4 files changed

+87
-8
lines changed

compiler/rustc_hir/src/hir.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,7 @@ impl<'hir> WherePredicate<'hir> {
734734
}
735735
}
736736

737-
#[derive(Debug, HashStable_Generic, PartialEq, Eq)]
737+
#[derive(Copy, Clone, Debug, HashStable_Generic, PartialEq, Eq)]
738738
pub enum PredicateOrigin {
739739
WhereClause,
740740
GenericParam,

compiler/rustc_resolve/src/late/lifetimes.rs

+64-7
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,13 @@ enum Scope<'a> {
207207
/// In some cases not allowing late bounds allows us to avoid ICEs.
208208
/// This is almost ways set to true.
209209
allow_late_bound: bool,
210+
211+
/// If this binder comes from a where clause, specify how it was created.
212+
/// This is used to diagnose inaccessible lifetimes in APIT:
213+
/// ```ignore (illustrative)
214+
/// fn foo(x: impl for<'a> Trait<'a, Assoc = impl Copy + 'a>) {}
215+
/// ```
216+
where_bound_origin: Option<hir::PredicateOrigin>,
210217
},
211218

212219
/// Lifetimes introduced by a fn are scoped to the call-site for that fn,
@@ -277,17 +284,19 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
277284
opaque_type_parent,
278285
scope_type,
279286
hir_id,
280-
s: _,
281287
allow_late_bound,
288+
where_bound_origin,
289+
s: _,
282290
} => f
283291
.debug_struct("Binder")
284292
.field("lifetimes", lifetimes)
285293
.field("next_early_index", next_early_index)
286294
.field("opaque_type_parent", opaque_type_parent)
287295
.field("scope_type", scope_type)
288296
.field("hir_id", hir_id)
289-
.field("s", &"..")
290297
.field("allow_late_bound", allow_late_bound)
298+
.field("where_bound_origin", where_bound_origin)
299+
.field("s", &"..")
291300
.finish(),
292301
Scope::Body { id, s: _ } => {
293302
f.debug_struct("Body").field("id", id).field("s", &"..").finish()
@@ -638,6 +647,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
638647
opaque_type_parent: false,
639648
scope_type: BinderScopeType::Normal,
640649
allow_late_bound: true,
650+
where_bound_origin: None,
641651
};
642652
self.with(scope, move |this| intravisit::walk_fn(this, fk, fd, b, s, hir_id));
643653
}
@@ -753,6 +763,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
753763
scope_type: BinderScopeType::Normal,
754764
s: ROOT_SCOPE,
755765
allow_late_bound: false,
766+
where_bound_origin: None,
756767
};
757768
self.with(scope, |this| {
758769
let scope = Scope::TraitRefBoundary { s: this.scope };
@@ -818,6 +829,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
818829
opaque_type_parent: false,
819830
scope_type: BinderScopeType::Normal,
820831
allow_late_bound: true,
832+
where_bound_origin: None,
821833
};
822834
self.with(scope, |this| {
823835
// a bare fn has no bounds, so everything
@@ -1006,6 +1018,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
10061018
opaque_type_parent: false,
10071019
scope_type: BinderScopeType::Normal,
10081020
allow_late_bound: false,
1021+
where_bound_origin: None,
10091022
};
10101023
this.with(scope, |this| {
10111024
this.visit_generics(generics);
@@ -1026,6 +1039,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
10261039
opaque_type_parent: false,
10271040
scope_type: BinderScopeType::Normal,
10281041
allow_late_bound: false,
1042+
where_bound_origin: None,
10291043
};
10301044
self.with(scope, |this| {
10311045
let scope = Scope::TraitRefBoundary { s: this.scope };
@@ -1084,6 +1098,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
10841098
opaque_type_parent: true,
10851099
scope_type: BinderScopeType::Normal,
10861100
allow_late_bound: false,
1101+
where_bound_origin: None,
10871102
};
10881103
self.with(scope, |this| {
10891104
let scope = Scope::TraitRefBoundary { s: this.scope };
@@ -1151,6 +1166,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
11511166
opaque_type_parent: true,
11521167
scope_type: BinderScopeType::Normal,
11531168
allow_late_bound: true,
1169+
where_bound_origin: None,
11541170
};
11551171
self.with(scope, |this| {
11561172
let scope = Scope::TraitRefBoundary { s: this.scope };
@@ -1266,6 +1282,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
12661282
ref bounded_ty,
12671283
bounds,
12681284
ref bound_generic_params,
1285+
origin,
12691286
..
12701287
}) => {
12711288
let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) =
@@ -1296,6 +1313,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
12961313
opaque_type_parent: false,
12971314
scope_type: BinderScopeType::Normal,
12981315
allow_late_bound: true,
1316+
where_bound_origin: Some(origin),
12991317
};
13001318
this.with(scope, |this| {
13011319
this.visit_ty(&bounded_ty);
@@ -1368,6 +1386,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
13681386
opaque_type_parent: false,
13691387
scope_type,
13701388
allow_late_bound: true,
1389+
where_bound_origin: None,
13711390
};
13721391
self.with(scope, |this| {
13731392
intravisit::walk_param_bound(this, bound);
@@ -1420,6 +1439,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
14201439
opaque_type_parent: false,
14211440
scope_type,
14221441
allow_late_bound: true,
1442+
where_bound_origin: None,
14231443
};
14241444
self.with(scope, |this| {
14251445
walk_list!(this, visit_generic_param, trait_ref.bound_generic_params);
@@ -1680,6 +1700,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
16801700
opaque_type_parent: true,
16811701
scope_type: BinderScopeType::Normal,
16821702
allow_late_bound: true,
1703+
where_bound_origin: None,
16831704
};
16841705
self.with(scope, walk);
16851706
}
@@ -1783,12 +1804,48 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
17831804
}
17841805

17851806
self.insert_lifetime(lifetime_ref, def);
1786-
} else {
1787-
self.tcx.sess.delay_span_bug(
1788-
lifetime_ref.span,
1789-
&format!("Could not resolve {:?} in scope {:#?}", lifetime_ref, self.scope,),
1790-
);
1807+
return;
17911808
}
1809+
1810+
// We may fail to resolve higher-ranked lifetimes that are mentionned by APIT.
1811+
// AST-based resolution does not care for impl-trait desugaring, which are the
1812+
// responibility of lowering. This may create a mismatch between the resolution
1813+
// AST found (`region_def_id`) which points to HRTB, and what HIR allows.
1814+
// ```
1815+
// fn foo(x: impl for<'a> Trait<'a, Assoc = impl Copy + 'a>) {}
1816+
// ```
1817+
//
1818+
// In such case, walk back the binders to diagnose it properly.
1819+
let mut scope = self.scope;
1820+
loop {
1821+
match *scope {
1822+
Scope::Binder {
1823+
where_bound_origin: Some(hir::PredicateOrigin::ImplTrait), ..
1824+
} => {
1825+
let mut err = self.tcx.sess.struct_span_err(
1826+
lifetime_ref.span,
1827+
"`impl Trait` can only mention lifetimes bound at the fn or impl level",
1828+
);
1829+
err.span_note(self.tcx.def_span(region_def_id), "lifetime declared here");
1830+
err.emit();
1831+
return;
1832+
}
1833+
Scope::Root => break,
1834+
Scope::Binder { s, .. }
1835+
| Scope::Body { s, .. }
1836+
| Scope::Elision { s, .. }
1837+
| Scope::ObjectLifetimeDefault { s, .. }
1838+
| Scope::Supertrait { s, .. }
1839+
| Scope::TraitRefBoundary { s, .. } => {
1840+
scope = s;
1841+
}
1842+
}
1843+
}
1844+
1845+
self.tcx.sess.delay_span_bug(
1846+
lifetime_ref.span,
1847+
&format!("Could not resolve {:?} in scope {:#?}", lifetime_ref, self.scope,),
1848+
);
17921849
}
17931850

17941851
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,14 @@
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+
note: lifetime declared here
8+
--> $DIR/universal_wrong_hrtb.rs:5:39
9+
|
10+
LL | fn test_argument_position(x: impl for<'a> Trait<'a, Assoc = impl Copy + 'a>) {}
11+
| ^^
12+
13+
error: aborting due to previous error
14+

0 commit comments

Comments
 (0)