From 6a04d1f292f14744c6b747fa39f1d1c1c20db0ee Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 23 Feb 2019 12:32:25 +0100 Subject: Fix resolution of associated method calls across crates I think it'll be better to make the path resolution the number of unresolved segments, not the first unresolved index; then this error could simply not have happened. But I'll do that separately. --- crates/ra_hir/src/nameres.rs | 6 +++++- crates/ra_hir/src/ty.rs | 9 +++++++++ crates/ra_hir/src/ty/tests.rs | 41 +++++++++++++++++++++++++++++++++++++++-- 3 files changed, 53 insertions(+), 3 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index 8067b8415..ac390c5db 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs @@ -642,7 +642,11 @@ impl ItemMap { log::debug!("resolving {:?} in other crate", path); let item_map = db.item_map(module.krate); let (def, s) = item_map.resolve_path(db, *module, &path); - return ResolvePathResult::with(def, ReachedFixedPoint::Yes, s); + return ResolvePathResult::with( + def, + ReachedFixedPoint::Yes, + s.map(|s| s + i), + ); } match self[module.module_id].items.get(&segment.name) { diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index ae595c16d..34f9ccd07 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -1170,6 +1170,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let (def, remaining_index) = resolved.into_inner(); + log::debug!( + "path {:?} resolved to {:?} with remaining index {:?}", + path, + def, + remaining_index + ); + // if the remaining_index is None, we expect the path // to be fully resolved, in this case we continue with // the default by attempting to `take_values´ from the resolution. @@ -1191,6 +1198,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { // if we have more segments to process let segment = &path.segments[remaining_index]; + log::debug!("looking for path segment: {:?}", segment); + // Attempt to find an impl_item for the type which has a name matching // the current segment let ty = ty.iterate_impl_items(self.db, |item| match item { diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index f04e9109c..77aeca669 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -1,8 +1,8 @@ use std::sync::Arc; use std::fmt::Write; -use ra_db::{SourceDatabase, salsa::Database}; -use ra_syntax::ast::{self, AstNode}; +use ra_db::{SourceDatabase, salsa::Database, FilePosition}; +use ra_syntax::{algo, ast::{self, AstNode}}; use test_utils::covers; use crate::{ @@ -946,6 +946,43 @@ fn test(query_response: Canonical>) { ); } +#[test] +fn cross_crate_associated_method_call() { + let (mut db, pos) = MockDatabase::with_position( + r#" +//- /main.rs +fn test() { + let x = other_crate::foo::S::thing(); + x<|>; +} + +//- /lib.rs +mod foo { + struct S; + impl S { + fn thing() -> i128 {} + } +} +"#, + ); + db.set_crate_graph_from_fixture(crate_graph! { + "main": ("/main.rs", ["other_crate"]), + "other_crate": ("/lib.rs", []), + }); + assert_eq!("i128", type_at_pos(&db, pos)); +} + +fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { + let func = source_binder::function_from_position(db, pos).unwrap(); + let body_syntax_mapping = func.body_syntax_mapping(db); + let inference_result = func.infer(db); + let (_, syntax) = func.source(db); + let node = algo::find_node_at_offset::(syntax.syntax(), pos.offset).unwrap(); + let expr = body_syntax_mapping.node_expr(node).unwrap(); + let ty = &inference_result[expr]; + ty.to_string() +} + fn infer(content: &str) -> String { let (db, _, file_id) = MockDatabase::with_single_file(content); let source_file = db.parse(file_id); -- cgit v1.2.3