Skip to content

Commit 6402c98

Browse files
Add consider_implied_clause
1 parent 82b5205 commit 6402c98

File tree

3 files changed

+97
-102
lines changed

3 files changed

+97
-102
lines changed

compiler/rustc_trait_selection/src/solve/assembly.rs

+11-19
Original file line numberDiff line numberDiff line change
@@ -90,28 +90,20 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy + Eq {
9090

9191
fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId;
9292

93-
fn consider_impl_candidate(
94-
ecx: &mut EvalCtxt<'_, 'tcx>,
95-
goal: Goal<'tcx, Self>,
96-
impl_def_id: DefId,
97-
) -> QueryResult<'tcx>;
98-
99-
// Consider a predicate we know holds (`assumption`) against a goal we're trying to prove.
100-
fn consider_assumption(
93+
// Consider a clause, which consists of a "assumption" and some "requirements",
94+
// to satisfy a goal. If the requirements hold, then attempt to satisfy our
95+
// goal by equating it with the assumption.
96+
fn consider_implied_clause(
10197
ecx: &mut EvalCtxt<'_, 'tcx>,
10298
goal: Goal<'tcx, Self>,
10399
assumption: ty::Predicate<'tcx>,
104-
) -> QueryResult<'tcx> {
105-
Self::consider_assumption_with_certainty(ecx, goal, assumption, Certainty::Yes)
106-
}
100+
requirements: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
101+
) -> QueryResult<'tcx>;
107102

