Skip to content

Commit cf5068b

Browse files
Rollup merge of rust-lang#107004 - compiler-errors:new-solver-new-candidates-2, r=lcnr
Implement some candidates for the new solver (redux) Based on rust-lang#106718, so the diff is hard to read without it. See [here](rust-lang/rust@98700cf...compiler-errors:rust:new-solver-new-candidates-2) for an easier view until that one lands. Of note: * 44af916020fb43c12070125c45b6dee4ec303bbc fixes a bug where we need to make the query response *inside* of a probe, or else we make no inference progress (I think) * 50daad5acd2f163d03e7ffab942534f09bc36e2e implements `consider_assumption` for traits and predicates. I'm not sure if using `sup` here is necessary or if `eq` is fine. * We decided that all of the `instantiate_constituent_tys_for_*` functions are verbose but ok, since they need to be exhaustive and the logic between each of them is not similar enough, right? r? ``@lcnr``
2 parents a637e2a + f672436 commit cf5068b

File tree

7 files changed

+442
-47
lines changed

7 files changed

+442
-47
lines changed

compiler/rustc_middle/src/ty/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -2357,6 +2357,11 @@ impl<'tcx> TyCtxt<'tcx> {
23572357
self.trait_def(trait_def_id).has_auto_impl
23582358
}
23592359

2360+
/// Returns `true` if this is a trait alias.
2361+
pub fn trait_is_alias(self, trait_def_id: DefId) -> bool {
2362+
self.def_kind(trait_def_id) == DefKind::TraitAlias
2363+
}
2364+
23602365
pub fn trait_is_coinductive(self, trait_def_id: DefId) -> bool {
23612366
self.trait_is_auto(trait_def_id) || self.lang_items().sized_trait() == Some(trait_def_id)
23622367
}

compiler/rustc_trait_selection/src/solve/assembly.rs

+86-17
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
//! Code shared by trait and projection goals for candidate assembly.
22
33
use super::infcx_ext::InferCtxtExt;
4-
use super::{CanonicalResponse, Certainty, EvalCtxt, Goal};
4+
use super::{CanonicalResponse, EvalCtxt, Goal, QueryResult};
55
use rustc_hir::def_id::DefId;
66
use rustc_infer::traits::query::NoSolution;
7+
use rustc_infer::traits::util::elaborate_predicates;
78
use rustc_middle::ty::TypeFoldable;
89
use rustc_middle::ty::{self, Ty, TyCtxt};
910
use std::fmt::Debug;
@@ -89,19 +90,35 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy {
8990
ecx: &mut EvalCtxt<'_, 'tcx>,
9091
goal: Goal<'tcx, Self>,
9192
impl_def_id: DefId,
92-
) -> Result<Certainty, NoSolution>;
93+
) -> QueryResult<'tcx>;
94+
95+
fn consider_assumption(
96+
ecx: &mut EvalCtxt<'_, 'tcx>,
97+
goal: Goal<'tcx, Self>,
98+
assumption: ty::Predicate<'tcx>,
99+
) -> QueryResult<'tcx>;
100+
101+
fn consider_auto_trait_candidate(
102+
ecx: &mut EvalCtxt<'_, 'tcx>,
103+
goal: Goal<'tcx, Self>,
104+
) -> QueryResult<'tcx>;
105+
106+
fn consider_trait_alias_candidate(
107+
ecx: &mut EvalCtxt<'_, 'tcx>,
108+
goal: Goal<'tcx, Self>,
109+
) -> QueryResult<'tcx>;
93110

94111
fn consider_builtin_sized_candidate(
95112
ecx: &mut EvalCtxt<'_, 'tcx>,
96113
goal: Goal<'tcx, Self>,
97-
) -> Result<Certainty, NoSolution>;
114+
) -> QueryResult<'tcx>;
98115

