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 +++++++++++++++++++++++++++++++++++-- crates/ra_hir/src/lib.rs | 2 +- crates/ra_hir/src/source_binder.rs | 46 +++++----- 3 files changed, 185 insertions(+), 29 deletions(-) (limited to 'crates/ra_hir') 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), diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 843ce6a88..b88e4c745 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -51,7 +51,7 @@ pub use crate::{ src::HasSource, Adt, AssocItem, AttrDef, Const, Container, Crate, CrateDependency, DefWithBody, Docs, Enum, EnumVariant, FieldSource, Function, GenericDef, GenericParam, HasAttrs, ImplBlock, Import, Local, MacroDef, Module, ModuleDef, ModuleSource, ScopeDef, - Static, Struct, StructField, Trait, TypeAlias, Union, VariantDef, + Static, Struct, StructField, Trait, Type, TypeAlias, Union, VariantDef, }, expr::ExprScopes, from_source::FromSource, diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index cbfeca3ab..95a94c3f0 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -28,10 +28,10 @@ use crate::{ expr::{BodySourceMap, ExprScopes, ScopeId}, ty::{ method_resolution::{self, implements_trait}, - TraitEnvironment, + InEnvironment, TraitEnvironment, Ty, }, Adt, AssocItem, Const, DefWithBody, Either, Enum, EnumVariant, FromSource, Function, - GenericParam, Local, MacroDef, Name, Path, ScopeDef, Static, Struct, Trait, Ty, TypeAlias, + GenericParam, Local, MacroDef, Name, Path, ScopeDef, Static, Struct, Trait, Type, TypeAlias, }; fn try_get_resolver_for_node(db: &impl HirDatabase, node: Source<&SyntaxNode>) -> Option { @@ -198,14 +198,18 @@ impl SourceAnalyzer { self.body_source_map.as_ref()?.node_pat(src) } - pub fn type_of(&self, _db: &impl HirDatabase, expr: &ast::Expr) -> Option { + pub fn type_of(&self, db: &impl HirDatabase, expr: &ast::Expr) -> Option { let expr_id = self.expr_id(expr)?; - Some(self.infer.as_ref()?[expr_id].clone()) + let ty = self.infer.as_ref()?[expr_id].clone(); + let environment = TraitEnvironment::lower(db, &self.resolver); + Some(Type { krate: self.resolver.krate()?, ty: InEnvironment { value: ty, environment } }) } - pub fn type_of_pat(&self, _db: &impl HirDatabase, pat: &ast::Pat) -> Option { + pub fn type_of_pat(&self, db: &impl HirDatabase, pat: &ast::Pat) -> Option { let pat_id = self.pat_id(pat)?; - Some(self.infer.as_ref()?[pat_id].clone()) + let ty = self.infer.as_ref()?[pat_id].clone(); + let environment = TraitEnvironment::lower(db, &self.resolver); + Some(Type { krate: self.resolver.krate()?, ty: InEnvironment { value: ty, environment } }) } pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option { @@ -361,14 +365,14 @@ impl SourceAnalyzer { pub fn iterate_method_candidates( &self, db: &impl HirDatabase, - ty: Ty, + ty: &Type, name: Option<&Name>, mut callback: impl FnMut(&Ty, Function) -> Option, ) -> Option { // There should be no inference vars in types passed here // FIXME check that? // FIXME replace Unknown by bound vars here - let canonical = crate::ty::Canonical { value: ty, num_vars: 0 }; + let canonical = crate::ty::Canonical { value: ty.ty.value.clone(), num_vars: 0 }; method_resolution::iterate_method_candidates( &canonical, db, @@ -403,19 +407,19 @@ impl SourceAnalyzer { ) } - pub fn autoderef<'a>( - &'a self, - db: &'a impl HirDatabase, - ty: Ty, - ) -> impl Iterator + 'a { - // There should be no inference vars in types passed here - // FIXME check that? - let canonical = crate::ty::Canonical { value: ty, num_vars: 0 }; - let krate = self.resolver.krate(); - let environment = TraitEnvironment::lower(db, &self.resolver); - let ty = crate::ty::InEnvironment { value: canonical, environment }; - crate::ty::autoderef(db, krate, ty).map(|canonical| canonical.value) - } + // pub fn autoderef<'a>( + // &'a self, + // db: &'a impl HirDatabase, + // ty: Ty, + // ) -> impl Iterator + 'a { + // // There should be no inference vars in types passed here + // // FIXME check that? + // let canonical = crate::ty::Canonical { value: ty, num_vars: 0 }; + // let krate = self.resolver.krate(); + // let environment = TraitEnvironment::lower(db, &self.resolver); + // let ty = crate::ty::InEnvironment { value: canonical, environment }; + // crate::ty::autoderef(db, krate, ty).map(|canonical| canonical.value) + // } /// Checks that particular type `ty` implements `std::future::Future`. /// This function is used in `.await` syntax completion. -- cgit v1.2.3