108-
// Consider a predicate we know holds (`assumption`) against a goal, unifying with
109-
// the `assumption_certainty` if it satisfies the goal.
110-
fn consider_assumption_with_certainty(
103+
fn consider_impl_candidate(
111104
ecx: &mut EvalCtxt<'_, 'tcx>,
112105
goal: Goal<'tcx, Self>,
113-
assumption: ty::Predicate<'tcx>,
114-
assumption_certainty: Certainty,
106+
impl_def_id: DefId,
115107
) -> QueryResult<'tcx>;
116108

117109
// A type implements an `auto trait` if its components do as well. These components
@@ -367,7 +359,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
367359
candidates: &mut Vec<Candidate<'tcx>>,
368360
) {
369361
for (i, assumption) in goal.param_env.caller_bounds().iter().enumerate() {
370-
match G::consider_assumption(self, goal, assumption) {
362+
match G::consider_implied_clause(self, goal, assumption, []) {
371363
Ok(result) => {
372364
candidates.push(Candidate { source: CandidateSource::ParamEnv(i), result })
373365
}
@@ -414,7 +406,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
414406

415407
for assumption in self.tcx().item_bounds(alias_ty.def_id).subst(self.tcx(), alias_ty.substs)
416408
{
417-
match G::consider_assumption(self, goal, assumption) {
409+
match G::consider_implied_clause(self, goal, assumption, []) {
418410
Ok(result) => {
419411
candidates.push(Candidate { source: CandidateSource::AliasBound, result })
420412
}
@@ -464,7 +456,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
464456
for assumption in
465457
elaborate_predicates(tcx, bounds.iter().map(|bound| bound.with_self_ty(tcx, self_ty)))
466458
{
467-
match G::consider_assumption(self, goal, assumption.predicate) {
459+
match G::consider_implied_clause(self, goal, assumption.predicate, []) {
468460
Ok(result) => {
469461
candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result })
470462
}

compiler/rustc_trait_selection/src/solve/project_goals.rs

+60-57
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,37 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
168168
self.trait_def_id(tcx)
169169
}
170170

171+
fn consider_implied_clause(
172+
ecx: &mut EvalCtxt<'_, 'tcx>,
173+
goal: Goal<'tcx, Self>,
174+
assumption: ty::Predicate<'tcx>,
175+
requirements: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
176+
) -> QueryResult<'tcx> {
177+
if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred()
178+
&& poly_projection_pred.projection_def_id() == goal.predicate.def_id()
179+
{
180+
ecx.infcx.probe(|_| {
181+
let assumption_projection_pred =
182+
ecx.infcx.instantiate_binder_with_infer(poly_projection_pred);
183+
let mut nested_goals = ecx.infcx.eq(
184+
goal.param_env,
185+
goal.predicate.projection_ty,
186+
assumption_projection_pred.projection_ty,
187+
)?;
188+
nested_goals.extend(requirements);
189+
let subst_certainty = ecx.evaluate_all(nested_goals)?;
190+
191+
ecx.eq_term_and_make_canonical_response(
192+
goal,
193+
subst_certainty,
194+
assumption_projection_pred.term,
195+
)
196+
})
197+
} else {
198+
Err(NoSolution)
199+
}
200+
}
201+
171202
fn consider_impl_candidate(
172203
ecx: &mut EvalCtxt<'_, 'tcx>,
173204
goal: Goal<'tcx, ProjectionPredicate<'tcx>>,
@@ -260,36 +291,6 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
260291
})
261292
}
262293

263-
fn consider_assumption_with_certainty(
264-
ecx: &mut EvalCtxt<'_, 'tcx>,
265-
goal: Goal<'tcx, Self>,
266-
assumption: ty::Predicate<'tcx>,
267-
assumption_certainty: Certainty,
268-
) -> QueryResult<'tcx> {
269-
if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred()
270-
&& poly_projection_pred.projection_def_id() == goal.predicate.def_id()
271-
{
272-
ecx.infcx.probe(|_| {
273-
let assumption_projection_pred =
274-
ecx.infcx.instantiate_binder_with_infer(poly_projection_pred);
275-
let nested_goals = ecx.infcx.eq(
276-
goal.param_env,
277-
goal.predicate.projection_ty,
278-
assumption_projection_pred.projection_ty,
279-
)?;
280-
let subst_certainty = ecx.evaluate_all(nested_goals)?;
281-
282-
ecx.eq_term_and_make_canonical_response(
283-
goal,
284-
subst_certainty.unify_and(assumption_certainty),
285-
assumption_projection_pred.term,
286-
)
287-
})
288-
} else {
289-
Err(NoSolution)
290-
}
291-
}
292-
293294
fn consider_auto_trait_candidate(
294295
_ecx: &mut EvalCtxt<'_, 'tcx>,
295296
goal: Goal<'tcx, Self>,
@@ -331,31 +332,27 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
331332
goal_kind: ty::ClosureKind,
332333
) -> QueryResult<'tcx> {
333334
let tcx = ecx.tcx();
334-
if let Some(tupled_inputs_and_output) =
335-
structural_traits::extract_tupled_inputs_and_output_from_callable(
336-
tcx,
337-
goal.predicate.self_ty(),
338-
goal_kind,
339-
)?
340-
{
341-
// A built-in `Fn` trait needs to check that its output is `Sized`
342-
// (FIXME: technically we only need to check this if the type is a fn ptr...)
343-
let output_is_sized_pred = tupled_inputs_and_output
344-
.map_bound(|(_, output)| tcx.at(DUMMY_SP).mk_trait_ref(LangItem::Sized, [output]));
345-
let (_, output_is_sized_certainty) =
346-
ecx.evaluate_goal(goal.with(tcx, output_is_sized_pred))?;
347-
348-
let pred = tupled_inputs_and_output
349-
.map_bound(|(inputs, output)| ty::ProjectionPredicate {
350-
projection_ty: tcx
351-
.mk_alias_ty(goal.predicate.def_id(), [goal.predicate.self_ty(), inputs]),
352-
term: output.into(),
353-
})
354-
.to_predicate(tcx);
355-
Self::consider_assumption_with_certainty(ecx, goal, pred, output_is_sized_certainty)
356-
} else {
357-
ecx.make_canonical_response(Certainty::AMBIGUOUS)
358-
}
335+
let Some(tupled_inputs_and_output) =
336+
structural_traits::extract_tupled_inputs_and_output_from_callable(
337+
tcx,
338+
goal.predicate.self_ty(),
339+
goal_kind,
340+
)? else {
341+
return ecx.make_canonical_response(Certainty::AMBIGUOUS);
342+
};
343+
let output_is_sized_pred = tupled_inputs_and_output
344+
.map_bound(|(_, output)| tcx.at(DUMMY_SP).mk_trait_ref(LangItem::Sized, [output]));
345+
346+
let pred = tupled_inputs_and_output
347+
.map_bound(|(inputs, output)| ty::ProjectionPredicate {
348+
projection_ty: tcx
349+
.mk_alias_ty(goal.predicate.def_id(), [goal.predicate.self_ty(), inputs]),
350+
term: output.into(),
351+
})
352+
.to_predicate(tcx);
353+
// A built-in `Fn` impl only holds if the output is sized.
354+
// (FIXME: technically we only need to check this if the type is a fn ptr...)
355+
Self::consider_implied_clause(ecx, goal, pred, [goal.with(tcx, output_is_sized_pred)])
359356
}
360357

361358
fn consider_builtin_tuple_candidate(
@@ -474,14 +471,17 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
474471

475472
let term = substs.as_generator().return_ty().into();
476473

477-
Self::consider_assumption(
474+
Self::consider_implied_clause(
478475
ecx,
479476
goal,
480477
ty::Binder::dummy(ty::ProjectionPredicate {
481478
projection_ty: ecx.tcx().mk_alias_ty(goal.predicate.def_id(), [self_ty]),
482479
term,
483480
})
484481
.to_predicate(tcx),
482+
// Technically, we need to check that the future type is Sized,
483+
// but that's already proven by the generator being WF.
484+
[],
485485
)
486486
}
487487

@@ -511,7 +511,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
511511
bug!("unexpected associated item `<{self_ty} as Generator>::{name}`")
512512
};
513513

514-
Self::consider_assumption(
514+
Self::consider_implied_clause(
515515
ecx,
516516
goal,
517517
ty::Binder::dummy(ty::ProjectionPredicate {
@@ -521,6 +521,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
521521
term,
522522
})
523523
.to_predicate(tcx),
524+
// Technically, we need to check that the future type is Sized,
525+
// but that's already proven by the generator being WF.
526+
[],
524527
)
525528
}
526529

compiler/rustc_trait_selection/src/solve/trait_goals.rs

+26-26
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
6262
})
6363
}
6464