99-
fn consider_assumption(
116+
fn consider_builtin_copy_clone_candidate(
100117
ecx: &mut EvalCtxt<'_, 'tcx>,
101118
goal: Goal<'tcx, Self>,
102-
assumption: ty::Predicate<'tcx>,
103-
) -> Result<Certainty, NoSolution>;
119+
) -> QueryResult<'tcx>;
104120
}
121+
105122
impl<'tcx> EvalCtxt<'_, 'tcx> {
106123
pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<'tcx>>(
107124
&mut self,
@@ -119,6 +136,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
119136

120137
self.assemble_alias_bound_candidates(goal, &mut candidates);
121138

139+
self.assemble_object_bound_candidates(goal, &mut candidates);
140+
122141
candidates
123142
}
124143

@@ -180,9 +199,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
180199
tcx.for_each_relevant_impl(
181200
goal.predicate.trait_def_id(tcx),
182201
goal.predicate.self_ty(),
183-
|impl_def_id| match G::consider_impl_candidate(self, goal, impl_def_id)
184-
.and_then(|certainty| self.make_canonical_response(certainty))
185-
{
202+
|impl_def_id| match G::consider_impl_candidate(self, goal, impl_def_id) {
186203
Ok(result) => candidates
187204
.push(Candidate { source: CandidateSource::Impl(impl_def_id), result }),
188205
Err(NoSolution) => (),
@@ -197,13 +214,21 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
197214
) {
198215
let lang_items = self.tcx().lang_items();
199216
let trait_def_id = goal.predicate.trait_def_id(self.tcx());
200-
let result = if lang_items.sized_trait() == Some(trait_def_id) {
217+
let result = if self.tcx().trait_is_auto(trait_def_id) {
218+
G::consider_auto_trait_candidate(self, goal)
219+
} else if self.tcx().trait_is_alias(trait_def_id) {
220+
G::consider_trait_alias_candidate(self, goal)
221+
} else if lang_items.sized_trait() == Some(trait_def_id) {
201222
G::consider_builtin_sized_candidate(self, goal)
223+
} else if lang_items.copy_trait() == Some(trait_def_id)
224+
|| lang_items.clone_trait() == Some(trait_def_id)
225+
{
226+
G::consider_builtin_copy_clone_candidate(self, goal)
202227
} else {
203228
Err(NoSolution)
204229
};
205230

206-
match result.and_then(|certainty| self.make_canonical_response(certainty)) {
231+
match result {
207232
Ok(result) => {
208233
candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result })
209234
}
@@ -217,9 +242,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
217242
candidates: &mut Vec<Candidate<'tcx>>,
218243
) {
219244
for (i, assumption) in goal.param_env.caller_bounds().iter().enumerate() {
220-
match G::consider_assumption(self, goal, assumption)
221-
.and_then(|certainty| self.make_canonical_response(certainty))
222-
{
245+
match G::consider_assumption(self, goal, assumption) {
223246
Ok(result) => {
224247
candidates.push(Candidate { source: CandidateSource::ParamEnv(i), result })
225248
}
@@ -268,14 +291,60 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
268291
.subst_iter_copied(self.tcx(), alias_ty.substs)
269292
.enumerate()
270293
{
271-
match G::consider_assumption(self, goal, assumption)
272-
.and_then(|certainty| self.make_canonical_response(certainty))
273-
{
294+
match G::consider_assumption(self, goal, assumption) {
274295
Ok(result) => {
275296
candidates.push(Candidate { source: CandidateSource::AliasBound(i), result })
276297
}
277298
Err(NoSolution) => (),
278299
}
279300
}
280301
}
302+
303+
fn assemble_object_bound_candidates<G: GoalKind<'tcx>>(
304+
&mut self,
305+
goal: Goal<'tcx, G>,
306+
candidates: &mut Vec<Candidate<'tcx>>,
307+
) {
308+
let self_ty = goal.predicate.self_ty();
309+
let bounds = match *self_ty.kind() {
310+
ty::Bool
311+
| ty::Char
312+
| ty::Int(_)
313+
| ty::Uint(_)
314+
| ty::Float(_)
315+
| ty::Adt(_, _)
316+
| ty::Foreign(_)
317+
| ty::Str
318+
| ty::Array(_, _)
319+
| ty::Slice(_)
320+
| ty::RawPtr(_)
321+
| ty::Ref(_, _, _)
322+
| ty::FnDef(_, _)
323+
| ty::FnPtr(_)
324+
| ty::Alias(..)
325+
| ty::Closure(..)
326+
| ty::Generator(..)
327+
| ty::GeneratorWitness(_)
328+
| ty::Never
329+
| ty::Tuple(_)
330+
| ty::Param(_)
331+
| ty::Placeholder(..)
332+
| ty::Infer(_)
333+
| ty::Error(_) => return,
334+
ty::Bound(..) => bug!("unexpected bound type: {goal:?}"),
335+
ty::Dynamic(bounds, ..) => bounds,
336+
};
337+
338+
let tcx = self.tcx();
339+
for assumption in
340+
elaborate_predicates(tcx, bounds.iter().map(|bound| bound.with_self_ty(tcx, self_ty)))
341+
{
342+
match G::consider_assumption(self, goal, assumption.predicate) {
343+
Ok(result) => {
344+
candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result })
345+
}
346+
Err(NoSolution) => (),
347+
}
348+
}
349+
}
281350
}

compiler/rustc_trait_selection/src/solve/infcx_ext.rs

+18-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use rustc_infer::infer::at::ToTrace;
22
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
3-
use rustc_infer::infer::{InferCtxt, InferOk};
3+
use rustc_infer::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
44
use rustc_infer::traits::query::NoSolution;
55
use rustc_infer::traits::ObligationCause;
66
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
7-
use rustc_middle::ty::{self, Ty};
7+
use rustc_middle::ty::{self, Ty, TypeFoldable};
88
use rustc_span::DUMMY_SP;
99

1010
use super::Goal;
@@ -25,6 +25,11 @@ pub(super) trait InferCtxtExt<'tcx> {
2525
lhs: T,
2626
rhs: T,
2727
) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution>;
28+
29+
fn instantiate_bound_vars_with_infer<T: TypeFoldable<'tcx> + Copy>(
30+
&self,
31+
value: ty::Binder<'tcx, T>,
32+
) -> T;
2833
}
2934

