Skip to content

Commit 7105d39

Browse files
trait_goals: Implement Fn-like goals
1 parent b32f73e commit 7105d39

File tree

4 files changed

+86
-1
lines changed

4 files changed

+86
-1
lines changed

compiler/rustc_trait_selection/src/solve/assembly.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//! Code shared by trait and projection goals for candidate assembly.
22
3+
use crate::traits::TupleArgumentsFlag;
4+
35
use super::infcx_ext::InferCtxtExt;
46
use super::{
57
fixme_instantiate_canonical_query_response, CanonicalGoal, CanonicalResponse, Certainty,
@@ -66,6 +68,13 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy {
6668
acx: &mut AssemblyCtxt<'_, 'tcx, Self>,
6769
goal: Goal<'tcx, Self>,
6870
);
71+
72+
fn consider_fn_candidate(
73+
acx: &mut AssemblyCtxt<'_, 'tcx, Self>,
74+
goal: Goal<'tcx, Self>,
75+
bound_sig: ty::PolyFnSig<'tcx>,
76+
tuple_arguments: TupleArgumentsFlag,
77+
);
6978
}
7079

7180
/// An abstraction which correctly deals with the canonical results for candidates.
@@ -97,6 +106,8 @@ impl<'a, 'tcx, G: GoalKind<'tcx>> AssemblyCtxt<'a, 'tcx, G> {
97106

98107
acx.assemble_auto_trait_candidates(goal);
99108

109+
acx.assemble_fn_like_candidates(goal);
110+
100111
acx.candidates
101112
}
102113

@@ -195,4 +206,27 @@ impl<'a, 'tcx, G: GoalKind<'tcx>> AssemblyCtxt<'a, 'tcx, G> {
195206
G::consider_auto_trait_candidate(self, goal);
196207
}
197208
}
209+
210+
fn assemble_fn_like_candidates(&mut self, goal: Goal<'tcx, G>) {
211+
let tcx = self.cx.tcx;
212+
let trait_def_id = goal.predicate.trait_def_id(tcx);
213+
if let Some(goal_kind) = tcx.fn_trait_kind_from_def_id(trait_def_id) {
214+
match *goal.predicate.self_ty().kind() {
215+
ty::FnDef(def_id, substs) => {
216+
G::consider_fn_candidate(self, goal, tcx.bound_fn_sig(def_id).subst(tcx, substs), TupleArgumentsFlag::Yes)
217+
}
218+
ty::FnPtr(sig) => {
219+
G::consider_fn_candidate(self, goal, sig, TupleArgumentsFlag::Yes)
220+
}
221+
ty::Closure(_, substs) => {
222+
if let Some(kind) = self.infcx.closure_kind(substs)
223+
&& kind.extends(goal_kind)
224+
{
225+
G::consider_fn_candidate(self, goal, substs.as_closure().sig(), TupleArgumentsFlag::No)
226+
}
227+
}
228+
_ => {}
229+
}
230+
}
231+
}
198232
}

compiler/rustc_trait_selection/src/solve/project_goals.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
241241
) {
242242
// Auto traits never have associated types
243243
}
244+
245+
fn consider_fn_candidate(
246+
_acx: &mut AssemblyCtxt<'_, 'tcx, Self>,
247+
_goal: Goal<'tcx, Self>,
248+
_bound_sig: ty::PolyFnSig<'tcx>,
249+
_tuple_arguments: crate::traits::TupleArgumentsFlag,
250+
) {
251+
todo!()
252+
}
244253
}
245254

246255
/// 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: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22
33
use std::iter;
44

