Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide/src/goto_definition.rs')
-rw-r--r--crates/ide/src/goto_definition.rs67
1 files changed, 39 insertions, 28 deletions
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index f804cc3677..2c6c6e6e6c 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -5,10 +5,14 @@ use crate::{
navigation_target::{self, ToNav},
FilePosition, NavigationTarget, RangeInfo, TryToNav, UpmappingResult,
};
-use hir::{AsAssocItem, AssocItem, FileRange, InFile, MacroFileIdExt, ModuleDef, Semantics};
+use hir::{
+ sym, AsAssocItem, AssocItem, CallableKind, FileRange, HasCrate, InFile, MacroFileIdExt,
+ ModuleDef, Semantics,
+};
use ide_db::{
base_db::{AnchoredPath, FileLoader, SourceDatabase},
defs::{Definition, IdentClass},
+ famous_defs::FamousDefs,
helpers::pick_best_token,
RootDatabase, SymbolKind,
};
@@ -129,15 +133,45 @@ pub(crate) fn goto_definition(
Some(RangeInfo::new(original_token.text_range(), navs))
}
-// If the token is into(), try_into(), parse(), search the definition of From, TryFrom, FromStr.
+// If the token is into(), try_into(), search the definition of From, TryFrom.
fn find_definition_for_known_blanket_dual_impls(
sema: &Semantics<'_, RootDatabase>,
original_token: &SyntaxToken,
) -> Option<Vec<NavigationTarget>> {
let method_call = ast::MethodCallExpr::cast(original_token.parent()?.parent()?)?;
- let target_method = sema.resolve_known_blanket_dual_impls(&method_call)?;
-
- let def = Definition::from(target_method);
+ let callable = sema.resolve_method_call_as_callable(&method_call)?;
+ let CallableKind::Function(f) = callable.kind() else { return None };
+ let t = f.as_assoc_item(sema.db)?.container_trait(sema.db)?;
+
+ let return_type = callable.return_type();
+ let fd = FamousDefs(sema, return_type.krate(sema.db));
+ let fn_name = f.name(sema.db);
+ let f = if fn_name == sym::into && fd.core_convert_Into() == Some(t) {
+ let dual = fd.core_convert_From()?;
+ let dual_f = dual.function(sema.db, &sym::from)?;
+ sema.resolve_impl_method(
+ return_type.clone(),
+ dual,
+ dual_f,
+ [return_type, callable.receiver_param(sema.db)?.1],
+ )?
+ } else if fn_name == sym::try_into && fd.core_convert_TryInto() == Some(t) {
+ let dual = fd.core_convert_TryFrom()?;
+ let dual_f = dual.function(sema.db, &sym::try_from)?;
+ sema.resolve_impl_method(
+ return_type.clone(),
+ dual,
+ dual_f,
+ // Extract the `T` from `Result<T, ..>`
+ [return_type.type_arguments().next()?, callable.receiver_param(sema.db)?.1],
+ )?
+ } else {
+ return None;
+ };
+ // Assert that we got a trait impl function, if we are back in a trait definition we didn't
+ // succeed
+ let _t = f.as_assoc_item(sema.db)?.implemented_trait(sema.db)?;
+ let def = Definition::from(f);
Some(def_to_nav(sema.db, def))
}
@@ -3161,27 +3195,4 @@ fn f() {
"#,
);
}
-
- #[test]
- fn parse_call_to_from_str_definition() {
- check(
- r#"
-//- minicore: from, str
-struct A;
-
-impl FromStr for A {
- type Error = String;
-
- fn from_str(value: &str) -> Result<Self, Self::Error> {
- //^^^^^^^^
- Ok(A)
- }
-}
-
-fn f() {
- let a: Result<A, _> = "aaaaaa".parse$0();
-}
- "#,
- );
- }
}