3035
impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
@@ -59,4 +64,15 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
5964
NoSolution
6065
})
6166
}
67+
68+
fn instantiate_bound_vars_with_infer<T: TypeFoldable<'tcx> + Copy>(
69+
&self,
70+
value: ty::Binder<'tcx, T>,
71+
) -> T {
72+
self.replace_bound_vars_with_fresh_vars(
73+
DUMMY_SP,
74+
LateBoundRegionConversionTime::HigherRankedType,
75+
value,
76+
)
77+
}
6278
}

compiler/rustc_trait_selection/src/solve/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
313313
}
314314
})
315315
}
316+
317+
fn evaluate_all_and_make_canonical_response(
318+
&mut self,
319+
goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
320+
) -> QueryResult<'tcx> {
321+
self.evaluate_all(goals).and_then(|certainty| self.make_canonical_response(certainty))
322+
}
316323
}
317324

318325
#[instrument(level = "debug", skip(infcx), ret)]

compiler/rustc_trait_selection/src/solve/project_goals.rs

+56-13
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
191191
ecx: &mut EvalCtxt<'_, 'tcx>,
192192
goal: Goal<'tcx, ProjectionPredicate<'tcx>>,
193193
impl_def_id: DefId,
194-
) -> Result<Certainty, NoSolution> {
194+
) -> QueryResult<'tcx> {
195195
let tcx = ecx.tcx();
196196

