]> git.lizzy.rs Git - rust.git/commitdiff
Add local functions to bodies
authorAleksey Kladov <aleksey.kladov@gmail.com>
Fri, 20 Dec 2019 10:19:09 +0000 (11:19 +0100)
committerAleksey Kladov <aleksey.kladov@gmail.com>
Fri, 20 Dec 2019 10:52:17 +0000 (11:52 +0100)
Cargo.lock
crates/ra_hir/src/from_source.rs
crates/ra_hir_def/Cargo.toml
crates/ra_hir_def/src/body.rs
crates/ra_hir_def/src/body/lower.rs
crates/ra_ide/src/goto_definition.rs

index b7a5108a496c1e6d1aeb5f32b245226077939442..3f2cbc8ab0b5d915cdb013de617754677e943b4d 100644 (file)
@@ -957,6 +957,7 @@ name = "ra_hir_def"
 version = "0.1.0"
 dependencies = [
  "anymap 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "drop_bomb 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "insta 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
index 7abb4bd75ad71f14cf497edd89c1a5f6a22bff25..b3ed88b6b62b3c3db9d60cf04b07293588b218b0 100644 (file)
@@ -1,8 +1,8 @@
 //! FIXME: write short doc here
 use hir_def::{
     child_by_source::ChildBySource, dyn_map::DynMap, keys, keys::Key, nameres::ModuleSource,
-    ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, ImplId, ModuleId, StaticId, StructId,
-    TraitId, TypeAliasId, UnionId, VariantId,
+    ConstId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, GenericDefId, ImplId, ModuleId,
+    StaticId, StructId, TraitId, TypeAliasId, UnionId, VariantId,
 };
 use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind};
 use ra_syntax::{
@@ -227,7 +227,12 @@ fn _analyze_container(db: &impl DefDatabase, src: InFile<&SyntaxNode>) -> Option
                 ast::ImplBlock(it) => {
                     let c = ImplBlock::from_source(db, src.with_value(it))?;
                     c.id.child_by_source(db)
-                 },
+                },
+                ast::FnDef(it) => {
+                    let f = Function::from_source(db, src.with_value(it))?;
+                    DefWithBodyId::from(f.id)
+                        .child_by_source(db)
+                },
                 _ => { continue },
             }
         };
index b1923bbf2edf5b119b9f3185b7d94924626d2e34..2c368f690b1bd0d71c5d433d81425121165ccab7 100644 (file)
@@ -13,6 +13,7 @@ once_cell = "1.0.1"
 rustc-hash = "1.0"
 either = "1.5"
 anymap = "0.12"
+drop_bomb = "0.1.4"
 
 ra_arena = { path = "../ra_arena" }
 ra_db = { path = "../ra_db" }
index 332c509e17063d3b520ad91d2c0bf944b477f54a..92c32b080c092c058ef8909da406ed6ce6327da7 100644 (file)
@@ -3,10 +3,13 @@
 mod lower;
 pub mod scope;
 
-use std::{ops::Index, sync::Arc};
+use std::{mem, ops::Index, sync::Arc};
 
+use drop_bomb::DropBomb;
 use either::Either;
-use hir_expand::{hygiene::Hygiene, AstId, HirFileId, InFile, MacroCallKind, MacroDefId};
+use hir_expand::{
+    ast_id_map::AstIdMap, hygiene::Hygiene, AstId, HirFileId, InFile, MacroCallKind, MacroDefId,
+};
 use ra_arena::{map::ArenaMap, Arena};
 use ra_syntax::{ast, AstNode, AstPtr};
 use rustc_hash::FxHashMap;
@@ -24,6 +27,7 @@ struct Expander {
     crate_def_map: Arc<CrateDefMap>,
     current_file_id: HirFileId,
     hygiene: Hygiene,
+    ast_id_map: Arc<AstIdMap>,
     module: ModuleId,
 }
 
