1 use crate::clauses::ClauseBuilder;
2 use crate::rust_ir::{ClosureKind, FnDefInputsAndOutputDatum, WellKnownTrait};
3 use crate::{Interner, RustIrDatabase, TraitRef};
4 use chalk_ir::cast::Cast;
5 use chalk_ir::{
6     AliasTy, Binders, Floundered, Normalize, ProjectionTy, Safety, Substitution, TraitId, Ty,
7     TyKind,
8 };
9 
push_clauses<I: Interner>( db: &dyn RustIrDatabase<I>, builder: &mut ClauseBuilder<'_, I>, well_known: WellKnownTrait, trait_id: TraitId<I>, self_ty: Ty<I>, arg_sub: Substitution<I>, return_type: Ty<I>, )10 fn push_clauses<I: Interner>(
11     db: &dyn RustIrDatabase<I>,
12     builder: &mut ClauseBuilder<'_, I>,
13     well_known: WellKnownTrait,
14     trait_id: TraitId<I>,
15     self_ty: Ty<I>,
16     arg_sub: Substitution<I>,
17     return_type: Ty<I>,
18 ) {
19     let interner = db.interner();
20     let tupled = TyKind::Tuple(arg_sub.len(interner), arg_sub).intern(interner);
21     let substitution =
22         Substitution::from_iter(interner, &[self_ty.cast(interner), tupled.cast(interner)]);
23     builder.push_fact(TraitRef {
24         trait_id,
25         substitution: substitution.clone(),
26     });
27 
28     // The `Output` type is defined on the `FnOnce`
29     if let WellKnownTrait::FnOnce = well_known {
30         let trait_datum = db.trait_datum(trait_id);
31         assert_eq!(
32             trait_datum.associated_ty_ids.len(),
33             1,
34             "FnOnce trait should have exactly one associated type, found {:?}",
35             trait_datum.associated_ty_ids
36         );
37         // Constructs the alias. For `Fn`, for example, this would look like
38         // `Normalize(<fn(A) -> B as FnOnce<(A,)>>::Output -> B)`
39         let output_id = trait_datum.associated_ty_ids[0];
40         let alias = AliasTy::Projection(ProjectionTy {
41             associated_ty_id: output_id,
42             substitution,
43         });
44         builder.push_fact(Normalize {
45             alias,
46             ty: return_type,
47         });
48     }
49 }
50 
push_clauses_for_apply<I: Interner>( db: &dyn RustIrDatabase<I>, builder: &mut ClauseBuilder<'_, I>, well_known: WellKnownTrait, trait_id: TraitId<I>, self_ty: Ty<I>, inputs_and_output: Binders<FnDefInputsAndOutputDatum<I>>, )51 fn push_clauses_for_apply<I: Interner>(
52     db: &dyn RustIrDatabase<I>,
53     builder: &mut ClauseBuilder<'_, I>,
54     well_known: WellKnownTrait,
55     trait_id: TraitId<I>,
56     self_ty: Ty<I>,
57     inputs_and_output: Binders<FnDefInputsAndOutputDatum<I>>,
58 ) {
59     let interner = db.interner();
60     builder.push_binders(inputs_and_output, |builder, inputs_and_output| {
61         let arg_sub = inputs_and_output
62             .argument_types
63             .iter()
64             .cloned()
65             .map(|ty| ty.cast(interner));
66         let arg_sub = Substitution::from_iter(interner, arg_sub);
67         let output_ty = inputs_and_output.return_type;
68 
69         push_clauses(
70             db, builder, well_known, trait_id, self_ty, arg_sub, output_ty,
71         );
72     });
73 }
74 
75 /// Handles clauses for FnOnce/FnMut/Fn.
76 /// If `self_ty` is a function, we push a clause of the form
77 /// `fn(A1, A2, ..., AN) -> O: FnTrait<(A1, A2, ..., AN)>`, where `FnTrait`
78 /// is the trait corresponding to `trait_id` (FnOnce/FnMut/Fn)
79 ///
80 /// If `trait_id` is `FnOnce`, we also push a clause for the output type of the form:
81 /// `Normalize(<fn(A) -> B as FnOnce<(A,)>>::Output -> B)`
82 /// We do not add the usual `Implemented(fn(A) -> b as FnOnce<(A,)>` clause
83 /// as a condition, since we already called `push_fact` with it
add_fn_trait_program_clauses<I: Interner>( db: &dyn RustIrDatabase<I>, builder: &mut ClauseBuilder<'_, I>, well_known: WellKnownTrait, self_ty: Ty<I>, ) -> Result<(), Floundered>84 pub fn add_fn_trait_program_clauses<I: Interner>(
85     db: &dyn RustIrDatabase<I>,
86     builder: &mut ClauseBuilder<'_, I>,
87     well_known: WellKnownTrait,
88     self_ty: Ty<I>,
89 ) -> Result<(), Floundered> {
90     let interner = db.interner();
91     let trait_id = db.well_known_trait_id(well_known).unwrap();
92 
93     match self_ty.kind(interner) {
94         TyKind::FnDef(fn_def_id, substitution) => {
95             let fn_def_datum = builder.db.fn_def_datum(*fn_def_id);
96             if fn_def_datum.sig.safety == Safety::Safe && !fn_def_datum.sig.variadic {
97                 let bound = fn_def_datum
98                     .binders
99                     .clone()
100                     .substitute(builder.interner(), &substitution);
101                 push_clauses_for_apply(
102                     db,
103                     builder,
104                     well_known,
105                     trait_id,
106                     self_ty,
107                     bound.inputs_and_output,
108                 );
109             }
110             Ok(())
111         }
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,
119                 _ => false,
120             };
121             if !trait_matches {
122                 return Ok(());
123             }
124             let closure_inputs_and_output =
125                 db.closure_inputs_and_output(*closure_id, &substitution);
126             push_clauses_for_apply(
127                 db,
128                 builder,
129                 well_known,
130                 trait_id,
131                 self_ty,
132                 closure_inputs_and_output,
133             );
134             Ok(())
135         }
136         TyKind::Function(fn_val) if fn_val.sig.safety == Safety::Safe && !fn_val.sig.variadic => {
137             let bound_ref = fn_val.clone().into_binders(interner);
138             builder.push_binders(bound_ref, |builder, orig_sub| {
139                 // The last parameter represents the function return type
140                 let (arg_sub, fn_output_ty) = orig_sub
141                     .0
142                     .as_slice(interner)
143                     .split_at(orig_sub.0.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();
146 
147                 push_clauses(
148                     db,
149                     builder,
150                     well_known,
151                     trait_id,
152                     self_ty.clone(),
153                     arg_sub,
154                     output_ty,
155                 );
156             });
157             Ok(())
158         }
159         // Function traits are non-enumerable
160         TyKind::InferenceVar(..) | TyKind::BoundVar(_) | TyKind::Alias(..) => Err(Floundered),
161         _ => Ok(()),
162     }
163 }
164