Skip to content

Commit feff26b

Browse files
committed
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

20 files changed

+418
-207
lines changed

compiler/rustc_infer/src/infer/mod.rs

+1-1
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

+6-6
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

+6
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 {
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

+1
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

-2
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

+1-14
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(

0 commit comments

Comments
 (0)