diff options
author | adamrk <[email protected]> | 2020-06-07 20:57:29 +0100 |
---|---|---|
committer | adamrk <[email protected]> | 2020-06-19 21:51:25 +0100 |
commit | 3f94a90c7bbc1b3116a7960ae9f25ebe35d68ad0 (patch) | |
tree | 82d8a965b9e01e136df4eeaee4c4fee4630ab2a7 /crates/ra_hir_ty/src/infer | |
parent | 6654055308515cb330f23942f347de5605f69be1 (diff) |
Infer FnSig from Fn traits
Diffstat (limited to 'crates/ra_hir_ty/src/infer')
-rw-r--r-- | crates/ra_hir_ty/src/infer/coerce.rs | 6 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/expr.rs | 102 |
2 files changed, 92 insertions, 16 deletions
diff --git a/crates/ra_hir_ty/src/infer/coerce.rs b/crates/ra_hir_ty/src/infer/coerce.rs index 32c7c57cd..4c5f171de 100644 --- a/crates/ra_hir_ty/src/infer/coerce.rs +++ b/crates/ra_hir_ty/src/infer/coerce.rs | |||
@@ -38,8 +38,8 @@ impl<'a> InferenceContext<'a> { | |||
38 | // Special case: two function types. Try to coerce both to | 38 | // Special case: two function types. Try to coerce both to |
39 | // pointers to have a chance at getting a match. See | 39 | // pointers to have a chance at getting a match. See |
40 | // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916 | 40 | // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916 |
41 | let sig1 = ty1.callable_sig(self.db).expect("FnDef without callable sig"); | 41 | let sig1 = self.callable_sig(ty1).expect("FnDef without callable sig"); |
42 | let sig2 = ty2.callable_sig(self.db).expect("FnDef without callable sig"); | 42 | let sig2 = self.callable_sig(ty2).expect("FnDef without callable sig"); |
43 | let ptr_ty1 = Ty::fn_ptr(sig1); | 43 | let ptr_ty1 = Ty::fn_ptr(sig1); |
44 | let ptr_ty2 = Ty::fn_ptr(sig2); | 44 | let ptr_ty2 = Ty::fn_ptr(sig2); |
45 | self.coerce_merge_branch(&ptr_ty1, &ptr_ty2) | 45 | self.coerce_merge_branch(&ptr_ty1, &ptr_ty2) |
@@ -93,7 +93,7 @@ impl<'a> InferenceContext<'a> { | |||
93 | 93 | ||
94 | // `{function_type}` -> `fn()` | 94 | // `{function_type}` -> `fn()` |
95 | (ty_app!(TypeCtor::FnDef(_)), ty_app!(TypeCtor::FnPtr { .. })) => { | 95 | (ty_app!(TypeCtor::FnDef(_)), ty_app!(TypeCtor::FnPtr { .. })) => { |
96 | match from_ty.callable_sig(self.db) { | 96 | match self.callable_sig(&from_ty) { |
97 | None => return false, | 97 | None => return false, |
98 | Some(sig) => { | 98 | Some(sig) => { |
99 | from_ty = Ty::fn_ptr(sig); | 99 | from_ty = Ty::fn_ptr(sig); |
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 9fd310f69..bba6daeb9 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs | |||
@@ -15,15 +15,15 @@ use ra_syntax::ast::RangeOp; | |||
15 | 15 | ||
16 | use crate::{ | 16 | use crate::{ |
17 | autoderef, method_resolution, op, | 17 | autoderef, method_resolution, op, |
18 | traits::InEnvironment, | 18 | traits::{builtin::get_fn_trait, FnTrait, InEnvironment, SolutionVariables}, |
19 | utils::{generics, variant_data, Generics}, | 19 | utils::{generics, variant_data, Generics}, |
20 | ApplicationTy, Binders, CallableDef, InferTy, IntTy, Mutability, Obligation, Rawness, Substs, | 20 | ApplicationTy, Binders, CallableDef, FnSig, InferTy, IntTy, Mutability, Obligation, Rawness, |
21 | TraitRef, Ty, TypeCtor, | 21 | Substs, TraitRef, Ty, TypeCtor, |
22 | }; | 22 | }; |
23 | 23 | ||
24 | use super::{ | 24 | use super::{ |
25 | find_breakable, BindingMode, BreakableContext, Diverges, Expectation, InferenceContext, | 25 | find_breakable, BindingMode, BreakableContext, Diverges, Expectation, InferenceContext, |
26 | InferenceDiagnostic, TypeMismatch, | 26 | InferenceDiagnostic, Solution, TypeMismatch, |
27 | }; | 27 | }; |
28 | 28 | ||
29 | impl<'a> InferenceContext<'a> { | 29 | impl<'a> InferenceContext<'a> { |
@@ -63,6 +63,75 @@ impl<'a> InferenceContext<'a> { | |||
63 | self.resolve_ty_as_possible(ty) | 63 | self.resolve_ty_as_possible(ty) |
64 | } | 64 | } |
65 | 65 | ||
66 | fn callable_sig_from_fn_trait(&mut self, ty: &Ty) -> Option<FnSig> { | ||
67 | if let Some(krate) = self.resolver.krate() { | ||
68 | let fn_traits: Vec<crate::TraitId> = [FnTrait::FnOnce, FnTrait::FnMut, FnTrait::Fn] | ||
69 | .iter() | ||
70 | .filter_map(|f| get_fn_trait(self.db, krate, *f)) | ||
71 | .collect(); | ||
72 | for fn_trait in fn_traits { | ||
73 | let fn_trait_data = self.db.trait_data(fn_trait); | ||
74 | let generic_params = generics(self.db.upcast(), fn_trait.into()); | ||
75 | if generic_params.len() != 2 { | ||
76 | continue; | ||
77 | } | ||
78 | |||
79 | let arg_ty = self.table.new_type_var(); | ||
80 | let substs = Substs::build_for_generics(&generic_params) | ||
81 | .push(ty.clone()) | ||
82 | .push(arg_ty.clone()) | ||
83 | .build(); | ||
84 | |||
85 | let trait_ref = TraitRef { trait_: fn_trait, substs: substs.clone() }; | ||
86 | let trait_env = Arc::clone(&self.trait_env); | ||
87 | let implements_fn_goal = | ||
88 | self.canonicalizer().canonicalize_obligation(InEnvironment { | ||
89 | value: Obligation::Trait(trait_ref), | ||
90 | environment: trait_env, | ||
91 | }); | ||
92 | if let Some(Solution::Unique(SolutionVariables(solution))) = | ||
93 | self.db.trait_solve(krate, implements_fn_goal.value.clone()) | ||
94 | { | ||
95 | match solution.value.as_slice() { | ||
96 | [Ty::Apply(ApplicationTy { | ||
97 | ctor: TypeCtor::Tuple { cardinality: _ }, | ||
98 | parameters, | ||
99 | })] => { | ||
100 | let output_assoc_type = match fn_trait_data | ||
101 | .associated_types() | ||
102 | .collect::<Vec<hir_def::TypeAliasId>>() | ||
103 | .as_slice() | ||
104 | { | ||
105 | [output] => *output, | ||
106 | _ => { | ||
107 | continue; | ||
108 | } | ||
109 | }; | ||
110 | let output_proj_ty = crate::ProjectionTy { | ||
111 | associated_ty: output_assoc_type, | ||
112 | parameters: substs, | ||
113 | }; | ||
114 | let return_ty = self.normalize_projection_ty(output_proj_ty); | ||
115 | return Some(FnSig::from_params_and_return( | ||
116 | parameters.into_iter().map(|ty| ty.clone()).collect(), | ||
117 | return_ty, | ||
118 | )); | ||
119 | } | ||
120 | _ => (), | ||
121 | } | ||
122 | } | ||
123 | } | ||
124 | }; | ||
125 | None | ||
126 | } | ||
127 | |||
128 | pub fn callable_sig(&mut self, ty: &Ty) -> Option<FnSig> { | ||
129 | match ty.callable_sig(self.db) { | ||
130 | result @ Some(_) => result, | ||
131 | None => self.callable_sig_from_fn_trait(ty), | ||
132 | } | ||
133 | } | ||
134 | |||
66 | fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { | 135 | fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { |
67 | let body = Arc::clone(&self.body); // avoid borrow checker problem | 136 | let body = Arc::clone(&self.body); // avoid borrow checker problem |
68 | let ty = match &body[tgt_expr] { | 137 | let ty = match &body[tgt_expr] { |
@@ -198,14 +267,21 @@ impl<'a> InferenceContext<'a> { | |||
198 | } | 267 | } |
199 | Expr::Call { callee, args } => { | 268 | Expr::Call { callee, args } => { |
200 | let callee_ty = self.infer_expr(*callee, &Expectation::none()); | 269 | let callee_ty = self.infer_expr(*callee, &Expectation::none()); |
201 | let (param_tys, ret_ty) = match callee_ty.callable_sig(self.db) { | 270 | let canonicalized = self.canonicalizer().canonicalize_ty(callee_ty.clone()); |
202 | Some(sig) => (sig.params().to_vec(), sig.ret().clone()), | 271 | let mut derefs = autoderef( |
203 | None => { | 272 | self.db, |
204 | // Not callable | 273 | self.resolver.krate(), |
205 | // FIXME: report an error | 274 | InEnvironment { |
206 | (Vec::new(), Ty::Unknown) | 275 | value: canonicalized.value.clone(), |
207 | } | 276 | environment: self.trait_env.clone(), |
208 | }; | 277 | }, |
278 | ); | ||
279 | let (param_tys, ret_ty): (Vec<Ty>, Ty) = derefs | ||
280 | .find_map(|callee_deref_ty| { | ||
281 | self.callable_sig(&canonicalized.decanonicalize_ty(callee_deref_ty.value)) | ||
282 | .map(|sig| (sig.params().to_vec(), sig.ret().clone())) | ||
283 | }) | ||
284 | .unwrap_or((Vec::new(), Ty::Unknown)); | ||
209 | self.register_obligations_for_call(&callee_ty); | 285 | self.register_obligations_for_call(&callee_ty); |
210 | self.check_call_arguments(args, ¶m_tys); | 286 | self.check_call_arguments(args, ¶m_tys); |
211 | self.normalize_associated_types_in(ret_ty) | 287 | self.normalize_associated_types_in(ret_ty) |
@@ -692,7 +768,7 @@ impl<'a> InferenceContext<'a> { | |||
692 | let method_ty = method_ty.subst(&substs); | 768 | let method_ty = method_ty.subst(&substs); |
693 | let method_ty = self.insert_type_vars(method_ty); | 769 | let method_ty = self.insert_type_vars(method_ty); |
694 | self.register_obligations_for_call(&method_ty); | 770 | self.register_obligations_for_call(&method_ty); |
695 | let (expected_receiver_ty, param_tys, ret_ty) = match method_ty.callable_sig(self.db) { | 771 | let (expected_receiver_ty, param_tys, ret_ty) = match self.callable_sig(&method_ty) { |
696 | Some(sig) => { | 772 | Some(sig) => { |
697 | if !sig.params().is_empty() { | 773 | if !sig.params().is_empty() { |
698 | (sig.params()[0].clone(), sig.params()[1..].to_vec(), sig.ret().clone()) | 774 | (sig.params()[0].clone(), sig.params()[1..].to_vec(), sig.ret().clone()) |