From 7650a44640a373e28f9eecc4623256ce6b9bbaa0 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Tue, 9 Apr 2019 22:16:20 +0200 Subject: Make callable signature handling a bit nicer --- crates/ra_hir/src/ty.rs | 22 ++++++++++++++++ crates/ra_hir/src/ty/infer.rs | 61 ++++++++++--------------------------------- 2 files changed, 36 insertions(+), 47 deletions(-) (limited to 'crates/ra_hir') diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index aa43bc800..12e10c751 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -221,6 +221,14 @@ impl FnSig { &self.params_and_return[self.params_and_return.len() - 1] } + /// Applies the given substitutions to all types in this signature and + /// returns the result. + pub fn subst(&self, substs: &Substs) -> FnSig { + let result: Vec<_> = + self.params_and_return.iter().map(|ty| ty.clone().subst(substs)).collect(); + FnSig { params_and_return: result.into() } + } + pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { // Without an Arc::make_mut_slice, we can't avoid the clone here: let mut v: Vec<_> = self.params_and_return.iter().cloned().collect(); @@ -320,6 +328,20 @@ impl Ty { } } + fn callable_sig(&self, db: &impl HirDatabase) -> Option { + match self { + Ty::Apply(a_ty) => match a_ty.ctor { + TypeCtor::FnPtr => Some(FnSig::from_fn_ptr_substs(&a_ty.parameters)), + TypeCtor::FnDef(def) => { + let sig = db.callable_item_signature(def); + Some(sig.subst(&a_ty.parameters)) + } + _ => None, + }, + _ => None, + } + } + /// If this is a type with type parameters (an ADT or function), replaces /// the `Substs` for these type parameters with the given ones. (So e.g. if /// `self` is `Option<_>` and the substs contain `u32`, we'll have diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index b28bb47c6..28459d750 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -41,7 +41,7 @@ use crate::{ ty::infer::diagnostics::InferenceDiagnostic, diagnostics::DiagnosticSink, }; -use super::{Ty, TypableDef, Substs, primitive, op, FnSig, ApplicationTy, TypeCtor, traits::{ Solution, Obligation, Guidance}, CallableDef, TraitRef}; +use super::{Ty, TypableDef, Substs, primitive, op, ApplicationTy, TypeCtor, traits::{ Solution, Obligation, Guidance}, CallableDef, TraitRef}; /// The entry point of type inference. pub fn infer(db: &impl HirDatabase, def: DefWithBody) -> Arc { @@ -839,32 +839,15 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let method_ty = method_ty.apply_substs(substs); let method_ty = self.insert_type_vars(method_ty); self.register_obligations_for_call(&method_ty); - let (expected_receiver_ty, param_tys, ret_ty) = match &method_ty { - Ty::Apply(a_ty) => match a_ty.ctor { - TypeCtor::FnPtr => { - let sig = FnSig::from_fn_ptr_substs(&a_ty.parameters); - if !sig.params().is_empty() { - (sig.params()[0].clone(), sig.params()[1..].to_vec(), sig.ret().clone()) - } else { - (Ty::Unknown, Vec::new(), sig.ret().clone()) - } - } - TypeCtor::FnDef(def) => { - let sig = self.db.callable_item_signature(def); - let ret_ty = sig.ret().clone().subst(&a_ty.parameters); - - if !sig.params().is_empty() { - let mut params_iter = - sig.params().iter().map(|ty| ty.clone().subst(&a_ty.parameters)); - let receiver_ty = params_iter.next().unwrap(); - (receiver_ty, params_iter.collect(), ret_ty) - } else { - (Ty::Unknown, Vec::new(), ret_ty) - } + let (expected_receiver_ty, param_tys, ret_ty) = match method_ty.callable_sig(self.db) { + Some(sig) => { + if !sig.params().is_empty() { + (sig.params()[0].clone(), sig.params()[1..].to_vec(), sig.ret().clone()) + } else { + (Ty::Unknown, Vec::new(), sig.ret().clone()) } - _ => (Ty::Unknown, Vec::new(), Ty::Unknown), - }, - _ => (Ty::Unknown, Vec::new(), Ty::Unknown), + } + None => (Ty::Unknown, Vec::new(), Ty::Unknown), }; // Apply autoref so the below unification works correctly // FIXME: return correct autorefs from lookup_method @@ -937,27 +920,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } Expr::Call { callee, args } => { let callee_ty = self.infer_expr(*callee, &Expectation::none()); - let (param_tys, ret_ty) = match &callee_ty { - Ty::Apply(a_ty) => match a_ty.ctor { - TypeCtor::FnPtr => { - let sig = FnSig::from_fn_ptr_substs(&a_ty.parameters); - (sig.params().to_vec(), sig.ret().clone()) - } - TypeCtor::FnDef(def) => { - let sig = self.db.callable_item_signature(def); - let ret_ty = sig.ret().clone().subst(&a_ty.parameters); - let param_tys = sig - .params() - .iter() - .map(|ty| ty.clone().subst(&a_ty.parameters)) - .collect(); - (param_tys, ret_ty) - } - _ => (Vec::new(), Ty::Unknown), - }, - _ => { - // not callable - // FIXME report an error? + let (param_tys, ret_ty) = match callee_ty.callable_sig(self.db) { + Some(sig) => (sig.params().to_vec(), sig.ret().clone()), + None => { + // Not callable + // FIXME: report an error (Vec::new(), Ty::Unknown) } }; -- cgit v1.2.3