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
, Safety
, Substitution
,
8 TraitId
, 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_iter(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_iter(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 if fn_def_datum
.safety
== Safety
::Safe
&& !fn_def_datum
.variadic
{
103 let bound
= fn_def_datum
105 .substitute(builder
.interner(), &apply
.substitution
);
106 push_clauses_for_apply(
112 &bound
.inputs_and_output
,
117 TypeName
::Closure(closure_id
) => {
118 let closure_kind
= db
.closure_kind(closure_id
, &apply
.substitution
);
119 let trait_matches
= match (well_known
, closure_kind
) {
120 (WellKnownTrait
::Fn
, ClosureKind
::Fn
) => true,
121 (WellKnownTrait
::FnMut
, ClosureKind
::FnMut
)
122 | (WellKnownTrait
::FnMut
, ClosureKind
::Fn
) => true,
123 (WellKnownTrait
::FnOnce
, _
) => true,
129 let closure_inputs_and_output
=
130 db
.closure_inputs_and_output(closure_id
, &apply
.substitution
);
131 push_clauses_for_apply(
137 &closure_inputs_and_output
,
143 TyData
::Function(fn_val
) if fn_val
.safety
== Safety
::Safe
&& !fn_val
.variadic
=> {
144 let (binders
, orig_sub
) = fn_val
.into_binders_and_value(interner
);
145 let bound_ref
= Binders
::new(VariableKinds
::from_iter(interner
, binders
), orig_sub
);
146 builder
.push_binders(&bound_ref
, |builder
, orig_sub
| {
147 // The last parameter represents the function return type
148 let (arg_sub
, fn_output_ty
) = orig_sub
150 .split_at(orig_sub
.len(interner
) - 1);
151 let arg_sub
= Substitution
::from_iter(interner
, arg_sub
);
152 let output_ty
= fn_output_ty
[0].assert_ty_ref(interner
).clone();
166 // Function traits are non-enumerable
167 TyData
::InferenceVar(..) | TyData
::Alias(..) => Err(Floundered
),