Represent FnPtr and Tuple using Substs

This commit is contained in:
Florian Diebold 2019-03-16 18:14:41 +01:00
parent 51323a852a
commit bc7752e527
3 changed files with 33 additions and 27 deletions

View File

@ -89,13 +89,13 @@ pub enum Ty {
/// fn foo() -> i32 { 1 }
/// let bar: fn() -> i32 = foo;
/// ```
FnPtr(FnSig),
FnPtr(Substs),
/// The never type `!`.
Never,
/// A tuple type. For example, `(i32, bool)`.
Tuple(Arc<[Ty]>),
Tuple(Substs),
/// A type parameter; for example, `T` in `fn f<T>(x: T) {}
Param {
@ -127,6 +127,10 @@ impl Substs {
Substs(Arc::new([]))
}
pub fn iter(&self) -> impl Iterator<Item = &Ty> {
self.0.iter()
}
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.0.iter().cloned().collect();
@ -148,6 +152,11 @@ impl FnSig {
params.push(ret);
FnSig { params_and_return: params.into() }
}
pub fn from_fn_ptr_substs(substs: &Substs) -> FnSig {
FnSig { params_and_return: Arc::clone(&substs.0) }
}
pub fn params(&self) -> &[Ty] {
&self.params_and_return[0..self.params_and_return.len() - 1]
}
@ -168,7 +177,7 @@ impl FnSig {
impl Ty {
pub fn unit() -> Self {
Ty::Tuple(Arc::new([]))
Ty::Tuple(Substs::empty())
}
pub fn walk(&self, f: &mut impl FnMut(&Ty)) {
@ -182,10 +191,9 @@ impl Ty {
}
}
Ty::FnPtr(sig) => {
for input in sig.params() {
input.walk(f);
for t in sig.iter() {
t.walk(f);
}
sig.ret().walk(f);
}
Ty::FnDef { substs, .. } => {
for t in substs.0.iter() {
@ -216,12 +224,7 @@ impl Ty {
Ty::RawPtr(t, _) => Arc::make_mut(t).walk_mut(f),
Ty::Ref(t, _) => Arc::make_mut(t).walk_mut(f),
Ty::Tuple(ts) => {
// Without an Arc::make_mut_slice, we can't avoid the clone here:
let mut v: Vec<_> = ts.iter().cloned().collect();
for t in &mut v {
t.walk_mut(f);
}
*ts = v.into();
ts.walk_mut(f);
}
Ty::FnPtr(sig) => {
sig.walk_mut(f);
@ -324,15 +327,16 @@ impl HirDisplay for Ty {
}
Ty::Never => write!(f, "!")?,
Ty::Tuple(ts) => {
if ts.len() == 1 {
write!(f, "({},)", ts[0].display(f.db))?;
if ts.0.len() == 1 {
write!(f, "({},)", ts.0[0].display(f.db))?;
} else {
write!(f, "(")?;
f.write_joined(&**ts, ", ")?;
f.write_joined(&*ts.0, ", ")?;
write!(f, ")")?;
}
}
Ty::FnPtr(sig) => {
let sig = FnSig::from_fn_ptr_substs(sig);
write!(f, "fn(")?;
f.write_joined(sig.params(), ", ")?;
write!(f, ") -> {}", sig.ret().display(f.db))?;

View File

@ -38,7 +38,7 @@ use crate::{
resolve::{Resolver, Resolution},
nameres::Namespace
};
use super::{Ty, TypableDef, Substs, primitive, op};
use super::{Ty, TypableDef, Substs, primitive, op, FnSig};
/// The entry point of type inference.
pub fn infer(db: &impl HirDatabase, func: Function) -> Arc<InferenceResult> {
@ -257,10 +257,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
self.unify_inner(t1, t2, depth + 1)
}
(Ty::Ref(t1, m1), Ty::Ref(t2, m2)) if m1 == m2 => self.unify_inner(t1, t2, depth + 1),
(Ty::FnPtr(sig1), Ty::FnPtr(sig2)) if sig1 == sig2 => true,
(Ty::Tuple(ts1), Ty::Tuple(ts2)) if ts1.len() == ts2.len() => {
ts1.iter().zip(ts2.iter()).all(|(t1, t2)| self.unify_inner(t1, t2, depth + 1))
}
(Ty::FnPtr(sig1), Ty::FnPtr(sig2)) => self.unify_substs(sig1, sig2, depth + 1),
(Ty::Tuple(ts1), Ty::Tuple(ts2)) => self.unify_substs(ts1, ts2, depth + 1),
(Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2)))
| (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2)))
| (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2))) => {
@ -632,7 +630,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
let ty = match &body[pat] {
Pat::Tuple(ref args) => {
let expectations = match *expected {
Ty::Tuple(ref tuple_args) => &**tuple_args,
Ty::Tuple(ref tuple_args) => &*tuple_args.0,
_ => &[],
};
let expectations_iter = expectations.iter().chain(repeat(&Ty::Unknown));
@ -644,7 +642,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
.collect::<Vec<_>>()
.into();
Ty::Tuple(inner_tys)
Ty::Tuple(Substs(inner_tys))
}
Pat::Ref { pat, mutability } => {
let expectation = match *expected {
@ -789,7 +787,10 @@ 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::FnPtr(sig) => (sig.params().to_vec(), sig.ret().clone()),
Ty::FnPtr(sig) => {
let sig = FnSig::from_fn_ptr_substs(sig);
(sig.params().to_vec(), sig.ret().clone())
}
Ty::FnDef { substs, def, .. } => {
let sig = self.db.callable_item_signature(*def);
let ret_ty = sig.ret().clone().subst(&substs);
@ -828,6 +829,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
let method_ty = self.insert_type_vars(method_ty);
let (expected_receiver_ty, param_tys, ret_ty) = match &method_ty {
Ty::FnPtr(sig) => {
let sig = FnSig::from_fn_ptr_substs(sig);
if !sig.params().is_empty() {
(sig.params()[0].clone(), sig.params()[1..].to_vec(), sig.ret().clone())
} else {
@ -923,7 +925,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
.find_map(|derefed_ty| match derefed_ty {
Ty::Tuple(fields) => {
let i = name.to_string().parse::<usize>().ok();
i.and_then(|i| fields.get(i).cloned())
i.and_then(|i| fields.0.get(i).cloned())
}
Ty::Adt { def_id: AdtDef::Struct(s), ref substs, .. } => {
s.field(self.db, name).map(|field| {
@ -1016,7 +1018,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
ty_vec.push(self.infer_expr(*arg, &Expectation::none()));
}
Ty::Tuple(Arc::from(ty_vec))
Ty::Tuple(Substs(ty_vec.into()))
}
Expr::Array { exprs } => {
let elem_ty = match &expected.ty {

View File

@ -30,7 +30,7 @@ impl Ty {
TypeRef::Tuple(inner) => {
let inner_tys =
inner.iter().map(|tr| Ty::from_hir(db, resolver, tr)).collect::<Vec<_>>();
Ty::Tuple(inner_tys.into())
Ty::Tuple(Substs(inner_tys.into()))
}
TypeRef::Path(path) => Ty::from_hir_path(db, resolver, path),
TypeRef::RawPtr(inner, mutability) => {
@ -53,7 +53,7 @@ impl Ty {
TypeRef::Fn(params) => {
let inner_tys =
params.iter().map(|tr| Ty::from_hir(db, resolver, tr)).collect::<Vec<_>>();
let sig = FnSig { params_and_return: inner_tys.into() };
let sig = Substs(inner_tys.into());
Ty::FnPtr(sig)
}
TypeRef::Error => Ty::Unknown,