Skip to content

Commit b32f73e

Browse files
trait_goals: Auto traits
1 parent 5e0859c commit b32f73e

File tree

3 files changed

+115
-1
lines changed

3 files changed

+115
-1
lines changed

compiler/rustc_trait_selection/src/solve/assembly.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy {
6161
acx: &mut AssemblyCtxt<'_, 'tcx, Self>,
6262
goal: Goal<'tcx, Self>,
6363
);
64+
65+
fn consider_auto_trait_candidate(
66+
acx: &mut AssemblyCtxt<'_, 'tcx, Self>,
67+
goal: Goal<'tcx, Self>,
68+
);
6469
}
6570

6671
/// An abstraction which correctly deals with the canonical results for candidates.
@@ -90,6 +95,8 @@ impl<'a, 'tcx, G: GoalKind<'tcx>> AssemblyCtxt<'a, 'tcx, G> {
9095

9196
acx.assemble_param_env_candidates(goal);
9297

98+
acx.assemble_auto_trait_candidates(goal);
99+
93100
acx.candidates
94101
}
95102

@@ -182,4 +189,10 @@ impl<'a, 'tcx, G: GoalKind<'tcx>> AssemblyCtxt<'a, 'tcx, G> {
182189
fn assemble_param_env_candidates(&mut self, goal: Goal<'tcx, G>) {
183190
G::consider_param_env_candidates(self, goal);
184191
}
192+
193+
fn assemble_auto_trait_candidates(&mut self, goal: Goal<'tcx, G>) {
194+
if self.cx.tcx.trait_is_auto(goal.predicate.trait_def_id(self.cx.tcx)) {
195+
G::consider_auto_trait_candidate(self, goal);
196+
}
197+
}
185198
}

compiler/rustc_trait_selection/src/solve/project_goals.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
234234
) {
235235
todo!()
236236
}
237+
238+
fn consider_auto_trait_candidate(
239+
_acx: &mut AssemblyCtxt<'_, 'tcx, Self>,
240+
_goal: Goal<'tcx, Self>,
241+
) {
242+
// Auto traits never have associated types
243+
}
237244
}
238245

239246
/// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code.

compiler/rustc_trait_selection/src/solve/trait_goals.rs

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::iter;
55
use super::assembly::{self, AssemblyCtxt};
66
use super::{CanonicalGoal, Certainty, EvalCtxt, Goal, QueryResult};
77
use rustc_hir::def_id::DefId;
8-
use rustc_infer::infer::{InferOk, LateBoundRegionConversionTime};
8+
use rustc_infer::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
99
use rustc_infer::traits::query::NoSolution;
1010
use rustc_infer::traits::util::supertraits;
1111
use rustc_infer::traits::ObligationCause;
@@ -191,6 +191,29 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
191191
);
192192
}
193193
}
194+
195+
fn consider_auto_trait_candidate(
196+
acx: &mut AssemblyCtxt<'_, 'tcx, Self>,
197+
goal: Goal<'tcx, Self>,
198+
) {
199+
// FIXME: We need to give auto trait candidates less precedence than impl candidates?
200+
acx.infcx.probe(|_| {
201+
let Ok(constituent_tys) =
202+
instantiate_constituent_tys_for_auto_trait(acx.infcx, goal.predicate.self_ty()) else { return };
203+
let nested_goals = constituent_tys
204+
.into_iter()
205+
.map(|ty| {
206+
Goal::new(
207+
acx.cx.tcx,
208+
goal.param_env,
209+
ty::Binder::dummy(goal.predicate.with_self_ty(acx.cx.tcx, ty)),
210+
)
211+
})
212+
.collect();
213+
let Ok(certainty) = acx.cx.evaluate_all(acx.infcx, nested_goals) else { return };
214+
acx.try_insert_candidate(CandidateSource::AutoImpl, certainty);
215+
})
216+
}
194217
}
195218

196219
fn match_poly_trait_ref_against_goal<'tcx>(
@@ -223,6 +246,77 @@ fn match_poly_trait_ref_against_goal<'tcx>(
223246
})
224247
}
225248

249+
// Calculates the constituent types of a type for `auto trait` purposes.
250+
//
251+
// For types with an "existential" binder, i.e. generator witnesses, we also
252+
// instantiate the binder with placeholders eagerly.
253+
fn instantiate_constituent_tys_for_auto_trait<'tcx>(
254+
infcx: &InferCtxt<'tcx>,
255+
ty: Ty<'tcx>,
256+
) -> Result<Vec<Ty<'tcx>>, ()> {
257+
let tcx = infcx.tcx;
258+
match *ty.kind() {
259+
ty::Uint(_)
260+
| ty::Int(_)
261+
| ty::Bool
262+
| ty::Float(_)
263+
| ty::FnDef(..)
264+
| ty::FnPtr(_)
265+
| ty::Str
266+
| ty::Error(_)
267+
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
268+
| ty::Never
269+
| ty::Char => Ok(vec![]),
270+
271+
ty::Placeholder(..)
272+
| ty::Dynamic(..)
273+
| ty::Param(..)
274+
| ty::Foreign(..)
275+
| ty::Alias(ty::Projection, ..)
276+
| ty::Bound(..)
277+
| ty::Infer(ty::TyVar(_)) => {
278+
// FIXME: Do we need to mark anything as ambiguous here? Yeah?
279+
Err(())
280+
}
281+
282+
ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(),
283+
284+
ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => {
285+
Ok(vec![element_ty])
286+
}
287+
288+
ty::Array(element_ty, _) | ty::Slice(element_ty) => Ok(vec![element_ty]),
289+
290+
ty::Tuple(ref tys) => {
291+
// (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
292+
Ok(tys.iter().collect())
293+
}
294+
295+
ty::Closure(_, ref substs) => Ok(vec![substs.as_closure().tupled_upvars_ty()]),
296+
297+
ty::Generator(_, ref substs, _) => {
298+
let generator_substs = substs.as_generator();
299+
Ok(vec![generator_substs.tupled_upvars_ty(), generator_substs.witness()])
300+
}
301+
302+
ty::GeneratorWitness(types) => {
303+
Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec())
304+
}
305+
306+
// For `PhantomData<T>`, we pass `T`.
307+
ty::Adt(def, substs) if def.is_phantom_data() => Ok(vec![substs.type_at(0)]),
308+
309+
ty::Adt(def, substs) => Ok(def.all_fields().map(|f| f.ty(tcx, substs)).collect()),
310+
311+
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
312+
// We can resolve the `impl Trait` to its concrete type,
313+
// which enforces a DAG between the functions requiring
314+
// the auto trait bounds in question.
315+
Ok(vec![tcx.bound_type_of(def_id).subst(tcx, substs)])
316+
}
317+
}
318+
}
319+
226320
impl<'tcx> EvalCtxt<'tcx> {
227321
pub(super) fn compute_trait_goal(
228322
&mut self,

0 commit comments

Comments
 (0)