@@ -31,7 +35,8 @@ impl Expander {
     fn new(db: &impl DefDatabase, current_file_id: HirFileId, module: ModuleId) -> Expander {
         let crate_def_map = db.crate_def_map(module.krate);
         let hygiene = Hygiene::new(db, current_file_id);
-        Expander { crate_def_map, current_file_id, hygiene, module }
+        let ast_id_map = db.ast_id_map(current_file_id);
+        Expander { crate_def_map, current_file_id, hygiene, ast_id_map, module }
     }
 
     fn enter_expand(
@@ -52,9 +57,14 @@ fn enter_expand(
                     if let Some(expr) = ast::Expr::cast(node) {
                         log::debug!("macro expansion {:#?}", expr.syntax());
 
-                        let mark = Mark { file_id: self.current_file_id };
+                        let mark = Mark {
+                            file_id: self.current_file_id,
+                            ast_id_map: mem::take(&mut self.ast_id_map),
+                            bomb: DropBomb::new("expansion mark dropped"),
+                        };
                         self.hygiene = Hygiene::new(db, file_id);
                         self.current_file_id = file_id;
+                        self.ast_id_map = db.ast_id_map(file_id);
 
                         return Some((mark, expr));
                     }
@@ -67,10 +77,11 @@ fn enter_expand(
         None
     }
 
-    fn exit(&mut self, db: &impl DefDatabase, mark: Mark) {
+    fn exit(&mut self, db: &impl DefDatabase, mut mark: Mark) {
         self.hygiene = Hygiene::new(db, mark.file_id);
         self.current_file_id = mark.file_id;
-        std::mem::forget(mark);
+        self.ast_id_map = mem::take(&mut mark.ast_id_map);
+        mark.bomb.defuse();
     }
 
     fn to_source<T>(&self, value: T) -> InFile<T> {
@@ -91,18 +102,17 @@ fn resolve_path_as_macro(&self, db: &impl DefDatabase, path: &ModPath) -> Option
             .0
             .take_macros()
     }
+
+    fn ast_id<N: AstNode>(&self, item: &N) -> AstId<N> {
+        let file_local_id = self.ast_id_map.ast_id(item);
+        AstId::new(self.current_file_id, file_local_id)
+    }
 }
 
 struct Mark {
     file_id: HirFileId,
-}
-
-impl Drop for Mark {
-    fn drop(&mut self) {
-        if !std::thread::panicking() {
-            panic!("dropped mark")
-        }
-    }
+    ast_id_map: Arc<AstIdMap>,
+    bomb: DropBomb,
 }
 
 /// The body of an item (function, const etc.).
@@ -174,7 +184,7 @@ pub(crate) fn body_with_source_map_query(
             }
         };
         let expander = Expander::new(db, file_id, module);
-        let (body, source_map) = Body::new(db, expander, params, body);
+        let (body, source_map) = Body::new(db, def, expander, params, body);
         (Arc::new(body), Arc::new(source_map))
     }
 
@@ -184,11 +194,12 @@ pub(crate) fn body_query(db: &impl DefDatabase, def: DefWithBodyId) -> Arc<Body>
 
     fn new(
         db: &impl DefDatabase,
+        def: DefWithBodyId,
         expander: Expander,
         params: Option<ast::ParamList>,
         body: Option<ast::Expr>,
     ) -> (Body, BodySourceMap) {
-        lower::lower(db, expander, params, body)
+        lower::lower(db, def, expander, params, body)
     }
 }
 
index 86960186f198407c3ad6588222bfd877ae8ed81e..17efa10e2919b0283c9557535bd25bbae91e8a51 100644 (file)
@@ -2,11 +2,12 @@
 //! representation.
 
 use either::Either;
+
 use hir_expand::name::{name, AsName, Name};
 use ra_arena::Arena;
 use ra_syntax::{
     ast::{
-        self, ArgListOwner, ArrayExprKind, LiteralKind, LoopBodyOwner, NameOwner,
+        self, ArgListOwner, ArrayExprKind, LiteralKind, LoopBodyOwner, ModuleItemOwner, NameOwner,
         TypeAscriptionOwner,
     },
     AstNode, AstPtr,
     path::GenericArgs,
     path::Path,
     type_ref::{Mutability, TypeRef},
+    ContainerId, DefWithBodyId, FunctionLoc, Intern,
 };
 
 pub(super) fn lower(
     db: &impl DefDatabase,
+    def: DefWithBodyId,
     expander: Expander,
     params: Option<ast::ParamList>,
     body: Option<ast::Expr>,
 ) -> (Body, BodySourceMap) {
     ExprCollector {
-        expander,
         db,
+        def,
+        expander,
         source_map: BodySourceMap::default(),
         body: Body {
             exprs: Arena::default(),
@@ -49,6 +53,7 @@ pub(super) fn lower(
 
 struct ExprCollector<DB> {
     db: DB,
+    def: DefWithBodyId,
     expander: Expander,
 
     body: Body,
@@ -467,6 +472,7 @@ fn collect_block(&mut self, expr: ast::BlockExpr) -> ExprId {
             Some(block) => block,
             None => return self.alloc_expr(Expr::Missing, syntax_node_ptr),
         };
+        self.collect_block_items(&block);
         let statements = block
             .statements()
             .map(|s| match s {
@@ -483,6 +489,20 @@ fn collect_block(&mut self, expr: ast::BlockExpr) -> ExprId {
         self.alloc_expr(Expr::Block { statements, tail }, syntax_node_ptr)
     }
 
+    fn collect_block_items(&mut self, block: &ast::Block) {
+        let container = ContainerId::DefWithBodyId(self.def);
+        for item in block.items() {
+            match item {
+                ast::ModuleItem::FnDef(def) => {
+                    let ast_id = self.expander.ast_id(&def);
+                    self.body.defs.push(FunctionLoc { container, ast_id }.intern(self.db).into())
+                }
+                // FIXME: handle other items
+                _ => (),
+            }
+        }
+    }
+
     fn collect_block_opt(&mut self, expr: Option<ast::BlockExpr>) -> ExprId {
         if let Some(block) = expr {
             self.collect_block(block)
index 184555792cea7ce49e8f07eabd9e82d35d4f636a..ee4ae3e03707f1830d7c2cb5c6d75fa3b25269f6 100644 (file)
@@ -858,4 +858,21 @@ fn foo() {
             "y",
         );
     }
+
+    #[test]
+    fn goto_def_in_local_fn() {
+        check_goto(
+            "
+            //- /lib.rs
+            fn main() {
+                fn foo() {
+                    let x = 92;
+                    <|>x;
+                }
+            }
+            ",
+            "x BIND_PAT FileId(1) [39; 40)",
+            "x",
+        );
+    }
 }