5+
use crate::traits::TupleArgumentsFlag;
6+
57
use super::assembly::{self, AssemblyCtxt};
68
use super::{CanonicalGoal, Certainty, EvalCtxt, Goal, QueryResult};
79
use rustc_hir::def_id::DefId;
10+
use rustc_hir::Unsafety;
811
use rustc_infer::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
912
use rustc_infer::traits::query::NoSolution;
1013
use rustc_infer::traits::util::supertraits;
@@ -13,6 +16,7 @@ use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
1316
use rustc_middle::ty::TraitPredicate;
1417
use rustc_middle::ty::{self, Ty, TyCtxt};
1518
use rustc_span::DUMMY_SP;
19+
use rustc_target::spec::abi::Abi;
1620

1721
#[allow(dead_code)] // FIXME: implement and use all variants.
1822
#[derive(Debug, Clone, Copy)]
@@ -53,6 +57,9 @@ pub(super) enum CandidateSource {
5357
/// at the constituent types of the `self_ty` to check whether the auto trait
5458
/// is implemented for those.
5559
AutoImpl,
60+
/// An automatic impl for `Fn`/`FnMut`/`FnOnce` for fn pointers, fn items,
61+
/// and closures.
62+
Fn,
5663
}
5764

5865
type Candidate<'tcx> = assembly::Candidate<'tcx, TraitPredicate<'tcx>>;
@@ -214,6 +221,39 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
214221
acx.try_insert_candidate(CandidateSource::AutoImpl, certainty);
215222
})
216223
}
224+
225+
fn consider_fn_candidate(
226+
acx: &mut AssemblyCtxt<'_, 'tcx, Self>,
227+
goal: Goal<'tcx, Self>,
228+
bound_sig: ty::PolyFnSig<'tcx>,
229+
tuple_args_flag: TupleArgumentsFlag,
230+
) {
231+
if bound_sig.unsafety() != Unsafety::Normal || bound_sig.c_variadic() {
232+
return;
233+
}
234+
235+
// Binder skipped here (*)
236+
let (arguments_tuple, expected_abi) = match tuple_args_flag {
237+
TupleArgumentsFlag::No => (bound_sig.skip_binder().inputs()[0], Abi::RustCall),
238+
TupleArgumentsFlag::Yes => {
239+
(acx.cx.tcx.intern_tup(bound_sig.skip_binder().inputs()), Abi::Rust)
240+
}
241+
};
242+
if expected_abi != bound_sig.abi() {
243+
return;
244+
}
245+
// (*) Rebound here
246+
let found_trait_ref = bound_sig.rebind(
247+
acx.cx
248+
.tcx
249+
.mk_trait_ref(goal.predicate.def_id(), [goal.predicate.self_ty(), arguments_tuple]),
250+
);
251+
252+
acx.infcx.probe(|_| {
253+
// FIXME: This needs to validate that `fn() -> TY` has `TY: Sized`.
254+
match_poly_trait_ref_against_goal(acx, goal, found_trait_ref, CandidateSource::Fn);
255+
})
256+
}
217257
}
218258

219259
fn match_poly_trait_ref_against_goal<'tcx>(
@@ -379,7 +419,8 @@ impl<'tcx> EvalCtxt<'tcx> {
379419
| (CandidateSource::ObjectBound(_), _)
380420
| (CandidateSource::ObjectAutoBound, _)
381421
| (CandidateSource::Builtin, _)
382-
| (CandidateSource::AutoImpl, _) => unimplemented!(),
422+
| (CandidateSource::AutoImpl, _)
423+
| (CandidateSource::Fn, _) => unimplemented!(),
383424
}
384425
}
385426

compiler/rustc_trait_selection/src/traits/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ pub use self::specialize::{specialization_graph, translate_substs, OverlapError}
6060
pub use self::structural_match::{
6161
search_for_adt_const_param_violation, search_for_structural_match_violation,
6262
};
63+
pub use self::util::TupleArgumentsFlag;
6364
pub use self::util::{
6465
elaborate_obligations, elaborate_predicates, elaborate_predicates_with_span,
6566
elaborate_trait_ref, elaborate_trait_refs,

0 commit comments

Comments
 (0)