65-
fn consider_assumption_with_certainty(
65+
fn consider_implied_clause(
6666
ecx: &mut EvalCtxt<'_, 'tcx>,
6767
goal: Goal<'tcx, Self>,
6868
assumption: ty::Predicate<'tcx>,
69-
assumption_certainty: Certainty,
69+
requirements: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
7070
) -> QueryResult<'tcx> {
7171
if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred()
7272
&& poly_trait_pred.def_id() == goal.predicate.def_id()
@@ -75,14 +75,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
7575
ecx.infcx.probe(|_| {
7676
let assumption_trait_pred =
7777
ecx.infcx.instantiate_binder_with_infer(poly_trait_pred);
78-
let nested_goals = ecx.infcx.eq(
78+
let mut nested_goals = ecx.infcx.eq(
7979
goal.param_env,
8080
goal.predicate.trait_ref,
8181
assumption_trait_pred.trait_ref,
8282
)?;
83-
ecx.evaluate_all(nested_goals).and_then(|certainty| {
84-
ecx.make_canonical_response(certainty.unify_and(assumption_certainty))
85-
})
83+
nested_goals.extend(requirements);
84+
ecx.evaluate_all_and_make_canonical_response(nested_goals)
8685
})
8786
} else {
8887
Err(NoSolution)
@@ -178,29 +177,25 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
178177
goal_kind: ty::ClosureKind,
179178
) -> QueryResult<'tcx> {
180179
let tcx = ecx.tcx();
181-
if let Some(tupled_inputs_and_output) =
180+
let Some(tupled_inputs_and_output) =
182181
structural_traits::extract_tupled_inputs_and_output_from_callable(
183182
tcx,
184183
goal.predicate.self_ty(),
185184
goal_kind,
186-
)?
187-
{
188-
// A built-in `Fn` trait needs to check that its output is `Sized`
189-
// (FIXME: technically we only need to check this if the type is a fn ptr...)
190-
let output_is_sized_pred = tupled_inputs_and_output
191-
.map_bound(|(_, output)| tcx.at(DUMMY_SP).mk_trait_ref(LangItem::Sized, [output]));
192-
let (_, output_is_sized_certainty) =
193-
ecx.evaluate_goal(goal.with(tcx, output_is_sized_pred))?;
194-
195-
let pred = tupled_inputs_and_output
196-
.map_bound(|(inputs, _)| {
197-
tcx.mk_trait_ref(goal.predicate.def_id(), [goal.predicate.self_ty(), inputs])
198-
})
199-
.to_predicate(tcx);
200-
Self::consider_assumption_with_certainty(ecx, goal, pred, output_is_sized_certainty)
201-
} else {
202-
ecx.make_canonical_response(Certainty::AMBIGUOUS)
203-
}
185+
)? else {
186+
return ecx.make_canonical_response(Certainty::AMBIGUOUS);
187+
};
188+
let output_is_sized_pred = tupled_inputs_and_output
189+
.map_bound(|(_, output)| tcx.at(DUMMY_SP).mk_trait_ref(LangItem::Sized, [output]));
190+
191+
let pred = tupled_inputs_and_output
192+
.map_bound(|(inputs, _)| {
193+
tcx.mk_trait_ref(goal.predicate.def_id(), [goal.predicate.self_ty(), inputs])
194+
})
195+
.to_predicate(tcx);
196+
// A built-in `Fn` impl only holds if the output is sized.
197+
// (FIXME: technically we only need to check this if the type is a fn ptr...)
198+
Self::consider_implied_clause(ecx, goal, pred, [goal.with(tcx, output_is_sized_pred)])
204199
}
205200

206201
fn consider_builtin_tuple_candidate(
@@ -236,6 +231,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
236231
}
237232

238233
// Async generator unconditionally implement `Future`
234+
// Technically, we need to check that the future output type is Sized,
235+
// but that's already proven by the generator being WF.
239236
ecx.make_canonical_response(Certainty::Yes)
240237
}
241238

@@ -255,13 +252,16 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
255252
}
256253

257254
let generator = substs.as_generator();
258-
Self::consider_assumption(
255+
Self::consider_implied_clause(
259256
ecx,
260257
goal,
261258
ty::Binder::dummy(
262259
tcx.mk_trait_ref(goal.predicate.def_id(), [self_ty, generator.resume_ty()]),
263260
)
264261
.to_predicate(tcx),
262+
// Technically, we need to check that the generator types are Sized,
263+
// but that's already proven by the generator being WF.
264+
[],
265265
)
266266
}
267267

0 commit comments

Comments
 (0)