From d55522aad87c5605d7edd5dd4b37926e8b446117 Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Tue, 11 Jul 2023 14:24:08 +0000 Subject: [PATCH] don't ICE on higher ranked hidden types --- .../rustc_borrowck/src/region_infer/mod.rs | 25 +++++++------ .../src/region_infer/opaque_types.rs | 15 ++++++++ .../src/infer/error_reporting/mod.rs | 9 +++++ tests/ui/impl-trait/nested-rpit-hrtb-2.rs | 9 +++++ tests/ui/impl-trait/nested-rpit-hrtb-2.stderr | 12 +++++++ .../type-alias-impl-trait/nested-tait-hrtb.rs | 15 ++++++++ .../nested-tait-hrtb.stderr | 35 +++++++++++++++++++ 7 files changed, 109 insertions(+), 11 deletions(-) create mode 100644 tests/ui/impl-trait/nested-rpit-hrtb-2.rs create mode 100644 tests/ui/impl-trait/nested-rpit-hrtb-2.stderr create mode 100644 tests/ui/type-alias-impl-trait/nested-tait-hrtb.rs create mode 100644 tests/ui/type-alias-impl-trait/nested-tait-hrtb.stderr diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 30dfb2d919a3c..b8cd94e542242 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -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 = choice_regions.to_vec(); @@ -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: {:?}", @@ -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); @@ -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); @@ -878,10 +885,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { min_choice, member_constraint_index, }); - - true - } else { - false } } diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 90bde88f79216..68dddd65acba9 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -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]; diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 69e5bda975e95..75cca9733060d 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -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(); } diff --git a/tests/ui/impl-trait/nested-rpit-hrtb-2.rs b/tests/ui/impl-trait/nested-rpit-hrtb-2.rs new file mode 100644 index 0000000000000..4d72962157b76 --- /dev/null +++ b/tests/ui/impl-trait/nested-rpit-hrtb-2.rs @@ -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() {} diff --git a/tests/ui/impl-trait/nested-rpit-hrtb-2.stderr b/tests/ui/impl-trait/nested-rpit-hrtb-2.stderr new file mode 100644 index 0000000000000..71d1d45f48bdb --- /dev/null +++ b/tests/ui/impl-trait/nested-rpit-hrtb-2.stderr @@ -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`. diff --git a/tests/ui/type-alias-impl-trait/nested-tait-hrtb.rs b/tests/ui/type-alias-impl-trait/nested-tait-hrtb.rs new file mode 100644 index 0000000000000..4a9631a720887 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/nested-tait-hrtb.rs @@ -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() {} diff --git a/tests/ui/type-alias-impl-trait/nested-tait-hrtb.stderr b/tests/ui/type-alias-impl-trait/nested-tait-hrtb.stderr new file mode 100644 index 0000000000000..9a783a6d92a2c --- /dev/null +++ b/tests/ui/type-alias-impl-trait/nested-tait-hrtb.stderr @@ -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`.