use la_arena::{Arena, ArenaMap};
use profile::Count;
use rustc_hash::FxHashMap;
-use syntax::{ast, AstNode, AstPtr, SyntaxNode};
+use syntax::{ast, AstNode, AstPtr};
pub use lower::LowerCtx;
}
}
- fn enter_expand_intern(
+ pub(crate) fn enter_expand<T: ast::AstNode>(
&mut self,
db: &dyn DefDatabase,
macro_call: ast::MacroCall,
- ) -> Result<
- ExpandResult<Option<(SyntaxNode, impl FnMut(&dyn DefDatabase) -> Mark + '_)>>,
- UnresolvedMacro,
- > {
+ ) -> Result<ExpandResult<Option<(Mark, T)>>, UnresolvedMacro> {
if self.recursion_limit + 1 > EXPANSION_RECURSION_LIMIT {
cov_mark::hit!(your_stack_belongs_to_me);
return Ok(ExpandResult::str_err(
}
};
- let this = self;
-
- let advance_state = move |db: &dyn DefDatabase| {
- this.recursion_limit += 1;
- let mark = Mark {
- file_id: this.current_file_id,
- ast_id_map: mem::take(&mut this.ast_id_map),
- bomb: DropBomb::new("expansion mark dropped"),
- };
- this.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id);
- this.current_file_id = file_id;
- this.ast_id_map = db.ast_id_map(file_id);
- mark
- };
-
- Ok(ExpandResult { value: Some((raw_node, advance_state)), err })
- }
-
- pub(crate) fn enter_expand_raw(
- &mut self,
- db: &dyn DefDatabase,
- macro_call: ast::MacroCall,
- ) -> Result<ExpandResult<Option<(Mark, SyntaxNode)>>, UnresolvedMacro> {
- let (raw_node, mut advance_state, err) = match self.enter_expand_intern(db, macro_call)? {
- ExpandResult { value: Some((raw_node, advance_state)), err } => {
- (raw_node, advance_state, err)
- }
- ExpandResult { value: None, err } => return Ok(ExpandResult { value: None, err }),
- };
-
- log::debug!("macro expansion {:#?}", raw_node);
-
- let mark = advance_state(db);
-
- Ok(ExpandResult { value: Some((mark, raw_node)), err })
- }
-
- pub(crate) fn enter_expand<T: ast::AstNode>(
- &mut self,
- db: &dyn DefDatabase,
- macro_call: ast::MacroCall,
- ) -> Result<ExpandResult<Option<(Mark, T)>>, UnresolvedMacro> {
- let (raw_node, mut advance_state, err) = match self.enter_expand_intern(db, macro_call)? {
- ExpandResult { value: Some((raw_node, advance_state)), err } => {
- (raw_node, advance_state, err)
- }
- ExpandResult { value: None, err } => return Ok(ExpandResult { value: None, err }),
- };
-
let node = match T::cast(raw_node) {
Some(it) => it,
None => {
log::debug!("macro expansion {:#?}", node.syntax());
- let mark = advance_state(db);
+ self.recursion_limit += 1;
+ 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.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id);
+ self.current_file_id = file_id;
+ self.ast_id_map = db.ast_id_map(file_id);
Ok(ExpandResult { value: Some((mark, node)), err })
}
&self.cfg_expander.cfg_options
}
+ pub(crate) fn current_file_id(&self) -> HirFileId {
+ self.current_file_id
+ }
+
fn parse_path(&mut self, path: ast::Path) -> Option<Path> {
let ctx = LowerCtx::with_hygiene(&self.cfg_expander.hygiene);
Path::from_src(path, &ctx)
//! HIR for references to types. Paths in these are not yet resolved. They can
//! be directly created from an ast::TypeRef, without further queries.
-use std::borrow::Cow;
use hir_expand::{ast_id_map::FileAstId, name::Name, ExpandResult, InFile};
-use syntax::{algo::SyntaxRewriter, ast, AstNode, SyntaxKind, SyntaxNode};
+use syntax::ast;
use crate::{
body::{Expander, LowerCtx},
TypeRef::Tuple(Vec::new())
}
- pub fn has_macro_calls(&self) -> bool {
- let mut has_macro_call = false;
- self.walk(&mut |ty_ref| {
- if let TypeRef::Macro(_) = ty_ref {
- has_macro_call |= true
- }
- });
- has_macro_call
- }
-
pub fn walk(&self, f: &mut impl FnMut(&TypeRef)) {
go(self, f);
}
}
-pub fn expand_type_ref<'a>(
+pub fn expand_macro_type(
db: &dyn DefDatabase,
module_id: ModuleId,
- type_ref: &'a TypeRef,
-) -> Option<Cow<'a, TypeRef>> {
- let macro_call = match type_ref {
+ macro_type: &TypeRef,
+) -> Option<TypeRef> {
+ let macro_call = match macro_type {
TypeRef::Macro(macro_call) => macro_call,
- _ => return Some(Cow::Borrowed(type_ref)),
+ _ => panic!("expected TypeRef::Macro"),
};
let file_id = macro_call.file_id;
let macro_call = macro_call.to_node(db.upcast());
let mut expander = Expander::new(db, file_id, module_id);
- let expanded = expand(db, &mut expander, ¯o_call, true)?;
-
- let node = ast::Type::cast(expanded)?;
-
- let ctx = LowerCtx::new(db, file_id);
- return Some(Cow::Owned(TypeRef::from_ast(&ctx, node)));
-
- fn expand(
- db: &dyn DefDatabase,
- expander: &mut Expander,
- macro_call: &ast::MacroCall,
- expect_type: bool,
- ) -> Option<SyntaxNode> {
- let (mark, mut expanded) = match expander.enter_expand_raw(db, macro_call.clone()) {
- Ok(ExpandResult { value: Some((mark, expanded)), .. }) => (mark, expanded),
- _ => return None,
- };
-
- if expect_type && !ast::Type::can_cast(expanded.kind()) {
+ let (file_id, expanded) = match expander.enter_expand::<ast::Type>(db, macro_call.clone()) {
+ Ok(ExpandResult { value: Some((mark, expanded)), .. }) => {
+ let file_id = expander.current_file_id();
expander.exit(db, mark);
- return None;
- }
-
- if ast::MacroType::can_cast(expanded.kind()) {
- expanded = expanded.first_child()?; // MACRO_CALL
+ (file_id, expanded)
}
+ _ => return None,
+ };
- let mut rewriter = SyntaxRewriter::default();
-
- let children = expanded.descendants().filter_map(ast::MacroCall::cast);
- for child in children {
- if let Some(new_node) = expand(db, expander, &child, false) {
- if expanded == *child.syntax() {
- expanded = new_node;
- } else {
- let parent = child.syntax().parent();
- let old_node = match &parent {
- Some(node) if node.kind() == SyntaxKind::MACRO_TYPE => node,
- _ => child.syntax(),
- };
- rewriter.replace(old_node, &new_node)
- }
- }
- }
-
- expander.exit(db, mark);
-
- let res = rewriter.rewrite(&expanded);
- Some(res)
- }
+ let ctx = LowerCtx::new(db, file_id);
+ return Some(TypeRef::from_ast(&ctx, expanded));
}
generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget},
path::{GenericArg, Path, PathSegment, PathSegments},
resolver::{HasResolver, Resolver, TypeNs},
- type_ref::{expand_type_ref, TraitRef as HirTraitRef, TypeBound, TypeRef},
+ type_ref::{expand_macro_type, TraitRef as HirTraitRef, TypeBound, TypeRef},
AdtId, AssocContainerId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId,
GenericDefId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId,
TypeAliasId, TypeParamId, UnionId, VariantId,
}
mt @ TypeRef::Macro(_) => {
if let Some(module_id) = self.resolver.module() {
- match expand_type_ref(self.db.upcast(), module_id, mt) {
- Some(type_ref) => self.lower_ty(type_ref.as_ref()),
+ match expand_macro_type(self.db.upcast(), module_id, mt) {
+ Some(type_ref) => self.lower_ty(&type_ref),
None => TyKind::Error.intern(&Interner),
}
} else {