]> git.lizzy.rs Git - rust.git/commitdiff
Initial implementation of generics for method calls
authorMarcus Klaas de Vries <mail@marcusklaas.nl>
Fri, 25 Jan 2019 21:18:13 +0000 (22:18 +0100)
committerMarcus Klaas de Vries <mail@marcusklaas.nl>
Sun, 27 Jan 2019 16:59:21 +0000 (17:59 +0100)
crates/ra_hir/src/code_model_api.rs
crates/ra_hir/src/ty.rs

index 82ebb275a756d4ae744ab88630bd003a78de31e3..defb9fd0af21d5c0a86c42de22235cd7cde1b49c 100644 (file)
@@ -424,6 +424,10 @@ pub fn module(&self, db: &impl HirDatabase) -> Module {
         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)
     }
index 95de916ee18582d1993adde86997c4e30a17f531..9b08b9c97b0d6223a51930ff3537d7416f7bddd2 100644 (file)
@@ -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 @@ fn walk_mut(&mut self, f: &mut impl FnMut(&mut 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 @@ pub fn apply_substs(self, substs: Substs) -> Ty {
                 name,
                 substs,
             },
-            Ty::FnDef(func, _) => Ty::FnDef(func, substs),
+            Ty::FnDef { def, name, .. } => Ty::FnDef {
+                def,
+                name,
+                substs,
+            },
             _ => self,
         }
     }
@@ -592,7 +603,6 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                         .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 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                     .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 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 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 @@ fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
                 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 @@ fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
                 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, Vec::new(), sig.output.clone())
+                        }
+                    }
+                    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, &[][..], sig.output.clone())
+                            (Ty::Unknown, Vec::new(), sig.output.clone())
                         }
                     }
-                    _ => (&Ty::Unknown, &[][..], Ty::Unknown),
+                    _ => (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,