Remove the old variants replaced by Ty::Apply

This commit is contained in:
Florian Diebold 2019-03-17 19:37:09 +01:00
parent 7a8ba53542
commit 8a5fbf4713
12 changed files with 265 additions and 403 deletions

View file

@ -1,7 +1,7 @@
use std::fmt::Write; use std::fmt::Write;
use hir::{ use hir::{
AdtDef, Ty, FieldSource, source_binder, AdtDef, FieldSource, source_binder,
db::HirDatabase, db::HirDatabase,
}; };
use ra_syntax::ast::{self, AstNode}; use ra_syntax::ast::{self, AstNode};
@ -26,14 +26,10 @@ pub(crate) fn fill_match_arms(mut ctx: AssistCtx<impl HirDatabase>) -> Option<As
let source_map = function.body_source_map(ctx.db); let source_map = function.body_source_map(ctx.db);
let node_expr = source_map.node_expr(expr)?; let node_expr = source_map.node_expr(expr)?;
let match_expr_ty = infer_result[node_expr].clone(); let match_expr_ty = infer_result[node_expr].clone();
let enum_def = match match_expr_ty { let enum_def = match_expr_ty.autoderef(ctx.db).find_map(|ty| match ty.as_adt() {
Ty::Adt { def_id: AdtDef::Enum(e), .. } => e, Some((AdtDef::Enum(e), _)) => Some(e),
Ty::Ref(adt, _) => match *adt { _ => None,
Ty::Adt { def_id: AdtDef::Enum(e), .. } => e, })?;
_ => return None,
},
_ => return None,
};
let enum_name = enum_def.name(ctx.db)?; let enum_name = enum_def.name(ctx.db)?;
let db = ctx.db; let db = ctx.db;

View file

@ -1,6 +1,6 @@
use std::fmt::Write; use std::fmt::Write;
use hir::{AdtDef, Ty, db::HirDatabase, source_binder::function_from_child_node}; use hir::{AdtDef, db::HirDatabase, source_binder::function_from_child_node};
use ra_syntax::ast::{self, AstNode}; use ra_syntax::ast::{self, AstNode};
@ -60,8 +60,8 @@ where
let source_map = function.body_source_map(self.ctx.db); let source_map = function.body_source_map(self.ctx.db);
let node_expr = source_map.node_expr(self.struct_lit.into())?; let node_expr = source_map.node_expr(self.struct_lit.into())?;
let struct_lit_ty = infer_result[node_expr].clone(); let struct_lit_ty = infer_result[node_expr].clone();
let struct_def = match struct_lit_ty { let struct_def = match struct_lit_ty.as_adt() {
Ty::Adt { def_id: AdtDef::Struct(s), .. } => s, Some((AdtDef::Struct(s), _)) => s,
_ => return None, _ => return None,
}; };
self.struct_fields = struct_def self.struct_fields = struct_def

View file

