]>
Commit | Line | Data |
---|---|---|
f035d41b XL |
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; | |
6 | use chalk_ir::{ | |
29967ef6 XL |
7 | AliasTy, Binders, Floundered, Normalize, ProjectionTy, Safety, Substitution, TraitId, Ty, |
8 | TyKind, VariableKinds, | |
f035d41b XL |
9 | }; |
10 | ||
11 | fn push_clauses<I: Interner>( | |
12 | db: &dyn RustIrDatabase<I>, | |
13 | builder: &mut ClauseBuilder<'_, I>, | |
14 | well_known: WellKnownTrait, | |
15 | trait_id: TraitId<I>, | |
16 | self_ty: Ty<I>, | |
17 | arg_sub: Substitution<I>, | |
18 | return_type: Ty<I>, | |
19 | ) { | |
20 | let interner = db.interner(); | |
29967ef6 | 21 | let tupled = TyKind::Tuple(arg_sub.len(interner), arg_sub).intern(interner); |
f035d41b | 22 | let substitution = |
3dfed10e | 23 | Substitution::from_iter(interner, &[self_ty.cast(interner), tupled.cast(interner)]); |
f035d41b XL |
24 | builder.push_fact(TraitRef { |
25 | trait_id, | |
26 | substitution: substitution.clone(), | |
27 | }); | |
28 | ||
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); | |
32 | assert_eq!( | |
33 | trait_datum.associated_ty_ids.len(), | |
34 | 1, | |
35 | "FnOnce trait should have exactly one associated type, found {:?}", | |
36 | trait_datum.associated_ty_ids | |
37 | ); | |
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, | |
43 | substitution, | |
44 | }); | |
45 | builder.push_fact(Normalize { | |
46 | alias, | |
47 | ty: return_type, | |
48 | }); | |
49 | } | |
50 | } | |
51 | ||
52 | fn push_clauses_for_apply<I: Interner>( | |
53 | db: &dyn RustIrDatabase<I>, | |
54 | builder: &mut ClauseBuilder<'_, I>, | |
55 | well_known: WellKnownTrait, | |
56 | trait_id: TraitId<I>, | |
57 | self_ty: Ty<I>, | |
58 | inputs_and_output: &Binders<FnDefInputsAndOutputDatum<I>>, | |
59 | ) { | |
60 | let interner = db.interner(); | |
61 | builder.push_binders(inputs_and_output, |builder, inputs_and_output| { | |
62 | let arg_sub = inputs_and_output | |
63 | .argument_types | |
64 | .iter() | |
65 | .cloned() | |
66 | .map(|ty| ty.cast(interner)); | |
3dfed10e | 67 | let arg_sub = Substitution::from_iter(interner, arg_sub); |
f035d41b XL |
68 | let output_ty = inputs_and_output.return_type; |
69 | ||
70 | push_clauses( | |
71 | db, builder, well_known, trait_id, self_ty, arg_sub, output_ty, | |
72 | ); | |
73 | }); | |
74 | } | |
75 | ||
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) | |
80 | /// | |
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, | |
89 | self_ty: Ty<I>, | |
90 | ) -> Result<(), Floundered> { | |
91 | let interner = db.interner(); | |
92 | let trait_id = db.well_known_trait_id(well_known).unwrap(); | |
93 | ||
29967ef6 XL |
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 | |
99 | .binders | |
100 | .substitute(builder.interner(), &substitution); | |
f035d41b XL |
101 | push_clauses_for_apply( |
102 | db, | |
103 | builder, | |
104 | well_known, | |
105 | trait_id, | |
106 | self_ty, | |
29967ef6 | 107 | &bound.inputs_and_output, |
f035d41b | 108 | ); |
f035d41b | 109 | } |
29967ef6 XL |
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 => { | |
f035d41b | 137 | let (binders, orig_sub) = fn_val.into_binders_and_value(interner); |
3dfed10e | 138 | let bound_ref = Binders::new(VariableKinds::from_iter(interner, binders), orig_sub); |
f035d41b XL |
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 | |
3dfed10e | 142 | .as_slice(interner) |
f035d41b | 143 | .split_at(orig_sub.len(interner) - 1); |
3dfed10e | 144 | let arg_sub = Substitution::from_iter(interner, arg_sub); |
f035d41b XL |
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 | |
29967ef6 | 160 | TyKind::InferenceVar(..) | TyKind::Alias(..) => Err(Floundered), |
f035d41b XL |
161 | _ => Ok(()), |
162 | } | |
163 | } |