mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-29 19:17:12 +00:00
Move dual blanket impl logic from source analyzer to goto_def
This commit is contained in:
parent
93a5846784
commit
03ea40369f
9 changed files with 92 additions and 113 deletions
|
|
@ -2756,6 +2756,15 @@ impl Trait {
|
|||
traits.iter().map(|tr| Trait::from(*tr)).collect()
|
||||
}
|
||||
|
||||
pub fn function(self, db: &dyn HirDatabase, name: impl PartialEq<Name>) -> Option<Function> {
|
||||
db.trait_data(self.id).items.iter().find(|(n, _)| name == *n).and_then(
|
||||
|&(_, it)| match it {
|
||||
AssocItemId::FunctionId(id) => Some(Function { id }),
|
||||
_ => None,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
|
||||
db.trait_data(self.id).items.iter().map(|(_name, it)| (*it).into()).collect()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1439,8 +1439,20 @@ impl<'db> SemanticsImpl<'db> {
|
|||
self.analyze(call.syntax())?.resolve_method_call_fallback(self.db, call)
|
||||
}
|
||||
|
||||
pub fn resolve_known_blanket_dual_impls(&self, call: &ast::MethodCallExpr) -> Option<Function> {
|
||||
self.analyze(call.syntax())?.resolve_known_blanket_dual_impls(self.db, call)
|
||||
/// Env is used to derive the trait environment
|
||||
// FIXME: better api for the trait environment
|
||||
pub fn resolve_impl_method(
|
||||
&self,
|
||||
env: Type,
|
||||
trait_: Trait,
|
||||
func: Function,
|
||||
subst: impl IntoIterator<Item = Type>,
|
||||
) -> Option<Function> {
|
||||
let mut substs = hir_ty::TyBuilder::subst_for_def(self.db, TraitId::from(trait_), None);
|
||||
for s in subst {
|
||||
substs = substs.push(s.ty);
|
||||
}
|
||||
Some(self.db.lookup_impl_method(env.env, func.into(), substs.build()).0.into())
|
||||
}
|
||||
|
||||
fn resolve_range_pat(&self, range_pat: &ast::RangePat) -> Option<StructId> {
|
||||
|
|
|
|||
|
|
@ -322,68 +322,6 @@ impl SourceAnalyzer {
|
|||
}
|
||||
}
|
||||
|
||||
// If the method is into(), try_into(), parse(), resolve it to from, try_from, from_str.
|
||||
pub(crate) fn resolve_known_blanket_dual_impls(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
call: &ast::MethodCallExpr,
|
||||
) -> Option<Function> {
|
||||
// e.g. if the method call is let b = a.into(),
|
||||
// - receiver_type is A (type of a)
|
||||
// - return_type is B (type of b)
|
||||
// We will find the definition of B::from(a: A).
|
||||
let callable = self.resolve_method_call_as_callable(db, call)?;
|
||||
let (_, receiver_type) = callable.receiver_param(db)?;
|
||||
let return_type = callable.return_type();
|
||||
let (search_method, substs) = match call.name_ref()?.text().as_str() {
|
||||
"into" => {
|
||||
let trait_ =
|
||||
self.resolver.resolve_known_trait(db.upcast(), &path![core::convert::From])?;
|
||||
(
|
||||
self.trait_fn(db, trait_, "from")?,
|
||||
hir_ty::TyBuilder::subst_for_def(db, trait_, None)
|
||||
.push(return_type.ty)
|
||||
.push(receiver_type.ty)
|
||||
.build(),
|
||||
)
|
||||
}
|
||||
"try_into" => {
|
||||
let trait_ = self
|
||||
.resolver
|
||||
.resolve_known_trait(db.upcast(), &path![core::convert::TryFrom])?;
|
||||
(
|
||||
self.trait_fn(db, trait_, "try_from")?,
|
||||
hir_ty::TyBuilder::subst_for_def(db, trait_, None)
|
||||
// If the method is try_into() or parse(), return_type is Result<T, Error>.
|
||||
// Get T from type arguments of Result<T, Error>.
|
||||
.push(return_type.type_arguments().next()?.ty)
|
||||
.push(receiver_type.ty)
|
||||
.build(),
|
||||
)
|
||||
}
|
||||
"parse" => {
|
||||
let trait_ =
|
||||
self.resolver.resolve_known_trait(db.upcast(), &path![core::str::FromStr])?;
|
||||
(
|
||||
self.trait_fn(db, trait_, "from_str")?,
|
||||
hir_ty::TyBuilder::subst_for_def(db, trait_, None)
|
||||
.push(return_type.type_arguments().next()?.ty)
|
||||
.build(),
|
||||
)
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
let found_method = self.resolve_impl_method_or_trait_def(db, search_method, substs);
|
||||
// If found_method == search_method, the method in trait itself is resolved.
|
||||
// It means the blanket dual impl is not found.
|
||||
if found_method == search_method {
|
||||
None
|
||||
} else {
|
||||
Some(found_method.into())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn resolve_expr_as_callable(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
|
|
@ -1309,18 +1247,6 @@ impl SourceAnalyzer {
|
|||
Some((trait_id, fn_id))
|
||||
}
|
||||
|
||||
fn trait_fn(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
trait_id: TraitId,
|
||||
method_name: &str,
|
||||
) -> Option<FunctionId> {
|
||||
db.trait_data(trait_id).items.iter().find_map(|(item_name, item)| match item {
|
||||
AssocItemId::FunctionId(t) if item_name.as_str() == method_name => Some(*t),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
fn ty_of_expr(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<&Ty> {
|
||||
self.infer.as_ref()?.type_of_expr_or_pat(self.expr_id(db, expr)?)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue