Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit feff26b

Browse files
committedFeb 2, 2024
new solver: make apply query response infallible
For this we have to provide the necessary information when canonicalizing the input, guaranteeing that if the canonical query successfully instantiates some inference variable, it will also succeed in the caller. This means we have to not merge universes in the canonical input.
1 parent fb4bca0 commit feff26b

File tree

20 files changed

+418
-207
lines changed

20 files changed

+418
-207
lines changed
 

‎compiler/rustc_infer/src/infer/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ pub mod opaque_types;
6767
pub mod outlives;
6868
mod projection;
6969
pub mod region_constraints;
70-
mod relate;
70+
pub mod relate;
7171
pub mod resolve;
7272
pub mod type_variable;
7373
mod undo_log;

‎compiler/rustc_infer/src/infer/relate/combine.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ impl<'tcx> InferCtxt<'tcx> {
335335
Ok(value)
336336
}
337337

338-
fn unify_integral_variable(
338+
pub(super) fn unify_integral_variable(
339339
&self,
340340
vid_is_expected: bool,
341341
vid: ty::IntVid,
@@ -352,7 +352,7 @@ impl<'tcx> InferCtxt<'tcx> {
352352
}
353353
}
354354

355-
fn unify_float_variable(
355+
pub(super) fn unify_float_variable(
356356
&self,
357357
vid_is_expected: bool,
358358
vid: ty::FloatVid,
@@ -366,7 +366,7 @@ impl<'tcx> InferCtxt<'tcx> {
366366
Ok(Ty::new_float(self.tcx, val))
367367
}
368368

369-
fn unify_effect_variable(
369+
pub(super) fn unify_effect_variable(
370370
&self,
371371
vid_is_expected: bool,
372372
vid: ty::EffectVid,
@@ -564,23 +564,23 @@ pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> {
564564
fn alias_relate_direction(&self) -> ty::AliasRelationDirection;
565565
}
566566

567-
fn int_unification_error<'tcx>(
567+
pub(super) fn int_unification_error<'tcx>(
568568
a_is_expected: bool,
569569
v: (ty::IntVarValue, ty::IntVarValue),
570570
) -> TypeError<'tcx> {
571571
let (a, b) = v;
572572
TypeError::IntMismatch(ExpectedFound::new(a_is_expected, a, b))
573573
}
574574

575-
fn float_unification_error<'tcx>(
575+
pub(super) fn float_unification_error<'tcx>(
576576
a_is_expected: bool,
577577
v: (ty::FloatVarValue, ty::FloatVarValue),
578578
) -> TypeError<'tcx> {
579579
let (ty::FloatVarValue(a), ty::FloatVarValue(b)) = v;
580580
TypeError::FloatMismatch(ExpectedFound::new(a_is_expected, a, b))
581581
}
582582

583-
fn effect_unification_error<'tcx>(
583+
pub(super) fn effect_unification_error<'tcx>(
584584
_tcx: TyCtxt<'tcx>,
585585
_a_is_expected: bool,
586586
(_a, _b): (EffectVarValue<'tcx>, EffectVarValue<'tcx>),

‎compiler/rustc_infer/src/infer/relate/generalize.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,8 @@ where
269269
ty::Invariant => {
270270
if self.for_universe.can_name(universe) {
271271
return Ok(t);
272+
} else if self.infcx.next_trait_solver() && self.in_alias {
273+
return Err(TypeError::Mismatch);
272274
}
273275
}
274276

@@ -400,6 +402,8 @@ where
400402
let r_universe = self.infcx.universe_of_region(r);
401403
if self.for_universe.can_name(r_universe) {
402404
return Ok(r);
405+
} else if self.infcx.next_trait_solver() && self.in_alias {
406+
return Err(TypeError::Mismatch);
403407
}
404408
}
405409

@@ -439,6 +443,8 @@ where
439443
ConstVariableValue::Unknown { origin, universe } => {
440444
if self.for_universe.can_name(universe) {
441445
Ok(c)
446+
} else if self.infcx.next_trait_solver() && self.in_alias {
447+
return Err(TypeError::Mismatch);
442448
} else {
443449
let new_var_id = variable_table
444450
.new_key(ConstVariableValue::Unknown {
Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
use super::combine::{float_unification_error, int_unification_error};
2+
use crate::infer::{InferCtxt, SubregionOrigin, TypeTrace, ValuePairs};
3+
4+
use rustc_middle::infer::unify_key::{ConstVariableValue, EffectVarValue};
5+
use rustc_middle::traits::ObligationCause;
6+
use rustc_middle::ty::error::ExpectedFound;
7+
use rustc_middle::ty::relate::{self, structurally_relate_tys, Relate, RelateResult, TypeRelation};
8+
use rustc_middle::ty::visit::MaxUniverse;
9+
use rustc_middle::ty::IntVarValue::{IntType, UintType};
10+
use rustc_middle::ty::TypeVisitable;
11+
use rustc_middle::ty::{self, Ty, TyCtxt};
12+
use rustc_middle::ty::{GenericArgsRef, InferConst};
13+
use rustc_middle::ty::{InferCtxtLike, TyVar};
14+
15+
use rustc_hir::def_id::DefId;
16+
17+
/// A visitor to instantiate inference variables assuming that the
18+
/// instantiation will definitely succeed.
19+
///
20+
/// Using this in places where that may not be the case can easily
21+
/// result in bugs or unsoudness. Used when instantiating a canonical
22+
/// response in the new solver.
23+
///
24+
/// Unlike `Equate` this always structurally relates aliases, meaning
25+
/// it always succeeds without emitting any nested obligations.
26+
pub struct InstantiateUnchecked<'a, 'tcx> {
27+
infcx: &'a InferCtxt<'tcx>,
28+
cause: &'a ObligationCause<'tcx>,
29+
}
30+
31+
impl<'a, 'tcx> InstantiateUnchecked<'a, 'tcx> {
32+
pub fn new(
33+
infcx: &'a InferCtxt<'tcx>,
34+
cause: &'a ObligationCause<'tcx>,
35+
) -> InstantiateUnchecked<'a, 'tcx> {
36+
InstantiateUnchecked { infcx, cause }
37+
}
38+
39+
/// Used by debug assertions to detect some unsound uses of this
40+
/// visitor.
41+
fn infer_var_can_name<T: TypeVisitable<TyCtxt<'tcx>>>(
42+
&self,
43+
universe_of_infer: ty::UniverseIndex,
44+
value: T,
45+
) -> bool {
46+
let mut visitor = MaxUniverse::new();
47+
value.visit_with(&mut visitor);
48+
universe_of_infer.can_name(visitor.max_universe())
49+
}
50+
}
51+
52+
impl<'tcx> TypeRelation<'tcx> for InstantiateUnchecked<'_, 'tcx> {
53+
fn tag(&self) -> &'static str {
54+
"InstantiateUnchecked"
55+
}
56+
57+
fn tcx(&self) -> TyCtxt<'tcx> {
58+
self.infcx.tcx
59+
}
60+
61+
fn a_is_expected(&self) -> bool {
62+
true
63+
}
64+
65+
fn relate_item_args(
66+
&mut self,
67+
_item_def_id: DefId,
68+
a_arg: GenericArgsRef<'tcx>,
69+
b_arg: GenericArgsRef<'tcx>,
70+
) -> RelateResult<'tcx, GenericArgsRef<'tcx>> {
71+
relate::relate_args_invariantly(self, a_arg, b_arg)
72+
}
73+
74+
fn relate_with_variance<T: Relate<'tcx>>(
75+
&mut self,
76+
_: ty::Variance,
77+
_info: ty::VarianceDiagInfo<'tcx>,
78+
a: T,
79+
b: T,
80+
) -> RelateResult<'tcx, T> {
81+
self.relate(a, b)
82+
}
83+
84+
#[instrument(skip(self), level = "debug")]
85+
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
86+
if a == b {
87+
return Ok(a);
88+
}
89+
90+
let infcx = self.infcx;
91+
let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a);
92+
let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b);
93+
94+
// This is pretty much a copy of `Equate::tys` and `fn super_combine_consts`.
95+
// We cannot use these directly as they emit `AliasRelate` goals when
96+
// relate aliases.
97+
match (a.kind(), b.kind()) {
98+
(&ty::Infer(TyVar(a_vid)), &ty::Infer(TyVar(b_vid))) => {
99+
infcx.inner.borrow_mut().type_variables().equate(a_vid, b_vid);
100+
Ok(a)
101+
}
102+
103+
(&ty::Infer(TyVar(a_vid)), _) => {
104+
debug_assert!(self.infer_var_can_name(infcx.universe_of_ty(a_vid).unwrap(), b));
105+
infcx.inner.borrow_mut().type_variables().instantiate(a_vid, b);
106+
Ok(b)
107+
}
108+
109+
(_, &ty::Infer(TyVar(b_vid))) => {
110+
debug_assert!(self.infer_var_can_name(infcx.universe_of_ty(b_vid).unwrap(), a));
111+
infcx.inner.borrow_mut().type_variables().instantiate(b_vid, a);
112+
Ok(a)
113+
}
114+
115+
(&ty::Infer(ty::IntVar(a_vid)), &ty::Infer(ty::IntVar(b_vid))) => {
116+
infcx
117+
.inner
118+
.borrow_mut()
119+
.int_unification_table()
120+
.unify_var_var(a_vid, b_vid)
121+
.map_err(|e| int_unification_error(true, e))?;
122+
Ok(a)
123+
}
124+
(&ty::Infer(ty::IntVar(v_id)), &ty::Int(v)) => {
125+
infcx.unify_integral_variable(true, v_id, IntType(v))
126+
}
127+
(&ty::Int(v), &ty::Infer(ty::IntVar(v_id))) => {
128+
infcx.unify_integral_variable(false, v_id, IntType(v))
129+
}
130+
(&ty::Infer(ty::IntVar(v_id)), &ty::Uint(v)) => {
131+
infcx.unify_integral_variable(true, v_id, UintType(v))
132+
}
133+
(&ty::Uint(v), &ty::Infer(ty::IntVar(v_id))) => {
134+
infcx.unify_integral_variable(false, v_id, UintType(v))
135+
}
136+
137+
// Relate floating-point variables to other types
138+
(&ty::Infer(ty::FloatVar(a_vid)), &ty::Infer(ty::FloatVar(b_vid))) => {
139+
infcx
140+
.inner
141+
.borrow_mut()
142+
.float_unification_table()
143+
.unify_var_var(a_vid, b_vid)
144+
.map_err(|e| float_unification_error(true, e))?;
145+
Ok(a)
146+
}
147+
(&ty::Infer(ty::FloatVar(v_id)), &ty::Float(v)) => {
148+
infcx.unify_float_variable(true, v_id, v)
149+
}
150+
(&ty::Float(v), &ty::Infer(ty::FloatVar(v_id))) => {
151+
infcx.unify_float_variable(false, v_id, v)
152+
}
153+
154+
_ => structurally_relate_tys(self, a, b),
155+
}
156+
}
157+
158+
fn regions(
159+
&mut self,
160+
a: ty::Region<'tcx>,
161+
b: ty::Region<'tcx>,
162+
) -> RelateResult<'tcx, ty::Region<'tcx>> {
163+
debug!("{}.regions({:?}, {:?})", self.tag(), a, b);
164+
let origin = SubregionOrigin::Subtype(Box::new(TypeTrace {
165+
cause: self.cause.clone(),
166+
values: ValuePairs::Regions(ExpectedFound::new(true, a, b)),
167+
}));
168+
self.infcx.inner.borrow_mut().unwrap_region_constraints().make_eqregion(origin, a, b);
169+
Ok(a)
170+
}
171+
172+
fn consts(
173+
&mut self,
174+
a: ty::Const<'tcx>,
175+
b: ty::Const<'tcx>,
176+
) -> RelateResult<'tcx, ty::Const<'tcx>> {
177+
let infcx = self.infcx;
178+
let a = infcx.shallow_resolve(a);
179+
let b = infcx.shallow_resolve(b);
180+
match (a.kind(), b.kind()) {
181+
(
182+
ty::ConstKind::Infer(InferConst::Var(a_vid)),
183+
ty::ConstKind::Infer(InferConst::Var(b_vid)),
184+
) => {
185+
infcx.inner.borrow_mut().const_unification_table().union(a_vid, b_vid);
186+
Ok(a)
187+
}
188+
189+
(
190+
ty::ConstKind::Infer(InferConst::EffectVar(a_vid)),
191+
ty::ConstKind::Infer(InferConst::EffectVar(b_vid)),
192+
) => {
193+
infcx
194+
.inner
195+
.borrow_mut()
196+
.effect_unification_table()
197+
.unify_var_var(a_vid, b_vid)
198+
.map_err(|_| bug!("unexpected error"))?;
199+
Ok(a)
200+
}
201+
202+
// All other cases of inference with other variables are errors.
203+
(
204+
ty::ConstKind::Infer(InferConst::Var(_) | InferConst::EffectVar(_)),
205+
ty::ConstKind::Infer(_),
206+
)
207+
| (
208+
ty::ConstKind::Infer(_),
209+
ty::ConstKind::Infer(InferConst::Var(_) | InferConst::EffectVar(_)),
210+
) => {
211+
bug!(
212+
"tried to combine ConstKind::Infer/ConstKind::Infer(InferConst::Var): {a:?} and {b:?}"
213+
)
214+
}
215+
216+
(ty::ConstKind::Infer(InferConst::Var(a_vid)), _) => {
217+
debug_assert!(self.infer_var_can_name(infcx.universe_of_ct(a_vid).unwrap(), b));
218+
infcx
219+
.inner
220+
.borrow_mut()
221+
.const_unification_table()
222+
.union_value(a_vid, ConstVariableValue::Known { value: b });
223+
Ok(b)
224+
}
225+
226+
(_, ty::ConstKind::Infer(InferConst::Var(b_vid))) => {
227+
debug_assert!(self.infer_var_can_name(infcx.universe_of_ct(b_vid).unwrap(), a));
228+
infcx
229+
.inner
230+
.borrow_mut()
231+
.const_unification_table()
232+
.union_value(b_vid, ConstVariableValue::Known { value: a });
233+
Ok(a)
234+
}
235+
236+
(ty::ConstKind::Infer(InferConst::EffectVar(vid)), _) => {
237+
infcx.unify_effect_variable(true, vid, EffectVarValue::Const(b))
238+
}
239+
240+
(_, ty::ConstKind::Infer(InferConst::EffectVar(vid))) => {
241+
infcx.unify_effect_variable(false, vid, EffectVarValue::Const(a))
242+
}
243+
244+
_ => ty::relate::structurally_relate_consts(self, a, b),
245+
}
246+
}
247+
248+
fn binders<T>(
249+
&mut self,
250+
a: ty::Binder<'tcx, T>,
251+
b: ty::Binder<'tcx, T>,
252+
) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
253+
where
254+
T: Relate<'tcx>,
255+
{
256+
if a != b {
257+
// This differs from `Equate`; we only care about structural equality here.
258+
assert_eq!(a.bound_vars(), b.bound_vars());
259+
let (a, b) = self
260+
.infcx
261+
.instantiate_binder_with_placeholders(a.map_bound(|a| (a, b.skip_binder())));
262+
self.relate(a, b)?;
263+
}
264+
Ok(a)
265+
}
266+
}

‎compiler/rustc_infer/src/infer/relate/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ mod equate;
66
pub(super) mod generalize;
77
mod glb;
88
mod higher_ranked;
9+
pub mod instantiate_unchecked;
910
mod lattice;
1011
mod lub;
1112
pub mod nll;

‎compiler/rustc_middle/src/traits/solve/inspect.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,6 @@ pub struct GoalEvaluation<'tcx> {
5858
pub uncanonicalized_goal: Goal<'tcx, ty::Predicate<'tcx>>,
5959
pub kind: GoalEvaluationKind<'tcx>,
6060
pub evaluation: CanonicalGoalEvaluation<'tcx>,
61-
/// The nested goals from instantiating the query response.
62-
pub returned_goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
6361
}
6462

6563
#[derive(Eq, PartialEq)]

‎compiler/rustc_middle/src/traits/solve/inspect/format.rs

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -48,20 +48,7 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
4848
},
4949
};
5050
writeln!(self.f, "{}: {:?}", goal_text, eval.uncanonicalized_goal)?;
51-
self.nested(|this| this.format_canonical_goal_evaluation(&eval.evaluation))?;
52-
if eval.returned_goals.len() > 0 {
53-
writeln!(self.f, "NESTED GOALS ADDED TO CALLER: [")?;
54-
self.nested(|this| {
55-
for goal in eval.returned_goals.iter() {
56-
writeln!(this.f, "ADDED GOAL: {goal:?},")?;
57-
}
58-
Ok(())
59-
})?;
60-
61-
writeln!(self.f, "]")
62-
} else {
63-
Ok(())
64-
}
51+
self.nested(|this| this.format_canonical_goal_evaluation(&eval.evaluation))
6552
}
6653

