Skip to content

Commit

Permalink
Rollup merge of rust-lang#112443 - compiler-errors:next-solver-opport…
Browse files Browse the repository at this point in the history
…unistically-resolve-regions, r=lcnr

Opportunistically resolve regions in new solver

Use `opportunistic_resolve_var` during canonicalization to collapse some regions.

We have to start using `CanonicalVarValues::is_identity_modulo_regions`. We also have to modify that function to consider responses like `['static, ^0, '^1, ^2]` to be an "identity" response, since because we opportunistically resolve regions, there's no longer a 1:1 mapping between canonical var values and bound var indices in the response...

There's one nasty side-effect -- one test (`tests/ui/dyn-star/param-env-infer.rs`) starts to ICE because the certainty goes from `Yes` to `Maybe(Overflow)`... Not exactly sure why, though? Putting this up for discussion/investigation.

r? ``@lcnr``
  • Loading branch information
Dylan-DPC committed Jun 16, 2023
2 parents 7403e87 + 01377e8 commit c8807ff
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 11 deletions.
41 changes: 33 additions & 8 deletions compiler/rustc_middle/src/infer/canonical.rs
Expand Up @@ -82,15 +82,40 @@ impl CanonicalVarValues<'_> {
}

pub fn is_identity_modulo_regions(&self) -> bool {
self.var_values.iter().enumerate().all(|(bv, arg)| match arg.unpack() {
ty::GenericArgKind::Lifetime(_) => true,
ty::GenericArgKind::Type(ty) => {
matches!(*ty.kind(), ty::Bound(ty::INNERMOST, bt) if bt.var.as_usize() == bv)
}
ty::GenericArgKind::Const(ct) => {
matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if bc.as_usize() == bv)
let mut var = ty::BoundVar::from_u32(0);
for arg in self.var_values {
match arg.unpack() {
ty::GenericArgKind::Lifetime(r) => {
if let ty::ReLateBound(ty::INNERMOST, br) = *r
&& var == br.var
{
var = var + 1;
} else {
// It's ok if this region var isn't unique
}
},
ty::GenericArgKind::Type(ty) => {
if let ty::Bound(ty::INNERMOST, bt) = *ty.kind()
&& var == bt.var
{
var = var + 1;
} else {
return false;
}
}
ty::GenericArgKind::Const(ct) => {
if let ty::ConstKind::Bound(ty::INNERMOST, bc) = ct.kind()
&& var == bc
{
var = var + 1;
} else {
return false;
}
}
}
})
}

true
}
}

Expand Down
21 changes: 19 additions & 2 deletions compiler/rustc_trait_selection/src/solve/canonicalize.rs
Expand Up @@ -208,8 +208,25 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
t
}

fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
let r = self.infcx.shallow_resolve(r);
fn fold_region(&mut self, mut r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match self.canonicalize_mode {
CanonicalizeMode::Input => {
// Don't resolve infer vars in input, since it affects
// caching and may cause trait selection bugs which rely
// on regions to be equal.
}
CanonicalizeMode::Response { .. } => {
if let ty::ReVar(vid) = *r {
r = self
.infcx
.inner
.borrow_mut()
.unwrap_region_constraints()
.opportunistic_resolve_var(self.infcx.tcx, vid);
}
}
}

let kind = match *r {
ty::ReLateBound(..) => return r,

Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
Expand Up @@ -263,7 +263,10 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
let (_orig_values, canonical_goal) = self.canonicalize_goal(goal);
let new_canonical_response =
EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?;
if !new_canonical_response.value.var_values.is_identity() {
// We only check for modulo regions as we convert all regions in
// the input to new existentials, even if they're expected to be
// `'static` or a placeholder region.
if !new_canonical_response.value.var_values.is_identity_modulo_regions() {
bug!(
"unstable result: re-canonicalized goal={canonical_goal:#?} \
first_response={canonical_response:#?} \
Expand Down
19 changes: 19 additions & 0 deletions tests/ui/traits/new-solver/opportunistic-region-resolve.rs
@@ -0,0 +1,19 @@
// compile-flags: -Ztrait-solver=next
// check-pass

#![feature(rustc_attrs)]

#[rustc_coinductive]
trait Trait {}

#[rustc_coinductive]
trait Indirect {}
impl<T: Trait + ?Sized> Indirect for T {}

impl<'a> Trait for &'a () where &'a (): Indirect {}

fn impls_trait<T: Trait>() {}

fn main() {
impls_trait::<&'static ()>();
}

0 comments on commit c8807ff

Please sign in to comment.