Skip to content

Commit 079ee28

Browse files
committed
Auto merge of #17518 - Veykril:expr-scopes-mac, r=Veykril
fix: Fix expression scope calculation when within macro expansions
2 parents acdfab6 + eb72a9e commit 079ee28

File tree

20 files changed

+198
-108
lines changed

20 files changed

+198
-108
lines changed

src/tools/rust-analyzer/Cargo.toml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@ license = "MIT OR Apache-2.0"
1010
authors = ["rust-analyzer team"]
1111

1212
[profile.dev]
13-
# Disabling debug info speeds up builds a bunch,
14-
# and we don't rely on it for debugging that much.
15-
debug = 0
13+
debug = 1
1614

1715
[profile.dev.package]
1816
# These speed up local tests.

src/tools/rust-analyzer/crates/hir-def/src/data.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -637,10 +637,6 @@ impl<'a> AssocItemCollector<'a> {
637637
attr,
638638
) {
639639
Ok(ResolvedAttr::Macro(call_id)) => {
640-
// If proc attribute macro expansion is disabled, skip expanding it here
641-
if !self.db.expand_proc_attr_macros() {
642-
continue 'attrs;
643-
}
644640
let loc = self.db.lookup_intern_macro_call(call_id);
645641
if let MacroDefKind::ProcMacro(_, exp, _) = loc.def.kind {
646642
// If there's no expander for the proc macro (e.g. the

src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,9 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeI
8383
let name = Name::new_text_dont_use(it.name.clone());
8484
(
8585
name,
86-
if it.disabled {
86+
if !db.expand_proc_attr_macros() {
87+
CustomProcMacroExpander::dummy()
88+
} else if it.disabled {
8789
CustomProcMacroExpander::disabled()
8890
} else {
8991
CustomProcMacroExpander::new(hir_expand::proc_macro::ProcMacroId::new(
@@ -1331,16 +1333,6 @@ impl DefCollector<'_> {
13311333

13321334
let call_id = call_id();
13331335
if let MacroDefKind::ProcMacro(_, exp, _) = def.kind {
1334-
// If proc attribute macro expansion is disabled, skip expanding it here
1335-
if !self.db.expand_proc_attr_macros() {
1336-
self.def_map.diagnostics.push(DefDiagnostic::unresolved_proc_macro(
1337-
directive.module_id,
1338-
self.db.lookup_intern_macro_call(call_id).kind,
1339-
def.krate,
1340-
));
1341-
return recollect_without(self);
1342-
}
1343-
13441336
// If there's no expander for the proc macro (e.g.
13451337
// because proc macros are disabled, or building the
13461338
// proc macro crate failed), report this and skip

src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,47 @@ use crate::{
1717

1818
#[derive(Debug, PartialEq, Eq)]
1919
pub enum DefDiagnosticKind {
20-
UnresolvedModule { ast: AstId<ast::Module>, candidates: Box<[String]> },
21-
UnresolvedExternCrate { ast: AstId<ast::ExternCrate> },
22-
UnresolvedImport { id: ItemTreeId<item_tree::Use>, index: Idx<ast::UseTree> },
23-
UnconfiguredCode { ast: ErasedAstId, cfg: CfgExpr, opts: CfgOptions },
24-
UnresolvedProcMacro { ast: MacroCallKind, krate: CrateId },
25-
UnresolvedMacroCall { ast: MacroCallKind, path: ModPath },
26-
UnimplementedBuiltinMacro { ast: AstId<ast::Macro> },
27-
InvalidDeriveTarget { ast: AstId<ast::Item>, id: usize },
28-
MalformedDerive { ast: AstId<ast::Adt>, id: usize },
29-
MacroDefError { ast: AstId<ast::Macro>, message: String },
20+
UnresolvedModule {
21+
ast: AstId<ast::Module>,
22+
candidates: Box<[String]>,
23+
},
24+
UnresolvedExternCrate {
25+
ast: AstId<ast::ExternCrate>,
26+
},
27+
UnresolvedImport {
28+
id: ItemTreeId<item_tree::Use>,
29+
index: Idx<ast::UseTree>,
30+
},
31+
UnconfiguredCode {
32+
ast: ErasedAstId,
33+
cfg: CfgExpr,
34+
opts: CfgOptions,
35+
},
36+
/// A proc-macro that is lacking an expander, this might be due to build scripts not yet having
37+
/// run or proc-macro expansion being disabled.
38+
UnresolvedProcMacro {
39+
ast: MacroCallKind,
40+
krate: CrateId,
41+
},
42+
UnresolvedMacroCall {
43+
ast: MacroCallKind,
44+
path: ModPath,
45+
},
46+
UnimplementedBuiltinMacro {
47+
ast: AstId<ast::Macro>,
48+
},
49+
InvalidDeriveTarget {
50+
ast: AstId<ast::Item>,
51+
id: usize,
52+
},
53+
MalformedDerive {
54+
ast: AstId<ast::Adt>,
55+
id: usize,
56+
},
57+
MacroDefError {
58+
ast: AstId<ast::Macro>,
59+
message: String,
60+
},
3061
}
3162

3263
#[derive(Clone, Debug, PartialEq, Eq)]
@@ -92,10 +123,6 @@ impl DefDiagnostic {
92123
Self { in_module: container, kind: DefDiagnosticKind::UnconfiguredCode { ast, cfg, opts } }
93124
}
94125

95-
// FIXME: Whats the difference between this and unresolved_macro_call
96-
// FIXME: This is used for a lot of things, unresolved proc macros, disabled proc macros, etc
97-
// yet the diagnostic handler in ide-diagnostics has to figure out what happened because this
98-
// struct loses all that information!
99126
pub fn unresolved_proc_macro(
100127
container: LocalModuleId,
101128
ast: MacroCallKind,

src/tools/rust-analyzer/crates/hir-expand/src/files.rs

Lines changed: 76 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
//! Things to wrap other things in file ids.
2+
use std::borrow::Borrow;
3+
24
use either::Either;
35
use span::{
46
AstIdNode, ErasedFileAstId, FileAstId, FileId, FileRange, HirFileId, HirFileIdRepr,
@@ -76,6 +78,13 @@ impl<FileKind: Copy, T> InFileWrapper<FileKind, T> {
7678
pub fn as_ref(&self) -> InFileWrapper<FileKind, &T> {
7779
self.with_value(&self.value)
7880
}
81+
82+
pub fn borrow<U>(&self) -> InFileWrapper<FileKind, &U>
83+
where
84+
T: Borrow<U>,
85+
{
86+
self.with_value(self.value.borrow())
87+
}
7988
}
8089

8190
impl<FileKind: Copy, T: Clone> InFileWrapper<FileKind, &T> {
@@ -156,30 +165,69 @@ impl<FileId: Copy, N: AstNode> InFileWrapper<FileId, &N> {
156165
}
157166

158167
// region:specific impls
168+
impl<SN: Borrow<SyntaxNode>> InRealFile<SN> {
169+
pub fn file_range(&self) -> FileRange {
170+
FileRange { file_id: self.file_id, range: self.value.borrow().text_range() }
171+
}
172+
}
173+
174+
impl<SN: Borrow<SyntaxNode>> InFile<SN> {
175+
pub fn parent_ancestors_with_macros(
176+
self,
177+
db: &dyn db::ExpandDatabase,
178+
) -> impl Iterator<Item = InFile<SyntaxNode>> + '_ {
179+
let succ = move |node: &InFile<SyntaxNode>| match node.value.parent() {
180+
Some(parent) => Some(node.with_value(parent)),
181+
None => db
182+
.lookup_intern_macro_call(node.file_id.macro_file()?.macro_call_id)
183+
.to_node_item(db)
184+
.syntax()
185+
.cloned()
186+
.map(|node| node.parent())
187+
.transpose(),
188+
};
189+
std::iter::successors(succ(&self.borrow().cloned()), succ)
190+
}
191+
192+
pub fn ancestors_with_macros(
193+
self,
194+
db: &dyn db::ExpandDatabase,
195+
) -> impl Iterator<Item = InFile<SyntaxNode>> + '_ {
196+
let succ = move |node: &InFile<SyntaxNode>| match node.value.parent() {
197+
Some(parent) => Some(node.with_value(parent)),
198+
None => db
199+
.lookup_intern_macro_call(node.file_id.macro_file()?.macro_call_id)
200+
.to_node_item(db)
201+
.syntax()
202+
.cloned()
203+
.map(|node| node.parent())
204+
.transpose(),
205+
};
206+
std::iter::successors(Some(self.borrow().cloned()), succ)
207+
}
208+
209+
pub fn kind(&self) -> parser::SyntaxKind {
210+
self.value.borrow().kind()
211+
}
212+
213+
pub fn text_range(&self) -> TextRange {
214+
self.value.borrow().text_range()
215+
}
159216

160-
impl InFile<&SyntaxNode> {
161217
/// Falls back to the macro call range if the node cannot be mapped up fully.
162218
///
163219
/// For attributes and derives, this will point back to the attribute only.
164220
/// For the entire item use [`InFile::original_file_range_full`].
165221
pub fn original_file_range_rooted(self, db: &dyn db::ExpandDatabase) -> FileRange {
166-
self.map(SyntaxNode::text_range).original_node_file_range_rooted(db)
222+
self.borrow().map(SyntaxNode::text_range).original_node_file_range_rooted(db)
167223
}
168224

169225
/// Falls back to the macro call range if the node cannot be mapped up fully.
170226
pub fn original_file_range_with_macro_call_body(
171227
self,
172228
db: &dyn db::ExpandDatabase,
173229
) -> FileRange {
174-
self.map(SyntaxNode::text_range).original_node_file_range_with_macro_call_body(db)
175-
}
176-
177-
/// Attempts to map the syntax node back up its macro calls.
178-
pub fn original_file_range_opt(
179-
self,
180-
db: &dyn db::ExpandDatabase,
181-
) -> Option<(FileRange, SyntaxContextId)> {
182-
self.map(SyntaxNode::text_range).original_node_file_range_opt(db)
230+
self.borrow().map(SyntaxNode::text_range).original_node_file_range_with_macro_call_body(db)
183231
}
184232

185233
pub fn original_syntax_node_rooted(
@@ -190,16 +238,19 @@ impl InFile<&SyntaxNode> {
190238
// as we don't have node inputs otherwise and therefore can't find an `N` node in the input
191239
let file_id = match self.file_id.repr() {
192240
HirFileIdRepr::FileId(file_id) => {
193-
return Some(InRealFile { file_id, value: self.value.clone() })
241+
return Some(InRealFile { file_id, value: self.value.borrow().clone() })
194242
}
195243
HirFileIdRepr::MacroFile(m) if m.is_attr_macro(db) => m,
196244
_ => return None,
197245
};
198246

199-
let FileRange { file_id, range } =
200-
map_node_range_up_rooted(db, &db.expansion_span_map(file_id), self.value.text_range())?;
247+
let FileRange { file_id, range } = map_node_range_up_rooted(
248+
db,
249+
&db.expansion_span_map(file_id),
250+
self.value.borrow().text_range(),
251+
)?;
201252

202-
let kind = self.value.kind();
253+
let kind = self.kind();
203254
let value = db
204255
.parse(file_id)
205256
.syntax_node()
@@ -211,6 +262,16 @@ impl InFile<&SyntaxNode> {
211262
}
212263
}
213264

265+
impl InFile<&SyntaxNode> {
266+
/// Attempts to map the syntax node back up its macro calls.
267+
pub fn original_file_range_opt(
268+
self,
269+
db: &dyn db::ExpandDatabase,
270+
) -> Option<(FileRange, SyntaxContextId)> {
271+
self.borrow().map(SyntaxNode::text_range).original_node_file_range_opt(db)
272+
}
273+
}
274+
214275
impl InMacroFile<SyntaxToken> {
215276
pub fn upmap_once(
216277
self,

src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -68,38 +68,44 @@ impl SourceAnalyzer {
6868
pub(crate) fn new_for_body(
6969
db: &dyn HirDatabase,
7070
def: DefWithBodyId,
71-
node @ InFile { file_id, .. }: InFile<&SyntaxNode>,
71+
node: InFile<&SyntaxNode>,
7272
offset: Option<TextSize>,
7373
) -> SourceAnalyzer {
74-
let (body, source_map) = db.body_with_source_map(def);
75-
let scopes = db.expr_scopes(def);
76-
let scope = match offset {
77-
None => scope_for(&scopes, &source_map, node),
78-
Some(offset) => scope_for_offset(db, &scopes, &source_map, node.file_id, offset),
79-
};
80-
let resolver = resolver_for_scope(db.upcast(), def, scope);
81-
SourceAnalyzer {
82-
resolver,
83-
def: Some((def, body, source_map)),
84-
infer: Some(db.infer(def)),
85-
file_id,
86-
}
74+
Self::new_for_body_(db, def, node, offset, Some(db.infer(def)))
8775
}
8876

8977
pub(crate) fn new_for_body_no_infer(
78+
db: &dyn HirDatabase,
79+
def: DefWithBodyId,
80+
node: InFile<&SyntaxNode>,
81+
offset: Option<TextSize>,
82+
) -> SourceAnalyzer {
83+
Self::new_for_body_(db, def, node, offset, None)
84+
}
85+
86+
pub(crate) fn new_for_body_(
9087
db: &dyn HirDatabase,
9188
def: DefWithBodyId,
9289
node @ InFile { file_id, .. }: InFile<&SyntaxNode>,
9390
offset: Option<TextSize>,
91+
infer: Option<Arc<InferenceResult>>,
9492
) -> SourceAnalyzer {
9593
let (body, source_map) = db.body_with_source_map(def);
9694
let scopes = db.expr_scopes(def);
9795
let scope = match offset {
98-
None => scope_for(&scopes, &source_map, node),
99-
Some(offset) => scope_for_offset(db, &scopes, &source_map, node.file_id, offset),
96+
None => scope_for(db, &scopes, &source_map, node),
97+
Some(offset) => {
98+
debug_assert!(
99+
node.text_range().contains_inclusive(offset),
100+
"{:?} not in {:?}",
101+
offset,
102+
node.text_range()
103+
);
104+
scope_for_offset(db, &scopes, &source_map, node.file_id, offset)
105+
}
100106
};
101107
let resolver = resolver_for_scope(db.upcast(), def, scope);
102-
SourceAnalyzer { resolver, def: Some((def, body, source_map)), infer: None, file_id }
108+
SourceAnalyzer { resolver, def: Some((def, body, source_map)), infer, file_id }
103109
}
104110

105111
pub(crate) fn new_for_resolver(
@@ -662,7 +668,6 @@ impl SourceAnalyzer {
662668
return resolved;
663669
}
664670

665-
// This must be a normal source file rather than macro file.
666671
let ctx = LowerCtx::new(db.upcast(), self.file_id);
667672
let hir_path = Path::from_src(&ctx, path.clone())?;
668673

@@ -955,14 +960,15 @@ impl SourceAnalyzer {
955960
}
956961

957962
fn scope_for(
963+
db: &dyn HirDatabase,
958964
scopes: &ExprScopes,
959965
source_map: &BodySourceMap,
960966
node: InFile<&SyntaxNode>,
961967
) -> Option<ScopeId> {
962-
node.value
963-
.ancestors()
964-
.filter_map(ast::Expr::cast)
965-
.filter_map(|it| source_map.node_expr(InFile::new(node.file_id, &it)))
968+
node.ancestors_with_macros(db.upcast())
969+
.take_while(|it| !ast::Item::can_cast(it.kind()) || ast::MacroCall::can_cast(it.kind()))
970+
.filter_map(|it| it.map(ast::Expr::cast).transpose())
971+
.filter_map(|it| source_map.node_expr(it.as_ref()))
966972
.find_map(|it| scopes.scope_for(it))
967973
}
968974

@@ -988,8 +994,8 @@ fn scope_for_offset(
988994
Some(it.file_id.macro_file()?.call_node(db.upcast()))
989995
})
990996
.find(|it| it.file_id == from_file)
991-
.filter(|it| it.value.kind() == SyntaxKind::MACRO_CALL)?;
992-
Some((source.value.text_range(), scope))
997+
.filter(|it| it.kind() == SyntaxKind::MACRO_CALL)?;
998+
Some((source.text_range(), scope))
993999
})
9941000
.filter(|(expr_range, _scope)| expr_range.start() <= offset && offset <= expr_range.end())
9951001
// find containing scope

src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -598,9 +598,8 @@ pub(super) fn famous_types<'a, DB: HirDatabase>(
598598
Expr::FamousType { ty: Type::new(db, module.id, TyBuilder::unit()), value: "()" },
599599
]
600600
.into_iter()
601-
.map(|exprs| {
601+
.inspect(|exprs| {
602602
lookup.insert(exprs.ty(db), std::iter::once(exprs.clone()));
603-
exprs
604603
})
605604
.filter(|expr| expr.ty(db).could_unify_with_deeply(db, &ctx.goal))
606605
}

0 commit comments

Comments
 (0)