Skip to content

Commit 03181e0

Browse files
committed
Auto merge of rust-lang#113575 - aliemjay:opaque-hrtb-ice, r=lcnr
don't ICE on higher ranked hidden types This shouldn't allow more code to compile, only replaces the ICE with a nicer error message. Fixes rust-lang#97098. Fixes rust-lang#97099. Fixes rust-lang#108399 Fixes rust-lang#104196 Fixes rust-lang#113481 Fixes rust-lang#103186 Fixes rust-lang#100818 r? `@lcnr` (because you showed interest in rust-lang#100503 :)
2 parents ec5b882 + d55522a commit 03181e0

File tree

7 files changed

+109
-11
lines changed

7 files changed

+109
-11
lines changed

compiler/rustc_borrowck/src/region_infer/mod.rs

+14-11
Original file line numberDiff line numberDiff line change
@@ -784,13 +784,20 @@ impl<'tcx> RegionInferenceContext<'tcx> {
784784
/// is considered a *lower bound*. If possible, we will modify
785785
/// the constraint to set it equal to one of the option regions.
786786
/// If we make any changes, returns true, else false.
787+
///
788+
/// This function only adds the member constraints to the region graph,
789+
/// it does not check them. They are later checked in
790+
/// `check_member_constraints` after the region graph has been computed.
787791
#[instrument(skip(self, member_constraint_index), level = "debug")]
788792
fn apply_member_constraint(
789793
&mut self,
790794
scc: ConstraintSccIndex,
791795
member_constraint_index: NllMemberConstraintIndex,
792796
choice_regions: &[ty::RegionVid],
793-
) -> bool {
797+
) {
798+
// Lazily compute the reverse graph, we'll need it later.
799+
self.compute_reverse_scc_graph();
800+
794801
// Create a mutable vector of the options. We'll try to winnow
795802
// them down.
796803
let mut choice_regions: Vec<ty::RegionVid> = choice_regions.to_vec();
@@ -805,10 +812,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
805812
*c_r = self.scc_representatives[scc];
806813
}
807814

808-
// The 'member region' in a member constraint is part of the
809-
// hidden type, which must be in the root universe. Therefore,
810-
// it cannot have any placeholders in its value.
811-
assert!(self.scc_universes[scc] == ty::UniverseIndex::ROOT);
815+
// If the member region lives in a higher universe, we currently choose
816+
// the most conservative option by leaving it unchanged.
817+
if self.scc_universes[scc] != ty::UniverseIndex::ROOT {
818+
return;
819+
}
812820
debug_assert!(
813821
self.scc_values.placeholders_contained_in(scc).next().is_none(),
814822
"scc {:?} in a member constraint has placeholder value: {:?}",
@@ -832,7 +840,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
832840
// free region that must outlive the member region `R0` (`UB:
833841
// R0`). Therefore, we need only keep an option `O` if `UB: O`
834842
// for all UB.
835-
self.compute_reverse_scc_graph();
836843
let universal_region_relations = &self.universal_region_relations;
837844
for ub in self.rev_scc_graph.as_ref().unwrap().upper_bounds(scc) {
838845
debug!(?ub);
@@ -867,7 +874,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
867874
}
868875
}) else {
869876
debug!("no unique minimum choice");
870-
return false;
877+
return;
871878
};
872879

873880
let min_choice_scc = self.constraint_sccs.scc(min_choice);
@@ -878,10 +885,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
878885
min_choice,
879886
member_constraint_index,
880887
});
881-
882-
true
883-
} else {
884-
false
885888
}
886889
}
887890

compiler/rustc_borrowck/src/region_infer/opaque_types.rs