197197
let goal_trait_ref = goal.predicate.projection_ty.trait_ref(tcx);
@@ -229,7 +229,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
229229
impl_def_id
230230
)? else {
231231
let certainty = Certainty::Maybe(MaybeCause::Ambiguity);
232-
return Ok(trait_ref_certainty.unify_and(certainty));
232+
return ecx.make_canonical_response(trait_ref_certainty.unify_and(certainty));
233233
};
234234

235235
if !assoc_def.item.defaultness(tcx).has_value() {
@@ -286,27 +286,70 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
286286
let rhs_certainty =
287287
ecx.evaluate_all(nested_goals).expect("failed to unify with unconstrained term");
288288

289-
Ok(trait_ref_certainty.unify_and(rhs_certainty))
289+
ecx.make_canonical_response(trait_ref_certainty.unify_and(rhs_certainty))
290290
})
291291
}
292292

293+
fn consider_assumption(
294+
ecx: &mut EvalCtxt<'_, 'tcx>,
295+
goal: Goal<'tcx, Self>,
296+
assumption: ty::Predicate<'tcx>,
297+
) -> QueryResult<'tcx> {
298+
if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred() {
299+
ecx.infcx.probe(|_| {
300+
let assumption_projection_pred =
301+
ecx.infcx.instantiate_bound_vars_with_infer(poly_projection_pred);
302+
let nested_goals = ecx.infcx.eq(
303+
goal.param_env,
304+
goal.predicate.projection_ty,
305+
assumption_projection_pred.projection_ty,
306+
)?;
307+
let subst_certainty = ecx.evaluate_all(nested_goals)?;
308+
309+
// The term of our goal should be fully unconstrained, so this should never fail.
310+
//
311+
// It can however be ambiguous when the resolved type is a projection.
312+
let nested_goals = ecx
313+
.infcx
314+
.eq(goal.param_env, goal.predicate.term, assumption_projection_pred.term)
315+
.expect("failed to unify with unconstrained term");
316+
let rhs_certainty = ecx
317+
.evaluate_all(nested_goals)
318+
.expect("failed to unify with unconstrained term");
319+
320+
ecx.make_canonical_response(subst_certainty.unify_and(rhs_certainty))
321+
})
322+
} else {
323+
Err(NoSolution)
324+
}
325+
}
326+
327+
fn consider_auto_trait_candidate(
328+
_ecx: &mut EvalCtxt<'_, 'tcx>,
329+
goal: Goal<'tcx, Self>,
330+
) -> QueryResult<'tcx> {
331+
bug!("auto traits do not have associated types: {:?}", goal);
332+
}
333+
334+
fn consider_trait_alias_candidate(
335+
_ecx: &mut EvalCtxt<'_, 'tcx>,
336+
goal: Goal<'tcx, Self>,
337+
) -> QueryResult<'tcx> {
338+
bug!("trait aliases do not have associated types: {:?}", goal);
339+
}
340+
293341
fn consider_builtin_sized_candidate(
294342
_ecx: &mut EvalCtxt<'_, 'tcx>,
295343
goal: Goal<'tcx, Self>,
296-
) -> Result<Certainty, NoSolution> {
344+
) -> QueryResult<'tcx> {
297345
bug!("`Sized` does not have an associated type: {:?}", goal);
298346
}
299347

300-
fn consider_assumption(
348+
fn consider_builtin_copy_clone_candidate(
301349
_ecx: &mut EvalCtxt<'_, 'tcx>,
302-
_goal: Goal<'tcx, Self>,
303-
assumption: ty::Predicate<'tcx>,
304-
) -> Result<Certainty, NoSolution> {
305-
if let Some(_poly_projection_pred) = assumption.to_opt_poly_projection_pred() {
306-
unimplemented!()
307-
} else {
308-
Err(NoSolution)
309-
}
350+
goal: Goal<'tcx, Self>,
351+
) -> QueryResult<'tcx> {
352+
bug!("`Copy`/`Clone` does not have an associated type: {:?}", goal);
310353
}
311354
}
312355

0 commit comments

Comments
 (0)