Make callable signature handling a bit nicer

This commit is contained in:
Florian Diebold 2019-04-09 22:16:20 +02:00
parent 9339241b78
commit 7650a44640
2 changed files with 36 additions and 47 deletions

View File

@ -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<FnSig> {
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

View File

@ -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<InferenceResult> {
@ -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())
}
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())
}
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)
}
}
_ => (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)
}
};