+15
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,21 @@ impl<'tcx> RegionInferenceContext<'tcx> {
185185
{
186186
tcx.fold_regions(ty, |region, _| match *region {
187187
ty::ReVar(vid) => {
188+
let scc = self.constraint_sccs.scc(vid);
189+
190+
// Special handling of higher-ranked regions.
191+
if self.scc_universes[scc] != ty::UniverseIndex::ROOT {
192+
match self.scc_values.placeholders_contained_in(scc).enumerate().last() {
193+
// If the region contains a single placeholder then they're equal.
194+
Some((0, placeholder)) => {
195+
return ty::Region::new_placeholder(tcx, placeholder);
196+
}
197+
198+
// Fallback: this will produce a cryptic error message.
199+
_ => return region,
200+
}
201+
}
202+
188203
// Find something that we can name
189204
let upper_bound = self.approx_universal_upper_bound(vid);
190205
let upper_bound = &self.definitions[upper_bound];

compiler/rustc_infer/src/infer/error_reporting/mod.rs

+9
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,15 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
351351
)
352352
}
353353
}
354+
ty::RePlaceholder(_) => {
355+
explain_free_region(
356+
tcx,
357+
&mut err,
358+
&format!("hidden type `{}` captures ", hidden_ty),
359+
hidden_region,
360+
"",
361+
);
362+
}
354363
ty::ReError(_) => {
355364
err.delay_as_bug();
356365
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// The nested impl Trait references a higher-ranked region
2+
3+
trait Trait<'a> { type Assoc; }
4+
impl<'a> Trait<'a> for () { type Assoc = &'a str; }
5+
6+
fn test() -> impl for<'a> Trait<'a, Assoc = impl Sized> {}
7+
//~^ ERROR captures lifetime that does not appear in bounds
8+
9+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds
2+
--> $DIR/nested-rpit-hrtb-2.rs:6:57
3+
|
4+
LL | fn test() -> impl for<'a> Trait<'a, Assoc = impl Sized> {}
5+
| -- ---------- ^^
6+
| | |
7+
| | opaque type defined here
8+
| hidden type `&'a str` captures the lifetime `'a` as defined here
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0700`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#![feature(type_alias_impl_trait)]
2+
3+
trait Trait<'a> { type Assoc; }
4+
impl<'a> Trait<'a> for () { type Assoc = &'a str; }
5+
6+
type WithoutLt = impl Sized;
7+
fn without_lt() -> impl for<'a> Trait<'a, Assoc = WithoutLt> {}
8+
//~^ ERROR captures lifetime that does not appear in bounds
9+
10+
type WithLt<'a> = impl Sized + 'a;
11+
//~^ ERROR concrete type differs from previous defining opaque type use
12+
fn with_lt() -> impl for<'a> Trait<'a, Assoc = WithLt<'a>> {}
13+
//~^ ERROR expected generic lifetime parameter, found `'a`
14+
15+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
error[E0700]: hidden type for `WithoutLt` captures lifetime that does not appear in bounds
2+
--> $DIR/nested-tait-hrtb.rs:7:62
3+
|
4+
LL | type WithoutLt = impl Sized;
5+
| ---------- opaque type defined here
6+
LL | fn without_lt() -> impl for<'a> Trait<'a, Assoc = WithoutLt> {}
7+
| -- ^^
8+
| |
9+
| hidden type `&'a str` captures the lifetime `'a` as defined here
10+
11+
error[E0792]: expected generic lifetime parameter, found `'a`
12+
--> $DIR/nested-tait-hrtb.rs:12:60
13+
|
14+
LL | type WithLt<'a> = impl Sized + 'a;
15+
| -- this generic parameter must be used with a generic lifetime parameter
16+
LL |
17+
LL | fn with_lt() -> impl for<'a> Trait<'a, Assoc = WithLt<'a>> {}
18+
| ^^
19+
20+
error: concrete type differs from previous defining opaque type use
21+
--> $DIR/nested-tait-hrtb.rs:10:19
22+
|
23+
LL | type WithLt<'a> = impl Sized + 'a;
24+
| ^^^^^^^^^^^^^^^ expected `&'a str`, got `{type error}`
25+
|
26+
note: previous use here
27+
--> $DIR/nested-tait-hrtb.rs:12:17
28+
|
29+
LL | fn with_lt() -> impl for<'a> Trait<'a, Assoc = WithLt<'a>> {}
30+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
31+
32+
error: aborting due to 3 previous errors
33+
34+
Some errors have detailed explanations: E0700, E0792.
35+
For more information about an error, try `rustc --explain E0700`.

0 commit comments

Comments
 (0)