Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-def/src/resolver.rs')
| -rw-r--r-- | crates/hir-def/src/resolver.rs | 59 |
1 files changed, 48 insertions, 11 deletions
diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs index f0f2210ec2..266851e3c0 100644 --- a/crates/hir-def/src/resolver.rs +++ b/crates/hir-def/src/resolver.rs @@ -10,7 +10,10 @@ use smallvec::{smallvec, SmallVec}; use triomphe::Arc; use crate::{ - body::scope::{ExprScopes, ScopeId}, + body::{ + scope::{ExprScopes, ScopeId}, + HygieneId, + }, builtin_type::BuiltinType, data::ExternCrateDeclData, db::DefDatabase, @@ -80,6 +83,8 @@ enum Scope { AdtScope(AdtId), /// Local bindings ExprScope(ExprScope), + /// Macro definition inside bodies that affects all paths after it in the same block. + MacroDefScope(Box<MacroDefId>), } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -188,7 +193,7 @@ impl Resolver { for scope in self.scopes() { match scope { - Scope::ExprScope(_) => continue, + Scope::ExprScope(_) | Scope::MacroDefScope(_) => continue, Scope::GenericParams { params, def } => { if let Some(id) = params.find_type_by_name(first_name, *def) { return Some((TypeNs::GenericParam(id), remaining_idx(), None)); @@ -257,6 +262,7 @@ impl Resolver { &self, db: &dyn DefDatabase, path: &Path, + mut hygiene_id: HygieneId, ) -> Option<ResolveValueResult> { let path = match path { Path::Normal { mod_path, .. } => mod_path, @@ -300,14 +306,22 @@ impl Resolver { } if n_segments <= 1 { + let mut hygiene_info = if !hygiene_id.is_root() { + let ctx = db.lookup_intern_syntax_context(hygiene_id.0); + ctx.outer_expn.map(|expansion| { + let expansion = db.lookup_intern_macro_call(expansion); + (ctx.parent, expansion.def) + }) + } else { + None + }; for scope in self.scopes() { match scope { Scope::ExprScope(scope) => { - let entry = scope - .expr_scopes - .entries(scope.scope_id) - .iter() - .find(|entry| entry.name() == first_name); + let entry = + scope.expr_scopes.entries(scope.scope_id).iter().find(|entry| { + entry.name() == first_name && entry.hygiene() == hygiene_id + }); if let Some(e) = entry { return Some(ResolveValueResult::ValueNs( @@ -316,6 +330,21 @@ impl Resolver { )); } } + Scope::MacroDefScope(macro_id) => { + if let Some((parent_ctx, label_macro_id)) = hygiene_info { + if label_macro_id == **macro_id { + // A macro is allowed to refer to variables from before its declaration. + // Therefore, if we got to the rib of its declaration, give up its hygiene + // and use its parent expansion. + let parent_ctx = db.lookup_intern_syntax_context(parent_ctx); + hygiene_id = HygieneId::new(parent_ctx.opaque_and_semitransparent); + hygiene_info = parent_ctx.outer_expn.map(|expansion| { + let expansion = db.lookup_intern_macro_call(expansion); + (parent_ctx.parent, expansion.def) + }); + } + } + } Scope::GenericParams { params, def } => { if let Some(id) = params.find_const_by_name(first_name, *def) { let val = ValueNs::GenericParam(id); @@ -342,7 +371,7 @@ impl Resolver { } else { for scope in self.scopes() { match scope { - Scope::ExprScope(_) => continue, + Scope::ExprScope(_) | Scope::MacroDefScope(_) => continue, Scope::GenericParams { params, def } => { if let Some(id) = params.find_type_by_name(first_name, *def) { let ty = TypeNs::GenericParam(id); @@ -393,8 +422,9 @@ impl Resolver { &self, db: &dyn DefDatabase, path: &Path, + hygiene: HygieneId, ) -> Option<ValueNs> { - match self.resolve_path_in_value_ns(db, path)? { + match self.resolve_path_in_value_ns(db, path, hygiene)? { ResolveValueResult::ValueNs(it, _) => Some(it), ResolveValueResult::Partial(..) => None, } @@ -622,7 +652,7 @@ impl Resolver { pub fn type_owner(&self) -> Option<TypeOwnerId> { self.scopes().find_map(|scope| match scope { - Scope::BlockScope(_) => None, + Scope::BlockScope(_) | Scope::MacroDefScope(_) => None, &Scope::GenericParams { def, .. } => Some(def.into()), &Scope::ImplDefScope(id) => Some(id.into()), &Scope::AdtScope(adt) => Some(adt.into()), @@ -653,6 +683,9 @@ impl Resolver { expr_scopes: &Arc<ExprScopes>, scope_id: ScopeId, ) { + if let Some(macro_id) = expr_scopes.macro_def(scope_id) { + resolver.scopes.push(Scope::MacroDefScope(macro_id.clone())); + } resolver.scopes.push(Scope::ExprScope(ExprScope { owner, expr_scopes: expr_scopes.clone(), @@ -670,7 +703,7 @@ impl Resolver { } let start = self.scopes.len(); - let innermost_scope = self.scopes().next(); + let innermost_scope = self.scopes().find(|scope| !matches!(scope, Scope::MacroDefScope(_))); match innermost_scope { Some(&Scope::ExprScope(ExprScope { scope_id, ref expr_scopes, owner })) => { let expr_scopes = expr_scopes.clone(); @@ -794,6 +827,7 @@ impl Scope { acc.add_local(e.name(), e.binding()); }); } + Scope::MacroDefScope(_) => {} } } } @@ -833,6 +867,9 @@ fn resolver_for_scope_( // already traverses all parents, so this is O(n²). I think we could only store the // innermost module scope instead? } + if let Some(macro_id) = scopes.macro_def(scope) { + r = r.push_scope(Scope::MacroDefScope(macro_id.clone())); + } r = r.push_expr_scope(owner, Arc::clone(&scopes), scope); } |