@@ -5,10 +5,14 @@ use crate::{
55 navigation_target::{self, ToNav},
66 FilePosition, NavigationTarget, RangeInfo, TryToNav, UpmappingResult,
77};
8- use hir::{AsAssocItem, AssocItem, FileRange, InFile, MacroFileIdExt, ModuleDef, Semantics};
8+ use hir::{
9+ sym, AsAssocItem, AssocItem, CallableKind, FileRange, HasCrate, InFile, MacroFileIdExt,
10+ ModuleDef, Semantics,
11+ };
912use ide_db::{
1013 base_db::{AnchoredPath, FileLoader, SourceDatabase},
1114 defs::{Definition, IdentClass},
15+ famous_defs::FamousDefs,
1216 helpers::pick_best_token,
1317 RootDatabase, SymbolKind,
1418};
@@ -129,15 +133,65 @@ pub(crate) fn goto_definition(
129133 Some(RangeInfo::new(original_token.text_range(), navs))
130134}
131135
132- // If the token is into(), try_into(), parse(), search the definition of From, TryFrom, FromStr .
136+ // If the token is into(), try_into(), search the definition of From, TryFrom.
133137fn find_definition_for_known_blanket_dual_impls(
134138 sema: &Semantics<'_, RootDatabase>,
135139 original_token: &SyntaxToken,
136140) -> Option<Vec<NavigationTarget>> {
137141 let method_call = ast::MethodCallExpr::cast(original_token.parent()?.parent()?)?;
138- let target_method = sema.resolve_known_blanket_dual_impls(&method_call)?;
142+ let callable = sema.resolve_method_call_as_callable(&method_call)?;
143+ let CallableKind::Function(f) = callable.kind() else { return None };
144+ let assoc = f.as_assoc_item(sema.db)?;
145+
146+ let return_type = callable.return_type();
147+ let fd = FamousDefs(sema, return_type.krate(sema.db));
148+
149+ let t = match assoc.container(sema.db) {
150+ hir::AssocItemContainer::Trait(t) => t,
151+ hir::AssocItemContainer::Impl(impl_)
152+ if impl_.self_ty(sema.db).is_str() && f.name(sema.db) == sym::parse =>
153+ {
154+ let t = fd.core_convert_FromStr()?;
155+ let t_f = t.function(sema.db, &sym::from_str)?;
156+ return sema
157+ .resolve_trait_impl_method(
158+ return_type.clone(),
159+ t,
160+ t_f,
161+ [return_type.type_arguments().next()?],
162+ )
163+ .map(|f| def_to_nav(sema.db, f.into()));
164+ }
165+ hir::AssocItemContainer::Impl(_) => return None,
166+ };
139167
140- let def = Definition::from(target_method);
168+ let fn_name = f.name(sema.db);
169+ let f = if fn_name == sym::into && fd.core_convert_Into() == Some(t) {
170+ let dual = fd.core_convert_From()?;
171+ let dual_f = dual.function(sema.db, &sym::from)?;
172+ sema.resolve_trait_impl_method(
173+ return_type.clone(),
174+ dual,
175+ dual_f,
176+ [return_type, callable.receiver_param(sema.db)?.1],
177+ )?
178+ } else if fn_name == sym::try_into && fd.core_convert_TryInto() == Some(t) {
179+ let dual = fd.core_convert_TryFrom()?;
180+ let dual_f = dual.function(sema.db, &sym::try_from)?;
181+ sema.resolve_trait_impl_method(
182+ return_type.clone(),
183+ dual,
184+ dual_f,
185+ // Extract the `T` from `Result<T, ..>`
186+ [return_type.type_arguments().next()?, callable.receiver_param(sema.db)?.1],
187+ )?
188+ } else {
189+ return None;
190+ };
191+ // Assert that we got a trait impl function, if we are back in a trait definition we didn't
192+ // succeed
193+ let _t = f.as_assoc_item(sema.db)?.implemented_trait(sema.db)?;
194+ let def = Definition::from(f);
141195 Some(def_to_nav(sema.db, def))
142196}
143197
@@ -3168,16 +3222,13 @@ fn f() {
31683222 r#"
31693223//- minicore: from, str
31703224struct A;
3171-
31723225impl FromStr for A {
31733226 type Error = String;
3174-
31753227 fn from_str(value: &str) -> Result<Self, Self::Error> {
31763228 //^^^^^^^^
31773229 Ok(A)
31783230 }
31793231}
3180-
31813232fn f() {
31823233 let a: Result<A, _> = "aaaaaa".parse$0();
31833234}
0 commit comments