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.rs59
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);
}