@ -53,7 +53,7 @@ pub use self::{
name::Name, name::Name,
ids::{HirFileId, MacroCallId, MacroCallLoc, HirInterner}, ids::{HirFileId, MacroCallId, MacroCallLoc, HirInterner},
nameres::{PerNs, Namespace}, nameres::{PerNs, Namespace},
ty::{Ty, Substs, display::HirDisplay}, ty::{Ty, ApplicationTy, TypeName, Substs, display::HirDisplay},
impl_block::{ImplBlock, ImplItem}, impl_block::{ImplBlock, ImplItem},
docs::{Docs, Documentation}, docs::{Docs, Documentation},
adt::AdtDef, adt::AdtDef,

View file

@ -20,7 +20,7 @@ pub(crate) use lower::{TypableDef, CallableDef, type_for_def, type_for_field, ca
pub(crate) use infer::{infer, InferenceResult, InferTy}; pub(crate) use infer::{infer, InferenceResult, InferTy};
use display::{HirDisplay, HirFormatter}; use display::{HirDisplay, HirFormatter};
#[derive(Copy, Clone, PartialEq, Eq, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub enum TypeName { pub enum TypeName {
/// The primitive boolean type. Written as `bool`. /// The primitive boolean type. Written as `bool`.
Bool, Bool,
@ -96,80 +96,11 @@ pub struct ApplicationTy {
/// This should be cheap to clone. /// This should be cheap to clone.
#[derive(Clone, PartialEq, Eq, Debug)] #[derive(Clone, PartialEq, Eq, Debug)]
pub enum Ty { pub enum Ty {
/// A nominal type with (maybe 0) type parameters. This might be a primitive
/// type like `bool`, a struct, tuple, function pointer, reference or
/// several other things.
Apply(ApplicationTy), Apply(ApplicationTy),
/// 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 {
/// The definition of the struct/enum.
def_id: AdtDef,
/// Substitutions for the generic parameters of the type.
substs: Substs,
},
/// The pointee of a string slice. Written as `str`.
Str,
/// The pointee of an array slice. Written as `[T]`.
Slice(Arc<Ty>),
/// An array with the given length. Written as `[T; n]`.
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),
/// 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
substs: Substs,
},
/// 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(Substs),
/// The never type `!`.
Never,
/// A tuple type. For example, `(i32, bool)`.
Tuple(Substs),
/// A type parameter; for example, `T` in `fn f<T>(x: T) {} /// A type parameter; for example, `T` in `fn f<T>(x: T) {}
Param { Param {
/// The index of the parameter (starting with parameters from the /// The index of the parameter (starting with parameters from the
@ -200,6 +131,10 @@ impl Substs {
Substs(Arc::new([])) Substs(Arc::new([]))
} }
pub fn single(ty: Ty) -> Substs {
Substs(Arc::new([ty]))
}
pub fn iter(&self) -> impl Iterator<Item = &Ty> { pub fn iter(&self) -> impl Iterator<Item = &Ty> {
self.0.iter() self.0.iter()
} }
@ -256,6 +191,12 @@ impl FnSig {
} }
impl Ty { impl Ty {
pub fn simple(name: TypeName) -> Ty {
Ty::Apply(ApplicationTy { name, parameters: Substs::empty() })
}
pub fn apply_one(name: TypeName, param: Ty) -> Ty {
Ty::Apply(ApplicationTy { name, parameters: Substs::single(param) })
}
pub fn apply(name: TypeName, parameters: Substs) -> Ty { pub fn apply(name: TypeName, parameters: Substs) -> Ty {
Ty::Apply(ApplicationTy { name, parameters }) Ty::Apply(ApplicationTy { name, parameters })
} }
@ -270,38 +211,7 @@ impl Ty {
t.walk(f); t.walk(f);
} }
} }
Ty::Slice(t) | Ty::Array(t) => t.walk(f), Ty::Param { .. } | Ty::Infer(_) | Ty::Unknown => {}
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) => {
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 => {}
} }
f(self); f(self);
} }
@ -311,30 +221,7 @@ impl Ty {
Ty::Apply(a_ty) => { Ty::Apply(a_ty) => {
a_ty.parameters.walk_mut(f); a_ty.parameters.walk_mut(f);
} }
Ty::Slice(t) | Ty::Array(t) => Arc::make_mut(t).walk_mut(f), Ty::Param { .. } | Ty::Infer(_) | Ty::Unknown => {}
Ty::RawPtr(t, _) => Arc::make_mut(t).walk_mut(f),
Ty::Ref(t, _) => Arc::make_mut(t).walk_mut(f),
Ty::Tuple(ts) => {
ts.walk_mut(f);
}
Ty::FnPtr(sig) => {
sig.walk_mut(f);
}
Ty::FnDef { substs, .. } => {
substs.walk_mut(f);
}
Ty::Adt { substs, .. } => {
substs.walk_mut(f);
}
Ty::Bool
| Ty::Char
| Ty::Int(_)
| Ty::Float(_)
| Ty::Str
| Ty::Never
| Ty::Param { .. }
| Ty::Infer(_)
| Ty::Unknown => {}
} }
f(self); f(self);
} }
@ -347,6 +234,31 @@ impl Ty {
self self
} }
pub fn as_reference(&self) -> Option<(&Ty, Mutability)> {
match self {
Ty::Apply(ApplicationTy { name: TypeName::Ref(mutability), parameters }) => {
Some((parameters.as_single(), *mutability))
}
_ => None,
}
}
pub fn as_adt(&self) -> Option<(AdtDef, &Substs)> {
match self {
Ty::Apply(ApplicationTy { name: TypeName::Adt(adt_def), parameters }) => {
Some((*adt_def, parameters))
}
_ => None,
}
}
pub fn as_tuple(&self) -> Option<&Substs> {
match self {
Ty::Apply(ApplicationTy { name: TypeName::Tuple, parameters }) => Some(parameters),
_ => None,
}
}
fn builtin_deref(&self) -> Option<Ty> { fn builtin_deref(&self) -> Option<Ty> {
match self { match self {
Ty::Apply(a_ty) => match a_ty.name { Ty::Apply(a_ty) => match a_ty.name {
@ -354,8 +266,6 @@ impl Ty {
TypeName::RawPtr(..) => Some(Ty::clone(a_ty.parameters.as_single())), TypeName::RawPtr(..) => Some(Ty::clone(a_ty.parameters.as_single())),
_ => None, _ => None,
}, },
Ty::Ref(t, _) => Some(Ty::clone(t)),
Ty::RawPtr(t, _) => Some(Ty::clone(t)),
_ => None, _ => None,
} }
} }
@ -369,8 +279,6 @@ impl Ty {
Ty::Apply(ApplicationTy { name, .. }) => { Ty::Apply(ApplicationTy { name, .. }) => {
Ty::Apply(ApplicationTy { name, parameters: substs }) Ty::Apply(ApplicationTy { name, parameters: substs })
} }
Ty::Adt { def_id, .. } => Ty::Adt { def_id, substs },
Ty::FnDef { def, .. } => Ty::FnDef { def, substs },
_ => self, _ => self,
} }
} }
@ -396,7 +304,6 @@ impl Ty {
fn substs(&self) -> Option<Substs> { fn substs(&self) -> Option<Substs> {
match self { match self {
Ty::Apply(ApplicationTy { parameters, .. }) => Some(parameters.clone()), Ty::Apply(ApplicationTy { parameters, .. }) => Some(parameters.clone()),
Ty::Adt { substs, .. } | Ty::FnDef { substs, .. } => Some(substs.clone()),
_ => None, _ => None,
} }
} }
@ -487,69 +394,6 @@ impl HirDisplay for Ty {
fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
match self { match self {
Ty::Apply(a_ty) => a_ty.hir_fmt(f)?, Ty::Apply(a_ty) => a_ty.hir_fmt(f)?,
Ty::Bool => write!(f, "bool")?,
Ty::Char => write!(f, "char")?,
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) => {
if ts.0.len() == 1 {
write!(f, "({},)", ts.0[0].display(f.db))?;
} else {
write!(f, "(")?;
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))?;
}
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, "(")?;
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::Param { name, .. } => write!(f, "{}", name)?,
Ty::Unknown => write!(f, "{{unknown}}")?, Ty::Unknown => write!(f, "{{unknown}}")?,
Ty::Infer(..) => write!(f, "_")?, Ty::Infer(..) => write!(f, "_")?,

View file

@ -38,7 +38,7 @@ use crate::{
resolve::{Resolver, Resolution}, resolve::{Resolver, Resolution},
nameres::Namespace nameres::Namespace
}; };
use super::{Ty, TypableDef, Substs, primitive, op, FnSig}; use super::{Ty, TypableDef, Substs, primitive, op, FnSig, ApplicationTy, TypeName};
/// The entry point of type inference. /// The entry point of type inference.
pub fn infer(db: &impl HirDatabase, func: Function) -> Arc<InferenceResult> { pub fn infer(db: &impl HirDatabase, func: Function) -> Arc<InferenceResult> {
@ -237,28 +237,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
match (&*ty1, &*ty2) { match (&*ty1, &*ty2) {
(Ty::Unknown, ..) => true, (Ty::Unknown, ..) => true,
(.., Ty::Unknown) => true, (.., Ty::Unknown) => true,
(Ty::Int(t1), Ty::Int(t2)) => match (t1, t2) { (Ty::Apply(a_ty1), Ty::Apply(a_ty2)) if a_ty1.name == a_ty2.name => {
(primitive::UncertainIntTy::Unknown, _) self.unify_substs(&a_ty1.parameters, &a_ty2.parameters, depth + 1)
| (_, primitive::UncertainIntTy::Unknown) => true,
_ => t1 == t2,
},
(Ty::Float(t1), Ty::Float(t2)) => match (t1, t2) {
(primitive::UncertainFloatTy::Unknown, _)
| (_, primitive::UncertainFloatTy::Unknown) => true,
_ => t1 == t2,
},
(Ty::Bool, _) | (Ty::Str, _) | (Ty::Never, _) | (Ty::Char, _) => ty1 == ty2,
(
Ty::Adt { def_id: def_id1, substs: substs1, .. },
Ty::Adt { def_id: def_id2, substs: substs2, .. },
) if def_id1 == def_id2 => self.unify_substs(substs1, substs2, depth + 1),
(Ty::Slice(t1), Ty::Slice(t2)) => self.unify_inner(t1, t2, depth + 1),
(Ty::RawPtr(t1, m1), Ty::RawPtr(t2, m2)) if m1 == m2 => {
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)) => 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::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2)))
| (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2))) | (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2)))
| (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2))) => { | (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2))) => {
@ -296,8 +277,14 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty {
match ty { match ty {
Ty::Unknown => self.new_type_var(), Ty::Unknown => self.new_type_var(),
Ty::Int(primitive::UncertainIntTy::Unknown) => self.new_integer_var(), Ty::Apply(ApplicationTy {
Ty::Float(primitive::UncertainFloatTy::Unknown) => self.new_float_var(), name: TypeName::Int(primitive::UncertainIntTy::Unknown),
..
}) => self.new_integer_var(),
Ty::Apply(ApplicationTy {
name: TypeName::Float(primitive::UncertainFloatTy::Unknown),
..
}) => self.new_float_var(),
_ => ty, _ => ty,
} }
} }
@ -608,12 +595,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Missing => false, Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Missing => false,
}; };
if is_non_ref_pat { if is_non_ref_pat {
while let Ty::Ref(inner, mutability) = expected { while let Some((inner, mutability)) = expected.as_reference() {
expected = inner; expected = inner;
default_bm = match default_bm { default_bm = match default_bm {
BindingMode::Move => BindingMode::Ref(*mutability), BindingMode::Move => BindingMode::Ref(mutability),
BindingMode::Ref(Mutability::Shared) => BindingMode::Ref(Mutability::Shared), BindingMode::Ref(Mutability::Shared) => BindingMode::Ref(Mutability::Shared),
BindingMode::Ref(Mutability::Mut) => BindingMode::Ref(*mutability), BindingMode::Ref(Mutability::Mut) => BindingMode::Ref(mutability),
} }
} }
} else if let Pat::Ref { .. } = &body[pat] { } else if let Pat::Ref { .. } = &body[pat] {
@ -629,8 +616,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
let ty = match &body[pat] { let ty = match &body[pat] {
Pat::Tuple(ref args) => { Pat::Tuple(ref args) => {
let expectations = match *expected { let expectations = match expected.as_tuple() {
Ty::Tuple(ref tuple_args) => &*tuple_args.0, Some(parameters) => &*parameters.0,
_ => &[], _ => &[],
}; };
let expectations_iter = expectations.iter().chain(repeat(&Ty::Unknown)); let expectations_iter = expectations.iter().chain(repeat(&Ty::Unknown));
@ -642,20 +629,20 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
.collect::<Vec<_>>() .collect::<Vec<_>>()
.into(); .into();
Ty::Tuple(Substs(inner_tys)) Ty::apply(TypeName::Tuple, Substs(inner_tys))
} }
Pat::Ref { pat, mutability } => { Pat::Ref { pat, mutability } => {
let expectation = match *expected { let expectation = match expected.as_reference() {
Ty::Ref(ref sub_ty, exp_mut) => { Some((inner_ty, exp_mut)) => {
if *mutability != exp_mut { if *mutability != exp_mut {
// TODO: emit type error? // TODO: emit type error?
} }
&**sub_ty inner_ty
} }
_ => &Ty::Unknown, _ => &Ty::Unknown,
}; };
let subty = self.infer_pat(*pat, expectation, default_bm); let subty = self.infer_pat(*pat, expectation, default_bm);
Ty::Ref(subty.into(), *mutability) Ty::apply_one(TypeName::Ref(*mutability), subty.into())
} }
Pat::TupleStruct { path: ref p, args: ref subpats } => { Pat::TupleStruct { path: ref p, args: ref subpats } => {
self.infer_tuple_struct_pat(p.as_ref(), subpats, expected, default_bm) self.infer_tuple_struct_pat(p.as_ref(), subpats, expected, default_bm)
@ -682,7 +669,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
let inner_ty = self.insert_type_vars_shallow(inner_ty); let inner_ty = self.insert_type_vars_shallow(inner_ty);
let bound_ty = match mode { let bound_ty = match mode {
BindingMode::Ref(mutability) => Ty::Ref(inner_ty.clone().into(), mutability), BindingMode::Ref(mutability) => {
Ty::apply_one(TypeName::Ref(mutability), inner_ty.clone().into())
}
BindingMode::Move => inner_ty.clone(), BindingMode::Move => inner_ty.clone(),
}; };
let bound_ty = self.resolve_ty_as_possible(&mut vec![], bound_ty); let bound_ty = self.resolve_ty_as_possible(&mut vec![], bound_ty);
@ -736,7 +725,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
Expr::Missing => Ty::Unknown, Expr::Missing => Ty::Unknown,
Expr::If { condition, then_branch, else_branch } => { Expr::If { condition, then_branch, else_branch } => {
// if let is desugared to match, so this is always simple if // if let is desugared to match, so this is always simple if
self.infer_expr(*condition, &Expectation::has_type(Ty::Bool)); self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeName::Bool)));
let then_ty = self.infer_expr(*then_branch, expected); let then_ty = self.infer_expr(*then_branch, expected);
match else_branch { match else_branch {
Some(else_branch) => { Some(else_branch) => {
@ -753,11 +742,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
Expr::Loop { body } => { Expr::Loop { body } => {
self.infer_expr(*body, &Expectation::has_type(Ty::unit())); self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
// TODO handle break with value // TODO handle break with value
Ty::Never Ty::simple(TypeName::Never)
} }
Expr::While { condition, body } => { Expr::While { condition, body } => {
// while let is desugared to a match loop, so this is always simple while // while let is desugared to a match loop, so this is always simple while
self.infer_expr(*condition, &Expectation::has_type(Ty::Bool)); self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeName::Bool)));
self.infer_expr(*body, &Expectation::has_type(Ty::unit())); self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
Ty::unit() Ty::unit()
} }
@ -787,17 +776,23 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
Expr::Call { callee, args } => { Expr::Call { callee, args } => {
let callee_ty = self.infer_expr(*callee, &Expectation::none()); let callee_ty = self.infer_expr(*callee, &Expectation::none());
let (param_tys, ret_ty) = match &callee_ty { let (param_tys, ret_ty) = match &callee_ty {
Ty::FnPtr(sig) => { Ty::Apply(a_ty) => match a_ty.name {
let sig = FnSig::from_fn_ptr_substs(sig); TypeName::FnPtr => {
(sig.params().to_vec(), sig.ret().clone()) let sig = FnSig::from_fn_ptr_substs(&a_ty.parameters);
} (sig.params().to_vec(), sig.ret().clone())
Ty::FnDef { substs, def, .. } => { }
let sig = self.db.callable_item_signature(*def); TypeName::FnDef(def) => {
let ret_ty = sig.ret().clone().subst(&substs); let sig = self.db.callable_item_signature(def);
let param_tys = let ret_ty = sig.ret().clone().subst(&a_ty.parameters);
sig.params().iter().map(|ty| ty.clone().subst(&substs)).collect(); let param_tys = sig
(param_tys, ret_ty) .params()
} .iter()
.map(|ty| ty.clone().subst(&a_ty.parameters))
.collect();
(param_tys, ret_ty)
}
_ => (Vec::new(), Ty::Unknown),
},
_ => { _ => {
// not callable // not callable
// TODO report an error? // TODO report an error?
@ -828,32 +823,43 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
let method_ty = method_ty.apply_substs(substs); let method_ty = method_ty.apply_substs(substs);
let method_ty = self.insert_type_vars(method_ty); let method_ty = self.insert_type_vars(method_ty);
let (expected_receiver_ty, param_tys, ret_ty) = match &method_ty { let (expected_receiver_ty, param_tys, ret_ty) = match &method_ty {
Ty::FnPtr(sig) => { Ty::Apply(a_ty) => match a_ty.name {
let sig = FnSig::from_fn_ptr_substs(sig); TypeName::FnPtr => {
if !sig.params().is_empty() { let sig = FnSig::from_fn_ptr_substs(&a_ty.parameters);
(sig.params()[0].clone(), sig.params()[1..].to_vec(), sig.ret().clone()) if !sig.params().is_empty() {
} else { (
(Ty::Unknown, Vec::new(), sig.ret().clone()) sig.params()[0].clone(),
sig.params()[1..].to_vec(),
sig.ret().clone(),
)
} else {
(Ty::Unknown, Vec::new(), sig.ret().clone())
}
} }
} TypeName::FnDef(def) => {
Ty::FnDef { substs, def, .. } => { let sig = self.db.callable_item_signature(def);
let sig = self.db.callable_item_signature(*def); let ret_ty = sig.ret().clone().subst(&a_ty.parameters);
let ret_ty = sig.ret().clone().subst(&substs);
if !sig.params().is_empty() { if !sig.params().is_empty() {
let mut params_iter = let mut params_iter = sig
sig.params().iter().map(|ty| ty.clone().subst(&substs)); .params()
let receiver_ty = params_iter.next().unwrap(); .iter()
(receiver_ty, params_iter.collect(), ret_ty) .map(|ty| ty.clone().subst(&a_ty.parameters));
} else { let receiver_ty = params_iter.next().unwrap();
(Ty::Unknown, Vec::new(), ret_ty) (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), _ => (Ty::Unknown, Vec::new(), Ty::Unknown),
}; };
// Apply autoref so the below unification works correctly // Apply autoref so the below unification works correctly
let actual_receiver_ty = match expected_receiver_ty { let actual_receiver_ty = match expected_receiver_ty.as_reference() {
Ty::Ref(_, mutability) => Ty::Ref(Arc::new(derefed_receiver_ty), mutability), Some((_, mutability)) => {
Ty::apply_one(TypeName::Ref(mutability), derefed_receiver_ty)
}
_ => derefed_receiver_ty, _ => derefed_receiver_ty,
}; };
self.unify(&expected_receiver_ty, &actual_receiver_ty); self.unify(&expected_receiver_ty, &actual_receiver_ty);
@ -877,7 +883,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
let _pat_ty = self.infer_pat(pat, &input_ty, BindingMode::default()); let _pat_ty = self.infer_pat(pat, &input_ty, BindingMode::default());
} }
if let Some(guard_expr) = arm.guard { if let Some(guard_expr) = arm.guard {
self.infer_expr(guard_expr, &Expectation::has_type(Ty::Bool)); self.infer_expr(
guard_expr,
&Expectation::has_type(Ty::simple(TypeName::Bool)),
);
} }
self.infer_expr(arm.expr, &expected); self.infer_expr(arm.expr, &expected);
} }
@ -889,19 +898,19 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
let resolver = expr::resolver_for_expr(self.body.clone(), self.db, tgt_expr); let resolver = expr::resolver_for_expr(self.body.clone(), self.db, tgt_expr);
self.infer_path_expr(&resolver, p, tgt_expr.into()).unwrap_or(Ty::Unknown) self.infer_path_expr(&resolver, p, tgt_expr.into()).unwrap_or(Ty::Unknown)
} }
Expr::Continue => Ty::Never, Expr::Continue => Ty::simple(TypeName::Never),
Expr::Break { expr } => { Expr::Break { expr } => {
if let Some(expr) = expr { if let Some(expr) = expr {
// TODO handle break with value // TODO handle break with value
self.infer_expr(*expr, &Expectation::none()); self.infer_expr(*expr, &Expectation::none());
} }
Ty::Never Ty::simple(TypeName::Never)
} }
Expr::Return { expr } => { Expr::Return { expr } => {
if let Some(expr) = expr { if let Some(expr) = expr {
self.infer_expr(*expr, &Expectation::has_type(self.return_ty.clone())); self.infer_expr(*expr, &Expectation::has_type(self.return_ty.clone()));
} }
Ty::Never Ty::simple(TypeName::Never)
} }
Expr::StructLit { path, fields, spread } => { Expr::StructLit { path, fields, spread } => {
let (ty, def_id) = self.resolve_variant(path.as_ref()); let (ty, def_id) = self.resolve_variant(path.as_ref());
@ -923,16 +932,19 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
let ty = receiver_ty let ty = receiver_ty
.autoderef(self.db) .autoderef(self.db)
.find_map(|derefed_ty| match derefed_ty { .find_map(|derefed_ty| match derefed_ty {
Ty::Tuple(fields) => { Ty::Apply(a_ty) => match a_ty.name {
let i = name.to_string().parse::<usize>().ok(); TypeName::Tuple => {
i.and_then(|i| fields.0.get(i).cloned()) let i = name.to_string().parse::<usize>().ok();
} i.and_then(|i| a_ty.parameters.0.get(i).cloned())
Ty::Adt { def_id: AdtDef::Struct(s), ref substs, .. } => { }
s.field(self.db, name).map(|field| { TypeName::Adt(AdtDef::Struct(s)) => {
self.write_field_resolution(tgt_expr, field); s.field(self.db, name).map(|field| {
field.ty(self.db).subst(substs) self.write_field_resolution(tgt_expr, field);
}) field.ty(self.db).subst(&a_ty.parameters)
} })
}
_ => None,
},
_ => None, _ => None,
}) })
.unwrap_or(Ty::Unknown); .unwrap_or(Ty::Unknown);
@ -949,18 +961,19 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
cast_ty cast_ty
} }
Expr::Ref { expr, mutability } => { Expr::Ref { expr, mutability } => {
let expectation = if let Ty::Ref(ref subty, expected_mutability) = expected.ty { let expectation =
if expected_mutability == Mutability::Mut && *mutability == Mutability::Shared { if let Some((exp_inner, exp_mutability)) = &expected.ty.as_reference() {
// TODO: throw type error - expected mut reference but found shared ref, if *exp_mutability == Mutability::Mut && *mutability == Mutability::Shared {
// which cannot be coerced // TODO: throw type error - expected mut reference but found shared ref,
} // which cannot be coerced
Expectation::has_type((**subty).clone()) }
} else { Expectation::has_type(Ty::clone(exp_inner))
Expectation::none() } else {
}; Expectation::none()
};
// TODO reference coercions etc. // TODO reference coercions etc.
let inner_ty = self.infer_expr(*expr, &expectation); let inner_ty = self.infer_expr(*expr, &expectation);
Ty::Ref(Arc::new(inner_ty), *mutability) Ty::apply_one(TypeName::Ref(*mutability), inner_ty)
} }
Expr::UnaryOp { expr, op } => { Expr::UnaryOp { expr, op } => {
let inner_ty = self.infer_expr(*expr, &Expectation::none()); let inner_ty = self.infer_expr(*expr, &Expectation::none());
@ -974,19 +987,27 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
} }
} }
UnaryOp::Neg => { UnaryOp::Neg => {
match inner_ty { match &inner_ty {
Ty::Int(primitive::UncertainIntTy::Unknown) Ty::Apply(a_ty) => match a_ty.name {
| Ty::Int(primitive::UncertainIntTy::Signed(..)) TypeName::Int(primitive::UncertainIntTy::Unknown)
| Ty::Infer(InferTy::IntVar(..)) | TypeName::Int(primitive::UncertainIntTy::Signed(..))
| Ty::Infer(InferTy::FloatVar(..)) | TypeName::Float(..) => inner_ty,
| Ty::Float(..) => inner_ty, _ => Ty::Unknown,
},
Ty::Infer(InferTy::IntVar(..)) | Ty::Infer(InferTy::FloatVar(..)) => {
inner_ty
}
// TODO: resolve ops::Neg trait // TODO: resolve ops::Neg trait
_ => Ty::Unknown, _ => Ty::Unknown,
} }
} }
UnaryOp::Not => { UnaryOp::Not => {
match inner_ty { match &inner_ty {
Ty::Bool | Ty::Int(_) | Ty::Infer(InferTy::IntVar(..)) => inner_ty, Ty::Apply(a_ty) => match a_ty.name {
TypeName::Bool | TypeName::Int(_) => inner_ty,
_ => Ty::Unknown,
},
Ty::Infer(InferTy::IntVar(..)) => inner_ty,
// TODO: resolve ops::Not trait for inner_ty // TODO: resolve ops::Not trait for inner_ty
_ => Ty::Unknown, _ => Ty::Unknown,
} }
@ -997,7 +1018,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
Some(op) => { Some(op) => {
let lhs_expectation = match op { let lhs_expectation = match op {
BinaryOp::BooleanAnd | BinaryOp::BooleanOr => { BinaryOp::BooleanAnd | BinaryOp::BooleanOr => {
Expectation::has_type(Ty::Bool) Expectation::has_type(Ty::simple(TypeName::Bool))
} }
_ => Expectation::none(), _ => Expectation::none(),
}; };
@ -1018,11 +1039,16 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
ty_vec.push(self.infer_expr(*arg, &Expectation::none())); ty_vec.push(self.infer_expr(*arg, &Expectation::none()));
} }
Ty::Tuple(Substs(ty_vec.into())) Ty::apply(TypeName::Tuple, Substs(ty_vec.into()))
} }
Expr::Array { exprs } => { Expr::Array { exprs } => {
let elem_ty = match &expected.ty { let elem_ty = match &expected.ty {
Ty::Slice(inner) | Ty::Array(inner) => Ty::clone(&inner), Ty::Apply(a_ty) => match a_ty.name {
TypeName::Slice | TypeName::Array => {
Ty::clone(&a_ty.parameters.as_single())
}
_ => self.new_type_var(),
},
_ => self.new_type_var(), _ => self.new_type_var(),
}; };
@ -1030,21 +1056,23 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
self.infer_expr(*expr, &Expectation::has_type(elem_ty.clone())); self.infer_expr(*expr, &Expectation::has_type(elem_ty.clone()));
} }
Ty::Array(Arc::new(elem_ty)) Ty::apply_one(TypeName::Array, elem_ty)
} }
Expr::Literal(lit) => match lit { Expr::Literal(lit) => match lit {
Literal::Bool(..) => Ty::Bool, Literal::Bool(..) => Ty::simple(TypeName::Bool),
Literal::String(..) => Ty::Ref(Arc::new(Ty::Str), Mutability::Shared), Literal::String(..) => {
Ty::apply_one(TypeName::Ref(Mutability::Shared), Ty::simple(TypeName::Str))
}
Literal::ByteString(..) => { Literal::ByteString(..) => {
let byte_type = Arc::new(Ty::Int(primitive::UncertainIntTy::Unsigned( let byte_type = Ty::simple(TypeName::Int(primitive::UncertainIntTy::Unsigned(
primitive::UintTy::U8, primitive::UintTy::U8,
))); )));
let slice_type = Arc::new(Ty::Slice(byte_type)); let slice_type = Ty::apply_one(TypeName::Slice, byte_type);
Ty::Ref(slice_type, Mutability::Shared) Ty::apply_one(TypeName::Ref(Mutability::Shared), slice_type)
} }
Literal::Char(..) => Ty::Char, Literal::Char(..) => Ty::simple(TypeName::Char),
Literal::Int(_v, ty) => Ty::Int(*ty), Literal::Int(_v, ty) => Ty::simple(TypeName::Int(*ty)),
Literal::Float(_v, ty) => Ty::Float(*ty), Literal::Float(_v, ty) => Ty::simple(TypeName::Float(*ty)),
}, },
}; };
// use a new type variable if we got Ty::Unknown here // use a new type variable if we got Ty::Unknown here
@ -1180,11 +1208,11 @@ impl InferTy {
match self { match self {
InferTy::TypeVar(..) => Ty::Unknown, InferTy::TypeVar(..) => Ty::Unknown,
InferTy::IntVar(..) => { InferTy::IntVar(..) => {
Ty::Int(primitive::UncertainIntTy::Signed(primitive::IntTy::I32)) Ty::simple(TypeName::Int(primitive::UncertainIntTy::Signed(primitive::IntTy::I32)))
}
InferTy::FloatVar(..) => {
Ty::Float(primitive::UncertainFloatTy::Known(primitive::FloatTy::F64))
} }
InferTy::FloatVar(..) => Ty::simple(TypeName::Float(
primitive::UncertainFloatTy::Known(primitive::FloatTy::F64),
)),
} }
} }
} }

View file

@ -6,8 +6,6 @@
//! //!
//! This usually involves resolving names, collecting generic arguments etc. //! This usually involves resolving names, collecting generic arguments etc.
use std::sync::Arc;
use crate::{ use crate::{
Function, Struct, StructField, Enum, EnumVariant, Path, Function, Struct, StructField, Enum, EnumVariant, Path,
ModuleDef, TypeAlias, ModuleDef, TypeAlias,
@ -21,40 +19,40 @@ use crate::{
generics::GenericParams, generics::GenericParams,
adt::VariantDef, adt::VariantDef,
}; };
use super::{Ty, primitive, FnSig, Substs}; use super::{Ty, primitive, FnSig, Substs, TypeName};
impl Ty { impl Ty {
pub(crate) fn from_hir(db: &impl HirDatabase, resolver: &Resolver, type_ref: &TypeRef) -> Self { pub(crate) fn from_hir(db: &impl HirDatabase, resolver: &Resolver, type_ref: &TypeRef) -> Self {
match type_ref { match type_ref {
TypeRef::Never => Ty::Never, TypeRef::Never => Ty::simple(TypeName::Never),
TypeRef::Tuple(inner) => { TypeRef::Tuple(inner) => {
let inner_tys = let inner_tys =
inner.iter().map(|tr| Ty::from_hir(db, resolver, tr)).collect::<Vec<_>>(); inner.iter().map(|tr| Ty::from_hir(db, resolver, tr)).collect::<Vec<_>>();
Ty::Tuple(Substs(inner_tys.into())) Ty::apply(TypeName::Tuple, Substs(inner_tys.into()))
} }
TypeRef::Path(path) => Ty::from_hir_path(db, resolver, path), TypeRef::Path(path) => Ty::from_hir_path(db, resolver, path),
TypeRef::RawPtr(inner, mutability) => { TypeRef::RawPtr(inner, mutability) => {
let inner_ty = Ty::from_hir(db, resolver, inner); let inner_ty = Ty::from_hir(db, resolver, inner);
Ty::RawPtr(Arc::new(inner_ty), *mutability) Ty::apply_one(TypeName::RawPtr(*mutability), inner_ty)
} }
TypeRef::Array(inner) => { TypeRef::Array(inner) => {
let inner_ty = Ty::from_hir(db, resolver, inner); let inner_ty = Ty::from_hir(db, resolver, inner);
Ty::Array(Arc::new(inner_ty)) Ty::apply_one(TypeName::Array, inner_ty)
} }
TypeRef::Slice(inner) => { TypeRef::Slice(inner) => {
let inner_ty = Ty::from_hir(db, resolver, inner); let inner_ty = Ty::from_hir(db, resolver, inner);
Ty::Slice(Arc::new(inner_ty)) Ty::apply_one(TypeName::Slice, inner_ty)
} }
TypeRef::Reference(inner, mutability) => { TypeRef::Reference(inner, mutability) => {
let inner_ty = Ty::from_hir(db, resolver, inner); let inner_ty = Ty::from_hir(db, resolver, inner);
Ty::Ref(Arc::new(inner_ty), *mutability) Ty::apply_one(TypeName::Ref(*mutability), inner_ty)
} }
TypeRef::Placeholder => Ty::Unknown, TypeRef::Placeholder => Ty::Unknown,
TypeRef::Fn(params) => { TypeRef::Fn(params) => {
let inner_tys = let inner_tys =
params.iter().map(|tr| Ty::from_hir(db, resolver, tr)).collect::<Vec<_>>(); params.iter().map(|tr| Ty::from_hir(db, resolver, tr)).collect::<Vec<_>>();
let sig = Substs(inner_tys.into()); let sig = Substs(inner_tys.into());
Ty::FnPtr(sig) Ty::apply(TypeName::FnPtr, sig)
} }
TypeRef::Error => Ty::Unknown, TypeRef::Error => Ty::Unknown,
} }
@ -64,14 +62,14 @@ impl Ty {
if let Some(name) = path.as_ident() { if let Some(name) = path.as_ident() {
// TODO handle primitive type names in resolver as well? // TODO handle primitive type names in resolver as well?
if let Some(int_ty) = primitive::UncertainIntTy::from_type_name(name) { if let Some(int_ty) = primitive::UncertainIntTy::from_type_name(name) {
return Ty::Int(int_ty); return Ty::simple(TypeName::Int(int_ty));
} else if let Some(float_ty) = primitive::UncertainFloatTy::from_type_name(name) { } else if let Some(float_ty) = primitive::UncertainFloatTy::from_type_name(name) {
return Ty::Float(float_ty); return Ty::simple(TypeName::Float(float_ty));
} else if let Some(known) = name.as_known_name() { } else if let Some(known) = name.as_known_name() {
match known { match known {
KnownName::Bool => return Ty::Bool, KnownName::Bool => return Ty::simple(TypeName::Bool),
KnownName::Char => return Ty::Char, KnownName::Char => return Ty::simple(TypeName::Char),
KnownName::Str => return Ty::Str, KnownName::Str => return Ty::simple(TypeName::Str),
_ => {} _ => {}
} }
} }
@ -247,7 +245,7 @@ fn fn_sig_for_fn(db: &impl HirDatabase, def: Function) -> FnSig {
fn type_for_fn(db: &impl HirDatabase, def: Function) -> Ty { fn type_for_fn(db: &impl HirDatabase, def: Function) -> Ty {
let generics = def.generic_params(db); let generics = def.generic_params(db);
let substs = make_substs(&generics); let substs = make_substs(&generics);
Ty::FnDef { def: def.into(), substs } Ty::apply(TypeName::FnDef(def.into()), substs)
} }
/// Build the declared type of a const. /// Build the declared type of a const.
@ -289,7 +287,7 @@ fn type_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> Ty {
} }
let generics = def.generic_params(db); let generics = def.generic_params(db);
let substs = make_substs(&generics); let substs = make_substs(&generics);
Ty::FnDef { def: def.into(), substs } Ty::apply(TypeName::FnDef(def.into()), substs)
} }
fn fn_sig_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariant) -> FnSig { fn fn_sig_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariant) -> FnSig {
@ -317,7 +315,7 @@ fn type_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariant) ->
} }
let generics = def.parent_enum(db).generic_params(db); let generics = def.parent_enum(db).generic_params(db);
let substs = make_substs(&generics); let substs = make_substs(&generics);
Ty::FnDef { def: def.into(), substs } Ty::apply(TypeName::FnDef(def.into()), substs)
} }
fn make_substs(generics: &GenericParams) -> Substs { fn make_substs(generics: &GenericParams) -> Substs {
@ -333,12 +331,12 @@ fn make_substs(generics: &GenericParams) -> Substs {
fn type_for_struct(db: &impl HirDatabase, s: Struct) -> Ty { fn type_for_struct(db: &impl HirDatabase, s: Struct) -> Ty {
let generics = s.generic_params(db); let generics = s.generic_params(db);
Ty::Adt { def_id: s.into(), substs: make_substs(&generics) } Ty::apply(TypeName::Adt(s.into()), make_substs(&generics))
} }
fn type_for_enum(db: &impl HirDatabase, s: Enum) -> Ty { fn type_for_enum(db: &impl HirDatabase, s: Enum) -> Ty {
let generics = s.generic_params(db); let generics = s.generic_params(db);
Ty::Adt { def_id: s.into(), substs: make_substs(&generics) } Ty::apply(TypeName::Adt(s.into()), make_substs(&generics))
} }
fn type_for_type_alias(db: &impl HirDatabase, t: TypeAlias) -> Ty { fn type_for_type_alias(db: &impl HirDatabase, t: TypeAlias) -> Ty {

View file

@ -10,7 +10,7 @@ use crate::{
HirDatabase, Module, Crate, Name, Function, Trait, HirDatabase, Module, Crate, Name, Function, Trait,
ids::TraitId, ids::TraitId,
impl_block::{ImplId, ImplBlock, ImplItem}, impl_block::{ImplId, ImplBlock, ImplItem},
ty::{AdtDef, Ty}, ty::{Ty, TypeName},
nameres::CrateModuleId, nameres::CrateModuleId,
}; };
@ -18,7 +18,7 @@ use crate::{
/// This is used as a key for indexing impls. /// This is used as a key for indexing impls.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum TyFingerprint { pub enum TyFingerprint {
Adt(AdtDef), // we'll also want to index impls for primitive types etc. Apply(TypeName),
} }
impl TyFingerprint { impl TyFingerprint {
@ -27,7 +27,7 @@ impl TyFingerprint {
/// `impl &S`. Hence, this will return `None` for reference types and such. /// `impl &S`. Hence, this will return `None` for reference types and such.
fn for_impl(ty: &Ty) -> Option<TyFingerprint> { fn for_impl(ty: &Ty) -> Option<TyFingerprint> {
match ty { match ty {
Ty::Adt { def_id, .. } => Some(TyFingerprint::Adt(*def_id)), Ty::Apply(a_ty) => Some(TyFingerprint::Apply(a_ty.name)),
_ => None, _ => None,
} }
} }
@ -111,7 +111,10 @@ impl CrateImplBlocks {
fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Option<Crate> { fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Option<Crate> {
match ty { match ty {
Ty::Adt { def_id, .. } => def_id.krate(db), Ty::Apply(a_ty) => match a_ty.name {
TypeName::Adt(def_id) => def_id.krate(db),
_ => None,
},
_ => None, _ => None,
} }
} }

View file

@ -1,5 +1,5 @@
use crate::expr::BinaryOp; use crate::{ ty::ApplicationTy, expr::BinaryOp};
use super::{Ty, InferTy}; use super::{Ty, TypeName, InferTy};
pub(super) fn binary_op_return_ty(op: BinaryOp, rhs_ty: Ty) -> Ty { pub(super) fn binary_op_return_ty(op: BinaryOp, rhs_ty: Ty) -> Ty {
match op { match op {
@ -10,7 +10,7 @@ pub(super) fn binary_op_return_ty(op: BinaryOp, rhs_ty: Ty) -> Ty {
| BinaryOp::LesserEqualTest | BinaryOp::LesserEqualTest
| BinaryOp::GreaterEqualTest | BinaryOp::GreaterEqualTest
| BinaryOp::LesserTest | BinaryOp::LesserTest
| BinaryOp::GreaterTest => Ty::Bool, | BinaryOp::GreaterTest => Ty::simple(TypeName::Bool),
BinaryOp::Assignment BinaryOp::Assignment
| BinaryOp::AddAssign | BinaryOp::AddAssign
| BinaryOp::SubAssign | BinaryOp::SubAssign
@ -32,10 +32,11 @@ pub(super) fn binary_op_return_ty(op: BinaryOp, rhs_ty: Ty) -> Ty {
| BinaryOp::BitwiseAnd | BinaryOp::BitwiseAnd
| BinaryOp::BitwiseOr | BinaryOp::BitwiseOr
| BinaryOp::BitwiseXor => match rhs_ty { | BinaryOp::BitwiseXor => match rhs_ty {
Ty::Int(..) Ty::Apply(ApplicationTy { name, .. }) => match name {
| Ty::Float(..) TypeName::Int(..) | TypeName::Float(..) => rhs_ty,
| Ty::Infer(InferTy::IntVar(..)) _ => Ty::Unknown,
| Ty::Infer(InferTy::FloatVar(..)) => rhs_ty, },
Ty::Infer(InferTy::IntVar(..)) | Ty::Infer(InferTy::FloatVar(..)) => rhs_ty,
_ => Ty::Unknown, _ => Ty::Unknown,
}, },
BinaryOp::RangeRightOpen | BinaryOp::RangeRightClosed => Ty::Unknown, BinaryOp::RangeRightOpen | BinaryOp::RangeRightClosed => Ty::Unknown,
@ -44,9 +45,17 @@ pub(super) fn binary_op_return_ty(op: BinaryOp, rhs_ty: Ty) -> Ty {
pub(super) fn binary_op_rhs_expectation(op: BinaryOp, lhs_ty: Ty) -> Ty { pub(super) fn binary_op_rhs_expectation(op: BinaryOp, lhs_ty: Ty) -> Ty {
match op { match op {
BinaryOp::BooleanAnd | BinaryOp::BooleanOr => Ty::Bool, BinaryOp::BooleanAnd | BinaryOp::BooleanOr => Ty::simple(TypeName::Bool),
BinaryOp::Assignment | BinaryOp::EqualityTest => match lhs_ty { BinaryOp::Assignment | BinaryOp::EqualityTest => match lhs_ty {
Ty::Int(..) | Ty::Float(..) | Ty::Str | Ty::Char | Ty::Bool => lhs_ty, Ty::Apply(ApplicationTy { name, .. }) => match name {
TypeName::Int(..)
| TypeName::Float(..)
| TypeName::Str
| TypeName::Char
| TypeName::Bool => lhs_ty,
_ => Ty::Unknown,
},
Ty::Infer(InferTy::IntVar(..)) | Ty::Infer(InferTy::FloatVar(..)) => lhs_ty,
_ => Ty::Unknown, _ => Ty::Unknown,
}, },
BinaryOp::LesserEqualTest BinaryOp::LesserEqualTest
@ -73,7 +82,11 @@ pub(super) fn binary_op_rhs_expectation(op: BinaryOp, lhs_ty: Ty) -> Ty {
| BinaryOp::BitwiseAnd | BinaryOp::BitwiseAnd
| BinaryOp::BitwiseOr | BinaryOp::BitwiseOr
| BinaryOp::BitwiseXor => match lhs_ty { | BinaryOp::BitwiseXor => match lhs_ty {
Ty::Int(..) | Ty::Float(..) => lhs_ty, Ty::Apply(ApplicationTy { name, .. }) => match name {
TypeName::Int(..) | TypeName::Float(..) => lhs_ty,
_ => Ty::Unknown,
},
Ty::Infer(InferTy::IntVar(..)) | Ty::Infer(InferTy::FloatVar(..)) => lhs_ty,
_ => Ty::Unknown, _ => Ty::Unknown,
}, },
_ => Ty::Unknown, _ => Ty::Unknown,

View file

@ -1,4 +1,4 @@
use hir::{Ty, AdtDef}; use hir::{Ty, AdtDef, TypeName};
use crate::completion::{CompletionContext, Completions}; use crate::completion::{CompletionContext, Completions};
@ -24,23 +24,20 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) { fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) {
for receiver in receiver.autoderef(ctx.db) { for receiver in receiver.autoderef(ctx.db) {
match receiver { match receiver {
Ty::Adt { def_id, ref substs, .. } => { Ty::Apply(a_ty) => match a_ty.name {
match def_id { TypeName::Adt(AdtDef::Struct(s)) => {
AdtDef::Struct(s) => { for field in s.fields(ctx.db) {
for field in s.fields(ctx.db) { acc.add_field(ctx, field, &a_ty.parameters);
acc.add_field(ctx, field, substs);
}
} }
// TODO unions
AdtDef::Enum(_) => (),
} }
} // TODO unions
Ty::Tuple(fields) => { TypeName::Tuple => {
for (i, ty) in fields.iter().enumerate() { for (i, ty) in a_ty.parameters.iter().enumerate() {
acc.add_pos_field(ctx, i, ty); acc.add_pos_field(ctx, i, ty);
}
} }
} _ => {}
},
_ => {} _ => {}
}; };
} }

View file

@ -1,4 +1,4 @@
use hir::{Ty, AdtDef}; use hir::AdtDef;
use crate::completion::{CompletionContext, Completions}; use crate::completion::{CompletionContext, Completions};
@ -15,8 +15,8 @@ pub(super) fn complete_struct_literal(acc: &mut Completions, ctx: &CompletionCon
None => return, None => return,
}; };
let ty = infer_result[expr].clone(); let ty = infer_result[expr].clone();
let (adt, substs) = match ty { let (adt, substs) = match ty.as_adt() {
Ty::Adt { def_id, ref substs, .. } => (def_id, substs), Some(res) => res,
_ => return, _ => return,
}; };
match adt { match adt {

View file

@ -87,14 +87,12 @@ pub(crate) fn reference_definition(
if let Some(expr) = struct_lit.and_then(|lit| source_map.node_expr(lit.into())) { if let Some(expr) = struct_lit.and_then(|lit| source_map.node_expr(lit.into())) {
let ty = infer_result[expr].clone(); let ty = infer_result[expr].clone();
if let hir::Ty::Adt { def_id, .. } = ty { if let Some((hir::AdtDef::Struct(s), _)) = ty.as_adt() {
if let hir::AdtDef::Struct(s) = def_id { let hir_path = hir::Path::from_name_ref(name_ref);
let hir_path = hir::Path::from_name_ref(name_ref); let hir_name = hir_path.as_ident().unwrap();
let hir_name = hir_path.as_ident().unwrap();
if let Some(field) = s.field(db, hir_name) { if let Some(field) = s.field(db, hir_name) {
return Exact(NavigationTarget::from_field(db, field)); return Exact(NavigationTarget::from_field(db, field));
}
} }
} }
} }
@ -124,7 +122,7 @@ pub(crate) fn reference_definition(
Some(Resolution::SelfType(impl_block)) => { Some(Resolution::SelfType(impl_block)) => {
let ty = impl_block.target_ty(db); let ty = impl_block.target_ty(db);
if let hir::Ty::Adt { def_id, .. } = ty { if let Some((def_id, _)) = ty.as_adt() {
return Exact(NavigationTarget::from_adt_def(db, def_id)); return Exact(NavigationTarget::from_adt_def(db, def_id));
} }
} }

View file

@ -517,23 +517,8 @@ The Some variant
assert_eq!("u32", &type_name); assert_eq!("u32", &type_name);
} }
// FIXME: improve type_of to make this work
#[test] #[test]
fn test_type_of_for_expr_1() { fn test_type_of_for_expr() {
let (analysis, range) = single_file_with_range(
"
fn main() {
let foo = <|>1 + foo_test<|>;
}
",
);
let type_name = analysis.type_of(range).unwrap().unwrap();
assert_eq!("{unknown}", &type_name);
}
#[test]
fn test_type_of_for_expr_2() {
let (analysis, range) = single_file_with_range( let (analysis, range) = single_file_with_range(
" "
fn main() { fn main() {