From e5eadb339039e21718d382c0b3d02a4bf053b3f4 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 26 Nov 2019 14:02:57 +0300 Subject: Introduce hir::Type It should provide a convenient API over more low-level Ty --- crates/ra_hir/src/code_model.rs | 166 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 159 insertions(+), 7 deletions(-) (limited to 'crates/ra_hir/src/code_model.rs') diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index f7fc80d4e..a7bba85e1 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -10,9 +10,9 @@ use hir_def::{ docs::Documentation, per_ns::PerNs, resolver::{HasResolver, TypeNs}, - type_ref::TypeRef, - AstItemDef, ConstId, ContainerId, EnumId, FunctionId, GenericDefId, HasModule, ImplId, - LocalEnumVariantId, LocalImportId, LocalModuleId, LocalStructFieldId, Lookup, ModuleId, + type_ref::{Mutability, TypeRef}, + AstItemDef, ConstId, ContainerId, DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, + ImplId, LocalEnumVariantId, LocalImportId, LocalModuleId, LocalStructFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, UnionId, }; use hir_expand::{ @@ -26,8 +26,12 @@ use ra_syntax::{ast, AstNode, SyntaxNode}; use crate::{ db::{DefDatabase, HirDatabase}, expr::{BindingAnnotation, Body, BodySourceMap, ExprValidator, Pat, PatId}, - ty::{InferenceResult, Namespace, TraitRef}, - Either, Name, Source, Ty, + ty::display::HirFormatter, + ty::{ + self, InEnvironment, InferenceResult, Namespace, TraitEnvironment, TraitRef, Ty, TypeCtor, + TypeWalk, + }, + CallableDef, Either, HirDisplay, Name, Source, }; /// hir::Crate describes a single crate. It's the main interface with which @@ -469,6 +473,10 @@ pub enum Adt { impl_froms!(Adt: Struct, Union, Enum); impl Adt { + pub fn has_non_default_type_params(self, db: &impl HirDatabase) -> bool { + let subst = db.generic_defaults(self.into()); + subst.iter().any(|ty| ty == &Ty::Unknown) + } pub fn ty(self, db: &impl HirDatabase) -> Ty { match self { Adt::Struct(it) => it.ty(db), @@ -777,6 +785,11 @@ pub struct TypeAlias { } impl TypeAlias { + pub fn has_non_default_type_params(self, db: &impl HirDatabase) -> bool { + let subst = db.generic_defaults(self.id.into()); + subst.iter().any(|ty| ty == &Ty::Unknown) + } + pub fn module(self, db: &impl DefDatabase) -> Module { Module { id: self.id.lookup(db).module(db) } } @@ -927,9 +940,14 @@ impl Local { self.parent.module(db) } - pub fn ty(self, db: &impl HirDatabase) -> Ty { + pub fn ty(self, db: &impl HirDatabase) -> Type { let infer = db.infer(self.parent); - infer[self.pat_id].clone() + let ty = infer[self.pat_id].clone(); + let def = DefWithBodyId::from(self.parent); + let resolver = def.resolver(db); + let krate = def.module(db).krate; + let environment = TraitEnvironment::lower(db, &resolver); + Type { krate, ty: InEnvironment { value: ty, environment } } } pub fn source(self, db: &impl HirDatabase) -> Source> { @@ -986,6 +1004,140 @@ impl ImplBlock { } } +#[derive(Clone, PartialEq, Eq)] +pub struct Type { + pub(crate) krate: CrateId, + pub(crate) ty: InEnvironment, +} + +impl Type { + pub fn is_bool(&self) -> bool { + match &self.ty.value { + Ty::Apply(a_ty) => match a_ty.ctor { + TypeCtor::Bool => true, + _ => false, + }, + _ => false, + } + } + + pub fn is_mutable_reference(&self) -> bool { + match &self.ty.value { + Ty::Apply(a_ty) => match a_ty.ctor { + TypeCtor::Ref(Mutability::Mut) => true, + _ => false, + }, + _ => false, + } + } + + pub fn is_unknown(&self) -> bool { + match &self.ty.value { + Ty::Unknown => true, + _ => false, + } + } + + // FIXME: this method is broken, as it doesn't take closures into account. + pub fn as_callable(&self) -> Option { + Some(self.ty.value.as_callable()?.0) + } + + pub fn contains_unknown(&self) -> bool { + return go(&self.ty.value); + + fn go(ty: &Ty) -> bool { + match ty { + Ty::Unknown => true, + Ty::Apply(a_ty) => a_ty.parameters.iter().any(go), + _ => false, + } + } + } + + pub fn fields(&self, db: &impl HirDatabase) -> Vec<(StructField, Type)> { + let mut res = Vec::new(); + if let Ty::Apply(a_ty) = &self.ty.value { + match a_ty.ctor { + ty::TypeCtor::Adt(Adt::Struct(s)) => { + for field in s.fields(db) { + let ty = field.ty(db).subst(&a_ty.parameters); + res.push((field, self.derived(ty))); + } + } + _ => {} + } + }; + res + } + + pub fn tuple_fields(&self, _db: &impl HirDatabase) -> Vec { + let mut res = Vec::new(); + if let Ty::Apply(a_ty) = &self.ty.value { + match a_ty.ctor { + ty::TypeCtor::Tuple { .. } => { + for ty in a_ty.parameters.iter() { + let ty = ty.clone().subst(&a_ty.parameters); + res.push(self.derived(ty)); + } + } + _ => {} + } + }; + res + } + + pub fn variant_fields( + &self, + db: &impl HirDatabase, + def: VariantDef, + ) -> Vec<(StructField, Type)> { + // FIXME: check that ty and def match + match &self.ty.value { + Ty::Apply(a_ty) => def + .fields(db) + .into_iter() + .map(|it| (it, self.derived(it.ty(db).subst(&a_ty.parameters)))) + .collect(), + _ => Vec::new(), + } + } + + pub fn autoderef<'a>(&'a self, db: &'a impl HirDatabase) -> impl Iterator + 'a { + // There should be no inference vars in types passed here + // FIXME check that? + let canonical = crate::ty::Canonical { value: self.ty.value.clone(), num_vars: 0 }; + let environment = self.ty.environment.clone(); + let ty = InEnvironment { value: canonical, environment: environment.clone() }; + ty::autoderef(db, Some(self.krate), ty) + .map(|canonical| canonical.value) + .map(move |ty| self.derived(ty)) + } + + // FIXME: remove + pub fn into_ty(self) -> Ty { + self.ty.value + } + + pub fn as_adt(&self) -> Option { + let (adt, _subst) = self.ty.value.as_adt()?; + Some(adt) + } + + fn derived(&self, ty: Ty) -> Type { + Type { + krate: self.krate, + ty: InEnvironment { value: ty, environment: self.ty.environment.clone() }, + } + } +} + +impl HirDisplay for Type { + fn hir_fmt(&self, f: &mut HirFormatter) -> std::fmt::Result { + self.ty.value.hir_fmt(f) + } +} + /// For IDE only pub enum ScopeDef { ModuleDef(ModuleDef), -- cgit v1.2.3