6754
pub(super) fn format_canonical_goal_evaluation(

‎compiler/rustc_next_trait_solver/src/canonicalizer.rs

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -107,21 +107,22 @@ impl<'a, Infcx: InferCtxtLike<Interner = I>, I: Interner> Canonicalizer<'a, Infc
107107
// universes `n`, this algorithm compresses them in place so that:
108108
//
109109
// - the new universe indices are as small as possible
110-
// - we only create a new universe if we would otherwise put a placeholder in
111-
// the same compressed universe as an existential which cannot name it
110+
// - we create a new universe if we would otherwise
111+
// 1. put existentials from a different universe into the same one
112+
// 2. put a placeholder in the same universe as an existential which cannot name it
112113
//
113114
// Let's walk through an example:
114115
// - var_infos: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 0, next_orig_uv: 0
115116
// - var_infos: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 0, next_orig_uv: 1
116117
// - var_infos: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 1, next_orig_uv: 2
117118
// - var_infos: [E0, U1, E5, U1, E1, E6, U6], curr_compressed_uv: 1, next_orig_uv: 5
118-
// - var_infos: [E0, U1, E1, U1, E1, E6, U6], curr_compressed_uv: 1, next_orig_uv: 6
119-
// - var_infos: [E0, U1, E1, U1, E1, E2, U2], curr_compressed_uv: 2, next_orig_uv: -
119+
// - var_infos: [E0, U1, E2, U1, E1, E6, U6], curr_compressed_uv: 2, next_orig_uv: 6
120+
// - var_infos: [E0, U1, E1, U1, E1, E3, U3], curr_compressed_uv: 2, next_orig_uv: -
120121
//
121122
// This algorithm runs in `O(n²)` where `n` is the number of different universe
122123
// indices in the input. This should be fine as `n` is expected to be small.
123124
let mut curr_compressed_uv = ty::UniverseIndex::ROOT;
124-
let mut existential_in_new_uv = false;
125+
let mut existential_in_new_uv = None;
125126
let mut next_orig_uv = Some(ty::UniverseIndex::ROOT);
126127
while let Some(orig_uv) = next_orig_uv.take() {
127128
let mut update_uv = |var: &mut CanonicalVarInfo<I>, orig_uv, is_existential| {
@@ -130,14 +131,25 @@ impl<'a, Infcx: InferCtxtLike<Interner = I>, I: Interner> Canonicalizer<'a, Infc
130131
Ordering::Less => (), // Already updated
131132
Ordering::Equal => {
132133
if is_existential {
133-
existential_in_new_uv = true;
134-
} else if existential_in_new_uv {
134+
if existential_in_new_uv.is_some_and(|uv| uv < orig_uv) {
135+
// Condition 1.
136+
//
137+
// We already put an existential from a outer universe
138+
// into the current compressed universe, so we need to
139+
// create a new one.
140+
curr_compressed_uv = curr_compressed_uv.next_universe();
141+
}
142+
143+
existential_in_new_uv = next_orig_uv;
144+
} else if existential_in_new_uv.is_some() {
145+
// Condition 2.
146+
//
135147
// `var` is a placeholder from a universe which is not nameable
136148
// by an existential which we already put into the compressed
137149
// universe `curr_compressed_uv`. We therefore have to create a
138150
// new universe for `var`.
139151
curr_compressed_uv = curr_compressed_uv.next_universe();
140-
existential_in_new_uv = false;
152+
existential_in_new_uv = None;
141153
}
142154

143155
*var = var.with_updated_universe(curr_compressed_uv);

‎compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs

Lines changed: 35 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,16 @@ use rustc_index::IndexVec;
1717
use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
1818
use rustc_infer::infer::canonical::CanonicalVarValues;
1919
use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints};
20+
use rustc_infer::infer::relate::instantiate_unchecked::InstantiateUnchecked;
2021
use rustc_infer::infer::resolve::EagerResolver;
21-
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
22+
use rustc_infer::infer::InferCtxt;
2223
use rustc_middle::infer::canonical::Canonical;
2324
use rustc_middle::traits::query::NoSolution;
2425
use rustc_middle::traits::solve::{
2526
ExternalConstraintsData, MaybeCause, PredefinedOpaquesData, QueryInput,
2627
};
2728
use rustc_middle::traits::ObligationCause;
29+
use rustc_middle::ty::relate::Relate;
2830
use rustc_middle::ty::{self, BoundVar, GenericArgKind, Ty, TyCtxt, TypeFoldable};
2931
use rustc_next_trait_solver::canonicalizer::{CanonicalizeMode, Canonicalizer};
3032
use rustc_span::DUMMY_SP;
@@ -191,22 +193,20 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
191193
param_env: ty::ParamEnv<'tcx>,
192194
original_values: Vec<ty::GenericArg<'tcx>>,
193195
response: CanonicalResponse<'tcx>,
194-
) -> Result<(Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution> {
196+
) -> Certainty {
195197
let substitution =
196198
Self::compute_query_response_substitution(self.infcx, &original_values, &response);
197199

198200
let Response { var_values, external_constraints, certainty } =
199201
response.substitute(self.tcx(), &substitution);
200202

201-
let nested_goals =
202-
Self::unify_query_var_values(self.infcx, param_env, &original_values, var_values)?;
203+
Self::unify_query_var_values(self.infcx, &original_values, var_values);
203204

204205
let ExternalConstraintsData { region_constraints, opaque_types } =
205206
external_constraints.deref();
206207
self.register_region_constraints(region_constraints);
207-
self.register_opaque_types(param_env, opaque_types)?;
208-
209-
Ok((certainty, nested_goals))
208+
self.register_new_opaque_types(param_env, opaque_types);
209+
certainty
210210
}
211211

212212
/// This returns the substitutions to instantiate the bound variables of
@@ -293,32 +293,32 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
293293
CanonicalVarValues { var_values }
294294
}
295295

296-
#[instrument(level = "debug", skip(infcx, param_env), ret)]
296+
297+
/// Unify the `original_values` with the `var_values` returned by the canonical query..
298+
///
299+
/// This assumes that this unification will always succeed. This is the case when
300+
/// applying a query response right away. However, calling a canonical query, doing any
301+
/// other kind of trait solving, and only then instantiating the result of the query
302+
/// can cause the instantiation to fail. This is not supported and we ICE in this case.
303+
///
304+
/// We need this assumption to be able to always structurally instantiate aliases.
305+
/// Relating aliases needs to be different depending on whether the alias is *rigid* or not.
306+
/// We're only really able to tell whether an alias is rigid by using the trait solver.
307+
/// When instantiating a response from the solver we assume that the solver correctly
308+
/// handled aliases and always relate them structurally.
309+
#[instrument(level = "debug", skip(infcx), ret)]
297310
fn unify_query_var_values(
298311
infcx: &InferCtxt<'tcx>,
299-
param_env: ty::ParamEnv<'tcx>,
300312
original_values: &[ty::GenericArg<'tcx>],
301313
var_values: CanonicalVarValues<'tcx>,
302-
) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
314+
) {
303315
assert_eq!(original_values.len(), var_values.len());
304316

305-
let mut nested_goals = vec![];
317+
let cause = ObligationCause::dummy();
318+
let mut rel = InstantiateUnchecked::new(infcx, &cause);
306319
for (&orig, response) in iter::zip(original_values, var_values.var_values) {
307-
nested_goals.extend(
308-
infcx
309-
.at(&ObligationCause::dummy(), param_env)
310-
.eq(DefineOpaqueTypes::No, orig, response)
311-
.map(|InferOk { value: (), obligations }| {
312-
obligations.into_iter().map(|o| Goal::from(o))
313-
})
314-
.map_err(|e| {
315-
debug!(?e, "failed to equate");
316-
NoSolution
317-
})?,
318-
);
320+
ty::GenericArg::relate(&mut rel, orig, response).unwrap();
319321
}
320-
321-
Ok(nested_goals)
322322
}
323323

324324
fn register_region_constraints(&mut self, region_constraints: &QueryRegionConstraints<'tcx>) {
@@ -330,21 +330,17 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
330330
}
331331
}
332332

333-
for member_constraint in &region_constraints.member_constraints {
334-
// FIXME: Deal with member constraints :<
335-
let _ = member_constraint;
336-
}
333+
assert!(region_constraints.member_constraints.is_empty());
337334
}
338335

