Skip to content

Commit 487152b

Browse files
committed
Auto merge of #18361 - Veykril:veykril/push-uzsokssoyznx, r=Veykril
fix: Fix token downmapping failing for include! inputs Supercedes #18325 Fixes #18325 Fixes #18313 Fixes #18314
2 parents b0b5d38 + d878b8c commit 487152b

File tree

6 files changed

+125
-41
lines changed

6 files changed

+125
-41
lines changed

crates/hir-expand/src/builtin/fn_macro.rs

+11-14
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,20 @@ use cfg::CfgExpr;
55
use either::Either;
66
use intern::{sym, Symbol};
77
use mbe::{expect_fragment, DelimiterKind};
8-
use span::{Edition, EditionedFileId, Span, SpanAnchor, SyntaxContextId, ROOT_ERASED_FILE_AST_ID};
8+
use span::{Edition, EditionedFileId, Span};
99
use stdx::format_to;
1010
use syntax::{
1111
format_smolstr,
1212
unescape::{unescape_byte, unescape_char, unescape_unicode, Mode},
1313
};
14-
use syntax_bridge::parse_to_token_tree;
14+
use syntax_bridge::syntax_node_to_token_tree;
1515

1616
use crate::{
1717
builtin::quote::{dollar_crate, quote},
1818
db::ExpandDatabase,
1919
hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt},
2020
name,
21+
span_map::SpanMap,
2122
tt::{self, DelimSpan},
2223
ExpandError, ExpandResult, HirFileIdExt, Lookup as _, MacroCallId,
2324
};
@@ -739,18 +740,14 @@ fn include_expand(
739740
return ExpandResult::new(tt::Subtree::empty(DelimSpan { open: span, close: span }), e)
740741
}
741742
};
742-
match parse_to_token_tree(
743-
file_id.edition(),
744-
SpanAnchor { file_id, ast_id: ROOT_ERASED_FILE_AST_ID },
745-
SyntaxContextId::ROOT,
746-
&db.file_text(file_id.file_id()),
747-
) {
748-
Some(it) => ExpandResult::ok(it),
749-
None => ExpandResult::new(
750-
tt::Subtree::empty(DelimSpan { open: span, close: span }),
751-
ExpandError::other(span, "failed to parse included file"),
752-
),
753-
}
743+
let span_map = db.real_span_map(file_id);
744+
// FIXME: Parse errors
745+
ExpandResult::ok(syntax_node_to_token_tree(
746+
&db.parse(file_id).syntax_node(),
747+
SpanMap::RealSpanMap(span_map),
748+
span,
749+
syntax_bridge::DocCommentDesugarMode::ProcMacro,
750+
))
754751
}
755752

756753
pub fn include_input_to_file_id(

crates/hir/src/semantics.rs

+29-23
Original file line numberDiff line numberDiff line change
@@ -892,29 +892,8 @@ impl<'db> SemanticsImpl<'db> {
892892
f: &mut dyn FnMut(InFile<SyntaxToken>, SyntaxContextId) -> ControlFlow<T>,
893893
) -> Option<T> {
894894
let _p = tracing::info_span!("descend_into_macros_impl").entered();
895-
let (sa, span, file_id) = token
896-
.parent()
897-
.and_then(|parent| {
898-
self.analyze_impl(InRealFile::new(file_id, &parent).into(), None, false)
899-
})
900-
.and_then(|sa| {
901-
let file_id = sa.file_id.file_id()?;
902-
Some((
903-
sa,
904-
self.db.real_span_map(file_id).span_for_range(token.text_range()),
905-
HirFileId::from(file_id),
906-
))
907-
})?;
908895

909-
let mut m_cache = self.macro_call_cache.borrow_mut();
910-
let def_map = sa.resolver.def_map();
911-
912-
// A stack of tokens to process, along with the file they came from
913-
// These are tracked to know which macro calls we still have to look into
914-
// the tokens themselves aren't that interesting as the span that is being used to map
915-
// things down never changes.
916-
let mut stack: Vec<(_, SmallVec<[_; 2]>)> =
917-
vec![(file_id, smallvec![(token, SyntaxContextId::ROOT)])];
896+
let span = self.db.real_span_map(file_id).span_for_range(token.text_range());
918897

919898
// Process the expansion of a call, pushing all tokens with our span in the expansion back onto our stack
920899
let process_expansion_for_token = |stack: &mut Vec<_>, macro_file| {
@@ -926,14 +905,40 @@ impl<'db> SemanticsImpl<'db> {
926905
.map(SmallVec::<[_; 2]>::from_iter),
927906
)
928907
})?;
929-
930908
// we have found a mapping for the token if the vec is non-empty
931909
let res = mapped_tokens.is_empty().not().then_some(());
932910
// requeue the tokens we got from mapping our current token down
933911
stack.push((HirFileId::from(file_id), mapped_tokens));
934912
res
935913
};
936914

