Move Type API to type

This commit is contained in:
Aleksey Kladov 2020-01-14 14:42:52 +01:00
parent 21c5fd8b1b
commit a38540771f
4 changed files with 102 additions and 85 deletions

View file

@ -21,8 +21,8 @@ use hir_expand::{
MacroDefId, MacroDefId,
}; };
use hir_ty::{ use hir_ty::{
autoderef, display::HirFormatter, expr::ExprValidator, method_resolution::implements_trait, autoderef, display::HirFormatter, expr::ExprValidator, method_resolution, ApplicationTy,
ApplicationTy, Canonical, InEnvironment, TraitEnvironment, Ty, TyDefId, TypeCtor, TypeWalk, Canonical, InEnvironment, TraitEnvironment, Ty, TyDefId, TypeCtor, TypeWalk,
}; };
use ra_db::{CrateId, Edition, FileId}; use ra_db::{CrateId, Edition, FileId};
use ra_prof::profile; use ra_prof::profile;
@ -120,7 +120,8 @@ impl_froms!(
BuiltinType BuiltinType
); );
pub use hir_def::{attr::Attrs, visibility::Visibility}; pub use hir_def::{attr::Attrs, visibility::Visibility, AssocItemId};
use rustc_hash::FxHashSet;
impl Module { impl Module {
pub(crate) fn new(krate: Crate, crate_module_id: LocalModuleId) -> Module { pub(crate) fn new(krate: Crate, crate_module_id: LocalModuleId) -> Module {
@ -891,7 +892,13 @@ impl Type {
}; };
let canonical_ty = Canonical { value: self.ty.value.clone(), num_vars: 0 }; let canonical_ty = Canonical { value: self.ty.value.clone(), num_vars: 0 };
implements_trait(&canonical_ty, db, self.ty.environment.clone(), krate, std_future_trait) method_resolution::implements_trait(
&canonical_ty,
db,
self.ty.environment.clone(),
krate,
std_future_trait,
)
} }
// FIXME: this method is broken, as it doesn't take closures into account. // FIXME: this method is broken, as it doesn't take closures into account.
@ -1002,6 +1009,65 @@ impl Type {
None None
} }
pub fn iterate_method_candidates<T>(
&self,
db: &impl HirDatabase,
krate: Crate,
traits_in_scope: &FxHashSet<TraitId>,
name: Option<&Name>,
mut callback: impl FnMut(&Ty, Function) -> Option<T>,
) -> Option<T> {
// There should be no inference vars in types passed here
// FIXME check that?
// FIXME replace Unknown by bound vars here
let canonical = Canonical { value: self.ty.value.clone(), num_vars: 0 };
let env = self.ty.environment.clone();
let krate = krate.id;
method_resolution::iterate_method_candidates(
&canonical,
db,
env,
krate,
traits_in_scope,
name,
method_resolution::LookupMode::MethodCall,
|ty, it| match it {
AssocItemId::FunctionId(f) => callback(ty, f.into()),
_ => None,
},
)
}
pub fn iterate_path_candidates<T>(
&self,
db: &impl HirDatabase,
krate: Crate,
traits_in_scope: &FxHashSet<TraitId>,
name: Option<&Name>,
mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>,
) -> Option<T> {
// There should be no inference vars in types passed here
// FIXME check that?
// FIXME replace Unknown by bound vars here
let canonical = Canonical { value: self.ty.value.clone(), num_vars: 0 };
let env = self.ty.environment.clone();
let krate = krate.id;
method_resolution::iterate_method_candidates(
&canonical,
db,
env,
krate,
traits_in_scope,
name,
method_resolution::LookupMode::Path,
|ty, it| callback(ty, it.into()),
)
}
pub fn as_adt(&self) -> Option<Adt> { pub fn as_adt(&self) -> Option<Adt> {
let (adt, _subst) = self.ty.value.as_adt()?; let (adt, _subst) = self.ty.value.as_adt()?;
Some(adt.into()) Some(adt.into())

View file

@ -16,12 +16,12 @@ use hir_def::{
expr::{ExprId, PatId}, expr::{ExprId, PatId},
nameres::ModuleSource, nameres::ModuleSource,
resolver::{self, resolver_for_scope, HasResolver, Resolver, TypeNs, ValueNs}, resolver::{self, resolver_for_scope, HasResolver, Resolver, TypeNs, ValueNs},
AssocItemId, DefWithBodyId, DefWithBodyId, TraitId,
}; };
use hir_expand::{ use hir_expand::{
hygiene::Hygiene, name::AsName, AstId, HirFileId, InFile, MacroCallId, MacroCallKind, hygiene::Hygiene, name::AsName, AstId, HirFileId, InFile, MacroCallId, MacroCallKind,
}; };
use hir_ty::{method_resolution, Canonical, InEnvironment, InferenceResult, TraitEnvironment, Ty}; use hir_ty::{InEnvironment, InferenceResult, TraitEnvironment};
use ra_prof::profile; use ra_prof::profile;
use ra_syntax::{ use ra_syntax::{
ast::{self, AstNode}, ast::{self, AstNode},
@ -29,11 +29,11 @@ use ra_syntax::{
SyntaxKind::*, SyntaxKind::*,
SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextUnit, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextUnit,
}; };
use rustc_hash::FxHashSet;
use crate::{ use crate::{
db::HirDatabase, Adt, AssocItem, Const, DefWithBody, Enum, EnumVariant, FromSource, Function, db::HirDatabase, Adt, Const, DefWithBody, Enum, EnumVariant, FromSource, Function, ImplBlock,
ImplBlock, Local, MacroDef, Name, Path, ScopeDef, Static, Struct, Trait, Type, TypeAlias, Local, MacroDef, Name, Path, ScopeDef, Static, Struct, Trait, Type, TypeAlias, TypeParam,
TypeParam,
}; };
/// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of /// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of
@ -347,63 +347,9 @@ impl SourceAnalyzer {
.collect() .collect()
} }
pub fn iterate_method_candidates<T>( /// Note: `FxHashSet<TraitId>` should be treated as an opaque type, passed into `Type
&self, pub fn traits_in_scope(&self, db: &impl HirDatabase) -> FxHashSet<TraitId> {
db: &impl HirDatabase, self.resolver.traits_in_scope(db)
ty: &Type,
name: Option<&Name>,
mut callback: impl FnMut(&Ty, Function) -> Option<T>,
) -> Option<T> {
// There should be no inference vars in types passed here
// FIXME check that?
// FIXME replace Unknown by bound vars here
let canonical = Canonical { value: ty.ty.value.clone(), num_vars: 0 };
let env = TraitEnvironment::lower(db, &self.resolver);
let krate = self.resolver.krate()?;
let traits_in_scope = self.resolver.traits_in_scope(db);
method_resolution::iterate_method_candidates(
&canonical,
db,
env,
krate,
&traits_in_scope,
name,
method_resolution::LookupMode::MethodCall,
|ty, it| match it {
AssocItemId::FunctionId(f) => callback(ty, f.into()),
_ => None,
},
)
}
pub fn iterate_path_candidates<T>(
&self,
db: &impl HirDatabase,
ty: &Type,
name: Option<&Name>,
mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>,
) -> Option<T> {
// There should be no inference vars in types passed here
// FIXME check that?
// FIXME replace Unknown by bound vars here
let canonical = Canonical { value: ty.ty.value.clone(), num_vars: 0 };
let env = TraitEnvironment::lower(db, &self.resolver);
let krate = self.resolver.krate()?;
let traits_in_scope = self.resolver.traits_in_scope(db);
method_resolution::iterate_method_candidates(
&canonical,
db,
env,
krate,
&traits_in_scope,
name,
method_resolution::LookupMode::Path,
|ty, it| callback(ty, it.into()),
)
} }
pub fn expand( pub fn expand(

View file

@ -53,14 +53,17 @@ fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Ty
} }
fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) { fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) {
if let Some(krate) = ctx.module.map(|it| it.krate()) {
let mut seen_methods = FxHashSet::default(); let mut seen_methods = FxHashSet::default();
ctx.analyzer.iterate_method_candidates(ctx.db, receiver, None, |_ty, func| { let traits_in_scope = ctx.analyzer.traits_in_scope(ctx.db);
receiver.iterate_method_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, func| {
if func.has_self_param(ctx.db) && seen_methods.insert(func.name(ctx.db)) { if func.has_self_param(ctx.db) && seen_methods.insert(func.name(ctx.db)) {
acc.add_function(ctx, func); acc.add_function(ctx, func);
} }
None::<()> None::<()>
}); });
} }
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {

View file

@ -49,7 +49,12 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
hir::ModuleDef::TypeAlias(a) => a.ty(ctx.db), hir::ModuleDef::TypeAlias(a) => a.ty(ctx.db),
_ => unreachable!(), _ => unreachable!(),
}; };
ctx.analyzer.iterate_path_candidates(ctx.db, &ty, None, |_ty, item| { // Iterate assoc types separately
// FIXME: complete T::AssocType
let krate = ctx.module.map(|m| m.krate());
if let Some(krate) = krate {
let traits_in_scope = ctx.analyzer.traits_in_scope(ctx.db);
ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| {
match item { match item {
hir::AssocItem::Function(func) => { hir::AssocItem::Function(func) => {
if !func.has_self_param(ctx.db) { if !func.has_self_param(ctx.db) {
@ -61,10 +66,7 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
} }
None::<()> None::<()>
}); });
// Iterate assoc types separately
// FIXME: complete T::AssocType
let krate = ctx.module.map(|m| m.krate());
if let Some(krate) = krate {
ty.iterate_impl_items(ctx.db, krate, |item| { ty.iterate_impl_items(ctx.db, krate, |item| {
match item { match item {
hir::AssocItem::Function(_) | hir::AssocItem::Const(_) => {} hir::AssocItem::Function(_) | hir::AssocItem::Const(_) => {}