339-
fn register_opaque_types(
336+
fn register_new_opaque_types(
340337
&mut self,
341338
param_env: ty::ParamEnv<'tcx>,
342339
opaque_types: &[(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)],
343-
) -> Result<(), NoSolution> {
340+
) {
344341
for &(key, ty) in opaque_types {
345-
self.insert_hidden_type(key, param_env, ty)?;
342+
self.insert_hidden_type(key, param_env, ty).unwrap();
346343
}
347-
Ok(())
348344
}
349345
}
350346

@@ -363,19 +359,20 @@ impl<'tcx> inspect::ProofTreeBuilder<'tcx> {
363359
)
364360
}
365361

362+
/// Instantiate a `CanonicalState`. This assumes that unifying the var values
363+
/// trivially succeeds. Adding any inference constraints which weren't present when
364+
/// originally computing the canonical query can result in bugs.
366365
pub fn instantiate_canonical_state<T: TypeFoldable<TyCtxt<'tcx>>>(
367366
infcx: &InferCtxt<'tcx>,
368-
param_env: ty::ParamEnv<'tcx>,
369367
original_values: &[ty::GenericArg<'tcx>],
370368
state: inspect::CanonicalState<'tcx, T>,
371-
) -> Result<(Vec<Goal<'tcx, ty::Predicate<'tcx>>>, T), NoSolution> {
369+
) -> T {
372370
let substitution =
373371
EvalCtxt::compute_query_response_substitution(infcx, original_values, &state);
374372

375373
let inspect::State { var_values, data } = state.substitute(infcx.tcx, &substitution);
376374

377-
let nested_goals =
378-
EvalCtxt::unify_query_var_values(infcx, param_env, original_values, var_values)?;
379-
Ok((nested_goals, data))
375+
EvalCtxt::unify_query_var_values(infcx, original_values, var_values);
376+
data
380377
}
381378
}

‎compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs

Lines changed: 17 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -140,10 +140,7 @@ pub trait InferCtxtEvalExt<'tcx> {
140140
&self,
141141
goal: Goal<'tcx, ty::Predicate<'tcx>>,
142142
generate_proof_tree: GenerateProofTree,
143-
) -> (
144-
Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution>,
145-
Option<inspect::GoalEvaluation<'tcx>>,
146-
);
143+
) -> (Result<(bool, Certainty), NoSolution>, Option<inspect::GoalEvaluation<'tcx>>);
147144
}
148145

149146
impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
@@ -152,10 +149,7 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
152149
&self,
153150
goal: Goal<'tcx, ty::Predicate<'tcx>>,
154151
generate_proof_tree: GenerateProofTree,
155-
) -> (
156-
Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution>,
157-
Option<inspect::GoalEvaluation<'tcx>>,
158-
) {
152+
) -> (Result<(bool, Certainty), NoSolution>, Option<inspect::GoalEvaluation<'tcx>>) {
159153
EvalCtxt::enter_root(self, generate_proof_tree, |ecx| {
160154
ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal)
161155
})
@@ -337,7 +331,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
337331
goal_evaluation_kind: GoalEvaluationKind,
338332
source: GoalSource,
339333
goal: Goal<'tcx, ty::Predicate<'tcx>>,
340-
) -> Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution> {
334+
) -> Result<(bool, Certainty), NoSolution> {
341335
let (orig_values, canonical_goal) = self.canonicalize_goal(goal);
342336
let mut goal_evaluation =
343337
self.inspect.new_goal_evaluation(goal, &orig_values, goal_evaluation_kind);
@@ -355,26 +349,13 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
355349
Ok(response) => response,
356350
};
357351

358-
let (certainty, has_changed, nested_goals) = match self
359-
.instantiate_response_discarding_overflow(
360-
goal.param_env,
361-
source,
362-
orig_values,
363-
canonical_response,
364-
) {
365-
Err(e) => {
366-
self.inspect.goal_evaluation(goal_evaluation);
367-
return Err(e);
368-
}
369-
Ok(response) => response,
370-
};
371-
goal_evaluation.returned_goals(&nested_goals);
352+
let (certainty, has_changed) = self.instantiate_response_discarding_overflow(
353+
goal.param_env,
354+
source,
355+
orig_values,
356+
canonical_response,
357+
);
372358
self.inspect.goal_evaluation(goal_evaluation);
373-
374-
if !has_changed && !nested_goals.is_empty() {
375-
bug!("an unchanged goal shouldn't have any side-effects on instantiation");
376-
}
377-
378359
// FIXME: We previously had an assert here that checked that recomputing
379360
// a goal after applying its constraints did not change its response.
380361
//
@@ -385,7 +366,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
385366
// Once we have decided on how to handle trait-system-refactor-initiative#75,
386367
// we should re-add an assert here.
387368

388-
Ok((has_changed, certainty, nested_goals))
369+
Ok((has_changed, certainty))
389370
}
390371

391372
fn instantiate_response_discarding_overflow(
@@ -394,7 +375,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
394375
source: GoalSource,
395376
original_values: Vec<ty::GenericArg<'tcx>>,
396377
response: CanonicalResponse<'tcx>,
397-
) -> Result<(Certainty, bool, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution> {
378+
) -> (Certainty, bool) {
398379
// The old solver did not evaluate nested goals when normalizing.
399380
// It returned the selection constraints allowing a `Projection`
400381
// obligation to not hold in coherence while avoiding the fatal error
@@ -415,14 +396,14 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
415396
};
416397

417398
if response.value.certainty == Certainty::OVERFLOW && !keep_overflow_constraints() {
418-
Ok((Certainty::OVERFLOW, false, Vec::new()))
399+
(Certainty::OVERFLOW, false)
419400
} else {
420401
let has_changed = !response.value.var_values.is_identity_modulo_regions()
421402
|| !response.value.external_constraints.opaque_types.is_empty();
422403

423-
let (certainty, nested_goals) =
424-
self.instantiate_and_apply_query_response(param_env, original_values, response)?;
425-
Ok((certainty, has_changed, nested_goals))
404+
let certainty =
405+
self.instantiate_and_apply_query_response(param_env, original_values, response);
406+
(certainty, has_changed)
426407
}
427408
}
428409

@@ -546,12 +527,11 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
546527
ty::NormalizesTo { alias: goal.predicate.alias, term: unconstrained_rhs },
547528
);
548529

549-
let (_, certainty, instantiate_goals) = self.evaluate_goal(
530+
let (_, certainty) = self.evaluate_goal(
550531
GoalEvaluationKind::Nested { is_normalizes_to_hack: IsNormalizesToHack::Yes },
551532
GoalSource::Misc,
552533
unconstrained_goal,
553534
)?;
554-
self.nested_goals.goals.extend(with_misc_source(instantiate_goals));
555535

556536
// Finally, equate the goal's RHS with the unconstrained var.
557537
// We put the nested goals from this into goals instead of
@@ -582,12 +562,11 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
582562
}
583563

584564
for (source, goal) in goals.goals.drain(..) {
585-
let (has_changed, certainty, instantiate_goals) = self.evaluate_goal(
565+
let (has_changed, certainty) = self.evaluate_goal(
586566
GoalEvaluationKind::Nested { is_normalizes_to_hack: IsNormalizesToHack::No },
587567
source,
588568
goal,
589569
)?;
590-
self.nested_goals.goals.extend(with_misc_source(instantiate_goals));
591570
if has_changed {
592571
unchanged_certainty = None;
593572
}

‎compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs

Lines changed: 18 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -67,37 +67,26 @@ impl<'tcx> InferCtxtSelectExt<'tcx> for InferCtxt<'tcx> {
6767
}
6868

6969
let candidate = candidates.pop().unwrap();
70-
let (certainty, nested_goals) = ecx
71-
.instantiate_and_apply_query_response(
72-
trait_goal.param_env,
73-
orig_values,
74-
candidate.result,
75-
)
76-
.map_err(|_| SelectionError::Unimplemented)?;
70+
let certainty = ecx.instantiate_and_apply_query_response(
71+
trait_goal.param_env,
72+
orig_values,
73+
candidate.result,
74+
);
7775

78-
Ok(Some((candidate, certainty, nested_goals)))
76+
Ok(Some((candidate, certainty)))
7977
});
8078

