1 use crate::clauses
::ClauseBuilder
;
2 use crate::infer
::instantiate
::IntoBindersAndValue
;
3 use crate::rust_ir
::{ClosureKind, FnDefInputsAndOutputDatum, WellKnownTrait}
;
4 use crate::{Interner, RustIrDatabase, TraitRef}
;
5 use chalk_ir
::cast
::Cast
;
7 AliasTy
, ApplicationTy
, Binders
, Floundered
, Normalize
, ProjectionTy
, Substitution
, TraitId
,
8 Ty
, TyData
, TypeName
, VariableKinds
,
11 fn push_clauses
<I
: Interner
>(
12 db
: &dyn RustIrDatabase
<I
>,
13 builder
: &mut ClauseBuilder
<'_
, I
>,
14 well_known
: WellKnownTrait
,
17 arg_sub
: Substitution
<I
>,
20 let interner
= db
.interner();
21 let tupled
= TyData
::Apply(ApplicationTy
{
22 name
: TypeName
::Tuple(arg_sub
.len(interner
)),
23 substitution
: arg_sub
,
27 Substitution
::from(interner
, &[self_ty
.cast(interner
), tupled
.cast(interner
)]);
28 builder
.push_fact(TraitRef
{
30 substitution
: substitution
.clone(),
33 // The `Output` type is defined on the `FnOnce`
34 if let WellKnownTrait
::FnOnce
= well_known
{
35 let trait_datum
= db
.trait_datum(trait_id
);
37 trait_datum
.associated_ty_ids
.len(),
39 "FnOnce trait should have exactly one associated type, found {:?}",
40 trait_datum
.associated_ty_ids
42 // Constructs the alias. For `Fn`, for example, this would look like
43 // `Normalize(<fn(A) -> B as FnOnce<(A,)>>::Output -> B)`
44 let output_id
= trait_datum
.associated_ty_ids
[0];
45 let alias
= AliasTy
::Projection(ProjectionTy
{
46 associated_ty_id
: output_id
,
49 builder
.push_fact(Normalize
{
56 fn push_clauses_for_apply
<I
: Interner
>(
57 db
: &dyn RustIrDatabase
<I
>,
58 builder
: &mut ClauseBuilder
<'_
, I
>,
59 well_known
: WellKnownTrait
,
62 inputs_and_output
: &Binders
<FnDefInputsAndOutputDatum
<I
>>,
64 let interner
= db
.interner();
65 builder
.push_binders(inputs_and_output
, |builder
, inputs_and_output
| {
66 let arg_sub
= inputs_and_output
70 .map(|ty
| ty
.cast(interner
));
71 let arg_sub
= Substitution
::from(interner
, arg_sub
);
72 let output_ty
= inputs_and_output
.return_type
;
75 db
, builder
, well_known
, trait_id
, self_ty
, arg_sub
, output_ty
,
80 /// Handles clauses for FnOnce/FnMut/Fn.
81 /// If `self_ty` is a function, we push a clause of the form
82 /// `fn(A1, A2, ..., AN) -> O: FnTrait<(A1, A2, ..., AN)>`, where `FnTrait`
83 /// is the trait corresponding to `trait_id` (FnOnce/FnMut/Fn)
85 /// If `trait_id` is `FnOnce`, we also push a clause for the output type of the form:
86 /// `Normalize(<fn(A) -> B as FnOnce<(A,)>>::Output -> B)`
87 /// We do not add the usual `Implemented(fn(A) -> b as FnOnce<(A,)>` clause
88 /// as a condition, since we already called `push_fact` with it
89 pub fn add_fn_trait_program_clauses
<I
: Interner
>(
90 db
: &dyn RustIrDatabase
<I
>,
91 builder
: &mut ClauseBuilder
<'_
, I
>,
92 well_known
: WellKnownTrait
,
94 ) -> Result
<(), Floundered
> {
95 let interner
= db
.interner();
96 let trait_id
= db
.well_known_trait_id(well_known
).unwrap();
98 match self_ty
.data(interner
) {
99 TyData
::Apply(apply
) => match apply
.name
{
100 TypeName
::FnDef(fn_def_id
) => {
101 let fn_def_datum
= builder
.db
.fn_def_datum(fn_def_id
);
102 let bound
= fn_def_datum
104 .substitute(builder
.interner(), &apply
.substitution
);
105 push_clauses_for_apply(
111 &bound
.inputs_and_output
,
115 TypeName
::Closure(closure_id
) => {
116 let closure_kind
= db
.closure_kind(closure_id
, &apply
.substitution
);
117 let trait_matches
= match (well_known
, closure_kind
) {
118 (WellKnownTrait
::Fn
, ClosureKind
::Fn
) => true,
119 (WellKnownTrait
::FnMut
, ClosureKind
::FnMut
)
120 | (WellKnownTrait
::FnMut
, ClosureKind
::Fn
) => true,
121 (WellKnownTrait
::FnOnce
, _
) => true,
127 let closure_inputs_and_output
=
128 db
.closure_inputs_and_output(closure_id
, &apply
.substitution
);
129 push_clauses_for_apply(
135 &closure_inputs_and_output
,
141 TyData
::Function(fn_val
) => {
142 let (binders
, orig_sub
) = fn_val
.into_binders_and_value(interner
);
143 let bound_ref
= Binders
::new(VariableKinds
::from(interner
, binders
), orig_sub
);
144 builder
.push_binders(&bound_ref
, |builder
, orig_sub
| {
145 // The last parameter represents the function return type
146 let (arg_sub
, fn_output_ty
) = orig_sub
147 .parameters(interner
)
148 .split_at(orig_sub
.len(interner
) - 1);
149 let arg_sub
= Substitution
::from(interner
, arg_sub
);
150 let output_ty
= fn_output_ty
[0].assert_ty_ref(interner
).clone();
164 // Function traits are non-enumerable
165 TyData
::InferenceVar(..) | TyData
::Alias(..) => Err(Floundered
),