Merge #988
988: Consolidate Ty variants into a new variant Ty::Apply r=matklad a=flodiebold This gets us a lot closer to Chalk. It also introduces a lot of boilerplate, though, especially when matching :/ A lot of this can probably be refactored to be nicer, though. Co-authored-by: Florian Diebold <flodiebold@gmail.com>
This commit is contained in:
commit
9c6c6a7cb5
12 changed files with 376 additions and 317 deletions
|
@ -1,7 +1,7 @@
|
|||
use std::fmt::Write;
|
||||
|
||||
use hir::{
|
||||
AdtDef, Ty, FieldSource, source_binder,
|
||||
AdtDef, FieldSource, source_binder,
|
||||
db::HirDatabase,
|
||||
};
|
||||
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 node_expr = source_map.node_expr(expr)?;
|
||||
let match_expr_ty = infer_result[node_expr].clone();
|
||||
let enum_def = match match_expr_ty {
|
||||
Ty::Adt { def_id: AdtDef::Enum(e), .. } => e,
|
||||
Ty::Ref(adt, _) => match *adt {
|
||||
Ty::Adt { def_id: AdtDef::Enum(e), .. } => e,
|
||||
_ => return None,
|
||||
},
|
||||
_ => return None,
|
||||
};
|
||||
let enum_def = match_expr_ty.autoderef(ctx.db).find_map(|ty| match ty.as_adt() {
|
||||
Some((AdtDef::Enum(e), _)) => Some(e),
|
||||
_ => None,
|
||||
})?;
|
||||
let enum_name = enum_def.name(ctx.db)?;
|
||||
let db = ctx.db;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
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};
|
||||
|
||||
|
@ -60,8 +60,8 @@ where
|
|||
let source_map = function.body_source_map(self.ctx.db);
|
||||
let node_expr = source_map.node_expr(self.struct_lit.into())?;
|
||||
let struct_lit_ty = infer_result[node_expr].clone();
|
||||
let struct_def = match struct_lit_ty {
|
||||
Ty::Adt { def_id: AdtDef::Struct(s), .. } => s,
|
||||
let struct_def = match struct_lit_ty.as_adt() {
|
||||
Some((AdtDef::Struct(s), _)) => s,
|
||||
_ => return None,
|
||||
};
|
||||
self.struct_fields = struct_def
|
||||
|
|
|
@ -53,7 +53,7 @@ pub use self::{
|
|||
name::Name,
|
||||
ids::{HirFileId, MacroCallId, MacroCallLoc, HirInterner},
|
||||
nameres::{PerNs, Namespace},
|
||||
ty::{Ty, Substs, display::HirDisplay},
|
||||
ty::{Ty, ApplicationTy, TypeCtor, Substs, display::HirDisplay},
|
||||
impl_block::{ImplBlock, ImplItem},
|
||||
docs::{Docs, Documentation},
|
||||
adt::AdtDef,
|
||||
|
|
|
@ -20,11 +20,11 @@ pub(crate) use lower::{TypableDef, CallableDef, type_for_def, type_for_field, ca
|
|||
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)]
|
||||
pub enum Ty {
|
||||
/// A type constructor or type name: this might be something like the primitive
|
||||
/// type `bool`, a struct like `Vec`, or things like function pointers or
|
||||
/// tuples.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub enum TypeCtor {
|
||||
/// The primitive boolean type. Written as `bool`.
|
||||
Bool,
|
||||
|
||||
|
@ -39,28 +39,23 @@ pub enum Ty {
|
|||
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,
|
||||
},
|
||||
Adt(AdtDef),
|
||||
|
||||
/// The pointee of a string slice. Written as `str`.
|
||||
Str,
|
||||
|
||||
/// The pointee of an array slice. Written as `[T]`.
|
||||
Slice(Arc<Ty>),
|
||||
Slice,
|
||||
|
||||
/// An array with the given length. Written as `[T; n]`.
|
||||
Array(Arc<Ty>),
|
||||
Array,
|
||||
|
||||
/// A raw pointer. Written as `*mut T` or `*const T`
|
||||
RawPtr(Arc<Ty>, Mutability),
|
||||
RawPtr(Mutability),
|
||||
|
||||
/// A reference; a pointer with an associated lifetime. Written as
|
||||
/// `&'a mut T` or `&'a T`.
|
||||
Ref(Arc<Ty>, Mutability),
|
||||
Ref(Mutability),
|
||||
|
||||
/// The anonymous type of a function declaration/definition. Each
|
||||
/// function has a unique type, which is output (for a function
|
||||
|
@ -74,12 +69,7 @@ pub enum Ty {
|
|||
/// 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,
|
||||
},
|
||||
FnDef(CallableDef),
|
||||
|
||||
/// A pointer to a function. Written as `fn() -> i32`.
|
||||
///
|
||||
|
@ -89,13 +79,36 @@ pub enum Ty {
|
|||
/// fn foo() -> i32 { 1 }
|
||||
/// let bar: fn() -> i32 = foo;
|
||||
/// ```
|
||||
FnPtr(FnSig),
|
||||
FnPtr,
|
||||
|
||||
/// The never type `!`.
|
||||
Never,
|
||||
|
||||
/// A tuple type. For example, `(i32, bool)`.
|
||||
Tuple(Arc<[Ty]>),
|
||||
Tuple,
|
||||
}
|
||||
|
||||
/// 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.
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct ApplicationTy {
|
||||
pub ctor: TypeCtor,
|
||||
pub parameters: Substs,
|
||||
}
|
||||
|
||||
/// A type.
|
||||
///
|
||||
/// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents
|
||||
/// the same thing (but in a different way).
|
||||
///
|
||||
/// This should be cheap to clone.
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
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),
|
||||
|
||||
/// A type parameter; for example, `T` in `fn f<T>(x: T) {}
|
||||
Param {
|
||||
|
@ -127,6 +140,18 @@ impl Substs {
|
|||
Substs(Arc::new([]))
|
||||
}
|
||||
|
||||
pub fn single(ty: Ty) -> Substs {
|
||||
Substs(Arc::new([ty]))
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = &Ty> {
|
||||
self.0.iter()
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
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();
|
||||
|
@ -135,9 +160,17 @@ impl Substs {
|
|||
}
|
||||
self.0 = v.into();
|
||||
}
|
||||
|
||||
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.
|
||||
/// A function signature as seen by type inference: Several parameter types and
|
||||
/// one return type.
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct FnSig {
|
||||
params_and_return: Arc<[Ty]>,
|
||||
|
@ -148,6 +181,11 @@ impl FnSig {
|
|||
params.push(ret);
|
||||
FnSig { params_and_return: params.into() }
|
||||
}
|
||||
|
||||
pub fn from_fn_ptr_substs(substs: &Substs) -> FnSig {
|
||||
FnSig { params_and_return: Arc::clone(&substs.0) }
|
||||
}
|
||||
|
||||
pub fn params(&self) -> &[Ty] {
|
||||
&self.params_and_return[0..self.params_and_return.len() - 1]
|
||||
}
|
||||
|
@ -167,80 +205,37 @@ impl FnSig {
|
|||
}
|
||||
|
||||
impl Ty {
|
||||
pub fn simple(ctor: TypeCtor) -> Ty {
|
||||
Ty::Apply(ApplicationTy { ctor, parameters: Substs::empty() })
|
||||
}
|
||||
pub fn apply_one(ctor: TypeCtor, param: Ty) -> Ty {
|
||||
Ty::Apply(ApplicationTy { ctor, parameters: Substs::single(param) })
|
||||
}
|
||||
pub fn apply(ctor: TypeCtor, parameters: Substs) -> Ty {
|
||||
Ty::Apply(ApplicationTy { ctor, parameters })
|
||||
}
|
||||
pub fn unit() -> Self {
|
||||
Ty::Tuple(Arc::new([]))
|
||||
Ty::apply(TypeCtor::Tuple, Substs::empty())
|
||||
}
|
||||
|
||||
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() {
|
||||
Ty::Apply(a_ty) => {
|
||||
for t in a_ty.parameters.iter() {
|
||||
t.walk(f);
|
||||
}
|
||||
}
|
||||
Ty::FnPtr(sig) => {
|
||||
for input in sig.params() {
|
||||
input.walk(f);
|
||||
}
|
||||
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 => {}
|
||||
Ty::Param { .. } | Ty::Infer(_) | Ty::Unknown => {}
|
||||
}
|
||||
f(self);
|
||||
}
|
||||
|
||||
fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
|
||||
match self {
|
||||
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::Apply(a_ty) => {
|
||||
a_ty.parameters.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 => {}
|
||||
Ty::Param { .. } | Ty::Infer(_) | Ty::Unknown => {}
|
||||
}
|
||||
f(self);
|
||||
}
|
||||
|
@ -253,10 +248,38 @@ impl Ty {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn as_reference(&self) -> Option<(&Ty, Mutability)> {
|
||||
match self {
|
||||
Ty::Apply(ApplicationTy { ctor: TypeCtor::Ref(mutability), parameters }) => {
|
||||
Some((parameters.as_single(), *mutability))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_adt(&self) -> Option<(AdtDef, &Substs)> {
|
||||
match self {
|
||||
Ty::Apply(ApplicationTy { ctor: TypeCtor::Adt(adt_def), parameters }) => {
|
||||
Some((*adt_def, parameters))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_tuple(&self) -> Option<&Substs> {
|
||||
match self {
|
||||
Ty::Apply(ApplicationTy { ctor: TypeCtor::Tuple, parameters }) => Some(parameters),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn builtin_deref(&self) -> Option<Ty> {
|
||||
match self {
|
||||
Ty::Ref(t, _) => Some(Ty::clone(t)),
|
||||
Ty::RawPtr(t, _) => Some(Ty::clone(t)),
|
||||
Ty::Apply(a_ty) => match a_ty.ctor {
|
||||
TypeCtor::Ref(..) => Some(Ty::clone(a_ty.parameters.as_single())),
|
||||
TypeCtor::RawPtr(..) => Some(Ty::clone(a_ty.parameters.as_single())),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -267,8 +290,10 @@ impl Ty {
|
|||
/// `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 },
|
||||
Ty::Apply(ApplicationTy { ctor, parameters: previous_substs }) => {
|
||||
assert_eq!(previous_substs.len(), substs.len());
|
||||
Ty::Apply(ApplicationTy { ctor, parameters: substs })
|
||||
}
|
||||
_ => self,
|
||||
}
|
||||
}
|
||||
|
@ -293,7 +318,7 @@ impl Ty {
|
|||
/// or function); so if `self` is `Option<u32>`, this returns the `u32`.
|
||||
fn substs(&self) -> Option<Substs> {
|
||||
match self {
|
||||
Ty::Adt { substs, .. } | Ty::FnDef { substs, .. } => Some(substs.clone()),
|
||||
Ty::Apply(ApplicationTy { parameters, .. }) => Some(parameters.clone()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -305,40 +330,45 @@ impl HirDisplay for &Ty {
|
|||
}
|
||||
}
|
||||
|
||||
impl HirDisplay for Ty {
|
||||
impl HirDisplay for ApplicationTy {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
|
||||
match self {
|
||||
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) => {
|
||||
match self.ctor {
|
||||
TypeCtor::Bool => write!(f, "bool")?,
|
||||
TypeCtor::Char => write!(f, "char")?,
|
||||
TypeCtor::Int(t) => write!(f, "{}", t)?,
|
||||
TypeCtor::Float(t) => write!(f, "{}", t)?,
|
||||
TypeCtor::Str => write!(f, "str")?,
|
||||
TypeCtor::Slice | TypeCtor::Array => {
|
||||
let t = self.parameters.as_single();
|
||||
write!(f, "[{}]", t.display(f.db))?;
|
||||
}
|
||||
Ty::RawPtr(t, m) => {
|
||||
TypeCtor::RawPtr(m) => {
|
||||
let t = self.parameters.as_single();
|
||||
write!(f, "*{}{}", m.as_keyword_for_ptr(), t.display(f.db))?;
|
||||
}
|
||||
Ty::Ref(t, m) => {
|
||||
TypeCtor::Ref(m) => {
|
||||
let t = self.parameters.as_single();
|
||||
write!(f, "&{}{}", m.as_keyword_for_ref(), t.display(f.db))?;
|
||||
}
|
||||
Ty::Never => write!(f, "!")?,
|
||||
Ty::Tuple(ts) => {
|
||||
if ts.len() == 1 {
|
||||
write!(f, "({},)", ts[0].display(f.db))?;
|
||||
TypeCtor::Never => write!(f, "!")?,
|
||||
TypeCtor::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, ", ")?;
|
||||
f.write_joined(&*ts.0, ", ")?;
|
||||
write!(f, ")")?;
|
||||
}
|
||||
}
|
||||
Ty::FnPtr(sig) => {
|
||||
TypeCtor::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))?;
|
||||
}
|
||||
Ty::FnDef { def, substs, .. } => {
|
||||
let sig = f.db.callable_item_signature(*def);
|
||||
TypeCtor::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),
|
||||
|
@ -348,28 +378,37 @@ impl HirDisplay for Ty {
|
|||
CallableDef::Function(_) => write!(f, "fn {}", name)?,
|
||||
CallableDef::Struct(_) | CallableDef::EnumVariant(_) => write!(f, "{}", name)?,
|
||||
}
|
||||
if substs.0.len() > 0 {
|
||||
if self.parameters.0.len() > 0 {
|
||||
write!(f, "<")?;
|
||||
f.write_joined(&*substs.0, ", ")?;
|
||||
f.write_joined(&*self.parameters.0, ", ")?;
|
||||
write!(f, ">")?;
|
||||
}
|
||||
write!(f, "(")?;
|
||||
f.write_joined(sig.params(), ", ")?;
|
||||
write!(f, ") -> {}", sig.ret().display(f.db))?;
|
||||
}
|
||||
Ty::Adt { def_id, substs, .. } => {
|
||||
TypeCtor::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 substs.0.len() > 0 {
|
||||
if self.parameters.0.len() > 0 {
|
||||
write!(f, "<")?;
|
||||
f.write_joined(&*substs.0, ", ")?;
|
||||
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 {
|
||||
Ty::Apply(a_ty) => a_ty.hir_fmt(f)?,
|
||||
Ty::Param { name, .. } => write!(f, "{}", name)?,
|
||||
Ty::Unknown => write!(f, "{{unknown}}")?,
|
||||
Ty::Infer(..) => write!(f, "_")?,
|
||||
|
|
|
@ -38,7 +38,7 @@ use crate::{
|
|||
resolve::{Resolver, Resolution},
|
||||
nameres::Namespace
|
||||
};
|
||||
use super::{Ty, TypableDef, Substs, primitive, op};
|
||||
use super::{Ty, TypableDef, Substs, primitive, op, FnSig, ApplicationTy, TypeCtor};
|
||||
|
||||
/// The entry point of type inference.
|
||||
pub fn infer(db: &impl HirDatabase, func: Function) -> Arc<InferenceResult> {
|
||||
|
@ -237,29 +237,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
match (&*ty1, &*ty2) {
|
||||
(Ty::Unknown, ..) => true,
|
||||
(.., Ty::Unknown) => true,
|
||||
(Ty::Int(t1), Ty::Int(t2)) => match (t1, t2) {
|
||||
(primitive::UncertainIntTy::Unknown, _)
|
||||
| (_, 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)) if sig1 == sig2 => true,
|
||||
(Ty::Tuple(ts1), Ty::Tuple(ts2)) if ts1.len() == ts2.len() => {
|
||||
ts1.iter().zip(ts2.iter()).all(|(t1, t2)| self.unify_inner(t1, t2, depth + 1))
|
||||
(Ty::Apply(a_ty1), Ty::Apply(a_ty2)) if a_ty1.ctor == a_ty2.ctor => {
|
||||
self.unify_substs(&a_ty1.parameters, &a_ty2.parameters, depth + 1)
|
||||
}
|
||||
(Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2)))
|
||||
| (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2)))
|
||||
|
@ -298,8 +277,14 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty {
|
||||
match ty {
|
||||
Ty::Unknown => self.new_type_var(),
|
||||
Ty::Int(primitive::UncertainIntTy::Unknown) => self.new_integer_var(),
|
||||
Ty::Float(primitive::UncertainFloatTy::Unknown) => self.new_float_var(),
|
||||
Ty::Apply(ApplicationTy {
|
||||
ctor: TypeCtor::Int(primitive::UncertainIntTy::Unknown),
|
||||
..
|
||||
}) => self.new_integer_var(),
|
||||
Ty::Apply(ApplicationTy {
|
||||
ctor: TypeCtor::Float(primitive::UncertainFloatTy::Unknown),
|
||||
..
|
||||
}) => self.new_float_var(),
|
||||
_ => ty,
|
||||
}
|
||||
}
|
||||
|
@ -610,12 +595,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Missing => false,
|
||||
};
|
||||
if is_non_ref_pat {
|
||||
while let Ty::Ref(inner, mutability) = expected {
|
||||
while let Some((inner, mutability)) = expected.as_reference() {
|
||||
expected = inner;
|
||||
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::Mut) => BindingMode::Ref(*mutability),
|
||||
BindingMode::Ref(Mutability::Mut) => BindingMode::Ref(mutability),
|
||||
}
|
||||
}
|
||||
} else if let Pat::Ref { .. } = &body[pat] {
|
||||
|
@ -631,8 +616,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
|
||||
let ty = match &body[pat] {
|
||||
Pat::Tuple(ref args) => {
|
||||
let expectations = match *expected {
|
||||
Ty::Tuple(ref tuple_args) => &**tuple_args,
|
||||
let expectations = match expected.as_tuple() {
|
||||
Some(parameters) => &*parameters.0,
|
||||
_ => &[],
|
||||
};
|
||||
let expectations_iter = expectations.iter().chain(repeat(&Ty::Unknown));
|
||||
|
@ -644,20 +629,20 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
.collect::<Vec<_>>()
|
||||
.into();
|
||||
|
||||
Ty::Tuple(inner_tys)
|
||||
Ty::apply(TypeCtor::Tuple, Substs(inner_tys))
|
||||
}
|
||||
Pat::Ref { pat, mutability } => {
|
||||
let expectation = match *expected {
|
||||
Ty::Ref(ref sub_ty, exp_mut) => {
|
||||
let expectation = match expected.as_reference() {
|
||||
Some((inner_ty, exp_mut)) => {
|
||||
if *mutability != exp_mut {
|
||||
// TODO: emit type error?
|
||||
}
|
||||
&**sub_ty
|
||||
inner_ty
|
||||
}
|
||||
_ => &Ty::Unknown,
|
||||
};
|
||||
let subty = self.infer_pat(*pat, expectation, default_bm);
|
||||
Ty::Ref(subty.into(), *mutability)
|
||||
Ty::apply_one(TypeCtor::Ref(*mutability), subty.into())
|
||||
}
|
||||
Pat::TupleStruct { path: ref p, args: ref subpats } => {
|
||||
self.infer_tuple_struct_pat(p.as_ref(), subpats, expected, default_bm)
|
||||
|
@ -684,7 +669,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
let inner_ty = self.insert_type_vars_shallow(inner_ty);
|
||||
|
||||
let bound_ty = match mode {
|
||||
BindingMode::Ref(mutability) => Ty::Ref(inner_ty.clone().into(), mutability),
|
||||
BindingMode::Ref(mutability) => {
|
||||
Ty::apply_one(TypeCtor::Ref(mutability), inner_ty.clone().into())
|
||||
}
|
||||
BindingMode::Move => inner_ty.clone(),
|
||||
};
|
||||
let bound_ty = self.resolve_ty_as_possible(&mut vec![], bound_ty);
|
||||
|
@ -738,7 +725,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
Expr::Missing => Ty::Unknown,
|
||||
Expr::If { condition, then_branch, else_branch } => {
|
||||
// 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(TypeCtor::Bool)));
|
||||
let then_ty = self.infer_expr(*then_branch, expected);
|
||||
match else_branch {
|
||||
Some(else_branch) => {
|
||||
|
@ -755,11 +742,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
Expr::Loop { body } => {
|
||||
self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
|
||||
// TODO handle break with value
|
||||
Ty::Never
|
||||
Ty::simple(TypeCtor::Never)
|
||||
}
|
||||
Expr::While { condition, body } => {
|
||||
// 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(TypeCtor::Bool)));
|
||||
self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
|
||||
Ty::unit()
|
||||
}
|
||||
|
@ -789,14 +776,23 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
Expr::Call { callee, args } => {
|
||||
let callee_ty = self.infer_expr(*callee, &Expectation::none());
|
||||
let (param_tys, ret_ty) = match &callee_ty {
|
||||
Ty::FnPtr(sig) => (sig.params().to_vec(), sig.ret().clone()),
|
||||
Ty::FnDef { substs, def, .. } => {
|
||||
let sig = self.db.callable_item_signature(*def);
|
||||
let ret_ty = sig.ret().clone().subst(&substs);
|
||||
let param_tys =
|
||||
sig.params().iter().map(|ty| ty.clone().subst(&substs)).collect();
|
||||
(param_tys, ret_ty)
|
||||
}
|
||||
Ty::Apply(a_ty) => match a_ty.ctor {
|
||||
TypeCtor::FnPtr => {
|
||||
let sig = FnSig::from_fn_ptr_substs(&a_ty.parameters);
|
||||
(sig.params().to_vec(), sig.ret().clone())
|
||||
}
|
||||
TypeCtor::FnDef(def) => {
|
||||
let sig = self.db.callable_item_signature(def);
|
||||
let ret_ty = sig.ret().clone().subst(&a_ty.parameters);
|
||||
let param_tys = sig
|
||||
.params()
|
||||
.iter()
|
||||
.map(|ty| ty.clone().subst(&a_ty.parameters))
|
||||
.collect();
|
||||
(param_tys, ret_ty)
|
||||
}
|
||||
_ => (Vec::new(), Ty::Unknown),
|
||||
},
|
||||
_ => {
|
||||
// not callable
|
||||
// TODO report an error?
|
||||
|
@ -821,37 +817,49 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
Some(func.generic_params(self.db)),
|
||||
)
|
||||
}
|
||||
None => (Ty::Unknown, receiver_ty, None),
|
||||
None => (receiver_ty, Ty::Unknown, None),
|
||||
};
|
||||
let substs = self.substs_for_method_call(def_generics, generic_args);
|
||||
let method_ty = method_ty.apply_substs(substs);
|
||||
let method_ty = self.insert_type_vars(method_ty);
|
||||
let (expected_receiver_ty, param_tys, ret_ty) = match &method_ty {
|
||||
Ty::FnPtr(sig) => {
|
||||
if !sig.params().is_empty() {
|
||||
(sig.params()[0].clone(), sig.params()[1..].to_vec(), sig.ret().clone())
|
||||
} else {
|
||||
(Ty::Unknown, Vec::new(), sig.ret().clone())
|
||||
Ty::Apply(a_ty) => match a_ty.ctor {
|
||||
TypeCtor::FnPtr => {
|
||||
let sig = FnSig::from_fn_ptr_substs(&a_ty.parameters);
|
||||
if !sig.params().is_empty() {
|
||||
(
|
||||
sig.params()[0].clone(),
|
||||
sig.params()[1..].to_vec(),
|
||||
sig.ret().clone(),
|
||||
)
|
||||
} else {
|
||||
(Ty::Unknown, Vec::new(), sig.ret().clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
Ty::FnDef { substs, def, .. } => {
|
||||
let sig = self.db.callable_item_signature(*def);
|
||||
let ret_ty = sig.ret().clone().subst(&substs);
|
||||
TypeCtor::FnDef(def) => {
|
||||
let sig = self.db.callable_item_signature(def);
|
||||
let ret_ty = sig.ret().clone().subst(&a_ty.parameters);
|
||||
|
||||
if !sig.params().is_empty() {
|
||||
let mut params_iter =
|
||||
sig.params().iter().map(|ty| ty.clone().subst(&substs));
|
||||
let receiver_ty = params_iter.next().unwrap();
|
||||
(receiver_ty, params_iter.collect(), ret_ty)
|
||||
} else {
|
||||
(Ty::Unknown, Vec::new(), ret_ty)
|
||||
if !sig.params().is_empty() {
|
||||
let mut params_iter = sig
|
||||
.params()
|
||||
.iter()
|
||||
.map(|ty| ty.clone().subst(&a_ty.parameters));
|
||||
let receiver_ty = params_iter.next().unwrap();
|
||||
(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),
|
||||
};
|
||||
// Apply autoref so the below unification works correctly
|
||||
let actual_receiver_ty = match expected_receiver_ty {
|
||||
Ty::Ref(_, mutability) => Ty::Ref(Arc::new(derefed_receiver_ty), mutability),
|
||||
let actual_receiver_ty = match expected_receiver_ty.as_reference() {
|
||||
Some((_, mutability)) => {
|
||||
Ty::apply_one(TypeCtor::Ref(mutability), derefed_receiver_ty)
|
||||
}
|
||||
_ => derefed_receiver_ty,
|
||||
};
|
||||
self.unify(&expected_receiver_ty, &actual_receiver_ty);
|
||||
|
@ -875,7 +883,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
let _pat_ty = self.infer_pat(pat, &input_ty, BindingMode::default());
|
||||
}
|
||||
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(TypeCtor::Bool)),
|
||||
);
|
||||
}
|
||||
self.infer_expr(arm.expr, &expected);
|
||||
}
|
||||
|
@ -887,19 +898,19 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
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)
|
||||
}
|
||||
Expr::Continue => Ty::Never,
|
||||
Expr::Continue => Ty::simple(TypeCtor::Never),
|
||||
Expr::Break { expr } => {
|
||||
if let Some(expr) = expr {
|
||||
// TODO handle break with value
|
||||
self.infer_expr(*expr, &Expectation::none());
|
||||
}
|
||||
Ty::Never
|
||||
Ty::simple(TypeCtor::Never)
|
||||
}
|
||||
Expr::Return { expr } => {
|
||||
if let Some(expr) = expr {
|
||||
self.infer_expr(*expr, &Expectation::has_type(self.return_ty.clone()));
|
||||
}
|
||||
Ty::Never
|
||||
Ty::simple(TypeCtor::Never)
|
||||
}
|
||||
Expr::StructLit { path, fields, spread } => {
|
||||
let (ty, def_id) = self.resolve_variant(path.as_ref());
|
||||
|
@ -921,16 +932,19 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
let ty = receiver_ty
|
||||
.autoderef(self.db)
|
||||
.find_map(|derefed_ty| match derefed_ty {
|
||||
Ty::Tuple(fields) => {
|
||||
let i = name.to_string().parse::<usize>().ok();
|
||||
i.and_then(|i| fields.get(i).cloned())
|
||||
}
|
||||
Ty::Adt { def_id: AdtDef::Struct(s), ref substs, .. } => {
|
||||
s.field(self.db, name).map(|field| {
|
||||
self.write_field_resolution(tgt_expr, field);
|
||||
field.ty(self.db).subst(substs)
|
||||
})
|
||||
}
|
||||
Ty::Apply(a_ty) => match a_ty.ctor {
|
||||
TypeCtor::Tuple => {
|
||||
let i = name.to_string().parse::<usize>().ok();
|
||||
i.and_then(|i| a_ty.parameters.0.get(i).cloned())
|
||||
}
|
||||
TypeCtor::Adt(AdtDef::Struct(s)) => {
|
||||
s.field(self.db, name).map(|field| {
|
||||
self.write_field_resolution(tgt_expr, field);
|
||||
field.ty(self.db).subst(&a_ty.parameters)
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
})
|
||||
.unwrap_or(Ty::Unknown);
|
||||
|
@ -947,18 +961,19 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
cast_ty
|
||||
}
|
||||
Expr::Ref { expr, mutability } => {
|
||||
let expectation = if let Ty::Ref(ref subty, expected_mutability) = expected.ty {
|
||||
if expected_mutability == Mutability::Mut && *mutability == Mutability::Shared {
|
||||
// TODO: throw type error - expected mut reference but found shared ref,
|
||||
// which cannot be coerced
|
||||
}
|
||||
Expectation::has_type((**subty).clone())
|
||||
} else {
|
||||
Expectation::none()
|
||||
};
|
||||
let expectation =
|
||||
if let Some((exp_inner, exp_mutability)) = &expected.ty.as_reference() {
|
||||
if *exp_mutability == Mutability::Mut && *mutability == Mutability::Shared {
|
||||
// TODO: throw type error - expected mut reference but found shared ref,
|
||||
// which cannot be coerced
|
||||
}
|
||||
Expectation::has_type(Ty::clone(exp_inner))
|
||||
} else {
|
||||
Expectation::none()
|
||||
};
|
||||
// TODO reference coercions etc.
|
||||
let inner_ty = self.infer_expr(*expr, &expectation);
|
||||
Ty::Ref(Arc::new(inner_ty), *mutability)
|
||||
Ty::apply_one(TypeCtor::Ref(*mutability), inner_ty)
|
||||
}
|
||||
Expr::UnaryOp { expr, op } => {
|
||||
let inner_ty = self.infer_expr(*expr, &Expectation::none());
|
||||
|
@ -972,19 +987,27 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
}
|
||||
}
|
||||
UnaryOp::Neg => {
|
||||
match inner_ty {
|
||||
Ty::Int(primitive::UncertainIntTy::Unknown)
|
||||
| Ty::Int(primitive::UncertainIntTy::Signed(..))
|
||||
| Ty::Infer(InferTy::IntVar(..))
|
||||
| Ty::Infer(InferTy::FloatVar(..))
|
||||
| Ty::Float(..) => inner_ty,
|
||||
match &inner_ty {
|
||||
Ty::Apply(a_ty) => match a_ty.ctor {
|
||||
TypeCtor::Int(primitive::UncertainIntTy::Unknown)
|
||||
| TypeCtor::Int(primitive::UncertainIntTy::Signed(..))
|
||||
| TypeCtor::Float(..) => inner_ty,
|
||||
_ => Ty::Unknown,
|
||||
},
|
||||
Ty::Infer(InferTy::IntVar(..)) | Ty::Infer(InferTy::FloatVar(..)) => {
|
||||
inner_ty
|
||||
}
|
||||
// TODO: resolve ops::Neg trait
|
||||
_ => Ty::Unknown,
|
||||
}
|
||||
}
|
||||
UnaryOp::Not => {
|
||||
match inner_ty {
|
||||
Ty::Bool | Ty::Int(_) | Ty::Infer(InferTy::IntVar(..)) => inner_ty,
|
||||
match &inner_ty {
|
||||
Ty::Apply(a_ty) => match a_ty.ctor {
|
||||
TypeCtor::Bool | TypeCtor::Int(_) => inner_ty,
|
||||
_ => Ty::Unknown,
|
||||
},
|
||||
Ty::Infer(InferTy::IntVar(..)) => inner_ty,
|
||||
// TODO: resolve ops::Not trait for inner_ty
|
||||
_ => Ty::Unknown,
|
||||
}
|
||||
|
@ -995,7 +1018,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
Some(op) => {
|
||||
let lhs_expectation = match op {
|
||||
BinaryOp::BooleanAnd | BinaryOp::BooleanOr => {
|
||||
Expectation::has_type(Ty::Bool)
|
||||
Expectation::has_type(Ty::simple(TypeCtor::Bool))
|
||||
}
|
||||
_ => Expectation::none(),
|
||||
};
|
||||
|
@ -1016,11 +1039,16 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
ty_vec.push(self.infer_expr(*arg, &Expectation::none()));
|
||||
}
|
||||
|
||||
Ty::Tuple(Arc::from(ty_vec))
|
||||
Ty::apply(TypeCtor::Tuple, Substs(ty_vec.into()))
|
||||
}
|
||||
Expr::Array { exprs } => {
|
||||
let elem_ty = match &expected.ty {
|
||||
Ty::Slice(inner) | Ty::Array(inner) => Ty::clone(&inner),
|
||||
Ty::Apply(a_ty) => match a_ty.ctor {
|
||||
TypeCtor::Slice | TypeCtor::Array => {
|
||||
Ty::clone(&a_ty.parameters.as_single())
|
||||
}
|
||||
_ => self.new_type_var(),
|
||||
},
|
||||
_ => self.new_type_var(),
|
||||
};
|
||||
|
||||
|
@ -1028,21 +1056,23 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
self.infer_expr(*expr, &Expectation::has_type(elem_ty.clone()));
|
||||
}
|
||||
|
||||
Ty::Array(Arc::new(elem_ty))
|
||||
Ty::apply_one(TypeCtor::Array, elem_ty)
|
||||
}
|
||||
Expr::Literal(lit) => match lit {
|
||||
Literal::Bool(..) => Ty::Bool,
|
||||
Literal::String(..) => Ty::Ref(Arc::new(Ty::Str), Mutability::Shared),
|
||||
Literal::Bool(..) => Ty::simple(TypeCtor::Bool),
|
||||
Literal::String(..) => {
|
||||
Ty::apply_one(TypeCtor::Ref(Mutability::Shared), Ty::simple(TypeCtor::Str))
|
||||
}
|
||||
Literal::ByteString(..) => {
|
||||
let byte_type = Arc::new(Ty::Int(primitive::UncertainIntTy::Unsigned(
|
||||
let byte_type = Ty::simple(TypeCtor::Int(primitive::UncertainIntTy::Unsigned(
|
||||
primitive::UintTy::U8,
|
||||
)));
|
||||
let slice_type = Arc::new(Ty::Slice(byte_type));
|
||||
Ty::Ref(slice_type, Mutability::Shared)
|
||||
let slice_type = Ty::apply_one(TypeCtor::Slice, byte_type);
|
||||
Ty::apply_one(TypeCtor::Ref(Mutability::Shared), slice_type)
|
||||
}
|
||||
Literal::Char(..) => Ty::Char,
|
||||
Literal::Int(_v, ty) => Ty::Int(*ty),
|
||||
Literal::Float(_v, ty) => Ty::Float(*ty),
|
||||
Literal::Char(..) => Ty::simple(TypeCtor::Char),
|
||||
Literal::Int(_v, ty) => Ty::simple(TypeCtor::Int(*ty)),
|
||||
Literal::Float(_v, ty) => Ty::simple(TypeCtor::Float(*ty)),
|
||||
},
|
||||
};
|
||||
// use a new type variable if we got Ty::Unknown here
|
||||
|
@ -1178,11 +1208,11 @@ impl InferTy {
|
|||
match self {
|
||||
InferTy::TypeVar(..) => Ty::Unknown,
|
||||
InferTy::IntVar(..) => {
|
||||
Ty::Int(primitive::UncertainIntTy::Signed(primitive::IntTy::I32))
|
||||
}
|
||||
InferTy::FloatVar(..) => {
|
||||
Ty::Float(primitive::UncertainFloatTy::Known(primitive::FloatTy::F64))
|
||||
Ty::simple(TypeCtor::Int(primitive::UncertainIntTy::Signed(primitive::IntTy::I32)))
|
||||
}
|
||||
InferTy::FloatVar(..) => Ty::simple(TypeCtor::Float(
|
||||
primitive::UncertainFloatTy::Known(primitive::FloatTy::F64),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
//!
|
||||
//! This usually involves resolving names, collecting generic arguments etc.
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::{
|
||||
Function, Struct, StructField, Enum, EnumVariant, Path,
|
||||
ModuleDef, TypeAlias,
|
||||
|
@ -21,40 +19,40 @@ use crate::{
|
|||
generics::GenericParams,
|
||||
adt::VariantDef,
|
||||
};
|
||||
use super::{Ty, primitive, FnSig, Substs};
|
||||
use super::{Ty, primitive, FnSig, Substs, TypeCtor};
|
||||
|
||||
impl Ty {
|
||||
pub(crate) fn from_hir(db: &impl HirDatabase, resolver: &Resolver, type_ref: &TypeRef) -> Self {
|
||||
match type_ref {
|
||||
TypeRef::Never => Ty::Never,
|
||||
TypeRef::Never => Ty::simple(TypeCtor::Never),
|
||||
TypeRef::Tuple(inner) => {
|
||||
let inner_tys =
|
||||
inner.iter().map(|tr| Ty::from_hir(db, resolver, tr)).collect::<Vec<_>>();
|
||||
Ty::Tuple(inner_tys.into())
|
||||
Ty::apply(TypeCtor::Tuple, Substs(inner_tys.into()))
|
||||
}
|
||||
TypeRef::Path(path) => Ty::from_hir_path(db, resolver, path),
|
||||
TypeRef::RawPtr(inner, mutability) => {
|
||||
let inner_ty = Ty::from_hir(db, resolver, inner);
|
||||
Ty::RawPtr(Arc::new(inner_ty), *mutability)
|
||||
Ty::apply_one(TypeCtor::RawPtr(*mutability), inner_ty)
|
||||
}
|
||||
TypeRef::Array(inner) => {
|
||||
let inner_ty = Ty::from_hir(db, resolver, inner);
|
||||
Ty::Array(Arc::new(inner_ty))
|
||||
Ty::apply_one(TypeCtor::Array, inner_ty)
|
||||
}
|
||||
TypeRef::Slice(inner) => {
|
||||
let inner_ty = Ty::from_hir(db, resolver, inner);
|
||||
Ty::Slice(Arc::new(inner_ty))
|
||||
Ty::apply_one(TypeCtor::Slice, inner_ty)
|
||||
}
|
||||
TypeRef::Reference(inner, mutability) => {
|
||||
let inner_ty = Ty::from_hir(db, resolver, inner);
|
||||
Ty::Ref(Arc::new(inner_ty), *mutability)
|
||||
Ty::apply_one(TypeCtor::Ref(*mutability), inner_ty)
|
||||
}
|
||||
TypeRef::Placeholder => Ty::Unknown,
|
||||
TypeRef::Fn(params) => {
|
||||
let inner_tys =
|
||||
params.iter().map(|tr| Ty::from_hir(db, resolver, tr)).collect::<Vec<_>>();
|
||||
let sig = FnSig { params_and_return: inner_tys.into() };
|
||||
Ty::FnPtr(sig)
|
||||
let sig = Substs(inner_tys.into());
|
||||
Ty::apply(TypeCtor::FnPtr, sig)
|
||||
}
|
||||
TypeRef::Error => Ty::Unknown,
|
||||
}
|
||||
|
@ -64,14 +62,14 @@ impl Ty {
|
|||
if let Some(name) = path.as_ident() {
|
||||
// TODO handle primitive type names in resolver as well?
|
||||
if let Some(int_ty) = primitive::UncertainIntTy::from_type_name(name) {
|
||||
return Ty::Int(int_ty);
|
||||
return Ty::simple(TypeCtor::Int(int_ty));
|
||||
} else if let Some(float_ty) = primitive::UncertainFloatTy::from_type_name(name) {
|
||||
return Ty::Float(float_ty);
|
||||
return Ty::simple(TypeCtor::Float(float_ty));
|
||||
} else if let Some(known) = name.as_known_name() {
|
||||
match known {
|
||||
KnownName::Bool => return Ty::Bool,
|
||||
KnownName::Char => return Ty::Char,
|
||||
KnownName::Str => return Ty::Str,
|
||||
KnownName::Bool => return Ty::simple(TypeCtor::Bool),
|
||||
KnownName::Char => return Ty::simple(TypeCtor::Char),
|
||||
KnownName::Str => return Ty::simple(TypeCtor::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 {
|
||||
let generics = def.generic_params(db);
|
||||
let substs = make_substs(&generics);
|
||||
Ty::FnDef { def: def.into(), substs }
|
||||
Ty::apply(TypeCtor::FnDef(def.into()), substs)
|
||||
}
|
||||
|
||||
/// 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 substs = make_substs(&generics);
|
||||
Ty::FnDef { def: def.into(), substs }
|
||||
Ty::apply(TypeCtor::FnDef(def.into()), substs)
|
||||
}
|
||||
|
||||
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 substs = make_substs(&generics);
|
||||
Ty::FnDef { def: def.into(), substs }
|
||||
Ty::apply(TypeCtor::FnDef(def.into()), 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 {
|
||||
let generics = s.generic_params(db);
|
||||
Ty::Adt { def_id: s.into(), substs: make_substs(&generics) }
|
||||
Ty::apply(TypeCtor::Adt(s.into()), make_substs(&generics))
|
||||
}
|
||||
|
||||
fn type_for_enum(db: &impl HirDatabase, s: Enum) -> Ty {
|
||||
let generics = s.generic_params(db);
|
||||
Ty::Adt { def_id: s.into(), substs: make_substs(&generics) }
|
||||
Ty::apply(TypeCtor::Adt(s.into()), make_substs(&generics))
|
||||
}
|
||||
|
||||
fn type_for_type_alias(db: &impl HirDatabase, t: TypeAlias) -> Ty {
|
||||
|
|
|
@ -10,7 +10,7 @@ use crate::{
|
|||
HirDatabase, Module, Crate, Name, Function, Trait,
|
||||
ids::TraitId,
|
||||
impl_block::{ImplId, ImplBlock, ImplItem},
|
||||
ty::{AdtDef, Ty},
|
||||
ty::{Ty, TypeCtor},
|
||||
nameres::CrateModuleId,
|
||||
|
||||
};
|
||||
|
@ -18,7 +18,7 @@ use crate::{
|
|||
/// This is used as a key for indexing impls.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum TyFingerprint {
|
||||
Adt(AdtDef), // we'll also want to index impls for primitive types etc.
|
||||
Apply(TypeCtor),
|
||||
}
|
||||
|
||||
impl TyFingerprint {
|
||||
|
@ -27,7 +27,7 @@ impl TyFingerprint {
|
|||
/// `impl &S`. Hence, this will return `None` for reference types and such.
|
||||
fn for_impl(ty: &Ty) -> Option<TyFingerprint> {
|
||||
match ty {
|
||||
Ty::Adt { def_id, .. } => Some(TyFingerprint::Adt(*def_id)),
|
||||
Ty::Apply(a_ty) => Some(TyFingerprint::Apply(a_ty.ctor)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -111,7 +111,10 @@ impl CrateImplBlocks {
|
|||
|
||||
fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Option<Crate> {
|
||||
match ty {
|
||||
Ty::Adt { def_id, .. } => def_id.krate(db),
|
||||
Ty::Apply(a_ty) => match a_ty.ctor {
|
||||
TypeCtor::Adt(def_id) => def_id.krate(db),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::expr::BinaryOp;
|
||||
use super::{Ty, InferTy};
|
||||
use crate::{ ty::ApplicationTy, expr::BinaryOp};
|
||||
use super::{Ty, TypeCtor, InferTy};
|
||||
|
||||
pub(super) fn binary_op_return_ty(op: BinaryOp, rhs_ty: Ty) -> Ty {
|
||||
match op {
|
||||
|
@ -10,7 +10,7 @@ pub(super) fn binary_op_return_ty(op: BinaryOp, rhs_ty: Ty) -> Ty {
|
|||
| BinaryOp::LesserEqualTest
|
||||
| BinaryOp::GreaterEqualTest
|
||||
| BinaryOp::LesserTest
|
||||
| BinaryOp::GreaterTest => Ty::Bool,
|
||||
| BinaryOp::GreaterTest => Ty::simple(TypeCtor::Bool),
|
||||
BinaryOp::Assignment
|
||||
| BinaryOp::AddAssign
|
||||
| BinaryOp::SubAssign
|
||||
|
@ -32,10 +32,11 @@ pub(super) fn binary_op_return_ty(op: BinaryOp, rhs_ty: Ty) -> Ty {
|
|||
| BinaryOp::BitwiseAnd
|
||||
| BinaryOp::BitwiseOr
|
||||
| BinaryOp::BitwiseXor => match rhs_ty {
|
||||
Ty::Int(..)
|
||||
| Ty::Float(..)
|
||||
| Ty::Infer(InferTy::IntVar(..))
|
||||
| Ty::Infer(InferTy::FloatVar(..)) => rhs_ty,
|
||||
Ty::Apply(ApplicationTy { ctor, .. }) => match ctor {
|
||||
TypeCtor::Int(..) | TypeCtor::Float(..) => rhs_ty,
|
||||
_ => Ty::Unknown,
|
||||
},
|
||||
Ty::Infer(InferTy::IntVar(..)) | Ty::Infer(InferTy::FloatVar(..)) => rhs_ty,
|
||||
_ => 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 {
|
||||
match op {
|
||||
BinaryOp::BooleanAnd | BinaryOp::BooleanOr => Ty::Bool,
|
||||
BinaryOp::BooleanAnd | BinaryOp::BooleanOr => Ty::simple(TypeCtor::Bool),
|
||||
BinaryOp::Assignment | BinaryOp::EqualityTest => match lhs_ty {
|
||||
Ty::Int(..) | Ty::Float(..) | Ty::Str | Ty::Char | Ty::Bool => lhs_ty,
|
||||
Ty::Apply(ApplicationTy { ctor, .. }) => match ctor {
|
||||
TypeCtor::Int(..)
|
||||
| TypeCtor::Float(..)
|
||||
| TypeCtor::Str
|
||||
| TypeCtor::Char
|
||||
| TypeCtor::Bool => lhs_ty,
|
||||
_ => Ty::Unknown,
|
||||
},
|
||||
Ty::Infer(InferTy::IntVar(..)) | Ty::Infer(InferTy::FloatVar(..)) => lhs_ty,
|
||||
_ => Ty::Unknown,
|
||||
},
|
||||
BinaryOp::LesserEqualTest
|
||||
|
@ -73,7 +82,11 @@ pub(super) fn binary_op_rhs_expectation(op: BinaryOp, lhs_ty: Ty) -> Ty {
|
|||
| BinaryOp::BitwiseAnd
|
||||
| BinaryOp::BitwiseOr
|
||||
| BinaryOp::BitwiseXor => match lhs_ty {
|
||||
Ty::Int(..) | Ty::Float(..) => lhs_ty,
|
||||
Ty::Apply(ApplicationTy { ctor, .. }) => match ctor {
|
||||
TypeCtor::Int(..) | TypeCtor::Float(..) => lhs_ty,
|
||||
_ => Ty::Unknown,
|
||||
},
|
||||
Ty::Infer(InferTy::IntVar(..)) | Ty::Infer(InferTy::FloatVar(..)) => lhs_ty,
|
||||
_ => Ty::Unknown,
|
||||
},
|
||||
_ => Ty::Unknown,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use hir::{Ty, AdtDef};
|
||||
use hir::{Ty, AdtDef, TypeCtor};
|
||||
|
||||
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) {
|
||||
for receiver in receiver.autoderef(ctx.db) {
|
||||
match receiver {
|
||||
Ty::Adt { def_id, ref substs, .. } => {
|
||||
match def_id {
|
||||
AdtDef::Struct(s) => {
|
||||
for field in s.fields(ctx.db) {
|
||||
acc.add_field(ctx, field, substs);
|
||||
}
|
||||
Ty::Apply(a_ty) => match a_ty.ctor {
|
||||
TypeCtor::Adt(AdtDef::Struct(s)) => {
|
||||
for field in s.fields(ctx.db) {
|
||||
acc.add_field(ctx, field, &a_ty.parameters);
|
||||
}
|
||||
|
||||
// TODO unions
|
||||
AdtDef::Enum(_) => (),
|
||||
}
|
||||
}
|
||||
Ty::Tuple(fields) => {
|
||||
for (i, ty) in fields.iter().enumerate() {
|
||||
acc.add_pos_field(ctx, i, ty);
|
||||
// TODO unions
|
||||
TypeCtor::Tuple => {
|
||||
for (i, ty) in a_ty.parameters.iter().enumerate() {
|
||||
acc.add_pos_field(ctx, i, ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use hir::{Ty, AdtDef};
|
||||
use hir::AdtDef;
|
||||
|
||||
use crate::completion::{CompletionContext, Completions};
|
||||
|
||||
|
@ -15,8 +15,8 @@ pub(super) fn complete_struct_literal(acc: &mut Completions, ctx: &CompletionCon
|
|||
None => return,
|
||||
};
|
||||
let ty = infer_result[expr].clone();
|
||||
let (adt, substs) = match ty {
|
||||
Ty::Adt { def_id, ref substs, .. } => (def_id, substs),
|
||||
let (adt, substs) = match ty.as_adt() {
|
||||
Some(res) => res,
|
||||
_ => return,
|
||||
};
|
||||
match adt {
|
||||
|
|
|
@ -87,14 +87,12 @@ pub(crate) fn reference_definition(
|
|||
|
||||
if let Some(expr) = struct_lit.and_then(|lit| source_map.node_expr(lit.into())) {
|
||||
let ty = infer_result[expr].clone();
|
||||
if let hir::Ty::Adt { def_id, .. } = ty {
|
||||
if let hir::AdtDef::Struct(s) = def_id {
|
||||
let hir_path = hir::Path::from_name_ref(name_ref);
|
||||
let hir_name = hir_path.as_ident().unwrap();
|
||||
if let Some((hir::AdtDef::Struct(s), _)) = ty.as_adt() {
|
||||
let hir_path = hir::Path::from_name_ref(name_ref);
|
||||
let hir_name = hir_path.as_ident().unwrap();
|
||||
|
||||
if let Some(field) = s.field(db, hir_name) {
|
||||
return Exact(NavigationTarget::from_field(db, field));
|
||||
}
|
||||
if let Some(field) = s.field(db, hir_name) {
|
||||
return Exact(NavigationTarget::from_field(db, field));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -124,7 +122,7 @@ pub(crate) fn reference_definition(
|
|||
Some(Resolution::SelfType(impl_block)) => {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -517,23 +517,8 @@ The Some variant
|
|||
assert_eq!("u32", &type_name);
|
||||
}
|
||||
|
||||
// FIXME: improve type_of to make this work
|
||||
#[test]
|
||||
fn test_type_of_for_expr_1() {
|
||||
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() {
|
||||
fn test_type_of_for_expr() {
|
||||
let (analysis, range) = single_file_with_range(
|
||||
"
|
||||
fn main() {
|
||||
|
|
Loading…
Add table
Reference in a new issue