Skip to content

Commit

Permalink
don't ICE on higher ranked hidden types
Browse files Browse the repository at this point in the history
  • Loading branch information
aliemjay authored and oli-obk committed Aug 4, 2023
1 parent 4f7bb98 commit d55522a
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 11 deletions.
25 changes: 14 additions & 11 deletions compiler/rustc_borrowck/src/region_infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -784,13 +784,20 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// is considered a *lower bound*. If possible, we will modify
/// the constraint to set it equal to one of the option regions.
/// If we make any changes, returns true, else false.
///
/// This function only adds the member constraints to the region graph,
/// it does not check them. They are later checked in
/// `check_member_constraints` after the region graph has been computed.
#[instrument(skip(self, member_constraint_index), level = "debug")]
fn apply_member_constraint(
&mut self,
scc: ConstraintSccIndex,
member_constraint_index: NllMemberConstraintIndex,
choice_regions: &[ty::RegionVid],
) -> bool {
) {
// Lazily compute the reverse graph, we'll need it later.
self.compute_reverse_scc_graph();

// Create a mutable vector of the options. We'll try to winnow
// them down.
let mut choice_regions: Vec<ty::RegionVid> = choice_regions.to_vec();
Expand All @@ -805,10 +812,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
*c_r = self.scc_representatives[scc];
}

// The 'member region' in a member constraint is part of the
// hidden type, which must be in the root universe. Therefore,
// it cannot have any placeholders in its value.
assert!(self.scc_universes[scc] == ty::UniverseIndex::ROOT);
// If the member region lives in a higher universe, we currently choose
// the most conservative option by leaving it unchanged.
if self.scc_universes[scc] != ty::UniverseIndex::ROOT {
return;
}
debug_assert!(
self.scc_values.placeholders_contained_in(scc).next().is_none(),
"scc {:?} in a member constraint has placeholder value: {:?}",
Expand All @@ -832,7 +840,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// free region that must outlive the member region `R0` (`UB:
// R0`). Therefore, we need only keep an option `O` if `UB: O`
// for all UB.
self.compute_reverse_scc_graph();
let universal_region_relations = &self.universal_region_relations;
for ub in self.rev_scc_graph.as_ref().unwrap().upper_bounds(scc) {
debug!(?ub);
Expand Down Expand Up @@ -867,7 +874,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}
}) else {
debug!("no unique minimum choice");
return false;
return;
};

let min_choice_scc = self.constraint_sccs.scc(min_choice);
Expand All @@ -878,10 +885,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
min_choice,
member_constraint_index,
});

true
} else {
false
}
}

Expand Down
15 changes: 15 additions & 0 deletions compiler/rustc_borrowck/src/region_infer/opaque_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,21 @@ impl<'tcx> RegionInferenceContext<'tcx> {
{
tcx.fold_regions(ty, |region, _| match *region {
ty::ReVar(vid) => {
let scc = self.constraint_sccs.scc(vid);

// Special handling of higher-ranked regions.
if self.scc_universes[scc] != ty::UniverseIndex::ROOT {
match self.scc_values.placeholders_contained_in(scc).enumerate().last() {
// If the region contains a single placeholder then they're equal.
Some((0, placeholder)) => {
return ty::Region::new_placeholder(tcx, placeholder);
}

// Fallback: this will produce a cryptic error message.
_ => return region,
}
}

// Find something that we can name
let upper_bound = self.approx_universal_upper_bound(vid);
let upper_bound = &self.definitions[upper_bound];
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_infer/src/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,15 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
)
}
}
ty::RePlaceholder(_) => {
explain_free_region(
tcx,
&mut err,
&format!("hidden type `{}` captures ", hidden_ty),
hidden_region,
"",
);
}
ty::ReError(_) => {
err.delay_as_bug();
}
Expand Down
9 changes: 9 additions & 0 deletions tests/ui/impl-trait/nested-rpit-hrtb-2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// The nested impl Trait references a higher-ranked region

trait Trait<'a> { type Assoc; }
impl<'a> Trait<'a> for () { type Assoc = &'a str; }

fn test() -> impl for<'a> Trait<'a, Assoc = impl Sized> {}
//~^ ERROR captures lifetime that does not appear in bounds

fn main() {}
12 changes: 12 additions & 0 deletions tests/ui/impl-trait/nested-rpit-hrtb-2.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds
--> $DIR/nested-rpit-hrtb-2.rs:6:57
|
LL | fn test() -> impl for<'a> Trait<'a, Assoc = impl Sized> {}
| -- ---------- ^^
| | |
| | opaque type defined here
| hidden type `&'a str` captures the lifetime `'a` as defined here

error: aborting due to previous error

For more information about this error, try `rustc --explain E0700`.
15 changes: 15 additions & 0 deletions tests/ui/type-alias-impl-trait/nested-tait-hrtb.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#![feature(type_alias_impl_trait)]

trait Trait<'a> { type Assoc; }
impl<'a> Trait<'a> for () { type Assoc = &'a str; }

type WithoutLt = impl Sized;
fn without_lt() -> impl for<'a> Trait<'a, Assoc = WithoutLt> {}
//~^ ERROR captures lifetime that does not appear in bounds

type WithLt<'a> = impl Sized + 'a;
//~^ ERROR concrete type differs from previous defining opaque type use
fn with_lt() -> impl for<'a> Trait<'a, Assoc = WithLt<'a>> {}
//~^ ERROR expected generic lifetime parameter, found `'a`

fn main() {}
35 changes: 35 additions & 0 deletions tests/ui/type-alias-impl-trait/nested-tait-hrtb.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
error[E0700]: hidden type for `WithoutLt` captures lifetime that does not appear in bounds
--> $DIR/nested-tait-hrtb.rs:7:62
|
LL | type WithoutLt = impl Sized;
| ---------- opaque type defined here
LL | fn without_lt() -> impl for<'a> Trait<'a, Assoc = WithoutLt> {}
| -- ^^
| |
| hidden type `&'a str` captures the lifetime `'a` as defined here

error[E0792]: expected generic lifetime parameter, found `'a`
--> $DIR/nested-tait-hrtb.rs:12:60
|
LL | type WithLt<'a> = impl Sized + 'a;
| -- this generic parameter must be used with a generic lifetime parameter
LL |
LL | fn with_lt() -> impl for<'a> Trait<'a, Assoc = WithLt<'a>> {}
| ^^

error: concrete type differs from previous defining opaque type use
--> $DIR/nested-tait-hrtb.rs:10:19
|
LL | type WithLt<'a> = impl Sized + 'a;
| ^^^^^^^^^^^^^^^ expected `&'a str`, got `{type error}`
|
note: previous use here
--> $DIR/nested-tait-hrtb.rs:12:17
|
LL | fn with_lt() -> impl for<'a> Trait<'a, Assoc = WithLt<'a>> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 3 previous errors

Some errors have detailed explanations: E0700, E0792.
For more information about an error, try `rustc --explain E0700`.

0 comments on commit d55522a

Please sign in to comment.