about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lower.rs26
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics.rs13
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs45
3 files changed, 80 insertions, 4 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs
index 6d1a3d17447..350bb8d5172 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs
@@ -2,7 +2,7 @@
 use std::{cell::OnceCell, mem};
 
 use hir_expand::{span_map::SpanMap, AstId, HirFileId, InFile};
-use span::{AstIdMap, AstIdNode};
+use span::{AstIdMap, AstIdNode, Edition, EditionedFileId, FileId, RealSpanMap};
 use stdx::thin_vec::ThinVec;
 use syntax::ast;
 use triomphe::Arc;
@@ -63,6 +63,30 @@ impl<'a> LowerCtx<'a> {
         }
     }
 
+    /// Prepares a `LowerCtx` for synthetic AST that needs to be lowered. This is intended for IDE things.
+    pub fn for_synthetic_ast(
+        db: &'a dyn DefDatabase,
+        ast_id_map: Arc<AstIdMap>,
+        types_map: &'a mut TypesMap,
+        types_source_map: &'a mut TypesSourceMap,
+    ) -> Self {
+        let file_id = EditionedFileId::new(
+            FileId::from_raw(EditionedFileId::MAX_FILE_ID),
+            Edition::Edition2015,
+        );
+        LowerCtx {
+            db,
+            // Make up an invalid file id, so that if we will try to actually access it salsa will panic.
+            file_id: file_id.into(),
+            span_map: SpanMap::RealSpanMap(Arc::new(RealSpanMap::absolute(file_id))).into(),
+            ast_id_map: ast_id_map.into(),
+            impl_trait_bounds: Vec::new(),
+            outer_impl_trait: false,
+            types_map,
+            types_source_map,
+        }
+    }
+
     pub(crate) fn span_map(&self) -> &SpanMap {
         self.span_map.get_or_init(|| self.db.span_map(self.file_id))
     }
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index 9d3f8e5fba4..46766fcc5b1 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -34,7 +34,7 @@ use intern::Symbol;
 use itertools::Itertools;
 use rustc_hash::{FxHashMap, FxHashSet};
 use smallvec::{smallvec, SmallVec};
-use span::{EditionedFileId, FileId, HirFileIdRepr, SyntaxContextId};
+use span::{AstIdMap, EditionedFileId, FileId, HirFileIdRepr, SyntaxContextId};
 use stdx::TupleExt;
 use syntax::{
     algo::skip_trivia_token,
@@ -42,6 +42,7 @@ use syntax::{
     AstNode, AstToken, Direction, SyntaxKind, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange,
     TextSize,
 };
+use triomphe::Arc;
 
 use crate::{
     db::HirDatabase,
@@ -1973,10 +1974,16 @@ impl SemanticsScope<'_> {
     /// Resolve a path as-if it was written at the given scope. This is
     /// necessary a heuristic, as it doesn't take hygiene into account.
     pub fn speculative_resolve(&self, ast_path: &ast::Path) -> Option<PathResolution> {
+        let root = ast_path.syntax().ancestors().last().unwrap();
+        let ast_id_map = Arc::new(AstIdMap::from_source(&root));
         let (mut types_map, mut types_source_map) =
             (TypesMap::default(), TypesSourceMap::default());
-        let mut ctx =
-            LowerCtx::new(self.db.upcast(), self.file_id, &mut types_map, &mut types_source_map);
+        let mut ctx = LowerCtx::for_synthetic_ast(
+            self.db.upcast(),
+            ast_id_map,
+            &mut types_map,
+            &mut types_source_map,
+        );
         let path = Path::from_src(&mut ctx, ast_path.clone())?;
         resolve_hir_path(
             self.db,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs
index 7f8ea44fb12..57df39d541e 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs
@@ -2318,4 +2318,49 @@ impl<'a> Test<'a, i32> for bool {
 "#,
         );
     }
+
+    #[test]
+    fn issue_17321() {
+        check_assist(
+            add_missing_impl_members,
+            r#"
+fn main() {}
+
+mod other_file_1 {
+    pub const SOME_CONSTANT: usize = 8;
+}
+
+mod other_file_2 {
+    use crate::other_file_1::SOME_CONSTANT;
+
+    pub trait Trait {
+        type Iter: Iterator<Item = [u8; SOME_CONSTANT]>;
+    }
+}
+
+pub struct MyStruct;
+
+impl other_file_2::Trait for MyStruct$0 {}"#,
+            r#"
+fn main() {}
+
+mod other_file_1 {
+    pub const SOME_CONSTANT: usize = 8;
+}
+
+mod other_file_2 {
+    use crate::other_file_1::SOME_CONSTANT;
+
+    pub trait Trait {
+        type Iter: Iterator<Item = [u8; SOME_CONSTANT]>;
+    }
+}
+
+pub struct MyStruct;
+
+impl other_file_2::Trait for MyStruct {
+    $0type Iter;
+}"#,
+        );
+    }
 }