From 67e40e431aa966a76b6a247b19505e22b620a0c7 Mon Sep 17 00:00:00 2001
From: Marcus Klaas de Vries <mail@marcusklaas.nl>
Date: Fri, 25 Jan 2019 22:18:13 +0100
Subject: [PATCH] Initial implementation of generics for method calls

---
 crates/ra_hir/src/code_model_api.rs |  4 ++
 crates/ra_hir/src/ty.rs             | 81 ++++++++++++++++++++++++-----
 2 files changed, 72 insertions(+), 13 deletions(-)

diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs
index 82ebb275a75..defb9fd0af2 100644
--- a/crates/ra_hir/src/code_model_api.rs
+++ b/crates/ra_hir/src/code_model_api.rs
@@ -424,6 +424,10 @@ impl Function {
         self.id.module(db)
     }
 
+    pub fn name(&self, db: &impl HirDatabase) -> Name {
+        self.signature(db).name.clone()
+    }
+
     pub fn body_syntax_mapping(&self, db: &impl HirDatabase) -> Arc<BodySyntaxMapping> {
         db.body_syntax_mapping(*self)
     }
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index 95de916ee18..9b08b9c97b0 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -185,7 +185,7 @@ pub enum Ty {
 
     /// Structures, enumerations and unions.
     Adt {
-        /// The DefId of the struct/enum.
+        /// The definition of the struct/enum.
         def_id: AdtDef,
         /// The name, for displaying.
         name: Name,
@@ -219,7 +219,14 @@ pub enum Ty {
     /// fn foo() -> i32 { 1 }
     /// let bar = foo; // bar: fn() -> i32 {foo}
     /// ```
-    FnDef(Function, Substs),
+    FnDef {
+        // Function definition
+        def: Function,
+        /// For display
+        name: Name,
+        /// Substitutions for the generic parameters of the type
+        substs: Substs
+    },
 
     /// A pointer to a function.  Written as `fn() -> i32`.
     ///
@@ -497,7 +504,7 @@ impl Ty {
                 }
                 sig_mut.output.walk_mut(f);
             }
-            Ty::FnDef(_, substs) | Ty::Adt { substs, .. } => {
+            Ty::FnDef { substs, .. } | Ty::Adt { substs, .. } => {
                 // Without an Arc::make_mut_slice, we can't avoid the clone here:
                 let mut v: Vec<_> = substs.0.iter().cloned().collect();
                 for t in &mut v {
@@ -536,7 +543,11 @@ impl Ty {
                 name,
                 substs,
             },
-            Ty::FnDef(func, _) => Ty::FnDef(func, substs),
+            Ty::FnDef { def, name, .. } => Ty::FnDef {
+                def,
+                name,
+                substs,
+            },
             _ => self,
         }
     }
@@ -592,7 +603,6 @@ impl fmt::Display for Ty {
                         .to_fmt(f)
                 }
             }
-            Ty::FnDef(_func, _substs) => write!(f, "FNDEF-IMPLEMENT-ME"),
             Ty::FnPtr(sig) => {
                 join(sig.input.iter())
                     .surround_with("fn(", ")")
@@ -600,6 +610,19 @@ impl fmt::Display for Ty {
                     .to_fmt(f)?;
                 write!(f, " -> {}", sig.output)
             }
+            Ty::FnDef { name, substs, .. } => {
+                // don't have access to the param types here :-(
+                // we could store them in the def, but not sure if it
+                // is worth it
+                write!(f, "fn {}", name)?;
+                if substs.0.len() > 0 {
+                    join(substs.0.iter())
+                        .surround_with("<", ">")
+                        .separator(", ")
+                        .to_fmt(f)?;
+                }
+                Ok(())
+            }
             Ty::Adt { name, substs, .. } => {
                 write!(f, "{}", name)?;
                 if substs.0.len() > 0 {
@@ -624,7 +647,12 @@ impl fmt::Display for Ty {
 fn type_for_fn(db: &impl HirDatabase, f: Function) -> Ty {
     let generics = f.generic_params(db);
     let substs = make_substs(&generics);
-    Ty::FnDef(f.into(), substs)
+    let name = f.name(db);
+    Ty::FnDef {
+        def: f.into(),
+        name,
+        substs
+    }
 }
 
 fn get_func_sig(db: &impl HirDatabase, f: Function) -> FnSig {
@@ -1355,16 +1383,18 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
                 Ty::Unknown
             }
             Expr::Call { callee, args } => {
+                // TODO: we should use turbofish hints like this:
+                // f::<u32>(x)
                 let callee_ty = self.infer_expr(*callee, &Expectation::none());
                 // FIXME: so manu unnecessary clones
                 let (param_tys, ret_ty) = match &callee_ty {
                     Ty::FnPtr(sig) => (sig.input.clone(), sig.output.clone()),
-                    Ty::FnDef(func, substs) => {
-                        let fn_sig = func.signature(self.db);
+                    Ty::FnDef { def, substs, .. } => {
+                        let fn_sig = def.signature(self.db);
                         // TODO: get input and return types from the fn_sig.
                         // it contains typerefs which we can make into proper tys
 
-                        let sig = get_func_sig(self.db, *func);
+                        let sig = get_func_sig(self.db, *def);
                         (
                             sig.input
                                 .iter()
@@ -1405,16 +1435,41 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
                 let (expected_receiver_ty, param_tys, ret_ty) = match &method_ty {
                     Ty::FnPtr(sig) => {
                         if sig.input.len() > 0 {
-                            (&sig.input[0], &sig.input[1..], sig.output.clone())
+                            (sig.input[0].clone(), sig.input[1..].iter().cloned().collect(), sig.output.clone())
                         } else {
-                            (&Ty::Unknown, &[][..], sig.output.clone())
+                            (Ty::Unknown, Vec::new(), sig.output.clone())
                         }
                     }
-                    _ => (&Ty::Unknown, &[][..], Ty::Unknown),
+                    Ty::FnDef { def, substs, .. } => {
+                        // TODO: fix deduplication with Expr::Call block above
+                        // TODO: fix the ridiculous number of clones
+                        let fn_sig = def.signature(self.db);
+                        // TODO: get input and return types from the fn_sig.
+                        // it contains typerefs which we can make into proper tys
+
+                        // check that len > 0
+                        let sig = get_func_sig(self.db, *def);
+                        if sig.input.len() > 0 {
+                            (
+                                sig.input[0].clone().subst(&substs),
+                                sig.input[1..]
+                                    .iter()
+                                    .map(|ty| ty.clone().subst(&substs))
+                                    .collect(),
+                                sig.output.clone().subst(&substs),
+                            )
+                        } else {
+                            (Ty::Unknown, Vec::new(), sig.output.clone())
+                        }
+                    }
+                    _ => (Ty::Unknown, Vec::new(), Ty::Unknown),
                 };
                 // TODO we would have to apply the autoderef/autoref steps here
                 // to get the correct receiver type to unify...
-                self.unify(expected_receiver_ty, &receiver_ty);
+                // 
+                // TODO: zip param_tys.chain(iter::repeat(Ty::Unknown)) above then its not so bad
+                // that we clone
+                self.unify(&expected_receiver_ty, &receiver_ty);
                 for (i, arg) in args.iter().enumerate() {
                     self.infer_expr(
                         *arg,