Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir/src/source_analyzer.rs')
-rw-r--r--crates/hir/src/source_analyzer.rs74
1 files changed, 67 insertions, 7 deletions
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 2298a75d57..984a464ed1 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -21,7 +21,8 @@ use hir_def::{
path::{ModPath, Path, PathKind},
resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
type_ref::Mutability,
- AsMacroCall, DefWithBodyId, FieldId, FunctionId, LocalFieldId, Lookup, ModuleDefId, VariantId,
+ AsMacroCall, AssocItemId, DefWithBodyId, FieldId, FunctionId, ItemContainerId, LocalFieldId,
+ Lookup, ModuleDefId, VariantId,
};
use hir_expand::{
builtin_fn_macro::BuiltinFnLikeExpander, hygiene::Hygiene, name::AsName, HirFileId, InFile,
@@ -31,8 +32,8 @@ use hir_ty::{
record_literal_missing_fields, record_pattern_missing_fields, unsafe_expressions,
UnsafeExpr,
},
- Adjust, Adjustment, AutoBorrow, InferenceResult, Interner, Substitution, TyExt,
- TyLoweringContext,
+ method_resolution, Adjust, Adjustment, AutoBorrow, InferenceResult, Interner, Substitution,
+ TyExt, TyKind, TyLoweringContext,
};
use smallvec::SmallVec;
use syntax::{
@@ -42,8 +43,8 @@ use syntax::{
use crate::{
db::HirDatabase, semantics::PathResolution, Adt, AssocItem, BindingMode, BuiltinAttr,
- BuiltinType, Const, Field, Function, Local, Macro, ModuleDef, Static, Struct, ToolModule,
- Trait, Type, TypeAlias, Variant,
+ BuiltinType, Callable, Const, Field, Function, Local, Macro, ModuleDef, Static, Struct,
+ ToolModule, Trait, Type, TypeAlias, Variant,
};
/// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of
@@ -232,13 +233,29 @@ impl SourceAnalyzer {
)
}
+ pub(crate) fn resolve_method_call_as_callable(
+ &self,
+ db: &dyn HirDatabase,
+ call: &ast::MethodCallExpr,
+ ) -> Option<Callable> {
+ let expr_id = self.expr_id(db, &call.clone().into())?;
+ let (func, substs) = self.infer.as_ref()?.method_resolution(expr_id)?;
+ let ty = db.value_ty(func.into()).substitute(Interner, &substs);
+ let ty = Type::new_with_resolver(db, &self.resolver, ty);
+ let mut res = ty.as_callable(db)?;
+ res.is_bound_method = true;
+ Some(res)
+ }
+
pub(crate) fn resolve_method_call(
&self,
db: &dyn HirDatabase,
call: &ast::MethodCallExpr,
- ) -> Option<(FunctionId, Substitution)> {
+ ) -> Option<FunctionId> {
let expr_id = self.expr_id(db, &call.clone().into())?;
- self.infer.as_ref()?.method_resolution(expr_id)
+ let (f_in_trait, substs) = self.infer.as_ref()?.method_resolution(expr_id)?;
+ let f_in_impl = self.resolve_impl_method(db, f_in_trait, &substs);
+ f_in_impl.or(Some(f_in_trait))
}
pub(crate) fn resolve_field(
@@ -336,6 +353,25 @@ impl SourceAnalyzer {
let expr_id = self.expr_id(db, &path_expr.into())?;
let infer = self.infer.as_ref()?;
if let Some(assoc) = infer.assoc_resolutions_for_expr(expr_id) {
+ let assoc = match assoc {
+ AssocItemId::FunctionId(f_in_trait) => {
+ match infer.type_of_expr.get(expr_id) {
+ None => assoc,
+ Some(func_ty) => {
+ if let TyKind::FnDef(_fn_def, subs) = func_ty.kind(Interner) {
+ self.resolve_impl_method(db, f_in_trait, subs)
+ .map(AssocItemId::FunctionId)
+ .unwrap_or(assoc)
+ } else {
+ assoc
+ }
+ }
+ }
+ }
+
+ _ => assoc,
+ };
+
return Some(PathResolution::Def(AssocItem::from(assoc).into()));
}
if let Some(VariantId::EnumVariantId(variant)) =
@@ -563,6 +599,30 @@ impl SourceAnalyzer {
}
false
}
+
+ fn resolve_impl_method(
+ &self,
+ db: &dyn HirDatabase,
+ func: FunctionId,
+ substs: &Substitution,
+ ) -> Option<FunctionId> {
+ let impled_trait = match func.lookup(db.upcast()).container {
+ ItemContainerId::TraitId(trait_id) => trait_id,
+ _ => return None,
+ };
+ if substs.is_empty(Interner) {
+ return None;
+ }
+ let self_ty = substs.at(Interner, 0).ty(Interner)?;
+ let krate = self.resolver.krate();
+ let trait_env = self.resolver.body_owner()?.as_generic_def_id().map_or_else(
+ || Arc::new(hir_ty::TraitEnvironment::empty(krate)),
+ |d| db.trait_environment(d),
+ );
+
+ let fun_data = db.function_data(func);
+ method_resolution::lookup_impl_method(self_ty, db, trait_env, impled_trait, &fun_data.name)
+ }
}
fn scope_for(