Skip to content

Commit 213a42f

Browse files
committed
how to handle non infer var_values
1 parent 9ab7ed3 commit 213a42f

File tree

11 files changed

+131
-184
lines changed

11 files changed

+131
-184
lines changed

compiler/rustc_infer/src/infer/mod.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,12 @@ impl<'tcx> InferCtxtInner<'tcx> {
201201
}
202202

203203
#[inline]
204-
fn type_variables(&mut self) -> type_variable::TypeVariableTable<'_, 'tcx> {
204+
pub fn instantiate_const_var(&mut self, var: ConstVid, value: ty::Const<'tcx>) {
205+
self.const_unification_table().union_value(var, ConstVariableValue::Known { value })
206+
}
207+
208+
#[inline]
209+
pub fn type_variables(&mut self) -> type_variable::TypeVariableTable<'_, 'tcx> {
205210
self.type_variable_storage.with_log(&mut self.undo_log)
206211
}
207212

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(

compiler/rustc_next_trait_solver/src/canonicalizer.rs

+20-8
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

+61-33
Original file line numberDiff line numberDiff line change
@@ -191,22 +191,20 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
191191
param_env: ty::ParamEnv<'tcx>,
192192
original_values: Vec<ty::GenericArg<'tcx>>,
193193
response: CanonicalResponse<'tcx>,
194-
) -> Result<(Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution> {
194+
) -> Certainty {
195195
let substitution =
196196
Self::compute_query_response_substitution(self.infcx, &original_values, &response);
197197

198198
let Response { var_values, external_constraints, certainty } =
199199
response.substitute(self.tcx(), &substitution);
200200

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

204203
let ExternalConstraintsData { region_constraints, opaque_types } =
205204
external_constraints.deref();
206205
self.register_region_constraints(region_constraints);
207-
self.register_opaque_types(param_env, opaque_types)?;
208-
209-
Ok((certainty, nested_goals))
206+
self.register_new_opaque_types(param_env, opaque_types);
207+
certainty
210208
}
211209

212210
/// This returns the substitutions to instantiate the bound variables of
@@ -299,26 +297,61 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
299297
param_env: ty::ParamEnv<'tcx>,
300298
original_values: &[ty::GenericArg<'tcx>],
301299
var_values: CanonicalVarValues<'tcx>,
302-
) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
300+
) {
303301
assert_eq!(original_values.len(), var_values.len());
304-
305-
let mut nested_goals = vec![];
306302
for (&orig, response) in iter::zip(original_values, var_values.var_values) {
307-
nested_goals.extend(
308-
infcx
303+
EvalCtxt::unify_var_value(infcx, param_env, orig, response);
304+
}
305+
}
306+
307+
fn unify_var_value(
308+
infcx: &InferCtxt<'tcx>,
309+
param_env: ty::ParamEnv<'tcx>,
310+
orig: ty::GenericArg<'tcx>,
311+
response: ty::GenericArg<'tcx>,
312+
) {
313+
let orig = infcx.shallow_resolve(orig);
314+
match (orig.unpack(), response.unpack()) {
315+
(ty::GenericArgKind::Lifetime(orig), ty::GenericArgKind::Lifetime(response)) => {
316+
let InferOk { value: (), obligations } = infcx
309317
.at(&ObligationCause::dummy(), param_env)
310318
.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-
);
319+
.unwrap();
320+
assert!(obligations.is_empty());
321+
}
322+
(ty::GenericArgKind::Type(orig), ty::GenericArgKind::Type(response)) => {
323+
if let ty::Infer(ty::TyVar(orig)) = *orig.kind()
324+
&& !response.is_ty_or_numeric_infer()
325+
{
326+
infcx.inner.borrow_mut().type_variables().instantiate(orig, response);
327+
} else {
328+
let InferOk { value: (), obligations } = infcx
329+
.at(&ObligationCause::dummy(), param_env)
330+
.eq(DefineOpaqueTypes::No, orig, response)
331+
.unwrap();
332+
assert!(obligations.is_empty());
333+
}
334+
}
335+
(ty::GenericArgKind::Const(orig), ty::GenericArgKind::Const(response)) => {
336+
if let ty::ConstKind::Infer(ty::InferConst::Var(orig)) = orig.kind()
337+
&& !response.is_ct_infer()
338+
{
339+
infcx.inner.borrow_mut().instantiate_const_var(orig, response);
340+
} else {
341+
let InferOk { value: (), obligations } = infcx
342+
.at(&ObligationCause::dummy(), param_env)
343+
.eq(DefineOpaqueTypes::No, orig, response)
344+
.unwrap();
345+
assert!(obligations.is_empty());
346+
}
347+
}
348+
(
349+
ty::GenericArgKind::Lifetime(_)
350+
| ty::GenericArgKind::Type(_)
351+
| ty::GenericArgKind::Const(_),
352+
_,
353+
) => unreachable!(),
319354
}
320-
321-
Ok(nested_goals)
322355
}
323356

324357
fn register_region_constraints(&mut self, region_constraints: &QueryRegionConstraints<'tcx>) {
@@ -330,21 +363,17 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
330363
}
331364
}
332365

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

339-
fn register_opaque_types(
369+
fn register_new_opaque_types(
340370
&mut self,
341371
param_env: ty::ParamEnv<'tcx>,
342372
opaque_types: &[(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)],
343-
) -> Result<(), NoSolution> {
373+
) {
344374
for &(key, ty) in opaque_types {
345-
self.insert_hidden_type(key, param_env, ty)?;
375+
self.insert_hidden_type(key, param_env, ty).unwrap();
346376
}
347-
Ok(())
348377
}
349378
}
350379

@@ -368,14 +397,13 @@ impl<'tcx> inspect::ProofTreeBuilder<'tcx> {
368397
param_env: ty::ParamEnv<'tcx>,
369398
original_values: &[ty::GenericArg<'tcx>],
370399
state: inspect::CanonicalState<'tcx, T>,
371-
) -> Result<(Vec<Goal<'tcx, ty::Predicate<'tcx>>>, T), NoSolution> {
400+
) -> T {
372401
let substitution =
373402
EvalCtxt::compute_query_response_substitution(infcx, original_values, &state);
374403

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

377-
let nested_goals =
378-
EvalCtxt::unify_query_var_values(infcx, param_env, original_values, var_values)?;
379-
Ok((nested_goals, data))
406+
EvalCtxt::unify_query_var_values(infcx, param_env, original_values, var_values);
407+
data
380408
}
381409
}

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

+17-38
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
}

0 commit comments

Comments
 (0)