diff options
Diffstat (limited to 'crates/ra_hir_ty/src/infer')
-rw-r--r-- | crates/ra_hir_ty/src/infer/expr.rs | 81 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/pat.rs | 33 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/path.rs | 2 |
3 files changed, 92 insertions, 24 deletions
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 9fd310f69..a9565a58d 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs | |||
@@ -10,12 +10,12 @@ use hir_def::{ | |||
10 | resolver::resolver_for_expr, | 10 | resolver::resolver_for_expr, |
11 | AdtId, AssocContainerId, FieldId, Lookup, | 11 | AdtId, AssocContainerId, FieldId, Lookup, |
12 | }; | 12 | }; |
13 | use hir_expand::name::Name; | 13 | use hir_expand::name::{name, Name}; |
14 | use ra_syntax::ast::RangeOp; | 14 | 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::{FnTrait, InEnvironment}, |
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, InferTy, IntTy, Mutability, Obligation, Rawness, Substs, |
21 | TraitRef, Ty, TypeCtor, | 21 | TraitRef, Ty, TypeCtor, |
@@ -63,6 +63,58 @@ 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, num_args: usize) -> Option<(Vec<Ty>, Ty)> { | ||
67 | let krate = self.resolver.krate()?; | ||
68 | let fn_once_trait = FnTrait::FnOnce.get_id(self.db, krate)?; | ||
69 | let output_assoc_type = | ||
70 | self.db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?; | ||
71 | let generic_params = generics(self.db.upcast(), fn_once_trait.into()); | ||
72 | if generic_params.len() != 2 { | ||
73 | return None; | ||
74 | } | ||
75 | |||
76 | let mut param_builder = Substs::builder(num_args); | ||
77 | let mut arg_tys = vec![]; | ||
78 | for _ in 0..num_args { | ||
79 | let arg = self.table.new_type_var(); | ||
80 | param_builder = param_builder.push(arg.clone()); | ||
81 | arg_tys.push(arg); | ||
82 | } | ||
83 | let parameters = param_builder.build(); | ||
84 | let arg_ty = Ty::Apply(ApplicationTy { | ||
85 | ctor: TypeCtor::Tuple { cardinality: num_args as u16 }, | ||
86 | parameters, | ||
87 | }); | ||
88 | let substs = Substs::build_for_generics(&generic_params) | ||
89 | .push(ty.clone()) | ||
90 | .push(arg_ty.clone()) | ||
91 | .build(); | ||
92 | |||
93 | let trait_env = Arc::clone(&self.trait_env); | ||
94 | let implements_fn_trait = | ||
95 | Obligation::Trait(TraitRef { trait_: fn_once_trait, substs: substs.clone() }); | ||
96 | let goal = self.canonicalizer().canonicalize_obligation(InEnvironment { | ||
97 | value: implements_fn_trait.clone(), | ||
98 | environment: trait_env, | ||
99 | }); | ||
100 | if self.db.trait_solve(krate, goal.value).is_some() { | ||
101 | self.obligations.push(implements_fn_trait); | ||
102 | let output_proj_ty = | ||
103 | crate::ProjectionTy { associated_ty: output_assoc_type, parameters: substs }; | ||
104 | let return_ty = self.normalize_projection_ty(output_proj_ty); | ||
105 | Some((arg_tys, return_ty)) | ||
106 | } else { | ||
107 | None | ||
108 | } | ||
109 | } | ||
110 | |||
111 | pub fn callable_sig(&mut self, ty: &Ty, num_args: usize) -> Option<(Vec<Ty>, Ty)> { | ||
112 | match ty.callable_sig(self.db) { | ||
113 | Some(sig) => Some((sig.params().to_vec(), sig.ret().clone())), | ||
114 | None => self.callable_sig_from_fn_trait(ty, num_args), | ||
115 | } | ||
116 | } | ||
117 | |||
66 | fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { | 118 | fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { |
67 | let body = Arc::clone(&self.body); // avoid borrow checker problem | 119 | let body = Arc::clone(&self.body); // avoid borrow checker problem |
68 | let ty = match &body[tgt_expr] { | 120 | let ty = match &body[tgt_expr] { |
@@ -198,14 +250,23 @@ impl<'a> InferenceContext<'a> { | |||
198 | } | 250 | } |
199 | Expr::Call { callee, args } => { | 251 | Expr::Call { callee, args } => { |
200 | let callee_ty = self.infer_expr(*callee, &Expectation::none()); | 252 | let callee_ty = self.infer_expr(*callee, &Expectation::none()); |
201 | let (param_tys, ret_ty) = match callee_ty.callable_sig(self.db) { | 253 | let canonicalized = self.canonicalizer().canonicalize_ty(callee_ty.clone()); |
202 | Some(sig) => (sig.params().to_vec(), sig.ret().clone()), | 254 | let mut derefs = autoderef( |
203 | None => { | 255 | self.db, |
204 | // Not callable | 256 | self.resolver.krate(), |
205 | // FIXME: report an error | 257 | InEnvironment { |
206 | (Vec::new(), Ty::Unknown) | 258 | value: canonicalized.value.clone(), |
207 | } | 259 | environment: self.trait_env.clone(), |
208 | }; | 260 | }, |
261 | ); | ||
262 | let (param_tys, ret_ty): (Vec<Ty>, Ty) = derefs | ||
263 | .find_map(|callee_deref_ty| { | ||
264 | self.callable_sig( | ||
265 | &canonicalized.decanonicalize_ty(callee_deref_ty.value), | ||
266 | args.len(), | ||
267 | ) | ||
268 | }) | ||
269 | .unwrap_or((Vec::new(), Ty::Unknown)); | ||
209 | self.register_obligations_for_call(&callee_ty); | 270 | self.register_obligations_for_call(&callee_ty); |
210 | self.check_call_arguments(args, ¶m_tys); | 271 | self.check_call_arguments(args, ¶m_tys); |
211 | self.normalize_associated_types_in(ret_ty) | 272 | self.normalize_associated_types_in(ret_ty) |
diff --git a/crates/ra_hir_ty/src/infer/pat.rs b/crates/ra_hir_ty/src/infer/pat.rs index 4006f595d..23de2bd6b 100644 --- a/crates/ra_hir_ty/src/infer/pat.rs +++ b/crates/ra_hir_ty/src/infer/pat.rs | |||
@@ -4,7 +4,7 @@ use std::iter::repeat; | |||
4 | use std::sync::Arc; | 4 | use std::sync::Arc; |
5 | 5 | ||
6 | use hir_def::{ | 6 | use hir_def::{ |
7 | expr::{BindingAnnotation, Pat, PatId, RecordFieldPat}, | 7 | expr::{BindingAnnotation, Expr, Literal, Pat, PatId, RecordFieldPat}, |
8 | path::Path, | 8 | path::Path, |
9 | type_ref::Mutability, | 9 | type_ref::Mutability, |
10 | FieldId, | 10 | FieldId, |
@@ -90,18 +90,7 @@ impl<'a> InferenceContext<'a> { | |||
90 | ) -> Ty { | 90 | ) -> Ty { |
91 | let body = Arc::clone(&self.body); // avoid borrow checker problem | 91 | let body = Arc::clone(&self.body); // avoid borrow checker problem |
92 | 92 | ||
93 | let is_non_ref_pat = match &body[pat] { | 93 | if is_non_ref_pat(&body, pat) { |
94 | Pat::Tuple { .. } | ||
95 | | Pat::Or(..) | ||
96 | | Pat::TupleStruct { .. } | ||
97 | | Pat::Record { .. } | ||
98 | | Pat::Range { .. } | ||
99 | | Pat::Slice { .. } => true, | ||
100 | // FIXME: Path/Lit might actually evaluate to ref, but inference is unimplemented. | ||
101 | Pat::Path(..) | Pat::Lit(..) => true, | ||
102 | Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Missing => false, | ||
103 | }; | ||
104 | if is_non_ref_pat { | ||
105 | while let Some((inner, mutability)) = expected.as_reference() { | 94 | while let Some((inner, mutability)) = expected.as_reference() { |
106 | expected = inner; | 95 | expected = inner; |
107 | default_bm = match default_bm { | 96 | default_bm = match default_bm { |
@@ -227,3 +216,21 @@ impl<'a> InferenceContext<'a> { | |||
227 | ty | 216 | ty |
228 | } | 217 | } |
229 | } | 218 | } |
219 | |||
220 | fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool { | ||
221 | match &body[pat] { | ||
222 | Pat::Tuple { .. } | ||
223 | | Pat::TupleStruct { .. } | ||
224 | | Pat::Record { .. } | ||
225 | | Pat::Range { .. } | ||
226 | | Pat::Slice { .. } => true, | ||
227 | Pat::Or(pats) => pats.iter().all(|p| is_non_ref_pat(body, *p)), | ||
228 | // FIXME: Path/Lit might actually evaluate to ref, but inference is unimplemented. | ||
229 | Pat::Path(..) => true, | ||
230 | Pat::Lit(expr) => match body[*expr] { | ||
231 | Expr::Literal(Literal::String(..)) => false, | ||
232 | _ => true, | ||
233 | }, | ||
234 | Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Missing => false, | ||
235 | } | ||
236 | } | ||
diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs index 1ad0d8397..80d7ed10e 100644 --- a/crates/ra_hir_ty/src/infer/path.rs +++ b/crates/ra_hir_ty/src/infer/path.rs | |||
@@ -81,7 +81,7 @@ impl<'a> InferenceContext<'a> { | |||
81 | let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); | 81 | let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); |
82 | let substs = Substs::type_params_for_generics(&generics); | 82 | let substs = Substs::type_params_for_generics(&generics); |
83 | let ty = self.db.impl_self_ty(impl_id).subst(&substs); | 83 | let ty = self.db.impl_self_ty(impl_id).subst(&substs); |
84 | if let Some((AdtId::StructId(struct_id), _)) = ty.as_adt() { | 84 | if let Some((AdtId::StructId(struct_id), substs)) = ty.as_adt() { |
85 | let ty = self.db.value_ty(struct_id.into()).subst(&substs); | 85 | let ty = self.db.value_ty(struct_id.into()).subst(&substs); |
86 | return Some(ty); | 86 | return Some(ty); |
87 | } else { | 87 | } else { |