81-
let (candidate, certainty, nested_goals) = match result {
82-
Ok(Some((candidate, certainty, nested_goals))) => (candidate, certainty, nested_goals),
79+
let (candidate, certainty) = match result {
80+
Ok(Some((candidate, certainty))) => (candidate, certainty),
8381
Ok(None) => return Ok(None),
8482
Err(e) => return Err(e),
8583
};
8684

87-
let nested_obligations: Vec<_> = nested_goals
88-
.into_iter()
89-
.map(|goal| {
90-
Obligation::new(self.tcx, ObligationCause::dummy(), goal.param_env, goal.predicate)
91-
})
92-
.collect();
93-
9485
let goal = self.resolve_vars_if_possible(trait_goal);
9586
match (certainty, candidate.source) {
9687
// Rematching the implementation will instantiate the same nested goals that
9788
// would have caused the ambiguity, so we can still make progress here regardless.
98-
(_, CandidateSource::Impl(def_id)) => {
99-
rematch_impl(self, goal, def_id, nested_obligations)
100-
}
89+
(_, CandidateSource::Impl(def_id)) => rematch_impl(self, goal, def_id),
10190

10291
// If an unsize goal is ambiguous, then we can manually rematch it to make
10392
// selection progress for coercion during HIR typeck. If it is *not* ambiguous,
@@ -110,20 +99,20 @@ impl<'tcx> InferCtxtSelectExt<'tcx> for InferCtxt<'tcx> {
11099
| (Certainty::Yes, CandidateSource::BuiltinImpl(src @ BuiltinImplSource::Misc))
111100
if self.tcx.lang_items().unsize_trait() == Some(goal.predicate.def_id()) =>
112101
{
113-
rematch_unsize(self, goal, nested_obligations, src, certainty)
102+
rematch_unsize(self, goal, src, certainty)
114103
}
115104

116105
// Technically some builtin impls have nested obligations, but if
117106
// `Certainty::Yes`, then they should've all been verified and don't
118107
// need re-checking.
119108
(Certainty::Yes, CandidateSource::BuiltinImpl(src)) => {
120-
Ok(Some(ImplSource::Builtin(src, nested_obligations)))
109+
Ok(Some(ImplSource::Builtin(src, Vec::new())))
121110
}
122111

123112
// It's fine not to do anything to rematch these, since there are no
124113
// nested obligations.
125114
(Certainty::Yes, CandidateSource::ParamEnv(_) | CandidateSource::AliasBound) => {
126-
Ok(Some(ImplSource::Param(nested_obligations)))
115+
Ok(Some(ImplSource::Param(Vec::new())))
127116
}
128117

129118
(Certainty::Maybe(_), _) => Ok(None),
@@ -193,19 +182,16 @@ fn rematch_impl<'tcx>(
193182
infcx: &InferCtxt<'tcx>,
194183
goal: Goal<'tcx, ty::TraitPredicate<'tcx>>,
195184
impl_def_id: DefId,
196-
mut nested: Vec<PredicateObligation<'tcx>>,
197185
) -> SelectionResult<'tcx, Selection<'tcx>> {
198186
let args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id);
199187
let impl_trait_ref =
200188
infcx.tcx.impl_trait_ref(impl_def_id).unwrap().instantiate(infcx.tcx, args);
201189

202-
nested.extend(
203-
infcx
204-
.at(&ObligationCause::dummy(), goal.param_env)
205-
.eq(DefineOpaqueTypes::No, goal.predicate.trait_ref, impl_trait_ref)
206-
.map_err(|_| SelectionError::Unimplemented)?
207-
.into_obligations(),
208-
);
190+
let mut nested = infcx
191+
.at(&ObligationCause::dummy(), goal.param_env)
192+
.eq(DefineOpaqueTypes::No, goal.predicate.trait_ref, impl_trait_ref)
193+
.map_err(|_| SelectionError::Unimplemented)?
194+
.into_obligations();
209195

210196
nested.extend(
211197
infcx.tcx.predicates_of(impl_def_id).instantiate(infcx.tcx, args).into_iter().map(
@@ -222,11 +208,11 @@ fn rematch_impl<'tcx>(
222208
fn rematch_unsize<'tcx>(
223209
infcx: &InferCtxt<'tcx>,
224210
goal: Goal<'tcx, ty::TraitPredicate<'tcx>>,
225-
mut nested: Vec<PredicateObligation<'tcx>>,
226211
source: BuiltinImplSource,
227212
certainty: Certainty,
228213
) -> SelectionResult<'tcx, Selection<'tcx>> {
229214
let tcx = infcx.tcx;
215+
let mut nested = vec![];
230216
let a_ty = structurally_normalize(goal.predicate.self_ty(), infcx, goal.param_env, &mut nested);
231217
let b_ty = structurally_normalize(
232218
goal.predicate.trait_ref.args.type_at(1),

‎compiler/rustc_trait_selection/src/solve/fulfill.rs

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use std::mem;
22

33
use rustc_infer::infer::InferCtxt;
44
use rustc_infer::traits::solve::MaybeCause;
5-
use rustc_infer::traits::Obligation;
65
use rustc_infer::traits::{
76
query::NoSolution, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes,
87
PredicateObligation, SelectionError, TraitEngine,
@@ -11,7 +10,7 @@ use rustc_middle::ty;
1110
use rustc_middle::ty::error::{ExpectedFound, TypeError};
1211

1312
use super::eval_ctxt::GenerateProofTree;
14-
use super::{Certainty, Goal, InferCtxtEvalExt};
13+
use super::{Certainty, InferCtxtEvalExt};
1514

1615
/// A trait engine using the new trait solver.
1716
///
@@ -48,11 +47,11 @@ impl<'tcx> FulfillmentCtxt<'tcx> {
4847
&self,
4948
infcx: &InferCtxt<'tcx>,
5049
obligation: &PredicateObligation<'tcx>,
51-
result: &Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution>,
50+
result: &Result<(bool, Certainty), NoSolution>,
5251
) {
5352
if let Some(inspector) = infcx.obligation_inspector.get() {
5453
let result = match result {
55-
Ok((_, c, _)) => Ok(*c),
54+
Ok((_, c)) => Ok(*c),
5655
Err(NoSolution) => Err(NoSolution),
5756
};
5857
(inspector)(infcx, &obligation, result);
@@ -80,13 +79,13 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
8079
.evaluate_root_goal(obligation.clone().into(), GenerateProofTree::IfEnabled)
8180
.0
8281
{
83-
Ok((_, Certainty::Maybe(MaybeCause::Ambiguity), _)) => {
82+
Ok((_, Certainty::Maybe(MaybeCause::Ambiguity))) => {
8483
FulfillmentErrorCode::Ambiguity { overflow: false }
8584
}
86-
Ok((_, Certainty::Maybe(MaybeCause::Overflow), _)) => {
85+
Ok((_, Certainty::Maybe(MaybeCause::Overflow))) => {
8786
FulfillmentErrorCode::Ambiguity { overflow: true }
8887
}
89-
Ok((_, Certainty::Yes, _)) => {
88+
Ok((_, Certainty::Yes)) => {
9089
bug!("did not expect successful goal when collecting ambiguity errors")
9190
}
9291
Err(_) => {
@@ -117,7 +116,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
117116
let goal = obligation.clone().into();
118117
let result = infcx.evaluate_root_goal(goal, GenerateProofTree::IfEnabled).0;
119118
self.inspect_evaluated_obligation(infcx, &obligation, &result);
120-
let (changed, certainty, nested_goals) = match result {
119+
let (changed, certainty) = match result {
121120
Ok(result) => result,
122121
Err(NoSolution) => {
123122
errors.push(FulfillmentError {
@@ -175,16 +174,6 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
175174
continue;
176175
}
177176
};
178-
// Push any nested goals that we get from unifying our canonical response
179-
// with our obligation onto the fulfillment context.
180-
self.obligations.extend(nested_goals.into_iter().map(|goal| {
181-
Obligation::new(
182-
infcx.tcx,
183-
obligation.cause.clone(),
184-
goal.param_env,
185-
goal.predicate,
186-
)
187-
}));
188177
has_changed |= changed;
189178
match certainty {
190179
Certainty::Yes => {}

‎compiler/rustc_trait_selection/src/solve/inspect/analyse.rs

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -63,21 +63,11 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
6363
infcx.probe(|_| {
6464
let mut instantiated_goals = vec![];
6565
for goal in &self.nested_goals {
66-
let goal = match ProofTreeBuilder::instantiate_canonical_state(
66+
let goal = ProofTreeBuilder::instantiate_canonical_state(
6767
infcx,
68-
self.goal.goal.param_env,
6968
self.goal.orig_values,
7069
*goal,
71-
) {
72-
Ok((_goals, goal)) => goal,
73-
Err(NoSolution) => {
74-
warn!(
75-
"unexpected failure when instantiating {:?}: {:?}",
76-
goal, self.nested_goals
77-
);
78-
return ControlFlow::Continue(());
79-
}
80-
};
70+
);
8171
instantiated_goals.push(goal);
8272
}
8373

‎compiler/rustc_trait_selection/src/solve/inspect/build.rs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@ struct WipGoalEvaluation<'tcx> {
8787
pub uncanonicalized_goal: Goal<'tcx, ty::Predicate<'tcx>>,
8888
pub kind: WipGoalEvaluationKind<'tcx>,
8989
pub evaluation: Option<WipCanonicalGoalEvaluation<'tcx>>,
90-
pub returned_goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
9190
}
9291

9392
impl<'tcx> WipGoalEvaluation<'tcx> {
@@ -103,7 +102,6 @@ impl<'tcx> WipGoalEvaluation<'tcx> {
103102
}
104103
},
105104
evaluation: self.evaluation.unwrap().finalize(),
106-
returned_goals: self.returned_goals,
107105
}
108106
}
109107
}
@@ -312,7 +310,6 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
312310
}
313311
},
314312
evaluation: None,
315-
returned_goals: vec![],
316313
})
317314
}
318315

@@ -369,17 +366,6 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
369366
}
370367
}
371368

372-
pub fn returned_goals(&mut self, goals: &[Goal<'tcx, ty::Predicate<'tcx>>]) {
373-
if let Some(this) = self.as_mut() {
374-
match this {
375-
DebugSolver::GoalEvaluation(evaluation) => {
376-
assert!(evaluation.returned_goals.is_empty());
377-
evaluation.returned_goals.extend(goals);
378-
}
379-
_ => unreachable!(),
380-
}
381-
}
382-
}
383369
pub fn goal_evaluation(&mut self, goal_evaluation: ProofTreeBuilder<'tcx>) {
384370
if let Some(this) = self.as_mut() {
385371
match (this, *goal_evaluation.state.unwrap()) {

‎tests/ui/traits/next-solver/generalize/generalize-proj-new-universe-index-2.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
// compile-flags: -Znext-solver
2-
// known-bug: trait-system-refactor-initiative#60
2+
// check-pass
33

44
// Generalizing a projection containing an inference variable
5-
// which cannot be named by the `root_vid` can result in ambiguity.
5+
// which cannot be named by the `root_vid` previously resulted in ambiguity.
66
//
77
// Because we do not decrement the universe index when exiting a forall,
88
// this can cause unexpected failures.

‎tests/ui/traits/next-solver/generalize/generalize-proj-new-universe-index-2.stderr

Lines changed: 0 additions & 19 deletions
This file was deleted.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// compile-flags: -Znext-solver
2+
// check-pass
3+
4+
// With #119106 generalization now results in `AliasRelate` if the generalized
5+
// alias contains an inference variable which is not nameable.
6+
//
7+
// We previously proved alias-relate after canonicalization, which does not keep track
8+
// of universe indices, so all inference vars are nameable inside of `AliasRelate`.
9+
//
10+
// If we now have a rigid projection containing an unnameable inference variables,
11+
// we should emit an alias-relate obligation, which constrains the type of `x` to
12+
// an alias, which then caused us to emit yet another equivalent alias-relate obligation
13+
// when trying to instantiate the query result. This resulted in overflow.
14+
trait Trait<'a> {
15+
type Assoc: Default;
16+
}
17+
18+
fn takes_alias<'a, T: Trait<'a>>(_: <T as Trait<'a>>::Assoc) {}
19+
20+
fn foo<T: for<'a> Trait<'a>>() {
21+
let x = Default::default();
22+
23+
let _incr_universe: for<'a, 'b> fn(&'a (), &'b ()) =
24+
(|&(), &()| ()) as for<'a> fn(&'a (), &'a ());
25+
26+
takes_alias::<T>(x);
27+
}
28+
29+
fn main() {}

‎tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.next.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0275]: overflow evaluating the requirement `<<T as Id<_>>::Id as Unnormalizable>::Assoc == _`
2-
--> $DIR/occurs-check-nested-alias.rs:36:9
2+
--> $DIR/occurs-check-nested-alias.rs:38:9
33
|
44
LL | x = y;
55
| ^

‎tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
// revisions: old next
22
//[old] check-pass
3+
//[next] compile-flags: -Znext-solver
4+
//[next] known-bug: trait-system-refactor-initiative#8
5+
6+
// case 3 of https://github.com/rust-lang/trait-system-refactor-initiative/issues/8.
37

48
// Currently always fails to generalize the outer alias, even if it
59
// is treated as rigid by `alias-relate`.
6-
//[next] compile-flags: -Znext-solver
7-
//[next] known-bug: trait-system-refactor-initiative#8
810
#![crate_type = "lib"]
911
#![allow(unused)]
1012
trait Unnormalizable {

‎tests/ui/traits/next-solver/issue-118950-root-region.stderr

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ LL | #![feature(lazy_type_alias)]
1515

1616
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) })
1717
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) })
18+
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) })
19+
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) })
1820
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) })
1921
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) })
2022
WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) })

0 commit comments

Comments
 (0)
Please sign in to comment.