mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 21:05:02 +00:00
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.
This commit is contained in:
parent
3d8a0982a1
commit
6a04d1f292
3 changed files with 53 additions and 3 deletions
|
@ -642,7 +642,11 @@ impl ItemMap {
|
||||||
log::debug!("resolving {:?} in other crate", path);
|
log::debug!("resolving {:?} in other crate", path);
|
||||||
let item_map = db.item_map(module.krate);
|
let item_map = db.item_map(module.krate);
|
||||||
let (def, s) = item_map.resolve_path(db, *module, &path);
|
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) {
|
match self[module.module_id].items.get(&segment.name) {
|
||||||
|
|
|
@ -1170,6 +1170,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
|
|
||||||
let (def, remaining_index) = resolved.into_inner();
|
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
|
// if the remaining_index is None, we expect the path
|
||||||
// to be fully resolved, in this case we continue with
|
// to be fully resolved, in this case we continue with
|
||||||
// the default by attempting to `take_values´ from the resolution.
|
// 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
|
// if we have more segments to process
|
||||||
let segment = &path.segments[remaining_index];
|
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
|
// Attempt to find an impl_item for the type which has a name matching
|
||||||
// the current segment
|
// the current segment
|
||||||
let ty = ty.iterate_impl_items(self.db, |item| match item {
|
let ty = ty.iterate_impl_items(self.db, |item| match item {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
use ra_db::{SourceDatabase, salsa::Database};
|
use ra_db::{SourceDatabase, salsa::Database, FilePosition};
|
||||||
use ra_syntax::ast::{self, AstNode};
|
use ra_syntax::{algo, ast::{self, AstNode}};
|
||||||
use test_utils::covers;
|
use test_utils::covers;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -946,6 +946,43 @@ fn test<R>(query_response: Canonical<QueryResponse<R>>) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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::<ast::Expr>(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 {
|
fn infer(content: &str) -> String {
|
||||||
let (db, _, file_id) = MockDatabase::with_single_file(content);
|
let (db, _, file_id) = MockDatabase::with_single_file(content);
|
||||||
let source_file = db.parse(file_id);
|
let source_file = db.parse(file_id);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue