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.rs45
1 files changed, 39 insertions, 6 deletions
diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs
index cf93958ecb..266851e3c0 100644
--- a/crates/hir-def/src/resolver.rs
+++ b/crates/hir-def/src/resolver.rs
@@ -83,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)]
@@ -191,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));
@@ -260,7 +262,7 @@ impl Resolver {
&self,
db: &dyn DefDatabase,
path: &Path,
- hygiene: HygieneId,
+ mut hygiene_id: HygieneId,
) -> Option<ResolveValueResult> {
let path = match path {
Path::Normal { mod_path, .. } => mod_path,
@@ -304,12 +306,21 @@ 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 && entry.hygiene() == hygiene
+ entry.name() == first_name && entry.hygiene() == hygiene_id
});
if let Some(e) = entry {
@@ -319,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);
@@ -345,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);
@@ -626,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()),
@@ -657,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(),
@@ -674,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();
@@ -798,6 +827,7 @@ impl Scope {
acc.add_local(e.name(), e.binding());
});
}
+ Scope::MacroDefScope(_) => {}
}
}
}
@@ -837,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);
}