mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-29 18:23:49 +00:00
Introduced resolve_macro_call on resolver
changed to manual expansion fix for nested macros
This commit is contained in:
parent
ce211434a6
commit
1ab7066e32
4
.vscode/launch.json
vendored
4
.vscode/launch.json
vendored
@ -14,9 +14,7 @@
|
||||
"--disable-extensions"
|
||||
],
|
||||
"env": {
|
||||
"__RA_LSP_SERVER_DEBUG": "${workspaceFolder}/target/debug/ra_lsp_server",
|
||||
"RUST_LOG" :"ra_hir=debug",
|
||||
"RA_INTERNAL_MODE":"1"
|
||||
"__RA_LSP_SERVER_DEBUG": "${workspaceFolder}/target/debug/ra_lsp_server"
|
||||
},
|
||||
"outFiles": ["${workspaceFolder}/editors/code/out/**/*.js"],
|
||||
"preLaunchTask": "Build All"
|
||||
|
@ -5,14 +5,14 @@ use rustc_hash::FxHashMap;
|
||||
|
||||
use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap};
|
||||
use ra_syntax::{
|
||||
SyntaxNodePtr, AstPtr, AstNode,
|
||||
SyntaxNodePtr, AstPtr, AstNode,TreeArc,
|
||||
ast::{self, LoopBodyOwner, ArgListOwner, NameOwner, LiteralKind,ArrayExprKind, TypeAscriptionOwner}
|
||||
};
|
||||
|
||||
use crate::{
|
||||
Path, Name, HirDatabase, Resolver,DefWithBody, Either,
|
||||
name::AsName,
|
||||
ids::{MacroCallLoc,HirFileId},
|
||||
ids::{MacroCallId},
|
||||
type_ref::{Mutability, TypeRef},
|
||||
};
|
||||
use crate::{path::GenericArgs, ty::primitive::{IntTy, UncertainIntTy, FloatTy, UncertainFloatTy}};
|
||||
@ -488,23 +488,45 @@ pub(crate) struct ExprCollector<DB> {
|
||||
params: Vec<PatId>,
|
||||
body_expr: Option<ExprId>,
|
||||
resolver: Resolver,
|
||||
// FIXEME: Its a quick hack,see issue #1196
|
||||
is_in_macro: bool,
|
||||
}
|
||||
|
||||
impl<'a, DB> ExprCollector<&'a DB>
|
||||
where
|
||||
DB: HirDatabase,
|
||||
{
|
||||
fn new(owner: DefWithBody, resolver: Resolver, db: &'a DB) -> Self {
|
||||
ExprCollector {
|
||||
owner,
|
||||
resolver,
|
||||
db,
|
||||
exprs: Arena::default(),
|
||||
pats: Arena::default(),
|
||||
source_map: BodySourceMap::default(),
|
||||
params: Vec::new(),
|
||||
body_expr: None,
|
||||
is_in_macro: false,
|
||||
}
|
||||
}
|
||||
fn alloc_expr(&mut self, expr: Expr, syntax_ptr: SyntaxNodePtr) -> ExprId {
|
||||
let id = self.exprs.alloc(expr);
|
||||
self.source_map.expr_map.insert(syntax_ptr, id);
|
||||
self.source_map.expr_map_back.insert(id, syntax_ptr);
|
||||
if !self.is_in_macro {
|
||||
self.source_map.expr_map.insert(syntax_ptr, id);
|
||||
self.source_map.expr_map_back.insert(id, syntax_ptr);
|
||||
}
|
||||
|
||||
id
|
||||
}
|
||||
|
||||
fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
|
||||
let id = self.pats.alloc(pat);
|
||||
self.source_map.pat_map.insert(ptr, id);
|
||||
self.source_map.pat_map_back.insert(id, ptr);
|
||||
|
||||
if !self.is_in_macro {
|
||||
self.source_map.pat_map.insert(ptr, id);
|
||||
self.source_map.pat_map_back.insert(id, ptr);
|
||||
}
|
||||
|
||||
id
|
||||
}
|
||||
|
||||
@ -790,40 +812,19 @@ where
|
||||
ast::ExprKind::IndexExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
|
||||
ast::ExprKind::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
|
||||
ast::ExprKind::MacroCall(e) => {
|
||||
// very hacky.TODO change to use the macro resolution
|
||||
let name = e
|
||||
.path()
|
||||
.and_then(Path::from_ast)
|
||||
.and_then(|path| path.expand_macro_expr())
|
||||
.unwrap_or_else(Name::missing);
|
||||
// very hacky.FIXME change to use the macro resolution
|
||||
let path = e.path().and_then(Path::from_ast);
|
||||
|
||||
if let Some(macro_id) = self.resolver.resolve_macro_call(&name) {
|
||||
if let Some((module, _)) = self.resolver.module() {
|
||||
// we do this to get the ast_id for the macro call
|
||||
// if we used the ast_id from the macro_id variable
|
||||
// it gives us the ast_id of the defenition site
|
||||
let module = module.mk_module(module.root());
|
||||
let hir_file_id = module.definition_source(self.db).0;
|
||||
let ast_id =
|
||||
self.db.ast_id_map(hir_file_id).ast_id(e).with_file_id(hir_file_id);
|
||||
|
||||
let call_loc = MacroCallLoc { def: *macro_id, ast_id };
|
||||
let call_id = call_loc.id(self.db);
|
||||
let file_id: HirFileId = call_id.into();
|
||||
|
||||
log::debug!(
|
||||
"expanded macro ast {}",
|
||||
self.db.hir_parse(file_id).syntax().debug_dump()
|
||||
);
|
||||
|
||||
self.db
|
||||
.hir_parse(file_id)
|
||||
.syntax()
|
||||
.descendants()
|
||||
.find_map(ast::Expr::cast)
|
||||
.map(|expr| self.collect_expr(expr))
|
||||
.unwrap_or(self.alloc_expr(Expr::Missing, syntax_ptr))
|
||||
if let Some(call_id) = self.resolver.resolve_macro_call(self.db, path, e) {
|
||||
if let Some(expr) = expand_macro_to_expr(self.db, call_id, e.token_tree()) {
|
||||
log::debug!("macro expansion {}", expr.syntax().debug_dump());
|
||||
let old = std::mem::replace(&mut self.is_in_macro, true);
|
||||
let id = self.collect_expr(&expr);
|
||||
self.is_in_macro = old;
|
||||
id
|
||||
} else {
|
||||
// FIXME: Instead of just dropping the error from expansion
|
||||
// report it
|
||||
self.alloc_expr(Expr::Missing, syntax_ptr)
|
||||
}
|
||||
} else {
|
||||
@ -987,20 +988,25 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn expand_macro_to_expr(
|
||||
db: &impl HirDatabase,
|
||||
macro_call: MacroCallId,
|
||||
args: Option<&ast::TokenTree>,
|
||||
) -> Option<TreeArc<ast::Expr>> {
|
||||
let rules = db.macro_def(macro_call.loc(db).def)?;
|
||||
|
||||
let args = mbe::ast_to_token_tree(args?)?.0;
|
||||
|
||||
let expanded = rules.expand(&args).ok()?;
|
||||
|
||||
mbe::token_tree_to_expr(&expanded).ok()
|
||||
}
|
||||
|
||||
pub(crate) fn body_with_source_map_query(
|
||||
db: &impl HirDatabase,
|
||||
def: DefWithBody,
|
||||
) -> (Arc<Body>, Arc<BodySourceMap>) {
|
||||
let mut collector = ExprCollector {
|
||||
db,
|
||||
owner: def,
|
||||
resolver: def.resolver(db),
|
||||
exprs: Arena::default(),
|
||||
pats: Arena::default(),
|
||||
source_map: BodySourceMap::default(),
|
||||
params: Vec::new(),
|
||||
body_expr: None,
|
||||
};
|
||||
let mut collector = ExprCollector::new(def, def.resolver(db), db);
|
||||
|
||||
match def {
|
||||
DefWithBody::Const(ref c) => collector.collect_const_body(&c.source(db).1),
|
||||
|
@ -101,7 +101,7 @@ fn parse_macro(
|
||||
return Err(format!("Total tokens count exceed limit : count = {}", count));
|
||||
}
|
||||
|
||||
Some(mbe::token_tree_to_ast_item_list(&tt))
|
||||
Ok(mbe::token_tree_to_ast_item_list(&tt))
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
|
@ -524,7 +524,7 @@ where
|
||||
{
|
||||
let macro_call_id = MacroCallLoc { def: *macro_id, ast_id }.id(self.def_collector.db);
|
||||
|
||||
self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, macro_id);
|
||||
self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, *macro_id);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -616,6 +616,7 @@ mod tests {
|
||||
modules,
|
||||
public_macros: FxHashMap::default(),
|
||||
poison_macros: FxHashSet::default(),
|
||||
local_macros: FxHashMap::default(),
|
||||
diagnostics: Vec::new(),
|
||||
}
|
||||
};
|
||||
|
@ -1,12 +1,15 @@
|
||||
//! Name resolution.
|
||||
use std::sync::Arc;
|
||||
|
||||
use ra_syntax::ast;
|
||||
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::{
|
||||
ModuleDef,
|
||||
code_model_api::Crate,
|
||||
MacroDefId,
|
||||
MacroCallId,
|
||||
MacroCallLoc,
|
||||
db::HirDatabase,
|
||||
name::{Name, KnownName},
|
||||
nameres::{PerNs, CrateDefMap, CrateModuleId},
|
||||
@ -131,8 +134,29 @@ impl Resolver {
|
||||
resolution
|
||||
}
|
||||
|
||||
pub fn resolve_macro_call(&self, name: &Name) -> Option<&MacroDefId> {
|
||||
self.module().and_then(|(module, _)| module.find_macro(name))
|
||||
pub fn resolve_macro_call(
|
||||
&self,
|
||||
db: &impl HirDatabase,
|
||||
path: Option<Path>,
|
||||
call: &ast::MacroCall,
|
||||
) -> Option<MacroCallId> {
|
||||
let name = path.and_then(|path| path.expand_macro_expr()).unwrap_or_else(Name::missing);
|
||||
let macro_def_id = self.module().and_then(|(module, _)| module.find_macro(&name));
|
||||
if let Some(def_id) = macro_def_id {
|
||||
self.module().and_then(|(module, _)| {
|
||||
// we do this to get the ast_id for the macro call
|
||||
// if we used the ast_id from the def_id variable
|
||||
// it gives us the ast_id of the defenition site
|
||||
let module = module.mk_module(module.root());
|
||||
let hir_file_id = module.definition_source(db).0;
|
||||
let ast_id = db.ast_id_map(hir_file_id).ast_id(call).with_file_id(hir_file_id);
|
||||
let call_loc = MacroCallLoc { def: *def_id, ast_id }.id(db);
|
||||
|
||||
Some(call_loc)
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the resolved path segments
|
||||
@ -197,7 +221,7 @@ impl Resolver {
|
||||
.flatten()
|
||||
}
|
||||
|
||||
pub(crate) fn module(&self) -> Option<(&CrateDefMap, CrateModuleId)> {
|
||||
fn module(&self) -> Option<(&CrateDefMap, CrateModuleId)> {
|
||||
self.scopes.iter().rev().find_map(|scope| match scope {
|
||||
Scope::ModuleScope(m) => Some((&*m.crate_def_map, m.module_id)),
|
||||
|
||||
|
@ -2417,6 +2417,30 @@ fn test() -> u64 {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn infer_macros_expanded() {
|
||||
assert_snapshot_matches!(
|
||||
infer(r#"
|
||||
struct Foo(Vec<i32>);
|
||||
|
||||
macro_rules! foo {
|
||||
($($item:expr),*) => {
|
||||
{
|
||||
Foo(vec![$($item,)*])
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = foo!(1,2);
|
||||
}
|
||||
"#),
|
||||
@r###"
|
||||
[156; 182) '{ ...,2); }': ()
|
||||
[166; 167) 'x': Foo"###
|
||||
);
|
||||
}
|
||||
|
||||
#[ignore]
|
||||
#[test]
|
||||
fn method_resolution_trait_before_autoref() {
|
||||
@ -2510,6 +2534,7 @@ fn type_at(content: &str) -> String {
|
||||
fn infer(content: &str) -> String {
|
||||
let (db, _, file_id) = MockDatabase::with_single_file(content);
|
||||
let source_file = db.parse(file_id);
|
||||
|
||||
let mut acc = String::new();
|
||||
acc.push_str("\n");
|
||||
|
||||
@ -2532,6 +2557,7 @@ fn infer(content: &str) -> String {
|
||||
};
|
||||
types.push((syntax_ptr, ty));
|
||||
}
|
||||
|
||||
// sort ranges for consistency
|
||||
types.sort_by_key(|(ptr, _)| (ptr.range().start(), ptr.range().end()));
|
||||
for (syntax_ptr, ty) in &types {
|
||||
|
Loading…
Reference in New Issue
Block a user