Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

don't ICE on higher ranked hidden types #113575

Merged
merged 1 commit into from
Aug 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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`.