Skip to content

fix(hir): stop panicking on macro-expanded files in container accessors#311

Merged
hongjr03 merged 2 commits into
masterfrom
fix/hir-file-id-macro-panic
Jul 24, 2026
Merged

fix(hir): stop panicking on macro-expanded files in container accessors#311
hongjr03 merged 2 commits into
masterfrom
fix/hir-file-id-macro-panic

Conversation

@hongjr03

Copy link
Copy Markdown
Member

Problem

HirFileId::file_id() looked like an ordinary accessor but panicked for HirFileId::Macro, and that assumption leaked into every container id (ScopeId, ModuleId, BlockId, GenerateBlockId, FileOrModule, SubroutineScope) plus type_infer/scope, all of which returned a vfs FileId by calling the panicking helper. Since HIR genuinely lowers macro expansions into modules and blocks (see db.rs parse/hir_file and the macro expansion tests), these accessors panicked whenever a macro-expanded definition was navigated, searched, or rendered.

The expanded text is not a user-facing file, so collapsing HirFileId to FileId was the wrong abstraction.

Change

HIR core (crates/hir):

  • Remove the panicking HirFileId::file_id() alias. Keep the honest expect_file(); add source_file_id(db) -> Option<FileId> which returns the file itself for real files and maps a macro expansion to the file containing its invocation via macro_file_expansion.
  • FileOrModule / SubroutineScope / ScopeId / BlockId / GenerateBlockId file_id() now return the HirFileId they actually live in. ModuleId::file_id() is removed (it duplicated the file_id field); callers use the field directly.
  • def_id.rs / scope.rs / type_infer.rs drop the HirFileId::File(x.file_id()) / .into() round-trips and use the HirFileId directly.

IDE boundary (crates/ide + src/):

  • Features that need a user-facing (FileId, range) resolve macro expansions to their call site through macro_file_expansion: navigation targets, reference search scopes, definition/side-comment rendering, the semantic module index, and inlay-hint link targets (nav_location / resolve_source_range helpers).
  • semantic_tokens parses macro-expanded blocks with the HirFileId directly (db.parse(block_id.file_id(db))) instead of wrapping in HirFileId::File(..), which discarded the expansion.
  • Rename and side-comment rendering skip macro-expanded origins, since their ranges live in expanded text that is not directly editable.
  • Source-context call sites that only ever hold real files use expect_file().

Verification

  • New test macro_expanded_module_keeps_macro_hir_file_id: lowers a \DECL-expanded module and asserts ScopeId::Module(id).file_id(&db) == HirFileId::Macro(..)(no panic) andsource_file_id` maps back to the call-site file.
  • cargo test -p hir (94), -p ide (137), -p vide (143) all green; cargo check --tests --workspace clean; cargo fmt applied.

Out of scope

Precise per-token origin mapping via ExpansionSourceMap::map_up (pointing into the \define body or the call-site argument rather than the whole call site) is intentionally left for later — it is a refinement, not a correctness fix, and has a span-ambiguity design decision best driven by real feedback. The call-site mapping shipped here is the natural fallback for unmappable origins (TokenPaste/Stringify/Builtin`), so nothing needs to be undone when that lands.

hongjr03 added 2 commits July 24, 2026 21:50
HirFileId::file_id() looked like an ordinary accessor but panicked for
HirFileId::Macro, and that assumption leaked into every container id
(ScopeId, ModuleId, BlockId, GenerateBlockId, FileOrModule,
SubroutineScope) plus type_infer/scope, all of which returned a vfs
FileId by calling the panicking helper. Since HIR genuinely lowers macro
expansions into modules/blocks, these accessors would panic whenever a
macro-expanded definition was navigated, searched, or rendered.

The expanded text is not a user-facing file, so collapsing HirFileId to
FileId was the wrong abstraction. The container accessors now return the
HirFileId they actually live in (File or Macro), and the panicking
HirFileId::file_id() alias is removed in favour of the honest
expect_file() and a new source_file_id(db) that maps a macro expansion
to the file containing its invocation.

IDE features that need a user-facing (FileId, range) resolve macro
expansions to their call site via macro_file_expansion: navigation
targets, reference search scopes, definition/side-comment rendering, the
semantic module index, and inlay-hint link targets. Rename and
side-comment rendering skip macro-expanded origins, since their ranges
live in expanded text that is not directly editable. Source-context
call sites that only ever hold real files use expect_file().
@hongjr03
hongjr03 merged commit 43fa550 into master Jul 24, 2026
22 of 23 checks passed
@hongjr03
hongjr03 deleted the fix/hir-file-id-macro-panic branch July 24, 2026 15:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant