2018-12-20 14:56:28 -06:00
|
|
|
mod primitive;
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests;
|
|
|
|
|
|
|
|
use std::sync::Arc;
|
2018-12-23 05:05:54 -06:00
|
|
|
use std::fmt;
|
2018-12-20 14:56:28 -06:00
|
|
|
|
2018-12-23 10:13:11 -06:00
|
|
|
use log;
|
2018-12-23 05:15:46 -06:00
|
|
|
use rustc_hash::{FxHashMap};
|
|
|
|
|
2018-12-23 10:13:11 -06:00
|
|
|
use ra_db::{LocalSyntaxPtr, Cancelable};
|
2018-12-20 14:56:28 -06:00
|
|
|
use ra_syntax::{
|
2018-12-23 05:15:46 -06:00
|
|
|
SmolStr,
|
|
|
|
ast::{self, AstNode, LoopBodyOwner, ArgListOwner},
|
2018-12-20 14:56:28 -06:00
|
|
|
SyntaxNodeRef
|
|
|
|
};
|
|
|
|
|
2018-12-24 13:32:39 -06:00
|
|
|
use crate::{
|
2018-12-24 14:00:14 -06:00
|
|
|
Def, DefId, FnScopes, Module, Function, Struct, Path,
|
|
|
|
db::HirDatabase,
|
|
|
|
adt::VariantData,
|
2018-12-24 13:32:39 -06:00
|
|
|
};
|
2018-12-20 14:56:28 -06:00
|
|
|
|
2018-12-24 12:07:48 -06:00
|
|
|
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
2018-12-20 14:56:28 -06: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`.
|
|
|
|
Char,
|
|
|
|
|
|
|
|
/// A primitive signed integer type. For example, `i32`.
|
|
|
|
Int(primitive::IntTy),
|
|
|
|
|
|
|
|
/// A primitive unsigned integer type. For example, `u32`.
|
|
|
|
Uint(primitive::UintTy),
|
|
|
|
|
|
|
|
/// A primitive floating-point type. For example, `f64`.
|
|
|
|
Float(primitive::FloatTy),
|
|
|
|
|
2018-12-24 12:07:48 -06:00
|
|
|
/// Structures, enumerations and unions.
|
|
|
|
Adt {
|
|
|
|
/// The DefId of the struct/enum.
|
|
|
|
def_id: DefId,
|
|
|
|
/// The name, for displaying.
|
|
|
|
name: SmolStr,
|
|
|
|
// later we'll need generic substitutions here
|
|
|
|
},
|
|
|
|
|
2018-12-20 14:56:28 -06:00
|
|
|
/// The pointee of a string slice. Written as `str`.
|
|
|
|
Str,
|
|
|
|
|
2018-12-24 08:17:34 -06:00
|
|
|
// An array with the given length. Written as `[T; n]`.
|
|
|
|
// Array(Ty, ty::Const),
|
2018-12-20 14:56:28 -06:00
|
|
|
/// The pointee of an array slice. Written as `[T]`.
|
|
|
|
Slice(TyRef),
|
|
|
|
|
2018-12-24 08:17:34 -06:00
|
|
|
// A raw pointer. Written as `*mut T` or `*const T`
|
2018-12-20 14:56:28 -06:00
|
|
|
// RawPtr(TypeAndMut<'tcx>),
|
|
|
|
|
2018-12-24 08:17:34 -06:00
|
|
|
// A reference; a pointer with an associated lifetime. Written as
|
|
|
|
// `&'a mut T` or `&'a T`.
|
|
|
|
// Ref(Ty<'tcx>, hir::Mutability),
|
2018-12-20 14:56:28 -06: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;
|
|
|
|
/// ```
|
2018-12-23 10:13:11 -06:00
|
|
|
FnPtr(Arc<FnSig>),
|
2018-12-20 14:56:28 -06:00
|
|
|
|
2018-12-24 08:17:34 -06:00
|
|
|
// A trait, defined with `dyn trait`.
|
|
|
|
// Dynamic(),
|
2018-12-20 14:56:28 -06:00
|
|
|
/// The anonymous type of a closure. Used to represent the type of
|
|
|
|
/// `|a| a`.
|
|
|
|
// Closure(DefId, ClosureSubsts<'tcx>),
|
|
|
|
|
|
|
|
/// The anonymous type of a generator. Used to represent the type of
|
|
|
|
/// `|a| yield a`.
|
|
|
|
// Generator(DefId, GeneratorSubsts<'tcx>, hir::GeneratorMovability),
|
|
|
|
|
|
|
|
/// A type representin the types stored inside a generator.
|
|
|
|
/// This should only appear in GeneratorInteriors.
|
|
|
|
// GeneratorWitness(Binder<&'tcx List<Ty<'tcx>>>),
|
|
|
|
|
|
|
|
/// The never type `!`
|
|
|
|
Never,
|
|
|
|
|
|
|
|
/// A tuple type. For example, `(i32, bool)`.
|
|
|
|
Tuple(Vec<Ty>),
|
|
|
|
|
2018-12-24 08:17:34 -06:00
|
|
|
// The projection of an associated type. For example,
|
|
|
|
// `<T as Trait<..>>::N`.
|
|
|
|
// Projection(ProjectionTy),
|
2018-12-20 14:56:28 -06:00
|
|
|
|
2018-12-24 08:17:34 -06:00
|
|
|
// Opaque (`impl Trait`) type found in a return type.
|
|
|
|
// The `DefId` comes either from
|
|
|
|
// * the `impl Trait` ast::Ty node,
|
|
|
|
// * or the `existential type` declaration
|
|
|
|
// The substitutions are for the generics of the function in question.
|
|
|
|
// Opaque(DefId, Substs),
|
2018-12-20 14:56:28 -06:00
|
|
|
|
2018-12-24 08:17:34 -06:00
|
|
|
// A type parameter; for example, `T` in `fn f<T>(x: T) {}
|
2018-12-20 14:56:28 -06:00
|
|
|
// Param(ParamTy),
|
|
|
|
|
2018-12-24 08:17:34 -06:00
|
|
|
// A placeholder type - universally quantified higher-ranked type.
|
2018-12-20 14:56:28 -06:00
|
|
|
// Placeholder(ty::PlaceholderType),
|
|
|
|
|
2018-12-24 08:17:34 -06:00
|
|
|
// A type variable used during type checking.
|
2018-12-20 14:56:28 -06:00
|
|
|
// Infer(InferTy),
|
|
|
|
/// A placeholder for a type which could not be computed; this is
|
|
|
|
/// propagated to avoid useless error messages.
|
|
|
|
Unknown,
|
|
|
|
}
|
|
|
|
|
|
|
|
type TyRef = Arc<Ty>;
|
|
|
|
|
2018-12-24 12:07:48 -06:00
|
|
|
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
2018-12-23 10:13:11 -06:00
|
|
|
pub struct FnSig {
|
|
|
|
input: Vec<Ty>,
|
|
|
|
output: Ty,
|
|
|
|
}
|
|
|
|
|
2018-12-20 14:56:28 -06:00
|
|
|
impl Ty {
|
2018-12-24 14:00:14 -06:00
|
|
|
pub(crate) fn new_from_ast_path(
|
|
|
|
db: &impl HirDatabase,
|
|
|
|
module: &Module,
|
|
|
|
path: ast::Path,
|
|
|
|
) -> Cancelable<Self> {
|
|
|
|
let path = if let Some(p) = Path::from_ast(path) {
|
|
|
|
p
|
|
|
|
} else {
|
|
|
|
return Ok(Ty::Unknown);
|
|
|
|
};
|
|
|
|
if path.is_ident() {
|
|
|
|
let name = &path.segments[0];
|
|
|
|
if let Some(int_ty) = primitive::IntTy::from_string(&name) {
|
|
|
|
return Ok(Ty::Int(int_ty));
|
|
|
|
} else if let Some(uint_ty) = primitive::UintTy::from_string(&name) {
|
|
|
|
return Ok(Ty::Uint(uint_ty));
|
|
|
|
} else if let Some(float_ty) = primitive::FloatTy::from_string(&name) {
|
|
|
|
return Ok(Ty::Float(float_ty));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Resolve in module (in type namespace)
|
|
|
|
let resolved = if let Some(r) = module.resolve_path(db, path)?.take_types() {
|
|
|
|
r
|
|
|
|
} else {
|
|
|
|
return Ok(Ty::Unknown);
|
|
|
|
};
|
|
|
|
let ty = db.type_for_def(resolved)?;
|
|
|
|
Ok(ty)
|
|
|
|
}
|
|
|
|
|
2018-12-25 06:31:30 -06:00
|
|
|
pub(crate) fn new_opt(
|
|
|
|
db: &impl HirDatabase,
|
|
|
|
module: &Module,
|
|
|
|
node: Option<ast::TypeRef>,
|
|
|
|
) -> Cancelable<Self> {
|
|
|
|
node.map(|n| Ty::new(db, module, n))
|
|
|
|
.unwrap_or(Ok(Ty::Unknown))
|
|
|
|
}
|
|
|
|
|
2018-12-24 12:07:48 -06:00
|
|
|
pub(crate) fn new(
|
|
|
|
db: &impl HirDatabase,
|
|
|
|
module: &Module,
|
|
|
|
node: ast::TypeRef,
|
|
|
|
) -> Cancelable<Self> {
|
2018-12-20 14:56:28 -06:00
|
|
|
use ra_syntax::ast::TypeRef::*;
|
2018-12-23 10:33:02 -06:00
|
|
|
Ok(match node {
|
2018-12-20 14:56:28 -06:00
|
|
|
ParenType(_inner) => Ty::Unknown, // TODO
|
|
|
|
TupleType(_inner) => Ty::Unknown, // TODO
|
|
|
|
NeverType(..) => Ty::Never,
|
2018-12-22 15:17:55 -06:00
|
|
|
PathType(inner) => {
|
2018-12-24 14:00:14 -06:00
|
|
|
if let Some(path) = inner.path() {
|
|
|
|
Ty::new_from_ast_path(db, module, path)?
|
2018-12-23 05:15:46 -06:00
|
|
|
} else {
|
2018-12-24 14:00:14 -06:00
|
|
|
Ty::Unknown
|
2018-12-22 15:17:55 -06:00
|
|
|
}
|
2018-12-23 05:15:46 -06:00
|
|
|
}
|
|
|
|
PointerType(_inner) => Ty::Unknown, // TODO
|
|
|
|
ArrayType(_inner) => Ty::Unknown, // TODO
|
|
|
|
SliceType(_inner) => Ty::Unknown, // TODO
|
|
|
|
ReferenceType(_inner) => Ty::Unknown, // TODO
|
2018-12-20 14:56:28 -06:00
|
|
|
PlaceholderType(_inner) => Ty::Unknown, // TODO
|
2018-12-23 05:15:46 -06:00
|
|
|
FnPointerType(_inner) => Ty::Unknown, // TODO
|
|
|
|
ForType(_inner) => Ty::Unknown, // TODO
|
|
|
|
ImplTraitType(_inner) => Ty::Unknown, // TODO
|
|
|
|
DynTraitType(_inner) => Ty::Unknown, // TODO
|
2018-12-23 10:33:02 -06:00
|
|
|
})
|
2018-12-20 14:56:28 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn unit() -> Self {
|
|
|
|
Ty::Tuple(Vec::new())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-23 05:05:54 -06:00
|
|
|
impl fmt::Display for Ty {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
match self {
|
|
|
|
Ty::Bool => write!(f, "bool"),
|
|
|
|
Ty::Char => write!(f, "char"),
|
|
|
|
Ty::Int(t) => write!(f, "{}", t.ty_to_string()),
|
|
|
|
Ty::Uint(t) => write!(f, "{}", t.ty_to_string()),
|
|
|
|
Ty::Float(t) => write!(f, "{}", t.ty_to_string()),
|
|
|
|
Ty::Str => write!(f, "str"),
|
|
|
|
Ty::Slice(t) => write!(f, "[{}]", t),
|
|
|
|
Ty::Never => write!(f, "!"),
|
|
|
|
Ty::Tuple(ts) => {
|
|
|
|
write!(f, "(")?;
|
|
|
|
for t in ts {
|
|
|
|
write!(f, "{},", t)?;
|
|
|
|
}
|
|
|
|
write!(f, ")")
|
|
|
|
}
|
2018-12-23 10:13:11 -06:00
|
|
|
Ty::FnPtr(sig) => {
|
|
|
|
write!(f, "fn(")?;
|
|
|
|
for t in &sig.input {
|
|
|
|
write!(f, "{},", t)?;
|
|
|
|
}
|
|
|
|
write!(f, ") -> {}", sig.output)
|
|
|
|
}
|
2018-12-24 12:07:48 -06:00
|
|
|
Ty::Adt { name, .. } => write!(f, "{}", name),
|
2018-12-23 05:15:46 -06:00
|
|
|
Ty::Unknown => write!(f, "[unknown]"),
|
2018-12-23 05:05:54 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-23 10:13:11 -06:00
|
|
|
pub fn type_for_fn(db: &impl HirDatabase, f: Function) -> Cancelable<Ty> {
|
|
|
|
let syntax = f.syntax(db);
|
2018-12-24 12:07:48 -06:00
|
|
|
let module = f.module(db)?;
|
2018-12-23 10:13:11 -06:00
|
|
|
let node = syntax.borrowed();
|
|
|
|
// TODO we ignore type parameters for now
|
|
|
|
let input = node
|
|
|
|
.param_list()
|
|
|
|
.map(|pl| {
|
|
|
|
pl.params()
|
2018-12-23 10:33:02 -06:00
|
|
|
.map(|p| {
|
|
|
|
p.type_ref()
|
2018-12-24 12:07:48 -06:00
|
|
|
.map(|t| Ty::new(db, &module, t))
|
2018-12-23 10:33:02 -06:00
|
|
|
.unwrap_or(Ok(Ty::Unknown))
|
|
|
|
})
|
2018-12-23 10:13:11 -06:00
|
|
|
.collect()
|
|
|
|
})
|
2018-12-23 10:33:02 -06:00
|
|
|
.unwrap_or_else(|| Ok(Vec::new()))?;
|
2018-12-23 10:13:11 -06:00
|
|
|
let output = node
|
|
|
|
.ret_type()
|
|
|
|
.and_then(|rt| rt.type_ref())
|
2018-12-24 12:07:48 -06:00
|
|
|
.map(|t| Ty::new(db, &module, t))
|
2018-12-23 10:33:02 -06:00
|
|
|
.unwrap_or(Ok(Ty::Unknown))?;
|
2018-12-23 10:13:11 -06:00
|
|
|
let sig = FnSig { input, output };
|
|
|
|
Ok(Ty::FnPtr(Arc::new(sig)))
|
|
|
|
}
|
|
|
|
|
2018-12-24 14:00:14 -06:00
|
|
|
pub fn type_for_struct(db: &impl HirDatabase, s: Struct) -> Cancelable<Ty> {
|
|
|
|
Ok(Ty::Adt {
|
|
|
|
def_id: s.def_id(),
|
|
|
|
name: s.name(db)?,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-12-23 10:33:02 -06:00
|
|
|
// TODO this should probably be per namespace (i.e. types vs. values), since for
|
|
|
|
// a tuple struct `struct Foo(Bar)`, Foo has function type as a value, but
|
|
|
|
// defines the struct type Foo when used in the type namespace. rustc has a
|
|
|
|
// separate DefId for the constructor, but with the current DefId approach, that
|
|
|
|
// seems complicated.
|
2018-12-23 10:13:11 -06:00
|
|
|
pub fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Ty> {
|
|
|
|
let def = def_id.resolve(db)?;
|
|
|
|
match def {
|
|
|
|
Def::Module(..) => {
|
|
|
|
log::debug!("trying to get type for module {:?}", def_id);
|
|
|
|
Ok(Ty::Unknown)
|
|
|
|
}
|
|
|
|
Def::Function(f) => type_for_fn(db, f),
|
2018-12-24 14:00:14 -06:00
|
|
|
Def::Struct(s) => type_for_struct(db, s),
|
2018-12-24 12:07:48 -06:00
|
|
|
Def::Enum(e) => Ok(Ty::Adt {
|
|
|
|
def_id,
|
|
|
|
name: e.name(db)?,
|
|
|
|
}),
|
2018-12-23 10:13:11 -06:00
|
|
|
Def::Item => {
|
|
|
|
log::debug!("trying to get type for item of unknown type {:?}", def_id);
|
|
|
|
Ok(Ty::Unknown)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-20 14:56:28 -06:00
|
|
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
|
|
|
pub struct InferenceResult {
|
2018-12-24 08:19:49 -06:00
|
|
|
type_of: FxHashMap<LocalSyntaxPtr, Ty>,
|
2018-12-20 14:56:28 -06:00
|
|
|
}
|
|
|
|
|
2018-12-23 05:05:54 -06:00
|
|
|
impl InferenceResult {
|
|
|
|
pub fn type_of_node(&self, node: SyntaxNodeRef) -> Option<Ty> {
|
2018-12-24 08:19:49 -06:00
|
|
|
self.type_of.get(&LocalSyntaxPtr::new(node)).cloned()
|
2018-12-23 05:05:54 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-23 10:13:11 -06:00
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct InferenceContext<'a, D: HirDatabase> {
|
|
|
|
db: &'a D,
|
2018-12-20 14:56:28 -06:00
|
|
|
scopes: Arc<FnScopes>,
|
2018-12-23 10:13:11 -06:00
|
|
|
module: Module,
|
2018-12-20 14:56:28 -06:00
|
|
|
// TODO unification tables...
|
2018-12-24 08:19:49 -06:00
|
|
|
type_of: FxHashMap<LocalSyntaxPtr, Ty>,
|
2018-12-20 14:56:28 -06:00
|
|
|
}
|
|
|
|
|
2018-12-23 10:13:11 -06:00
|
|
|
impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|
|
|
fn new(db: &'a D, scopes: Arc<FnScopes>, module: Module) -> Self {
|
2018-12-20 14:56:28 -06:00
|
|
|
InferenceContext {
|
2018-12-24 08:19:49 -06:00
|
|
|
type_of: FxHashMap::default(),
|
2018-12-23 10:13:11 -06:00
|
|
|
db,
|
2018-12-23 05:15:46 -06:00
|
|
|
scopes,
|
2018-12-23 10:13:11 -06:00
|
|
|
module,
|
2018-12-20 14:56:28 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn write_ty(&mut self, node: SyntaxNodeRef, ty: Ty) {
|
2018-12-24 08:19:49 -06:00
|
|
|
self.type_of.insert(LocalSyntaxPtr::new(node), ty);
|
2018-12-20 14:56:28 -06:00
|
|
|
}
|
|
|
|
|
2018-12-23 06:22:29 -06:00
|
|
|
fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> Option<Ty> {
|
|
|
|
if *ty1 == Ty::Unknown {
|
|
|
|
return Some(ty2.clone());
|
|
|
|
}
|
|
|
|
if *ty2 == Ty::Unknown {
|
|
|
|
return Some(ty1.clone());
|
|
|
|
}
|
|
|
|
if ty1 == ty2 {
|
|
|
|
return Some(ty1.clone());
|
|
|
|
}
|
|
|
|
// TODO implement actual unification
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn unify_with_coercion(&mut self, ty1: &Ty, ty2: &Ty) -> Option<Ty> {
|
|
|
|
// TODO implement coercion
|
|
|
|
self.unify(ty1, ty2)
|
2018-12-20 14:56:28 -06:00
|
|
|
}
|
|
|
|
|
2018-12-23 10:13:11 -06:00
|
|
|
fn infer_path_expr(&mut self, expr: ast::PathExpr) -> Cancelable<Option<Ty>> {
|
|
|
|
let ast_path = ctry!(expr.path());
|
|
|
|
let path = ctry!(Path::from_ast(ast_path));
|
|
|
|
if path.is_ident() {
|
|
|
|
// resolve locally
|
|
|
|
let name = ctry!(ast_path.segment().and_then(|s| s.name_ref()));
|
|
|
|
if let Some(scope_entry) = self.scopes.resolve_local_name(name) {
|
2018-12-24 08:19:49 -06:00
|
|
|
let ty = ctry!(self.type_of.get(&scope_entry.ptr()));
|
2018-12-23 10:13:11 -06:00
|
|
|
return Ok(Some(ty.clone()));
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
// resolve in module
|
2018-12-24 14:00:14 -06:00
|
|
|
let resolved = ctry!(self.module.resolve_path(self.db, path)?.take_values());
|
2018-12-23 10:13:11 -06:00
|
|
|
let ty = self.db.type_for_def(resolved)?;
|
|
|
|
// TODO we will need to add type variables for type parameters etc. here
|
|
|
|
Ok(Some(ty))
|
2018-12-23 05:54:53 -06:00
|
|
|
}
|
|
|
|
|
2018-12-24 14:00:14 -06:00
|
|
|
fn resolve_variant(
|
|
|
|
&self,
|
|
|
|
path: Option<ast::Path>,
|
|
|
|
) -> Cancelable<(Ty, Option<Arc<VariantData>>)> {
|
|
|
|
let path = if let Some(path) = path.and_then(Path::from_ast) {
|
|
|
|
path
|
|
|
|
} else {
|
|
|
|
return Ok((Ty::Unknown, None));
|
|
|
|
};
|
|
|
|
let def_id = if let Some(def_id) = self.module.resolve_path(self.db, path)?.take_types() {
|
|
|
|
def_id
|
|
|
|
} else {
|
|
|
|
return Ok((Ty::Unknown, None));
|
|
|
|
};
|
|
|
|
Ok(match def_id.resolve(self.db)? {
|
|
|
|
Def::Struct(s) => {
|
|
|
|
let struct_data = self.db.struct_data(def_id)?;
|
|
|
|
let ty = type_for_struct(self.db, s)?;
|
|
|
|
(ty, Some(struct_data.variant_data().clone()))
|
|
|
|
}
|
|
|
|
_ => (Ty::Unknown, None),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-12-23 10:13:11 -06:00
|
|
|
fn infer_expr(&mut self, expr: ast::Expr) -> Cancelable<Ty> {
|
2018-12-20 14:56:28 -06:00
|
|
|
let ty = match expr {
|
|
|
|
ast::Expr::IfExpr(e) => {
|
|
|
|
if let Some(condition) = e.condition() {
|
|
|
|
if let Some(e) = condition.expr() {
|
|
|
|
// TODO if no pat, this should be bool
|
2018-12-23 10:13:11 -06:00
|
|
|
self.infer_expr(e)?;
|
2018-12-20 14:56:28 -06:00
|
|
|
}
|
|
|
|
// TODO write type for pat
|
|
|
|
};
|
|
|
|
let if_ty = if let Some(block) = e.then_branch() {
|
2018-12-23 10:13:11 -06:00
|
|
|
self.infer_block(block)?
|
2018-12-20 14:56:28 -06:00
|
|
|
} else {
|
|
|
|
Ty::Unknown
|
|
|
|
};
|
|
|
|
let else_ty = if let Some(block) = e.else_branch() {
|
2018-12-23 10:13:11 -06:00
|
|
|
self.infer_block(block)?
|
2018-12-20 14:56:28 -06:00
|
|
|
} else {
|
|
|
|
Ty::Unknown
|
|
|
|
};
|
2018-12-23 06:22:29 -06:00
|
|
|
if let Some(ty) = self.unify(&if_ty, &else_ty) {
|
|
|
|
ty
|
2018-12-20 14:56:28 -06:00
|
|
|
} else {
|
|
|
|
// TODO report diagnostic
|
|
|
|
Ty::Unknown
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast::Expr::BlockExpr(e) => {
|
|
|
|
if let Some(block) = e.block() {
|
2018-12-23 10:13:11 -06:00
|
|
|
self.infer_block(block)?
|
2018-12-20 14:56:28 -06:00
|
|
|
} else {
|
|
|
|
Ty::Unknown
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast::Expr::LoopExpr(e) => {
|
|
|
|
if let Some(block) = e.loop_body() {
|
2018-12-23 10:13:11 -06:00
|
|
|
self.infer_block(block)?;
|
2018-12-20 14:56:28 -06:00
|
|
|
};
|
|
|
|
// TODO never, or the type of the break param
|
|
|
|
Ty::Unknown
|
|
|
|
}
|
|
|
|
ast::Expr::WhileExpr(e) => {
|
|
|
|
if let Some(condition) = e.condition() {
|
|
|
|
if let Some(e) = condition.expr() {
|
|
|
|
// TODO if no pat, this should be bool
|
2018-12-23 10:13:11 -06:00
|
|
|
self.infer_expr(e)?;
|
2018-12-20 14:56:28 -06:00
|
|
|
}
|
|
|
|
// TODO write type for pat
|
|
|
|
};
|
|
|
|
if let Some(block) = e.loop_body() {
|
|
|
|
// TODO
|
2018-12-23 10:13:11 -06:00
|
|
|
self.infer_block(block)?;
|
2018-12-20 14:56:28 -06:00
|
|
|
};
|
|
|
|
// TODO always unit?
|
|
|
|
Ty::Unknown
|
|
|
|
}
|
|
|
|
ast::Expr::ForExpr(e) => {
|
|
|
|
if let Some(expr) = e.iterable() {
|
2018-12-23 10:13:11 -06:00
|
|
|
self.infer_expr(expr)?;
|
2018-12-20 14:56:28 -06:00
|
|
|
}
|
2018-12-23 05:15:46 -06:00
|
|
|
if let Some(_pat) = e.pat() {
|
2018-12-20 14:56:28 -06:00
|
|
|
// TODO write type for pat
|
|
|
|
}
|
|
|
|
if let Some(block) = e.loop_body() {
|
2018-12-23 10:13:11 -06:00
|
|
|
self.infer_block(block)?;
|
2018-12-20 14:56:28 -06:00
|
|
|
}
|
|
|
|
// TODO always unit?
|
|
|
|
Ty::Unknown
|
|
|
|
}
|
|
|
|
ast::Expr::LambdaExpr(e) => {
|
2018-12-23 05:15:46 -06:00
|
|
|
let _body_ty = if let Some(body) = e.body() {
|
2018-12-23 10:13:11 -06:00
|
|
|
self.infer_expr(body)?
|
2018-12-20 14:56:28 -06:00
|
|
|
} else {
|
|
|
|
Ty::Unknown
|
|
|
|
};
|
|
|
|
Ty::Unknown
|
|
|
|
}
|
|
|
|
ast::Expr::CallExpr(e) => {
|
2018-12-23 10:16:47 -06:00
|
|
|
let callee_ty = if let Some(e) = e.expr() {
|
2018-12-23 10:13:11 -06:00
|
|
|
self.infer_expr(e)?
|
|
|
|
} else {
|
|
|
|
Ty::Unknown
|
|
|
|
};
|
2018-12-20 14:56:28 -06:00
|
|
|
if let Some(arg_list) = e.arg_list() {
|
|
|
|
for arg in arg_list.args() {
|
|
|
|
// TODO unify / expect argument type
|
2018-12-23 10:13:11 -06:00
|
|
|
self.infer_expr(arg)?;
|
2018-12-20 14:56:28 -06:00
|
|
|
}
|
|
|
|
}
|
2018-12-23 10:16:47 -06:00
|
|
|
match callee_ty {
|
2018-12-23 10:33:02 -06:00
|
|
|
Ty::FnPtr(sig) => sig.output.clone(),
|
2018-12-23 10:16:47 -06:00
|
|
|
_ => {
|
|
|
|
// not callable
|
|
|
|
// TODO report an error?
|
|
|
|
Ty::Unknown
|
|
|
|
}
|
|
|
|
}
|
2018-12-20 14:56:28 -06:00
|
|
|
}
|
|
|
|
ast::Expr::MethodCallExpr(e) => {
|
2018-12-23 10:13:11 -06:00
|
|
|
let _receiver_ty = if let Some(e) = e.expr() {
|
|
|
|
self.infer_expr(e)?
|
|
|
|
} else {
|
|
|
|
Ty::Unknown
|
|
|
|
};
|
2018-12-20 14:56:28 -06:00
|
|
|
if let Some(arg_list) = e.arg_list() {
|
|
|
|
for arg in arg_list.args() {
|
|
|
|
// TODO unify / expect argument type
|
2018-12-23 10:13:11 -06:00
|
|
|
self.infer_expr(arg)?;
|
2018-12-20 14:56:28 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Ty::Unknown
|
|
|
|
}
|
|
|
|
ast::Expr::MatchExpr(e) => {
|
2018-12-23 05:15:46 -06:00
|
|
|
let _ty = if let Some(match_expr) = e.expr() {
|
2018-12-23 10:13:11 -06:00
|
|
|
self.infer_expr(match_expr)?
|
2018-12-20 14:56:28 -06:00
|
|
|
} else {
|
|
|
|
Ty::Unknown
|
|
|
|
};
|
|
|
|
if let Some(match_arm_list) = e.match_arm_list() {
|
|
|
|
for arm in match_arm_list.arms() {
|
|
|
|
// TODO type the bindings in pat
|
|
|
|
// TODO type the guard
|
2018-12-23 05:15:46 -06:00
|
|
|
let _ty = if let Some(e) = arm.expr() {
|
2018-12-23 10:13:11 -06:00
|
|
|
self.infer_expr(e)?
|
2018-12-20 14:56:28 -06:00
|
|
|
} else {
|
|
|
|
Ty::Unknown
|
|
|
|
};
|
|
|
|
}
|
|
|
|
// TODO unify all the match arm types
|
|
|
|
Ty::Unknown
|
|
|
|
} else {
|
|
|
|
Ty::Unknown
|
|
|
|
}
|
|
|
|
}
|
2018-12-23 05:15:46 -06:00
|
|
|
ast::Expr::TupleExpr(_e) => Ty::Unknown,
|
|
|
|
ast::Expr::ArrayExpr(_e) => Ty::Unknown,
|
2018-12-23 10:13:11 -06:00
|
|
|
ast::Expr::PathExpr(e) => self.infer_path_expr(e)?.unwrap_or(Ty::Unknown),
|
2018-12-23 05:15:46 -06:00
|
|
|
ast::Expr::ContinueExpr(_e) => Ty::Never,
|
|
|
|
ast::Expr::BreakExpr(_e) => Ty::Never,
|
2018-12-20 14:56:28 -06:00
|
|
|
ast::Expr::ParenExpr(e) => {
|
|
|
|
if let Some(e) = e.expr() {
|
2018-12-23 10:13:11 -06:00
|
|
|
self.infer_expr(e)?
|
2018-12-20 14:56:28 -06:00
|
|
|
} else {
|
|
|
|
Ty::Unknown
|
|
|
|
}
|
|
|
|
}
|
2018-12-23 05:15:46 -06:00
|
|
|
ast::Expr::Label(_e) => Ty::Unknown,
|
2018-12-20 14:56:28 -06:00
|
|
|
ast::Expr::ReturnExpr(e) => {
|
|
|
|
if let Some(e) = e.expr() {
|
2018-12-24 14:00:14 -06:00
|
|
|
// TODO unify with / expect return type
|
2018-12-23 10:13:11 -06:00
|
|
|
self.infer_expr(e)?;
|
2018-12-20 14:56:28 -06:00
|
|
|
};
|
|
|
|
Ty::Never
|
|
|
|
}
|
|
|
|
ast::Expr::MatchArmList(_) | ast::Expr::MatchArm(_) | ast::Expr::MatchGuard(_) => {
|
|
|
|
// Can this even occur outside of a match expression?
|
|
|
|
Ty::Unknown
|
|
|
|
}
|
2018-12-24 14:00:14 -06:00
|
|
|
ast::Expr::StructLit(e) => {
|
2018-12-25 06:31:30 -06:00
|
|
|
let (ty, _variant_data) = self.resolve_variant(e.path())?;
|
2018-12-24 14:00:14 -06:00
|
|
|
if let Some(nfl) = e.named_field_list() {
|
|
|
|
for field in nfl.fields() {
|
|
|
|
if let Some(e) = field.expr() {
|
|
|
|
// TODO unify with / expect field type
|
|
|
|
self.infer_expr(e)?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ty
|
|
|
|
}
|
2018-12-20 14:56:28 -06:00
|
|
|
ast::Expr::NamedFieldList(_) | ast::Expr::NamedField(_) => {
|
|
|
|
// Can this even occur outside of a struct literal?
|
|
|
|
Ty::Unknown
|
|
|
|
}
|
2018-12-23 05:15:46 -06:00
|
|
|
ast::Expr::IndexExpr(_e) => Ty::Unknown,
|
|
|
|
ast::Expr::FieldExpr(_e) => Ty::Unknown,
|
2018-12-20 14:56:28 -06:00
|
|
|
ast::Expr::TryExpr(e) => {
|
2018-12-23 05:15:46 -06:00
|
|
|
let _inner_ty = if let Some(e) = e.expr() {
|
2018-12-23 10:13:11 -06:00
|
|
|
self.infer_expr(e)?
|
2018-12-20 14:56:28 -06:00
|
|
|
} else {
|
|
|
|
Ty::Unknown
|
|
|
|
};
|
|
|
|
Ty::Unknown
|
|
|
|
}
|
|
|
|
ast::Expr::CastExpr(e) => {
|
2018-12-23 05:15:46 -06:00
|
|
|
let _inner_ty = if let Some(e) = e.expr() {
|
2018-12-23 10:13:11 -06:00
|
|
|
self.infer_expr(e)?
|
2018-12-20 14:56:28 -06:00
|
|
|
} else {
|
|
|
|
Ty::Unknown
|
|
|
|
};
|
2018-12-23 10:33:02 -06:00
|
|
|
let cast_ty = e
|
|
|
|
.type_ref()
|
2018-12-24 12:07:48 -06:00
|
|
|
.map(|t| Ty::new(self.db, &self.module, t))
|
2018-12-23 10:33:02 -06:00
|
|
|
.unwrap_or(Ok(Ty::Unknown))?;
|
2018-12-20 14:56:28 -06:00
|
|
|
// TODO do the coercion...
|
|
|
|
cast_ty
|
|
|
|
}
|
|
|
|
ast::Expr::RefExpr(e) => {
|
2018-12-23 05:15:46 -06:00
|
|
|
let _inner_ty = if let Some(e) = e.expr() {
|
2018-12-23 10:13:11 -06:00
|
|
|
self.infer_expr(e)?
|
2018-12-20 14:56:28 -06:00
|
|
|
} else {
|
|
|
|
Ty::Unknown
|
|
|
|
};
|
|
|
|
Ty::Unknown
|
|
|
|
}
|
|
|
|
ast::Expr::PrefixExpr(e) => {
|
2018-12-23 05:15:46 -06:00
|
|
|
let _inner_ty = if let Some(e) = e.expr() {
|
2018-12-23 10:13:11 -06:00
|
|
|
self.infer_expr(e)?
|
2018-12-20 14:56:28 -06:00
|
|
|
} else {
|
|
|
|
Ty::Unknown
|
|
|
|
};
|
|
|
|
Ty::Unknown
|
|
|
|
}
|
2018-12-23 05:15:46 -06:00
|
|
|
ast::Expr::RangeExpr(_e) => Ty::Unknown,
|
|
|
|
ast::Expr::BinExpr(_e) => Ty::Unknown,
|
|
|
|
ast::Expr::Literal(_e) => Ty::Unknown,
|
2018-12-20 14:56:28 -06:00
|
|
|
};
|
|
|
|
self.write_ty(expr.syntax(), ty.clone());
|
2018-12-23 10:13:11 -06:00
|
|
|
Ok(ty)
|
2018-12-20 14:56:28 -06:00
|
|
|
}
|
|
|
|
|
2018-12-23 10:13:11 -06:00
|
|
|
fn infer_block(&mut self, node: ast::Block) -> Cancelable<Ty> {
|
2018-12-20 14:56:28 -06:00
|
|
|
for stmt in node.statements() {
|
|
|
|
match stmt {
|
|
|
|
ast::Stmt::LetStmt(stmt) => {
|
2018-12-23 06:22:29 -06:00
|
|
|
let decl_ty = if let Some(type_ref) = stmt.type_ref() {
|
2018-12-24 12:07:48 -06:00
|
|
|
Ty::new(self.db, &self.module, type_ref)?
|
2018-12-23 06:22:29 -06:00
|
|
|
} else {
|
|
|
|
Ty::Unknown
|
|
|
|
};
|
|
|
|
let ty = if let Some(expr) = stmt.initializer() {
|
|
|
|
// TODO pass expectation
|
2018-12-23 10:13:11 -06:00
|
|
|
let expr_ty = self.infer_expr(expr)?;
|
2018-12-23 06:22:29 -06:00
|
|
|
self.unify_with_coercion(&expr_ty, &decl_ty)
|
|
|
|
.unwrap_or(decl_ty)
|
|
|
|
} else {
|
|
|
|
decl_ty
|
|
|
|
};
|
|
|
|
|
|
|
|
if let Some(pat) = stmt.pat() {
|
|
|
|
self.write_ty(pat.syntax(), ty);
|
|
|
|
};
|
2018-12-20 14:56:28 -06:00
|
|
|
}
|
|
|
|
ast::Stmt::ExprStmt(expr_stmt) => {
|
|
|
|
if let Some(expr) = expr_stmt.expr() {
|
2018-12-23 10:13:11 -06:00
|
|
|
self.infer_expr(expr)?;
|
2018-12-20 14:56:28 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let ty = if let Some(expr) = node.expr() {
|
2018-12-23 10:13:11 -06:00
|
|
|
self.infer_expr(expr)?
|
2018-12-20 14:56:28 -06:00
|
|
|
} else {
|
|
|
|
Ty::unit()
|
|
|
|
};
|
|
|
|
self.write_ty(node.syntax(), ty.clone());
|
2018-12-23 10:13:11 -06:00
|
|
|
Ok(ty)
|
2018-12-20 14:56:28 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-23 10:13:11 -06:00
|
|
|
pub fn infer(db: &impl HirDatabase, function: Function) -> Cancelable<InferenceResult> {
|
|
|
|
let scopes = function.scopes(db);
|
|
|
|
let module = function.module(db)?;
|
|
|
|
let mut ctx = InferenceContext::new(db, scopes, module);
|
|
|
|
|
|
|
|
let syntax = function.syntax(db);
|
|
|
|
let node = syntax.borrowed();
|
2018-12-20 14:56:28 -06:00
|
|
|
|
2018-12-23 05:59:38 -06:00
|
|
|
if let Some(param_list) = node.param_list() {
|
|
|
|
for param in param_list.params() {
|
|
|
|
let pat = if let Some(pat) = param.pat() {
|
|
|
|
pat
|
|
|
|
} else {
|
|
|
|
continue;
|
|
|
|
};
|
|
|
|
if let Some(type_ref) = param.type_ref() {
|
2018-12-24 12:07:48 -06:00
|
|
|
let ty = Ty::new(db, &ctx.module, type_ref)?;
|
2018-12-24 08:19:49 -06:00
|
|
|
ctx.type_of.insert(LocalSyntaxPtr::new(pat.syntax()), ty);
|
2018-12-23 05:59:38 -06:00
|
|
|
} else {
|
|
|
|
// TODO self param
|
2018-12-24 08:19:49 -06:00
|
|
|
ctx.type_of
|
2018-12-23 05:59:38 -06:00
|
|
|
.insert(LocalSyntaxPtr::new(pat.syntax()), Ty::Unknown);
|
|
|
|
};
|
|
|
|
}
|
2018-12-20 14:56:28 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO get Ty for node.ret_type() and pass that to infer_block as expectation
|
|
|
|
// (see Expectation in rustc_typeck)
|
|
|
|
|
2018-12-23 05:59:38 -06:00
|
|
|
if let Some(block) = node.body() {
|
2018-12-23 10:13:11 -06:00
|
|
|
ctx.infer_block(block)?;
|
2018-12-23 05:59:38 -06:00
|
|
|
}
|
2018-12-20 14:56:28 -06:00
|
|
|
|
|
|
|
// TODO 'resolve' the types: replace inference variables by their inferred results
|
|
|
|
|
2018-12-23 10:13:11 -06:00
|
|
|
Ok(InferenceResult {
|
2018-12-24 08:19:49 -06:00
|
|
|
type_of: ctx.type_of,
|
2018-12-23 10:13:11 -06:00
|
|
|
})
|
2018-12-20 14:56:28 -06:00
|
|
|
}
|