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

560 lines
18 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};
2019-03-17 17:20:51 +00:00
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum TypeName {
/// 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`.
Char,
/// A primitive integer type. For example, `i32`.
Int(primitive::UncertainIntTy),
/// A primitive floating-point type. For example, `f64`.
Float(primitive::UncertainFloatTy),
/// Structures, enumerations and unions.
Adt(AdtDef),
/// The pointee of a string slice. Written as `str`.
Str,
/// The pointee of an array slice. Written as `[T]`.
Slice,
/// An array with the given length. Written as `[T; n]`.
Array,
/// A raw pointer. Written as `*mut T` or `*const T`
RawPtr(Mutability),
/// A reference; a pointer with an associated lifetime. Written as
/// `&'a mut T` or `&'a T`.
Ref(Mutability),
/// 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(CallableDef),
/// 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;
/// ```
FnPtr,
/// The never type `!`.
Never,
/// A tuple type. For example, `(i32, bool)`.
Tuple,
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct ApplicationTy {
pub name: TypeName,
pub parameters: Substs,
}
/// 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 {
2019-03-17 17:20:51 +00:00
Apply(ApplicationTy),
2018-12-20 20:56:28 +00:00
/// 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 17:14:41 +00:00
FnPtr(Substs),
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)`.
2019-03-16 17:14:41 +00:00
Tuple(Substs),
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
2019-03-16 17:14:41 +00:00
pub fn iter(&self) -> impl Iterator<Item = &Ty> {
self.0.iter()
}
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();
}
2019-03-17 17:20:51 +00:00
pub fn as_single(&self) -> &Ty {
if self.0.len() != 1 {
panic!("expected substs of len 1, got {:?}", self);
}
&self.0[0]
}
}
/// 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() }
}
2019-03-16 17:14:41 +00:00
pub fn from_fn_ptr_substs(substs: &Substs) -> FnSig {
FnSig { params_and_return: Arc::clone(&substs.0) }
}
2019-03-16 16:21:32 +00:00
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 {
2019-03-17 17:20:51 +00:00
pub fn apply(name: TypeName, parameters: Substs) -> Ty {
Ty::Apply(ApplicationTy { name, parameters })
}
2018-12-20 20:56:28 +00:00
pub fn unit() -> Self {
2019-03-17 17:20:51 +00:00
Ty::apply(TypeName::Tuple, Substs::empty())
}
pub fn walk(&self, f: &mut impl FnMut(&Ty)) {
match self {
2019-03-17 17:20:51 +00:00
Ty::Apply(a_ty) => {
for t in a_ty.parameters.iter() {
t.walk(f);
}
}
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 17:14:41 +00:00
for t in sig.iter() {
t.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-03-17 17:20:51 +00:00
Ty::Apply(a_ty) => {
a_ty.parameters.walk_mut(f);
}
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) => {
2019-03-16 17:14:41 +00:00
ts.walk_mut(f);
}
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 {
2019-03-17 17:20:51 +00:00
Ty::Apply(a_ty) => match a_ty.name {
TypeName::Ref(..) => Some(Ty::clone(a_ty.parameters.as_single())),
TypeName::RawPtr(..) => Some(Ty::clone(a_ty.parameters.as_single())),
_ => None,
},
2019-01-06 18:51:42 +00:00
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 {
2019-03-17 17:20:51 +00:00
Ty::Apply(ApplicationTy { name, .. }) => {
Ty::Apply(ApplicationTy { name, parameters: substs })
}
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-03-17 17:20:51 +00:00
Ty::Apply(ApplicationTy { parameters, .. }) => Some(parameters.clone()),
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)
}
}
2019-03-17 17:20:51 +00:00
impl HirDisplay for ApplicationTy {
fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
match self.name {
TypeName::Bool => write!(f, "bool")?,
TypeName::Char => write!(f, "char")?,
TypeName::Int(t) => write!(f, "{}", t)?,
TypeName::Float(t) => write!(f, "{}", t)?,
TypeName::Str => write!(f, "str")?,
TypeName::Slice | TypeName::Array => {
let t = self.parameters.as_single();
write!(f, "[{}]", t.display(f.db))?;
}
TypeName::RawPtr(m) => {
let t = self.parameters.as_single();
write!(f, "*{}{}", m.as_keyword_for_ptr(), t.display(f.db))?;
}
TypeName::Ref(m) => {
let t = self.parameters.as_single();
write!(f, "&{}{}", m.as_keyword_for_ref(), t.display(f.db))?;
}
TypeName::Never => write!(f, "!")?,
TypeName::Tuple => {
let ts = &self.parameters;
if ts.0.len() == 1 {
write!(f, "({},)", ts.0[0].display(f.db))?;
} else {
write!(f, "(")?;
f.write_joined(&*ts.0, ", ")?;
write!(f, ")")?;
}
}
TypeName::FnPtr => {
let sig = FnSig::from_fn_ptr_substs(&self.parameters);
write!(f, "fn(")?;
f.write_joined(sig.params(), ", ")?;
write!(f, ") -> {}", sig.ret().display(f.db))?;
}
TypeName::FnDef(def) => {
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 self.parameters.0.len() > 0 {
write!(f, "<")?;
f.write_joined(&*self.parameters.0, ", ")?;
write!(f, ">")?;
}
write!(f, "(")?;
f.write_joined(sig.params(), ", ")?;
write!(f, ") -> {}", sig.ret().display(f.db))?;
}
TypeName::Adt(def_id) => {
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 self.parameters.0.len() > 0 {
write!(f, "<")?;
f.write_joined(&*self.parameters.0, ", ")?;
write!(f, ">")?;
}
}
}
Ok(())
}
}
impl HirDisplay for Ty {
fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
match self {
2019-03-17 17:20:51 +00:00
Ty::Apply(a_ty) => a_ty.hir_fmt(f)?,
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-03-16 17:14:41 +00:00
if ts.0.len() == 1 {
write!(f, "({},)", ts.0[0].display(f.db))?;
2019-01-09 16:14:21 +00:00
} else {
write!(f, "(")?;
2019-03-16 17:14:41 +00:00
f.write_joined(&*ts.0, ", ")?;
write!(f, ")")?;
}
}
Ty::FnPtr(sig) => {
2019-03-16 17:14:41 +00:00
let sig = FnSig::from_fn_ptr_substs(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(())
}
}