rust-analyzer/crates/ra_hir/src/ty.rs

380 lines
12 KiB
Rust
Raw Normal View History

//! The type system. We currently use this to infer types for completion, hover
//! information and various assists.
2019-01-06 18:51:42 +00:00
mod autoderef;
pub(crate) mod primitive;
2018-12-20 20:56:28 +00:00
#[cfg(test)]
mod tests;
pub(crate) mod method_resolution;
mod op;
mod lower;
mod infer;
pub(crate) mod display;
2018-12-20 20:56:28 +00:00
use std::sync::Arc;
use std::{fmt, mem};
2018-12-20 20:56:28 +00:00
use crate::{Name, AdtDef, type_ref::Mutability, db::HirDatabase};
2019-01-26 22:57:03 +00:00
pub(crate) use lower::{TypableDef, CallableDef, type_for_def, type_for_field, callable_item_sig};
pub(crate) use infer::{infer, InferenceResult, InferTy};
use display::{HirDisplay, HirFormatter};
/// A type. This is based on the `TyKind` enum in rustc (librustc/ty/sty.rs).
///
/// This should be cheap to clone.
#[derive(Clone, PartialEq, Eq, Debug)]
2018-12-20 20:56:28 +00:00
pub enum Ty {
/// The primitive boolean type. Written as `bool`.
Bool,
/// The primitive character type; holds a Unicode scalar value
/// (a non-surrogate code point). Written as `char`.
2018-12-20 20:56:28 +00:00
Char,
/// A primitive integer type. For example, `i32`.
Int(primitive::UncertainIntTy),
2018-12-20 20:56:28 +00:00
/// A primitive floating-point type. For example, `f64`.
Float(primitive::UncertainFloatTy),
2018-12-20 20:56:28 +00:00
/// Structures, enumerations and unions.
Adt {
/// The definition of the struct/enum.
2019-01-24 14:54:18 +00:00
def_id: AdtDef,
/// Substitutions for the generic parameters of the type.
substs: Substs,
},
2018-12-20 20:56:28 +00:00
/// The pointee of a string slice. Written as `str`.
Str,
/// The pointee of an array slice. Written as `[T]`.
Slice(Arc<Ty>),
2018-12-20 20:56:28 +00:00
2019-03-02 13:53:12 +00:00
/// An array with the given length. Written as `[T; n]`.
2019-01-14 13:51:54 +00:00
Array(Arc<Ty>),
/// A raw pointer. Written as `*mut T` or `*const T`
RawPtr(Arc<Ty>, Mutability),
/// A reference; a pointer with an associated lifetime. Written as
/// `&'a mut T` or `&'a T`.
Ref(Arc<Ty>, Mutability),
2018-12-20 20:56:28 +00:00
/// The anonymous type of a function declaration/definition. Each
/// function has a unique type, which is output (for a function
/// named `foo` returning an `i32`) as `fn() -> i32 {foo}`.
///
/// This includes tuple struct / enum variant constructors as well.
///
/// For example the type of `bar` here:
///
/// ```rust
/// fn foo() -> i32 { 1 }
/// let bar = foo; // bar: fn() -> i32 {foo}
/// ```
FnDef {
/// The definition of the function / constructor.
def: CallableDef,
/// Substitutions for the generic parameters of the type
2019-01-25 23:30:56 +00:00
substs: Substs,
},
2018-12-20 20:56:28 +00:00
/// A pointer to a function. Written as `fn() -> i32`.
///
/// For example the type of `bar` here:
///
/// ```rust
/// fn foo() -> i32 { 1 }
/// let bar: fn() -> i32 = foo;
/// ```
2019-03-16 16:21:32 +00:00
FnPtr(FnSig),
2018-12-20 20:56:28 +00:00
/// The never type `!`.
2018-12-20 20:56:28 +00:00
Never,
/// A tuple type. For example, `(i32, bool)`.
Tuple(Arc<[Ty]>),
2018-12-20 20:56:28 +00:00
/// A type parameter; for example, `T` in `fn f<T>(x: T) {}
Param {
/// The index of the parameter (starting with parameters from the
/// surrounding impl, then the current function).
idx: u32,
/// The name of the parameter, for displaying.
name: Name,
},
2018-12-20 20:56:28 +00:00
/// A type variable used during type checking. Not to be confused with a
/// type parameter.
Infer(InferTy),
/// A placeholder for a type which could not be computed; this is propagated
/// to avoid useless error messages. Doubles as a placeholder where type
/// variables are inserted before type checking, since we want to try to
/// infer a better type here anyway -- for the IDE use case, we want to try
/// to infer as much as possible even in the presence of type errors.
2018-12-20 20:56:28 +00:00
Unknown,
}
/// A list of substitutions for generic parameters.
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Substs(Arc<[Ty]>);
impl Substs {
pub fn empty() -> Substs {
Substs(Arc::new([]))
}
2019-03-16 16:21:32 +00:00
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();
for t in &mut v {
t.walk_mut(f);
}
self.0 = v.into();
}
}
/// A function signature.
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct FnSig {
2019-03-16 16:21:32 +00:00
params_and_return: Arc<[Ty]>,
}
impl FnSig {
pub fn from_params_and_return(mut params: Vec<Ty>, ret: Ty) -> FnSig {
params.push(ret);
FnSig { params_and_return: params.into() }
}
pub fn params(&self) -> &[Ty] {
&self.params_and_return[0..self.params_and_return.len() - 1]
}
pub fn ret(&self) -> &Ty {
&self.params_and_return[self.params_and_return.len() - 1]
}
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();
for t in &mut v {
t.walk_mut(f);
}
self.params_and_return = v.into();
}
}
2018-12-20 20:56:28 +00:00
impl Ty {
pub fn unit() -> Self {
Ty::Tuple(Arc::new([]))
}
pub fn walk(&self, f: &mut impl FnMut(&Ty)) {
match self {
Ty::Slice(t) | Ty::Array(t) => t.walk(f),
Ty::RawPtr(t, _) => t.walk(f),
Ty::Ref(t, _) => t.walk(f),
Ty::Tuple(ts) => {
for t in ts.iter() {
t.walk(f);
}
}
Ty::FnPtr(sig) => {
2019-03-16 16:21:32 +00:00
for input in sig.params() {
input.walk(f);
}
2019-03-16 16:21:32 +00:00
sig.ret().walk(f);
}
Ty::FnDef { substs, .. } => {
for t in substs.0.iter() {
t.walk(f);
}
}
Ty::Adt { substs, .. } => {
for t in substs.0.iter() {
t.walk(f);
}
}
Ty::Bool
| Ty::Char
| Ty::Int(_)
| Ty::Float(_)
| Ty::Str
| Ty::Never
| Ty::Param { .. }
| Ty::Infer(_)
| Ty::Unknown => {}
}
2019-02-11 22:01:52 +00:00
f(self);
}
fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
match self {
2019-01-16 15:08:53 +00:00
Ty::Slice(t) | Ty::Array(t) => Arc::make_mut(t).walk_mut(f),
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();
}
Ty::FnPtr(sig) => {
2019-03-16 16:21:32 +00:00
sig.walk_mut(f);
}
Ty::FnDef { substs, .. } => {
2019-03-16 16:21:32 +00:00
substs.walk_mut(f);
2019-01-27 16:59:09 +00:00
}
Ty::Adt { substs, .. } => {
2019-03-16 16:21:32 +00:00
substs.walk_mut(f);
}
Ty::Bool
| Ty::Char
| Ty::Int(_)
| Ty::Float(_)
| Ty::Str
| Ty::Never
| Ty::Param { .. }
| Ty::Infer(_)
| Ty::Unknown => {}
}
2019-02-11 22:01:52 +00:00
f(self);
}
fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Ty {
self.walk_mut(&mut |ty_mut| {
let ty = mem::replace(ty_mut, Ty::Unknown);
*ty_mut = f(ty);
});
self
2018-12-20 20:56:28 +00:00
}
2019-01-06 18:51:42 +00:00
fn builtin_deref(&self) -> Option<Ty> {
match self {
Ty::Ref(t, _) => Some(Ty::clone(t)),
Ty::RawPtr(t, _) => Some(Ty::clone(t)),
_ => 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
/// `Option<u32>` afterwards.)
pub fn apply_substs(self, substs: Substs) -> Ty {
match self {
Ty::Adt { def_id, .. } => Ty::Adt { def_id, substs },
Ty::FnDef { def, .. } => Ty::FnDef { def, substs },
_ => self,
}
}
/// Replaces type parameters in this type using the given `Substs`. (So e.g.
/// if `self` is `&[T]`, where type parameter T has index 0, and the
/// `Substs` contain `u32` at index 0, we'll have `&[u32]` afterwards.)
pub fn subst(self, substs: &Substs) -> Ty {
self.fold(&mut |ty| match ty {
Ty::Param { idx, name } => {
if (idx as usize) < substs.0.len() {
substs.0[idx as usize].clone()
} else {
Ty::Param { idx, name }
}
}
ty => ty,
})
}
/// Returns the type parameters of this type if it has some (i.e. is an ADT
/// or function); so if `self` is `Option<u32>`, this returns the `u32`.
fn substs(&self) -> Option<Substs> {
match self {
2019-01-27 16:59:09 +00:00
Ty::Adt { substs, .. } | Ty::FnDef { substs, .. } => Some(substs.clone()),
_ => None,
}
}
2018-12-20 20:56:28 +00:00
}
impl HirDisplay for &Ty {
fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
HirDisplay::hir_fmt(*self, f)
}
}
impl HirDisplay for Ty {
fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
match self {
Ty::Bool => write!(f, "bool")?,
Ty::Char => write!(f, "char")?,
2019-03-16 15:50:31 +00:00
Ty::Int(t) => write!(f, "{}", t)?,
Ty::Float(t) => write!(f, "{}", t)?,
Ty::Str => write!(f, "str")?,
Ty::Slice(t) | Ty::Array(t) => {
write!(f, "[{}]", t.display(f.db))?;
}
Ty::RawPtr(t, m) => {
write!(f, "*{}{}", m.as_keyword_for_ptr(), t.display(f.db))?;
}
Ty::Ref(t, m) => {
write!(f, "&{}{}", m.as_keyword_for_ref(), t.display(f.db))?;
}
Ty::Never => write!(f, "!")?,
Ty::Tuple(ts) => {
2019-01-09 16:14:21 +00:00
if ts.len() == 1 {
write!(f, "({},)", ts[0].display(f.db))?;
2019-01-09 16:14:21 +00:00
} else {
write!(f, "(")?;
f.write_joined(&**ts, ", ")?;
write!(f, ")")?;
}
}
Ty::FnPtr(sig) => {
write!(f, "fn(")?;
2019-03-16 16:21:32 +00:00
f.write_joined(sig.params(), ", ")?;
write!(f, ") -> {}", sig.ret().display(f.db))?;
}
Ty::FnDef { def, substs, .. } => {
let sig = f.db.callable_item_signature(*def);
let name = match def {
CallableDef::Function(ff) => ff.name(f.db),
CallableDef::Struct(s) => s.name(f.db).unwrap_or_else(Name::missing),
CallableDef::EnumVariant(e) => e.name(f.db).unwrap_or_else(Name::missing),
};
match def {
CallableDef::Function(_) => write!(f, "fn {}", name)?,
CallableDef::Struct(_) | CallableDef::EnumVariant(_) => write!(f, "{}", name)?,
}
if substs.0.len() > 0 {
write!(f, "<")?;
f.write_joined(&*substs.0, ", ")?;
write!(f, ">")?;
}
write!(f, "(")?;
2019-03-16 16:21:32 +00:00
f.write_joined(sig.params(), ", ")?;
write!(f, ") -> {}", sig.ret().display(f.db))?;
}
Ty::Adt { def_id, substs, .. } => {
let name = match def_id {
AdtDef::Struct(s) => s.name(f.db),
AdtDef::Enum(e) => e.name(f.db),
}
.unwrap_or_else(Name::missing);
write!(f, "{}", name)?;
if substs.0.len() > 0 {
write!(f, "<")?;
f.write_joined(&*substs.0, ", ")?;
write!(f, ">")?;
}
}
Ty::Param { name, .. } => write!(f, "{}", name)?,
Ty::Unknown => write!(f, "{{unknown}}")?,
Ty::Infer(..) => write!(f, "_")?,
}
Ok(())
}
}