aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcus Klaas de Vries <[email protected]>2019-01-25 20:16:02 +0000
committerMarcus Klaas de Vries <[email protected]>2019-01-27 16:59:21 +0000
commit3bd47c0285433b5eb258196a81b95141d2a70505 (patch)
tree41bd19f6e95e4c22bd39c35702a1d2e048dd9cef
parent3f4f50baaa21cb2d0f6c102f1ca521946071a8dc (diff)
First attempt at generic type inference for fns
-rw-r--r--crates/ra_hir/src/code_model_api.rs6
-rw-r--r--crates/ra_hir/src/code_model_impl/function.rs8
-rw-r--r--crates/ra_hir/src/generics.rs3
-rw-r--r--crates/ra_hir/src/ty.rs61
-rw-r--r--crates/ra_hir/src/ty/tests.rs22
-rw-r--r--crates/ra_ide_api/src/completion/completion_item.rs2
6 files changed, 81 insertions, 21 deletions
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs
index 191104890..82ebb275a 100644
--- a/crates/ra_hir/src/code_model_api.rs
+++ b/crates/ra_hir/src/code_model_api.rs
@@ -388,7 +388,7 @@ pub use crate::code_model_impl::function::ScopeEntryWithSyntax;
388#[derive(Debug, Clone, PartialEq, Eq)] 388#[derive(Debug, Clone, PartialEq, Eq)]
389pub struct FnSignature { 389pub struct FnSignature {
390 pub(crate) name: Name, 390 pub(crate) name: Name,
391 pub(crate) params: Vec<TypeRef>, 391 pub(crate) args: Vec<TypeRef>,
392 pub(crate) ret_type: TypeRef, 392 pub(crate) ret_type: TypeRef,
393 /// True if the first param is `self`. This is relevant to decide whether this 393 /// True if the first param is `self`. This is relevant to decide whether this
394 /// can be called as a method. 394 /// can be called as a method.
@@ -400,8 +400,8 @@ impl FnSignature {
400 &self.name 400 &self.name
401 } 401 }
402 402
403 pub fn params(&self) -> &[TypeRef] { 403 pub fn args(&self) -> &[TypeRef] {
404 &self.params 404 &self.args
405 } 405 }
406 406
407 pub fn ret_type(&self) -> &TypeRef { 407 pub fn ret_type(&self) -> &TypeRef {
diff --git a/crates/ra_hir/src/code_model_impl/function.rs b/crates/ra_hir/src/code_model_impl/function.rs
index e0dd4d629..b4aa18540 100644
--- a/crates/ra_hir/src/code_model_impl/function.rs
+++ b/crates/ra_hir/src/code_model_impl/function.rs
@@ -32,7 +32,7 @@ impl FnSignature {
32 .name() 32 .name()
33 .map(|n| n.as_name()) 33 .map(|n| n.as_name())
34 .unwrap_or_else(Name::missing); 34 .unwrap_or_else(Name::missing);
35 let mut params = Vec::new(); 35 let mut args = Vec::new();
36 let mut has_self_param = false; 36 let mut has_self_param = false;
37 if let Some(param_list) = node.param_list() { 37 if let Some(param_list) = node.param_list() {
38 if let Some(self_param) = param_list.self_param() { 38 if let Some(self_param) = param_list.self_param() {
@@ -50,12 +50,12 @@ impl FnSignature {
50 } 50 }
51 } 51 }
52 }; 52 };
53 params.push(self_type); 53 args.push(self_type);
54 has_self_param = true; 54 has_self_param = true;
55 } 55 }
56 for param in param_list.params() { 56 for param in param_list.params() {
57 let type_ref = TypeRef::from_ast_opt(param.type_ref()); 57 let type_ref = TypeRef::from_ast_opt(param.type_ref());
58 params.push(type_ref); 58 args.push(type_ref);
59 } 59 }
60 } 60 }
61 let ret_type = if let Some(type_ref) = node.ret_type().and_then(|rt| rt.type_ref()) { 61 let ret_type = if let Some(type_ref) = node.ret_type().and_then(|rt| rt.type_ref()) {
@@ -66,7 +66,7 @@ impl FnSignature {
66 66
67 let sig = FnSignature { 67 let sig = FnSignature {
68 name, 68 name,
69 params, 69 args,
70 ret_type, 70 ret_type,
71 has_self_param, 71 has_self_param,
72 }; 72 };
diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs
index 64c20a462..a5501d543 100644
--- a/crates/ra_hir/src/generics.rs
+++ b/crates/ra_hir/src/generics.rs
@@ -49,7 +49,8 @@ impl GenericParams {
49 Arc::new(generics) 49 Arc::new(generics)
50 } 50 }
51 51
52 fn fill(&mut self, node: &impl TypeParamsOwner) { 52 // FIXME: probably shouldnt be pub(crate)
53 pub(crate) fn fill(&mut self, node: &impl TypeParamsOwner) {
53 if let Some(params) = node.type_param_list() { 54 if let Some(params) = node.type_param_list() {
54 self.fill_params(params) 55 self.fill_params(params)
55 } 56 }
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index 31ea45706..95de916ee 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -209,6 +209,18 @@ pub enum Ty {
209 /// `&'a mut T` or `&'a T`. 209 /// `&'a mut T` or `&'a T`.
210 Ref(Arc<Ty>, Mutability), 210 Ref(Arc<Ty>, Mutability),
211 211
212 /// The anonymous type of a function declaration/definition. Each
213 /// function has a unique type, which is output (for a function
214 /// named `foo` returning an `i32`) as `fn() -> i32 {foo}`.
215 ///
216 /// For example the type of `bar` here:
217 ///
218 /// ```rust
219 /// fn foo() -> i32 { 1 }
220 /// let bar = foo; // bar: fn() -> i32 {foo}
221 /// ```
222 FnDef(Function, Substs),
223
212 /// A pointer to a function. Written as `fn() -> i32`. 224 /// A pointer to a function. Written as `fn() -> i32`.
213 /// 225 ///
214 /// For example the type of `bar` here: 226 /// For example the type of `bar` here:
@@ -485,7 +497,7 @@ impl Ty {
485 } 497 }
486 sig_mut.output.walk_mut(f); 498 sig_mut.output.walk_mut(f);
487 } 499 }
488 Ty::Adt { substs, .. } => { 500 Ty::FnDef(_, substs) | Ty::Adt { substs, .. } => {
489 // Without an Arc::make_mut_slice, we can't avoid the clone here: 501 // Without an Arc::make_mut_slice, we can't avoid the clone here:
490 let mut v: Vec<_> = substs.0.iter().cloned().collect(); 502 let mut v: Vec<_> = substs.0.iter().cloned().collect();
491 for t in &mut v { 503 for t in &mut v {
@@ -524,6 +536,7 @@ impl Ty {
524 name, 536 name,
525 substs, 537 substs,
526 }, 538 },
539 Ty::FnDef(func, _) => Ty::FnDef(func, substs),
527 _ => self, 540 _ => self,
528 } 541 }
529 } 542 }
@@ -579,6 +592,7 @@ impl fmt::Display for Ty {
579 .to_fmt(f) 592 .to_fmt(f)
580 } 593 }
581 } 594 }
595 Ty::FnDef(_func, _substs) => write!(f, "FNDEF-IMPLEMENT-ME"),
582 Ty::FnPtr(sig) => { 596 Ty::FnPtr(sig) => {
583 join(sig.input.iter()) 597 join(sig.input.iter())
584 .surround_with("fn(", ")") 598 .surround_with("fn(", ")")
@@ -608,12 +622,18 @@ impl fmt::Display for Ty {
608/// Compute the declared type of a function. This should not need to look at the 622/// Compute the declared type of a function. This should not need to look at the
609/// function body. 623/// function body.
610fn type_for_fn(db: &impl HirDatabase, f: Function) -> Ty { 624fn type_for_fn(db: &impl HirDatabase, f: Function) -> Ty {
625 let generics = f.generic_params(db);
626 let substs = make_substs(&generics);
627 Ty::FnDef(f.into(), substs)
628}
629
630fn get_func_sig(db: &impl HirDatabase, f: Function) -> FnSig {
611 let signature = f.signature(db); 631 let signature = f.signature(db);
612 let module = f.module(db); 632 let module = f.module(db);
613 let impl_block = f.impl_block(db); 633 let impl_block = f.impl_block(db);
614 let generics = f.generic_params(db); 634 let generics = f.generic_params(db);
615 let input = signature 635 let input = signature
616 .params() 636 .args()
617 .iter() 637 .iter()
618 .map(|tr| Ty::from_hir(db, &module, impl_block.as_ref(), &generics, tr)) 638 .map(|tr| Ty::from_hir(db, &module, impl_block.as_ref(), &generics, tr))
619 .collect::<Vec<_>>(); 639 .collect::<Vec<_>>();
@@ -624,8 +644,7 @@ fn type_for_fn(db: &impl HirDatabase, f: Function) -> Ty {
624 &generics, 644 &generics,
625 signature.ret_type(), 645 signature.ret_type(),
626 ); 646 );
627 let sig = FnSig { input, output }; 647 FnSig { input, output }
628 Ty::FnPtr(Arc::new(sig))
629} 648}
630 649
631fn make_substs(generics: &GenericParams) -> Substs { 650fn make_substs(generics: &GenericParams) -> Substs {
@@ -1142,7 +1161,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1142 let ty = self.insert_type_vars(ty.apply_substs(substs)); 1161 let ty = self.insert_type_vars(ty.apply_substs(substs));
1143 (ty, Some(var.into())) 1162 (ty, Some(var.into()))
1144 } 1163 }
1145 TypableDef::Enum(_) | TypableDef::Function(_) => (Ty::Unknown, None), 1164 TypableDef::Function(func) => {
1165 let ty = type_for_fn(self.db, func);
1166 let ty = self.insert_type_vars(ty.apply_substs(substs));
1167 // FIXME: is this right?
1168 (ty, None)
1169 }
1170 TypableDef::Enum(_) => (Ty::Unknown, None),
1146 } 1171 }
1147 } 1172 }
1148 1173
@@ -1331,12 +1356,27 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1331 } 1356 }
1332 Expr::Call { callee, args } => { 1357 Expr::Call { callee, args } => {
1333 let callee_ty = self.infer_expr(*callee, &Expectation::none()); 1358 let callee_ty = self.infer_expr(*callee, &Expectation::none());
1359 // FIXME: so manu unnecessary clones
1334 let (param_tys, ret_ty) = match &callee_ty { 1360 let (param_tys, ret_ty) = match &callee_ty {
1335 Ty::FnPtr(sig) => (&sig.input[..], sig.output.clone()), 1361 Ty::FnPtr(sig) => (sig.input.clone(), sig.output.clone()),
1362 Ty::FnDef(func, substs) => {
1363 let fn_sig = func.signature(self.db);
1364 // TODO: get input and return types from the fn_sig.
1365 // it contains typerefs which we can make into proper tys
1366
1367 let sig = get_func_sig(self.db, *func);
1368 (
1369 sig.input
1370 .iter()
1371 .map(|ty| ty.clone().subst(&substs))
1372 .collect(),
1373 sig.output.clone().subst(&substs),
1374 )
1375 }
1336 _ => { 1376 _ => {
1337 // not callable 1377 // not callable
1338 // TODO report an error? 1378 // TODO report an error?
1339 (&[][..], Ty::Unknown) 1379 (Vec::new(), Ty::Unknown)
1340 } 1380 }
1341 }; 1381 };
1342 for (i, arg) in args.iter().enumerate() { 1382 for (i, arg) in args.iter().enumerate() {
@@ -1604,15 +1644,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1604 1644
1605 fn collect_fn_signature(&mut self, signature: &FnSignature) { 1645 fn collect_fn_signature(&mut self, signature: &FnSignature) {
1606 let body = Arc::clone(&self.body); // avoid borrow checker problem 1646 let body = Arc::clone(&self.body); // avoid borrow checker problem
1607 for (type_ref, pat) in signature.params().iter().zip(body.params()) { 1647 for (type_ref, pat) in signature.args().iter().zip(body.params()) {
1608 let ty = self.make_ty(type_ref); 1648 let ty = self.make_ty(type_ref);
1609 1649
1610 self.infer_pat(*pat, &ty); 1650 self.infer_pat(*pat, &ty);
1611 } 1651 }
1612 self.return_ty = { 1652 self.return_ty = self.make_ty(signature.ret_type());
1613 let ty = self.make_ty(signature.ret_type());
1614 ty
1615 };
1616 } 1653 }
1617 1654
1618 fn infer_body(&mut self) { 1655 fn infer_body(&mut self) {
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index f74d6f5ea..40913b164 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -594,6 +594,28 @@ fn test() {
594 ); 594 );
595} 595}
596 596
597#[test]
598fn infer_type_param() {
599 check_inference(
600 "generic_fn",
601 r#"
602fn id<T>(x: T) -> T {
603 x
604}
605
606fn clone<T>(x: &T) -> T {
607 x
608}
609
610fn test() {
611 let y = 10u32;
612 id(y);
613 let x: bool = clone(z);
614}
615"#,
616 );
617}
618
597fn infer(content: &str) -> String { 619fn infer(content: &str) -> String {
598 let (db, _, file_id) = MockDatabase::with_single_file(content); 620 let (db, _, file_id) = MockDatabase::with_single_file(content);
599 let source_file = db.parse(file_id); 621 let source_file = db.parse(file_id);
diff --git a/crates/ra_ide_api/src/completion/completion_item.rs b/crates/ra_ide_api/src/completion/completion_item.rs
index b16ac2b28..6e9a68e40 100644
--- a/crates/ra_ide_api/src/completion/completion_item.rs
+++ b/crates/ra_ide_api/src/completion/completion_item.rs
@@ -240,7 +240,7 @@ impl Builder {
240 if ctx.use_item_syntax.is_none() && !ctx.is_call { 240 if ctx.use_item_syntax.is_none() && !ctx.is_call {
241 tested_by!(inserts_parens_for_function_calls); 241 tested_by!(inserts_parens_for_function_calls);
242 let sig = function.signature(ctx.db); 242 let sig = function.signature(ctx.db);
243 if sig.params().is_empty() || sig.has_self_param() && sig.params().len() == 1 { 243 if sig.args().is_empty() || sig.has_self_param() && sig.args().len() == 1 {
244 self.insert_text = Some(format!("{}()$0", self.label)); 244 self.insert_text = Some(format!("{}()$0", self.label));
245 } else { 245 } else {
246 self.insert_text = Some(format!("{}($0)", self.label)); 246 self.insert_text = Some(format!("{}($0)", self.label));