From 4be4829ae6ce3e3da5d6ddde878feb05b805278d Mon Sep 17 00:00:00 2001 From: Ali MJ Al-Nasrawy Date: Sun, 19 Mar 2023 17:12:25 +0300 Subject: [PATCH] interpret region vars as universals ... in implied bounds query --- .../src/implied_outlives_bounds.rs | 59 +++++++++++++++++-- .../normalization-preserve-equality.rs | 18 ++++++ 2 files changed, 71 insertions(+), 6 deletions(-) create mode 100644 tests/ui/implied-bounds/normalization-preserve-equality.rs diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index ddd4ca1436c09..d32db5aa8709a 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -3,6 +3,7 @@ //! [`rustc_trait_selection::traits::query::type_op::implied_outlives_bounds`]. use rustc_infer::infer::canonical::{self, Canonical}; +use rustc_infer::infer::canonical::{CanonicalVarInfo, CanonicalVarKind}; use rustc_infer::infer::outlives::components::{push_outlives_components, Component}; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::query::OutlivesBound; @@ -20,17 +21,63 @@ pub(crate) fn provide(p: &mut Providers) { *p = Providers { implied_outlives_bounds, ..*p }; } +struct MapRegionsToUniversals<'tcx> { + tcx: TyCtxt<'tcx>, + query_max_universe: ty::UniverseIndex, +} + +impl<'tcx> MapRegionsToUniversals<'tcx> { + fn map(tcx: TyCtxt<'tcx>, value: Canonical<'tcx, K>) -> (Canonical<'tcx, K>, Self) { + let variables = value.variables.iter().zip(0u32..).map(|(var, idx)| match var.kind { + CanonicalVarKind::Region(universe) => { + let name = ty::BoundRegionKind::BrAnon(idx, None); + let placeholder = ty::Placeholder { universe, name }; + CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderRegion(placeholder) } + } + CanonicalVarKind::PlaceholderRegion(_) => bug!("unimplemented: placeholder region"), + + CanonicalVarKind::Ty(_) => bug!("unexpected ty var"), + CanonicalVarKind::PlaceholderTy(_) => var, + + CanonicalVarKind::Const(..) => bug!("unexpected const var"), + CanonicalVarKind::PlaceholderConst(..) => var, + }); + let variables = tcx.mk_canonical_var_infos_from_iter(variables); + let query_max_universe = value.max_universe; + + (Canonical { variables, ..value }, Self { tcx, query_max_universe }) + } + + fn reverse_map(&self, value: Canonical<'tcx, K>) -> Canonical<'tcx, K> { + let variables = value.variables.iter().map(|var| match var.kind { + CanonicalVarKind::PlaceholderRegion(ty::Placeholder { universe, .. }) + if self.query_max_universe.can_name(universe) => + { + CanonicalVarInfo { kind: CanonicalVarKind::Region(universe) } + } + CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => var, + + CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => var, + CanonicalVarKind::Const(..) | CanonicalVarKind::PlaceholderConst(..) => var, + }); + let variables = self.tcx.mk_canonical_var_infos_from_iter(variables); + Canonical { variables, ..value } + } +} + fn implied_outlives_bounds<'tcx>( tcx: TyCtxt<'tcx>, goal: CanonicalTyGoal<'tcx>, -) -> Result< - &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec>>>, - NoSolution, -> { - tcx.infer_ctxt().enter_canonical_trait_query(&goal, |ocx, key| { +) -> Fallible<&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec>>>> { + let (goal, map) = MapRegionsToUniversals::map(tcx, goal); + + let result = tcx.infer_ctxt().enter_canonical_trait_query(&goal, |ocx, key| { let (param_env, ty) = key.into_parts(); compute_implied_outlives_bounds(ocx, param_env, ty) - }) + })?; + + let result = MapRegionsToUniversals::reverse_map(&map, result.clone()); + Ok(tcx.arena.alloc(result)) } fn compute_implied_outlives_bounds<'tcx>( diff --git a/tests/ui/implied-bounds/normalization-preserve-equality.rs b/tests/ui/implied-bounds/normalization-preserve-equality.rs new file mode 100644 index 0000000000000..a5e2c4a035e00 --- /dev/null +++ b/tests/ui/implied-bounds/normalization-preserve-equality.rs @@ -0,0 +1,18 @@ +// check-pass +// issue: #106569 + +struct Equal<'a, 'b>(&'a &'b (), &'b &'a ()); // implies 'a == 'b + +trait Trait { type Ty; } + +impl<'x> Trait for Equal<'x, 'x> { type Ty = (); } + +fn test1<'a, 'b>(_: ( as Trait>::Ty, Equal<'a, 'b>)) { + let _ = None::>; +} + +fn test2<'a, 'b>(_: as Trait>::Ty, _: Equal<'a, 'b>) { + let _ = None::>; +} + +fn main() {}