915+
// A stack of tokens to process, along with the file they came from
916+
// These are tracked to know which macro calls we still have to look into
917+
// the tokens themselves aren't that interesting as the span that is being used to map
918+
// things down never changes.
919+
let mut stack: Vec<(_, SmallVec<[_; 2]>)> = vec![];
920+
let include = self.s2d_cache.borrow_mut().get_or_insert_include_for(self.db, file_id);
921+
match include {
922+
Some(include) => {
923+
// include! inputs are always from real files, so they only need to be handled once upfront
924+
process_expansion_for_token(&mut stack, include)?;
925+
}
926+
None => {
927+
stack.push((file_id.into(), smallvec![(token, SyntaxContextId::ROOT)]));
928+
}
929+
}
930+
931+
let (file_id, tokens) = stack.first()?;
932+
// make sure we pick the token in the expanded include if we encountered an include,
933+
// otherwise we'll get the wrong semantics
934+
let sa =
935+
tokens.first()?.0.parent().and_then(|parent| {
936+
self.analyze_impl(InFile::new(*file_id, &parent), None, false)
937+
})?;
938+
939+
let mut m_cache = self.macro_call_cache.borrow_mut();
940+
let def_map = sa.resolver.def_map();
941+
937942
// Filters out all tokens that contain the given range (usually the macro call), any such
938943
// token is redundant as the corresponding macro call has already been processed
939944
let filter_duplicates = |tokens: &mut SmallVec<_>, range: TextRange| {
@@ -1011,6 +1016,7 @@ impl<'db> SemanticsImpl<'db> {
10111016
) {
10121017
call.as_macro_file()
10131018
} else {
1019+
// FIXME: This is wrong, the SourceAnalyzer might be invalid here
10141020
sa.expand(self.db, mcall.as_ref())?
10151021
};
10161022
m_cache.insert(mcall, it);

crates/hir/src/semantics/source_to_def.rs

+25-3
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ use hir_expand::{
104104
};
105105
use rustc_hash::FxHashMap;
106106
use smallvec::SmallVec;
107-
use span::{FileId, MacroFileId};
107+
use span::{EditionedFileId, FileId, MacroFileId};
108108
use stdx::impl_from;
109109
use syntax::{
110110
ast::{self, HasName},
@@ -118,9 +118,27 @@ pub(super) struct SourceToDefCache {
118118
pub(super) dynmap_cache: FxHashMap<(ChildContainer, HirFileId), DynMap>,
119119
expansion_info_cache: FxHashMap<MacroFileId, ExpansionInfo>,
120120
pub(super) file_to_def_cache: FxHashMap<FileId, SmallVec<[ModuleId; 1]>>,
121+
pub(super) included_file_cache: FxHashMap<EditionedFileId, Option<MacroFileId>>,
121122
}
122123

123124
impl SourceToDefCache {
125+
pub(super) fn get_or_insert_include_for(
126+
&mut self,
127+
db: &dyn HirDatabase,
128+
file: EditionedFileId,
129+
) -> Option<MacroFileId> {
130+
if let Some(&m) = self.included_file_cache.get(&file) {
131+
return m;
132+
}
133+
self.included_file_cache.insert(file, None);
134+
for &crate_id in db.relevant_crates(file.into()).iter() {
135+
db.include_macro_invoc(crate_id).iter().for_each(|&(macro_call_id, file_id)| {
136+
self.included_file_cache.insert(file_id, Some(MacroFileId { macro_call_id }));
137+
});
138+
}
139+
self.included_file_cache.get(&file).copied().flatten()
140+
}
141+
124142
pub(super) fn get_or_insert_expansion(
125143
&mut self,
126144
sema: &SemanticsImpl<'_>,
@@ -163,9 +181,13 @@ impl SourceToDefCtx<'_, '_> {
163181
.include_macro_invoc(crate_id)
164182
.iter()
165183
.filter(|&&(_, file_id)| file_id == file)
166-
.flat_map(|(call, _)| {
184+
.flat_map(|&(macro_call_id, file_id)| {
185+
self.cache
186+
.included_file_cache
187+
.insert(file_id, Some(MacroFileId { macro_call_id }));
167188
modules(
168-
call.lookup(self.db.upcast())
189+
macro_call_id
190+
.lookup(self.db.upcast())
169191
.kind
170192
.file_id()
171193
.original_file(self.db.upcast())

crates/ide/src/goto_definition.rs

+38
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,44 @@ fn func_in_include() {
497497
//^^^^^^^^^^^^^^^
498498
}
499499
500+
fn foo() {
501+
func_in_include$0();
502+
}
503+
"#,
504+
);
505+
}
506+
507+
#[test]
508+
fn goto_def_in_included_file_inside_mod() {
509+
check(
510+
r#"
511+
//- minicore:include
512+
//- /main.rs
513+
mod a {
514+
include!("b.rs");
515+
}
516+
//- /b.rs
517+
fn func_in_include() {
518+
//^^^^^^^^^^^^^^^
519+
}
520+
fn foo() {
521+
func_in_include$0();
522+
}
523+
"#,
524+
);
525+
526+
check(
527+
r#"
528+
//- minicore:include
529+
//- /main.rs
530+
mod a {
531+
include!("a.rs");
532+
}
533+
//- /a.rs
534+
fn func_in_include() {
535+
//^^^^^^^^^^^^^^^
536+
}
537+
500538
fn foo() {
501539
func_in_include$0();
502540
}

crates/ide/src/references.rs

+21
Original file line numberDiff line numberDiff line change
@@ -2750,4 +2750,25 @@ impl Foo {
27502750
"#]],
27512751
);
27522752
}
2753+
2754+
#[test]
2755+
fn goto_ref_on_included_file() {
2756+
check(
2757+
r#"
2758+
//- minicore:include
2759+
//- /lib.rs
2760+
include!("foo.rs");
2761+
fn howdy() {
2762+
let _ = FOO;
2763+
}
2764+
//- /foo.rs
2765+
const FOO$0: i32 = 0;
2766+
"#,
2767+
expect![[r#"
2768+
FOO Const FileId(1) 0..19 6..9
2769+
2770+
FileId(0) 45..48
2771+
"#]],
2772+
);
2773+
}
27532774
}

crates/syntax/src/ptr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ pub struct AstPtr<N: AstNode> {
2727
_ty: PhantomData<fn() -> N>,
2828
}
2929

30-
impl<N: AstNode + std::fmt::Debug> std::fmt::Debug for AstPtr<N> {
30+
impl<N: AstNode> std::fmt::Debug for AstPtr<N> {
3131
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3232
f.debug_tuple("AstPtr").field(&self.raw).finish()
3333
}

0 commit comments

Comments
 (0)