Skip to content

Commit

Permalink
Auto merge of #113575 - aliemjay:opaque-hrtb-ice, r=lcnr
Browse files Browse the repository at this point in the history
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 #97098.
Fixes #97099.
Fixes #108399
Fixes #104196
Fixes #113481
Fixes #103186
Fixes #100818

r? `@lcnr` (because you showed interest in #100503 :)
  • Loading branch information
bors committed Aug 4, 2023
2 parents ec5b882 + d55522a commit 03181e0
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 03181e0

Please sign in to comment.