mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +00:00
Merge #2235
2235: Handle macro-generated expressions slightly less wrong r=matklad a=matklad Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
commit
8af85263f7
7 changed files with 156 additions and 100 deletions
|
@ -40,8 +40,8 @@ pub(crate) fn body_with_source_map_query(
|
|||
(src.file_id, src.ast.body())
|
||||
}
|
||||
};
|
||||
let resolver = hir_def::body::MacroResolver::new(db, def.module(db).id);
|
||||
let (body, source_map) = Body::new(db, resolver, file_id, params, body);
|
||||
let expander = hir_def::body::Expander::new(db, file_id, def.module(db).id);
|
||||
let (body, source_map) = Body::new(db, expander, params, body);
|
||||
(Arc::new(body), Arc::new(source_map))
|
||||
}
|
||||
|
||||
|
|
|
@ -166,6 +166,7 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use hir_expand::Source;
|
||||
use ra_db::{fixture::WithFixture, SourceDatabase};
|
||||
use ra_syntax::{algo::find_node_at_offset, ast, AstNode};
|
||||
use test_utils::{assert_eq_text, extract_offset};
|
||||
|
@ -189,7 +190,10 @@ mod tests {
|
|||
let analyzer = SourceAnalyzer::new(&db, file_id, marker.syntax(), None);
|
||||
|
||||
let scopes = analyzer.scopes();
|
||||
let expr_id = analyzer.body_source_map().node_expr(&marker.into()).unwrap();
|
||||
let expr_id = analyzer
|
||||
.body_source_map()
|
||||
.node_expr(Source { file_id: file_id.into(), ast: &marker.into() })
|
||||
.unwrap();
|
||||
let scope = scopes.scope_for(expr_id);
|
||||
|
||||
let actual = scopes
|
||||
|
|
|
@ -145,7 +145,8 @@ impl Local {
|
|||
Some(res)
|
||||
})?;
|
||||
let (_body, source_map) = db.body_with_source_map(parent);
|
||||
let pat_id = source_map.node_pat(&src.ast.into())?;
|
||||
let src = src.map(ast::Pat::from);
|
||||
let pat_id = source_map.node_pat(src.as_ref())?;
|
||||
Some(Local { parent, pat_id })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,11 @@
|
|||
//! purely for "IDE needs".
|
||||
use std::sync::Arc;
|
||||
|
||||
use hir_def::path::known;
|
||||
use hir_expand::name::AsName;
|
||||
use hir_def::{
|
||||
expr::{ExprId, PatId},
|
||||
path::known,
|
||||
};
|
||||
use hir_expand::{name::AsName, Source};
|
||||
use ra_db::FileId;
|
||||
use ra_syntax::{
|
||||
ast::{self, AstNode},
|
||||
|
@ -93,6 +96,8 @@ fn def_with_body_from_child_node(
|
|||
/// original source files. It should not be used inside the HIR itself.
|
||||
#[derive(Debug)]
|
||||
pub struct SourceAnalyzer {
|
||||
// FIXME: this doesn't handle macros at all
|
||||
file_id: FileId,
|
||||
resolver: Resolver,
|
||||
body_owner: Option<DefWithBody>,
|
||||
body_source_map: Option<Arc<BodySourceMap>>,
|
||||
|
@ -147,7 +152,7 @@ impl SourceAnalyzer {
|
|||
let source_map = def.body_source_map(db);
|
||||
let scopes = db.expr_scopes(def);
|
||||
let scope = match offset {
|
||||
None => scope_for(&scopes, &source_map, &node),
|
||||
None => scope_for(&scopes, &source_map, file_id.into(), &node),
|
||||
Some(offset) => scope_for_offset(&scopes, &source_map, file_id.into(), offset),
|
||||
};
|
||||
let resolver = expr::resolver_for_scope(db, def, scope);
|
||||
|
@ -157,6 +162,7 @@ impl SourceAnalyzer {
|
|||
body_source_map: Some(source_map),
|
||||
infer: Some(def.infer(db)),
|
||||
scopes: Some(scopes),
|
||||
file_id,
|
||||
}
|
||||
} else {
|
||||
SourceAnalyzer {
|
||||
|
@ -168,17 +174,28 @@ impl SourceAnalyzer {
|
|||
body_source_map: None,
|
||||
infer: None,
|
||||
scopes: None,
|
||||
file_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn expr_id(&self, expr: &ast::Expr) -> Option<ExprId> {
|
||||
let src = Source { file_id: self.file_id.into(), ast: expr };
|
||||
self.body_source_map.as_ref()?.node_expr(src)
|
||||
}
|
||||
|
||||
fn pat_id(&self, pat: &ast::Pat) -> Option<PatId> {
|
||||
let src = Source { file_id: self.file_id.into(), ast: pat };
|
||||
self.body_source_map.as_ref()?.node_pat(src)
|
||||
}
|
||||
|
||||
pub fn type_of(&self, _db: &impl HirDatabase, expr: &ast::Expr) -> Option<crate::Ty> {
|
||||
let expr_id = self.body_source_map.as_ref()?.node_expr(expr)?;
|
||||
let expr_id = self.expr_id(expr)?;
|
||||
Some(self.infer.as_ref()?[expr_id].clone())
|
||||
}
|
||||
|
||||
pub fn type_of_pat(&self, _db: &impl HirDatabase, pat: &ast::Pat) -> Option<crate::Ty> {
|
||||
let pat_id = self.body_source_map.as_ref()?.node_pat(pat)?;
|
||||
let pat_id = self.pat_id(pat)?;
|
||||
Some(self.infer.as_ref()?[pat_id].clone())
|
||||
}
|
||||
|
||||
|
@ -191,22 +208,22 @@ impl SourceAnalyzer {
|
|||
}
|
||||
|
||||
pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> {
|
||||
let expr_id = self.body_source_map.as_ref()?.node_expr(&call.clone().into())?;
|
||||
let expr_id = self.expr_id(&call.clone().into())?;
|
||||
self.infer.as_ref()?.method_resolution(expr_id)
|
||||
}
|
||||
|
||||
pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<crate::StructField> {
|
||||
let expr_id = self.body_source_map.as_ref()?.node_expr(&field.clone().into())?;
|
||||
let expr_id = self.expr_id(&field.clone().into())?;
|
||||
self.infer.as_ref()?.field_resolution(expr_id)
|
||||
}
|
||||
|
||||
pub fn resolve_record_literal(&self, record_lit: &ast::RecordLit) -> Option<crate::VariantDef> {
|
||||
let expr_id = self.body_source_map.as_ref()?.node_expr(&record_lit.clone().into())?;
|
||||
let expr_id = self.expr_id(&record_lit.clone().into())?;
|
||||
self.infer.as_ref()?.variant_resolution_for_expr(expr_id)
|
||||
}
|
||||
|
||||
pub fn resolve_record_pattern(&self, record_pat: &ast::RecordPat) -> Option<crate::VariantDef> {
|
||||
let pat_id = self.body_source_map.as_ref()?.node_pat(&record_pat.clone().into())?;
|
||||
let pat_id = self.pat_id(&record_pat.clone().into())?;
|
||||
self.infer.as_ref()?.variant_resolution_for_pat(pat_id)
|
||||
}
|
||||
|
||||
|
@ -264,13 +281,13 @@ impl SourceAnalyzer {
|
|||
|
||||
pub fn resolve_path(&self, db: &impl HirDatabase, path: &ast::Path) -> Option<PathResolution> {
|
||||
if let Some(path_expr) = path.syntax().parent().and_then(ast::PathExpr::cast) {
|
||||
let expr_id = self.body_source_map.as_ref()?.node_expr(&path_expr.into())?;
|
||||
let expr_id = self.expr_id(&path_expr.into())?;
|
||||
if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_expr(expr_id) {
|
||||
return Some(PathResolution::AssocItem(assoc));
|
||||
}
|
||||
}
|
||||
if let Some(path_pat) = path.syntax().parent().and_then(ast::PathPat::cast) {
|
||||
let pat_id = self.body_source_map.as_ref()?.node_pat(&path_pat.into())?;
|
||||
let pat_id = self.pat_id(&path_pat.into())?;
|
||||
if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_pat(pat_id) {
|
||||
return Some(PathResolution::AssocItem(assoc));
|
||||
}
|
||||
|
@ -285,7 +302,7 @@ impl SourceAnalyzer {
|
|||
let name = name_ref.as_name();
|
||||
let source_map = self.body_source_map.as_ref()?;
|
||||
let scopes = self.scopes.as_ref()?;
|
||||
let scope = scope_for(scopes, source_map, name_ref.syntax());
|
||||
let scope = scope_for(scopes, source_map, self.file_id.into(), name_ref.syntax());
|
||||
let ret = scopes
|
||||
.scope_chain(scope)
|
||||
.flat_map(|scope| scopes.entries(scope).iter())
|
||||
|
@ -418,11 +435,12 @@ impl SourceAnalyzer {
|
|||
fn scope_for(
|
||||
scopes: &ExprScopes,
|
||||
source_map: &BodySourceMap,
|
||||
file_id: HirFileId,
|
||||
node: &SyntaxNode,
|
||||
) -> Option<ScopeId> {
|
||||
node.ancestors()
|
||||
.filter_map(ast::Expr::cast)
|
||||
.filter_map(|it| source_map.node_expr(&it))
|
||||
.filter_map(|it| source_map.node_expr(Source { file_id, ast: &it }))
|
||||
.find_map(|it| scopes.scope_for(it))
|
||||
}
|
||||
|
||||
|
|
|
@ -3,9 +3,12 @@ mod lower;
|
|||
|
||||
use std::{ops::Index, sync::Arc};
|
||||
|
||||
use hir_expand::{either::Either, HirFileId, MacroDefId, Source};
|
||||
use hir_expand::{
|
||||
either::Either, hygiene::Hygiene, AstId, HirFileId, MacroCallLoc, MacroDefId, MacroFileKind,
|
||||
Source,
|
||||
};
|
||||
use ra_arena::{map::ArenaMap, Arena};
|
||||
use ra_syntax::{ast, AstPtr};
|
||||
use ra_syntax::{ast, AstNode, AstPtr};
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::{
|
||||
|
@ -16,25 +19,87 @@ use crate::{
|
|||
ModuleId,
|
||||
};
|
||||
|
||||
pub struct MacroResolver {
|
||||
pub struct Expander {
|
||||
crate_def_map: Arc<CrateDefMap>,
|
||||
current_file_id: HirFileId,
|
||||
hygiene: Hygiene,
|
||||
module: ModuleId,
|
||||
}
|
||||
|
||||
impl MacroResolver {
|
||||
pub fn new(db: &impl DefDatabase2, module: ModuleId) -> MacroResolver {
|
||||
MacroResolver { crate_def_map: db.crate_def_map(module.krate), module }
|
||||
impl Expander {
|
||||
pub fn new(db: &impl DefDatabase2, 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 }
|
||||
}
|
||||
|
||||
pub(crate) fn resolve_path_as_macro(
|
||||
&self,
|
||||
fn expand(
|
||||
&mut self,
|
||||
db: &impl DefDatabase2,
|
||||
path: &Path,
|
||||
) -> Option<MacroDefId> {
|
||||
macro_call: ast::MacroCall,
|
||||
) -> Option<(Mark, ast::Expr)> {
|
||||
let ast_id = AstId::new(
|
||||
self.current_file_id,
|
||||
db.ast_id_map(self.current_file_id).ast_id(¯o_call),
|
||||
);
|
||||
|
||||
if let Some(path) = macro_call.path().and_then(|path| self.parse_path(path)) {
|
||||
if let Some(def) = self.resolve_path_as_macro(db, &path) {
|
||||
let call_id = db.intern_macro(MacroCallLoc { def, ast_id });
|
||||
let file_id = call_id.as_file(MacroFileKind::Expr);
|
||||
if let Some(node) = db.parse_or_expand(file_id) {
|
||||
if let Some(expr) = ast::Expr::cast(node) {
|
||||
log::debug!("macro expansion {:#?}", expr.syntax());
|
||||
let mark = self.enter(db, file_id);
|
||||
return Some((mark, expr));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Instead of just dropping the error from expansion
|
||||
// report it
|
||||
None
|
||||
}
|
||||
|
||||
fn enter(&mut self, db: &impl DefDatabase2, file_id: HirFileId) -> Mark {
|
||||
let mark = Mark { file_id: self.current_file_id };
|
||||
self.hygiene = Hygiene::new(db, file_id);
|
||||
self.current_file_id = file_id;
|
||||
mark
|
||||
}
|
||||
|
||||
fn exit(&mut self, db: &impl DefDatabase2, mark: Mark) {
|
||||
self.hygiene = Hygiene::new(db, mark.file_id);
|
||||
self.current_file_id = mark.file_id;
|
||||
std::mem::forget(mark);
|
||||
}
|
||||
|
||||
fn to_source<T>(&self, ast: T) -> Source<T> {
|
||||
Source { file_id: self.current_file_id, ast }
|
||||
}
|
||||
|
||||
fn parse_path(&mut self, path: ast::Path) -> Option<Path> {
|
||||
Path::from_src(path, &self.hygiene)
|
||||
}
|
||||
|
||||
fn resolve_path_as_macro(&self, db: &impl DefDatabase2, path: &Path) -> Option<MacroDefId> {
|
||||
self.crate_def_map.resolve_path(db, self.module.module_id, path).0.get_macros()
|
||||
}
|
||||
}
|
||||
|
||||
struct Mark {
|
||||
file_id: HirFileId,
|
||||
}
|
||||
|
||||
impl Drop for Mark {
|
||||
fn drop(&mut self) {
|
||||
if !std::thread::panicking() {
|
||||
panic!("dropped mark")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The body of an item (function, const etc.).
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct Body {
|
||||
|
@ -70,9 +135,9 @@ pub type PatSource = Source<PatPtr>;
|
|||
/// this properly for macros.
|
||||
#[derive(Default, Debug, Eq, PartialEq)]
|
||||
pub struct BodySourceMap {
|
||||
expr_map: FxHashMap<ExprPtr, ExprId>,
|
||||
expr_map: FxHashMap<ExprSource, ExprId>,
|
||||
expr_map_back: ArenaMap<ExprId, ExprSource>,
|
||||
pat_map: FxHashMap<PatPtr, PatId>,
|
||||
pat_map: FxHashMap<PatSource, PatId>,
|
||||
pat_map_back: ArenaMap<PatId, PatSource>,
|
||||
field_map: FxHashMap<(ExprId, usize), AstPtr<ast::RecordField>>,
|
||||
}
|
||||
|
@ -80,12 +145,11 @@ pub struct BodySourceMap {
|
|||
impl Body {
|
||||
pub fn new(
|
||||
db: &impl DefDatabase2,
|
||||
resolver: MacroResolver,
|
||||
file_id: HirFileId,
|
||||
expander: Expander,
|
||||
params: Option<ast::ParamList>,
|
||||
body: Option<ast::Expr>,
|
||||
) -> (Body, BodySourceMap) {
|
||||
lower::lower(db, resolver, file_id, params, body)
|
||||
lower::lower(db, expander, params, body)
|
||||
}
|
||||
|
||||
pub fn params(&self) -> &[PatId] {
|
||||
|
@ -126,16 +190,18 @@ impl BodySourceMap {
|
|||
self.expr_map_back.get(expr).copied()
|
||||
}
|
||||
|
||||
pub fn node_expr(&self, node: &ast::Expr) -> Option<ExprId> {
|
||||
self.expr_map.get(&Either::A(AstPtr::new(node))).cloned()
|
||||
pub fn node_expr(&self, node: Source<&ast::Expr>) -> Option<ExprId> {
|
||||
let src = node.map(|it| Either::A(AstPtr::new(it)));
|
||||
self.expr_map.get(&src).cloned()
|
||||
}
|
||||
|
||||
pub fn pat_syntax(&self, pat: PatId) -> Option<PatSource> {
|
||||
self.pat_map_back.get(pat).copied()
|
||||
}
|
||||
|
||||
pub fn node_pat(&self, node: &ast::Pat) -> Option<PatId> {
|
||||
self.pat_map.get(&Either::A(AstPtr::new(node))).cloned()
|
||||
pub fn node_pat(&self, node: Source<&ast::Pat>) -> Option<PatId> {
|
||||
let src = node.map(|it| Either::A(AstPtr::new(it)));
|
||||
self.pat_map.get(&src).cloned()
|
||||
}
|
||||
|
||||
pub fn field_syntax(&self, expr: ExprId, field: usize) -> AstPtr<ast::RecordField> {
|
||||
|
|
|
@ -2,9 +2,7 @@
|
|||
|
||||
use hir_expand::{
|
||||
either::Either,
|
||||
hygiene::Hygiene,
|
||||
name::{self, AsName, Name},
|
||||
AstId, HirFileId, MacroCallLoc, MacroFileKind, Source,
|
||||
};
|
||||
use ra_arena::Arena;
|
||||
use ra_syntax::{
|
||||
|
@ -16,7 +14,7 @@ use ra_syntax::{
|
|||
};
|
||||
|
||||
use crate::{
|
||||
body::{Body, BodySourceMap, MacroResolver, PatPtr},
|
||||
body::{Body, BodySourceMap, Expander, PatPtr},
|
||||
builtin_type::{BuiltinFloat, BuiltinInt},
|
||||
db::DefDatabase2,
|
||||
expr::{
|
||||
|
@ -30,16 +28,13 @@ use crate::{
|
|||
|
||||
pub(super) fn lower(
|
||||
db: &impl DefDatabase2,
|
||||
resolver: MacroResolver,
|
||||
file_id: HirFileId,
|
||||
expander: Expander,
|
||||
params: Option<ast::ParamList>,
|
||||
body: Option<ast::Expr>,
|
||||
) -> (Body, BodySourceMap) {
|
||||
ExprCollector {
|
||||
resolver,
|
||||
expander,
|
||||
db,
|
||||
original_file_id: file_id,
|
||||
current_file_id: file_id,
|
||||
source_map: BodySourceMap::default(),
|
||||
body: Body {
|
||||
exprs: Arena::default(),
|
||||
|
@ -53,9 +48,7 @@ pub(super) fn lower(
|
|||
|
||||
struct ExprCollector<DB> {
|
||||
db: DB,
|
||||
resolver: MacroResolver,
|
||||
original_file_id: HirFileId,
|
||||
current_file_id: HirFileId,
|
||||
expander: Expander,
|
||||
|
||||
body: Body,
|
||||
source_map: BodySourceMap,
|
||||
|
@ -101,12 +94,9 @@ where
|
|||
fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId {
|
||||
let ptr = Either::A(ptr);
|
||||
let id = self.body.exprs.alloc(expr);
|
||||
if self.current_file_id == self.original_file_id {
|
||||
self.source_map.expr_map.insert(ptr, id);
|
||||
}
|
||||
self.source_map
|
||||
.expr_map_back
|
||||
.insert(id, Source { file_id: self.current_file_id, ast: ptr });
|
||||
let src = self.expander.to_source(ptr);
|
||||
self.source_map.expr_map.insert(src, id);
|
||||
self.source_map.expr_map_back.insert(id, src);
|
||||
id
|
||||
}
|
||||
// desugared exprs don't have ptr, that's wrong and should be fixed
|
||||
|
@ -117,20 +107,16 @@ where
|
|||
fn alloc_expr_field_shorthand(&mut self, expr: Expr, ptr: AstPtr<ast::RecordField>) -> ExprId {
|
||||
let ptr = Either::B(ptr);
|
||||
let id = self.body.exprs.alloc(expr);
|
||||
if self.current_file_id == self.original_file_id {
|
||||
self.source_map.expr_map.insert(ptr, id);
|
||||
}
|
||||
self.source_map
|
||||
.expr_map_back
|
||||
.insert(id, Source { file_id: self.current_file_id, ast: ptr });
|
||||
let src = self.expander.to_source(ptr);
|
||||
self.source_map.expr_map.insert(src, id);
|
||||
self.source_map.expr_map_back.insert(id, src);
|
||||
id
|
||||
}
|
||||
fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
|
||||
let id = self.body.pats.alloc(pat);
|
||||
if self.current_file_id == self.original_file_id {
|
||||
self.source_map.pat_map.insert(ptr, id);
|
||||
}
|
||||
self.source_map.pat_map_back.insert(id, Source { file_id: self.current_file_id, ast: ptr });
|
||||
let src = self.expander.to_source(ptr);
|
||||
self.source_map.pat_map.insert(src, id);
|
||||
self.source_map.pat_map_back.insert(id, src);
|
||||
id
|
||||
}
|
||||
|
||||
|
@ -272,7 +258,7 @@ where
|
|||
ast::Expr::PathExpr(e) => {
|
||||
let path = e
|
||||
.path()
|
||||
.and_then(|path| self.parse_path(path))
|
||||
.and_then(|path| self.expander.parse_path(path))
|
||||
.map(Expr::Path)
|
||||
.unwrap_or(Expr::Missing);
|
||||
self.alloc_expr(path, syntax_ptr)
|
||||
|
@ -288,7 +274,8 @@ where
|
|||
ast::Expr::ParenExpr(e) => {
|
||||
let inner = self.collect_expr_opt(e.expr());
|
||||
// make the paren expr point to the inner expression as well
|
||||
self.source_map.expr_map.insert(Either::A(syntax_ptr), inner);
|
||||
let src = self.expander.to_source(Either::A(syntax_ptr));
|
||||
self.source_map.expr_map.insert(src, inner);
|
||||
inner
|
||||
}
|
||||
ast::Expr::ReturnExpr(e) => {
|
||||
|
@ -296,7 +283,7 @@ where
|
|||
self.alloc_expr(Expr::Return { expr }, syntax_ptr)
|
||||
}
|
||||
ast::Expr::RecordLit(e) => {
|
||||
let path = e.path().and_then(|path| self.parse_path(path));
|
||||
let path = e.path().and_then(|path| self.expander.parse_path(path));
|
||||
let mut field_ptrs = Vec::new();
|
||||
let record_lit = if let Some(nfl) = e.record_field_list() {
|
||||
let fields = nfl
|
||||
|
@ -443,32 +430,14 @@ where
|
|||
// FIXME implement HIR for these:
|
||||
ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
|
||||
ast::Expr::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
|
||||
ast::Expr::MacroCall(e) => {
|
||||
let ast_id = AstId::new(
|
||||
self.current_file_id,
|
||||
self.db.ast_id_map(self.current_file_id).ast_id(&e),
|
||||
);
|
||||
|
||||
if let Some(path) = e.path().and_then(|path| self.parse_path(path)) {
|
||||
if let Some(def) = self.resolver.resolve_path_as_macro(self.db, &path) {
|
||||
let call_id = self.db.intern_macro(MacroCallLoc { def, ast_id });
|
||||
let file_id = call_id.as_file(MacroFileKind::Expr);
|
||||
if let Some(node) = self.db.parse_or_expand(file_id) {
|
||||
if let Some(expr) = ast::Expr::cast(node) {
|
||||
log::debug!("macro expansion {:#?}", expr.syntax());
|
||||
let old_file_id =
|
||||
std::mem::replace(&mut self.current_file_id, file_id);
|
||||
let id = self.collect_expr(expr);
|
||||
self.current_file_id = old_file_id;
|
||||
return id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// FIXME: Instead of just dropping the error from expansion
|
||||
// report it
|
||||
self.alloc_expr(Expr::Missing, syntax_ptr)
|
||||
ast::Expr::MacroCall(e) => match self.expander.expand(self.db, e) {
|
||||
Some((mark, expansion)) => {
|
||||
let id = self.collect_expr(expansion);
|
||||
self.expander.exit(self.db, mark);
|
||||
id
|
||||
}
|
||||
None => self.alloc_expr(Expr::Missing, syntax_ptr),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -519,7 +488,7 @@ where
|
|||
Pat::Bind { name, mode: annotation, subpat }
|
||||
}
|
||||
ast::Pat::TupleStructPat(p) => {
|
||||
let path = p.path().and_then(|path| self.parse_path(path));
|
||||
let path = p.path().and_then(|path| self.expander.parse_path(path));
|
||||
let args = p.args().map(|p| self.collect_pat(p)).collect();
|
||||
Pat::TupleStruct { path, args }
|
||||
}
|
||||
|
@ -529,7 +498,7 @@ where
|
|||
Pat::Ref { pat, mutability }
|
||||
}
|
||||
ast::Pat::PathPat(p) => {
|
||||
let path = p.path().and_then(|path| self.parse_path(path));
|
||||
let path = p.path().and_then(|path| self.expander.parse_path(path));
|
||||
path.map(Pat::Path).unwrap_or(Pat::Missing)
|
||||
}
|
||||
ast::Pat::TuplePat(p) => {
|
||||
|
@ -538,7 +507,7 @@ where
|
|||
}
|
||||
ast::Pat::PlaceholderPat(_) => Pat::Wild,
|
||||
ast::Pat::RecordPat(p) => {
|
||||
let path = p.path().and_then(|path| self.parse_path(path));
|
||||
let path = p.path().and_then(|path| self.expander.parse_path(path));
|
||||
let record_field_pat_list =
|
||||
p.record_field_pat_list().expect("every struct should have a field list");
|
||||
let mut fields: Vec<_> = record_field_pat_list
|
||||
|
@ -579,11 +548,6 @@ where
|
|||
self.missing_pat()
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_path(&mut self, path: ast::Path) -> Option<Path> {
|
||||
let hygiene = Hygiene::new(self.db, self.current_file_id);
|
||||
Path::from_src(path, &hygiene)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ast::BinOp> for BinaryOp {
|
||||
|
|
|
@ -223,7 +223,7 @@ impl<N: AstNode> AstId<N> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
|
||||
pub struct Source<T> {
|
||||
pub file_id: HirFileId,
|
||||
pub ast: T,
|
||||
|
@ -233,6 +233,9 @@ impl<T> Source<T> {
|
|||
pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
|
||||
Source { file_id: self.file_id, ast: f(self.ast) }
|
||||
}
|
||||
pub fn as_ref(&self) -> Source<&T> {
|
||||
Source { file_id: self.file_id, ast: &self.ast }
|
||||
}
|
||||
pub fn file_syntax(&self, db: &impl db::AstDatabase) -> SyntaxNode {
|
||||
db.parse_or_expand(self.file_id).expect("source created from invalid file")
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue