Skip to content

Commit 0bebfa3

Browse files
Rollup merge of #114117 - compiler-errors:return-to-uniq, r=lcnr
Restore region uniquification in the new solver 🎉 All of the bugs that were "due" to uniquification have been settled via other means (e.g. bidirectional alias-relate, param-env incompleteness, etc). Firstly, revert the functional changes in #110180. 😸 Secondly, we need to ignore regions when considering if a goal has changed (the "has_changed" boolean returned from `evaluate_goal`) -- otherwise, because we're doing region uniquification, we may perpetually consider a goal to be changed. See the UI test I committed for an explanation.
2 parents eb1f1a4 + 1ffc6ca commit 0bebfa3

File tree

4 files changed

+48
-13
lines changed

4 files changed

+48
-13
lines changed

compiler/rustc_trait_selection/src/solve/canonicalize.rs

+14-11
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,8 @@ impl<'a, 'tcx> Canonicalizer<'a, 'tcx> {
125125
// - var_infos: [E0, U1, E1, U1, E1, E6, U6], curr_compressed_uv: 1, next_orig_uv: 6
126126
// - var_infos: [E0, U1, E1, U1, E1, E2, U2], curr_compressed_uv: 2, next_orig_uv: -
127127
//
128-
// This algorithm runs in `O(nm)` where `n` is the number of different universe
129-
// indices in the input and `m` is the number of canonical variables.
130-
// This should be fine as both `n` and `m` are expected to be small.
128+
// This algorithm runs in `O(n²)` where `n` is the number of different universe
129+
// indices in the input. This should be fine as `n` is expected to be small.
131130
let mut curr_compressed_uv = ty::UniverseIndex::ROOT;
132131
let mut existential_in_new_uv = false;
133132
let mut next_orig_uv = Some(ty::UniverseIndex::ROOT);
@@ -263,14 +262,18 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
263262
ty::ReError(_) => return r,
264263
};
265264

266-
let var = ty::BoundVar::from(
267-
self.variables.iter().position(|&v| v == r.into()).unwrap_or_else(|| {
268-
let var = self.variables.len();
269-
self.variables.push(r.into());
270-
self.primitive_var_infos.push(CanonicalVarInfo { kind });
271-
var
272-
}),
273-
);
265+
let existing_bound_var = match self.canonicalize_mode {
266+
CanonicalizeMode::Input => None,
267+
CanonicalizeMode::Response { .. } => {
268+
self.variables.iter().position(|&v| v == r.into()).map(ty::BoundVar::from)
269+
}
270+
};
271+
let var = existing_bound_var.unwrap_or_else(|| {
272+
let var = ty::BoundVar::from(self.variables.len());
273+
self.variables.push(r.into());
274+
self.primitive_var_infos.push(CanonicalVarInfo { kind });
275+
var
276+
});
274277
let br = ty::BoundRegion { var, kind: BrAnon(None) };
275278
ty::Region::new_late_bound(self.interner(), self.binder_index, br)
276279
}

compiler/rustc_trait_selection/src/solve/eval_ctxt.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
344344
Ok(response) => response,
345345
};
346346

347-
let has_changed = !canonical_response.value.var_values.is_identity()
347+
let has_changed = !canonical_response.value.var_values.is_identity_modulo_regions()
348348
|| !canonical_response.value.external_constraints.opaque_types.is_empty();
349349
let (certainty, nested_goals) = match self.instantiate_and_apply_query_response(
350350
goal.param_env,

tests/ui/impl-trait/autoderef.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// revisions: current next
2-
//[next] compile-flag: -Ztrait-solver=next
2+
//[next] compile-flags: -Ztrait-solver=next
33
// check-pass
44

55
use std::path::Path;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// compile-flags: -Ztrait-solver=next
2+
// check-pass
3+
4+
trait Eq<'a, 'b, T> {}
5+
6+
trait Ambig {}
7+
impl Ambig for () {}
8+
9+
impl<'a, T> Eq<'a, 'a, T> for () where T: Ambig {}
10+
11+
fn eq<'a, 'b, T>(t: T)
12+
where
13+
(): Eq<'a, 'b, T>,
14+
{
15+
}
16+
17+
fn test<'r>() {
18+
let mut x = Default::default();
19+
20+
// When we evaluate `(): Eq<'r, 'r, ?0>` we uniquify the regions.
21+
// That leads us to evaluate `(): Eq<'?0, '?1, ?0>`. The response of this
22+
// will be ambiguous (because `?0: Ambig` is ambig) and also not an "identity"
23+
// response, since the region constraints will contain `'?0 == '?1` (so
24+
// `is_changed` will return true). Since it's both ambig and changed,
25+
// fulfillment will both re-register the goal AND loop again. This hits the
26+
// overflow limit. This should neither be considered overflow, nor ICE.
27+
eq::<'r, 'r, _>(x);
28+
29+
x = ();
30+
}
31+
32+
fn main() {}

0 commit comments

Comments
 (0)