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
, Binders
, Floundered
, Normalize
, ProjectionTy
, Safety
, Substitution
, TraitId
, Ty
,
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
= TyKind
::Tuple(arg_sub
.len(interner
), arg_sub
).intern(interner
);
23 Substitution
::from_iter(interner
, &[self_ty
.cast(interner
), tupled
.cast(interner
)]);
24 builder
.push_fact(TraitRef
{
26 substitution
: substitution
.clone(),
29 // The `Output` type is defined on the `FnOnce`
30 if let WellKnownTrait
::FnOnce
= well_known
{
31 let trait_datum
= db
.trait_datum(trait_id
);
33 trait_datum
.associated_ty_ids
.len(),
35 "FnOnce trait should have exactly one associated type, found {:?}",
36 trait_datum
.associated_ty_ids
38 // Constructs the alias. For `Fn`, for example, this would look like
39 // `Normalize(<fn(A) -> B as FnOnce<(A,)>>::Output -> B)`
40 let output_id
= trait_datum
.associated_ty_ids
[0];
41 let alias
= AliasTy
::Projection(ProjectionTy
{
42 associated_ty_id
: output_id
,
45 builder
.push_fact(Normalize
{
52 fn push_clauses_for_apply
<I
: Interner
>(
53 db
: &dyn RustIrDatabase
<I
>,
54 builder
: &mut ClauseBuilder
<'_
, I
>,
55 well_known
: WellKnownTrait
,
58 inputs_and_output
: &Binders
<FnDefInputsAndOutputDatum
<I
>>,
60 let interner
= db
.interner();
61 builder
.push_binders(inputs_and_output
, |builder
, inputs_and_output
| {
62 let arg_sub
= inputs_and_output
66 .map(|ty
| ty
.cast(interner
));
67 let arg_sub
= Substitution
::from_iter(interner
, arg_sub
);
68 let output_ty
= inputs_and_output
.return_type
;
71 db
, builder
, well_known
, trait_id
, self_ty
, arg_sub
, output_ty
,
76 /// Handles clauses for FnOnce/FnMut/Fn.
77 /// If `self_ty` is a function, we push a clause of the form
78 /// `fn(A1, A2, ..., AN) -> O: FnTrait<(A1, A2, ..., AN)>`, where `FnTrait`
79 /// is the trait corresponding to `trait_id` (FnOnce/FnMut/Fn)
81 /// If `trait_id` is `FnOnce`, we also push a clause for the output type of the form:
82 /// `Normalize(<fn(A) -> B as FnOnce<(A,)>>::Output -> B)`
83 /// We do not add the usual `Implemented(fn(A) -> b as FnOnce<(A,)>` clause
84 /// as a condition, since we already called `push_fact` with it
85 pub fn add_fn_trait_program_clauses
<I
: Interner
>(
86 db
: &dyn RustIrDatabase
<I
>,
87 builder
: &mut ClauseBuilder
<'_
, I
>,
88 well_known
: WellKnownTrait
,
90 ) -> Result
<(), Floundered
> {
91 let interner
= db
.interner();
92 let trait_id
= db
.well_known_trait_id(well_known
).unwrap();
94 match self_ty
.kind(interner
) {
95 TyKind
::FnDef(fn_def_id
, substitution
) => {
96 let fn_def_datum
= builder
.db
.fn_def_datum(*fn_def_id
);
97 if fn_def_datum
.sig
.safety
== Safety
::Safe
&& !fn_def_datum
.sig
.variadic
{
98 let bound
= fn_def_datum
100 .substitute(builder
.interner(), &substitution
);
101 push_clauses_for_apply(
107 &bound
.inputs_and_output
,
112 TyKind
::Closure(closure_id
, substitution
) => {
113 let closure_kind
= db
.closure_kind(*closure_id
, &substitution
);
114 let trait_matches
= match (well_known
, closure_kind
) {
115 (WellKnownTrait
::Fn
, ClosureKind
::Fn
) => true,
116 (WellKnownTrait
::FnMut
, ClosureKind
::FnMut
)
117 | (WellKnownTrait
::FnMut
, ClosureKind
::Fn
) => true,
118 (WellKnownTrait
::FnOnce
, _
) => true,
124 let closure_inputs_and_output
=
125 db
.closure_inputs_and_output(*closure_id
, &substitution
);
126 push_clauses_for_apply(
132 &closure_inputs_and_output
,
136 TyKind
::Function(fn_val
) if fn_val
.sig
.safety
== Safety
::Safe
&& !fn_val
.sig
.variadic
=> {
137 let (binders
, orig_sub
) = fn_val
.into_binders_and_value(interner
);
138 let bound_ref
= Binders
::new(VariableKinds
::from_iter(interner
, binders
), orig_sub
);
139 builder
.push_binders(&bound_ref
, |builder
, orig_sub
| {
140 // The last parameter represents the function return type
141 let (arg_sub
, fn_output_ty
) = orig_sub
143 .split_at(orig_sub
.len(interner
) - 1);
144 let arg_sub
= Substitution
::from_iter(interner
, arg_sub
);
145 let output_ty
= fn_output_ty
[0].assert_ty_ref(interner
).clone();
159 // Function traits are non-enumerable
160 TyKind
::InferenceVar(..) | TyKind
::Alias(..) => Err(Floundered
),