crates.sage_ir.modules.expand.recursion_and_fixpoint

Recursive expansion and same-module fixed points are distinct. Recursive processing expands invocations emitted directly by another invocation. Salsa fixed-point recovery is used only when resolving a macro requires the provisional expanded members of that same module; convergence does not imply completeness.

Read in specification context · design/crates/sage_ir/modules.sage

Implementation

Implemented crates/sage-ir/src/check/resolve/mod.rs:101–106

sage_ir::check::resolve · lib:sage_ir

#![allow(unused)]
fn main() {
    // {anchor}`crates.sage_ir.modules.expand.recursion_and_fixpoint`
    pub fn new_for_macro_expansion(
        db: &'db dyn Db,
        module: crate::local_syms::mods::LocalModSym<'db>,
    ) -> Self {
        Self {

}

See more source ↗

Implemented crates/sage-ir/src/local_syms/mods.rs:103–108

sage_ir::local_syms::mods · lib:sage_ir

#![allow(unused)]
fn main() {
// {anchor}`crates.sage_ir.modules.expand.recursion_and_fixpoint`
pub fn local_expanded_module_items<'db>(
    db: &'db dyn Db,
    module: LocalModSym<'db>,
) -> Vec<Symbol<'db>> {
    let mut entries: Vec<Symbol<'db>> = Vec::new();

}

See more source ↗

Tests and review

Indexed tests and the implementation-completeness and test-adequacy review; no test run is implied.

TODO sage_meta::todo::modules_expand_recursion_and_fixpoint

crates/sage-meta/tests/semantic_spec.rs · test:semantic_spec

#![allow(unused)]
fn main() {
#[test]
    #[sage::test(crates.sage_ir.modules.expand.recursion_and_fixpoint)]
    fn modules_expand_recursion_and_fixpoint() {
        // TODO: Complete the claim-specific verification matrix:
        // One fixture exercises nested emitted invocations, another requires a macro definition emitted
        // earlier in the same module, and traces show bounded fixed-point reexecution followed by stable
        // warm reuse.
    }
}

See more source ↗

Implemented sage_test_harness::macro_expansion_tests::same_module_macro_resolution_reaches_a_fixed_point

crates/sage-test-harness/src/lib.rs · lib:sage_test_harness

#![allow(unused)]
fn main() {
#[test]
    #[sage::test(crates.sage_ir.modules.expand.recursion_and_fixpoint)]
    fn same_module_macro_resolution_reaches_a_fixed_point() {
        with_test_crate(
            r#"
                macro_rules! define_macro {
                    () => {
                        macro_rules! define_generated {
                            () => { struct Generated; }
                        }
                    }
                }

                define_macro!();
                define_generated!();
            "#,
            |db, root| {
                assert!(root.expanded_module_items(db).iter().any(|symbol| {
                    matches!(
                        symbol.data(db),
                        SymbolData::StructSymbol(StructSymbol::Local(strukt))
                            if strukt.name(db).text(db) == "Generated"
                    )
                }));
            },
        );
    }
}

Conditional source: #[cfg(test)]

See more source ↗

Implemented sage_test_harness::converged_expansion_can_remain_incomplete

crates/sage-test-harness/tests/macro_fixpoint_review.rs · test:macro_fixpoint_review

#![allow(unused)]
fn main() {
#[test]
#[sage::test(crates.sage_ir.modules.expand.recursion_and_fixpoint)]
fn converged_expansion_can_remain_incomplete() {
    with_test_crate("missing!();", |db, root| {
        assert!(root.expanded_module_items(db).is_empty());
        assert!(root.expanded_module_items(db).is_empty());
        let ModSymbol::Local(module) = root else {
            panic!("fixture root must be local");
        };
        assert!(!module_expansion_complete_for_symbol_listing(db, module));
    });
}
}

See more source ↗

Implemented sage_test_harness::directly_emitted_invocations_are_expanded

crates/sage-test-harness/tests/macro_fixpoint_review.rs · test:macro_fixpoint_review

#![allow(unused)]
fn main() {
#[test]
#[sage::test(crates.sage_ir.modules.expand.recursion_and_fixpoint)]
fn directly_emitted_invocations_are_expanded() {
    with_test_crate(
        r#"
            macro_rules! inner { () => { struct Generated; } }
            macro_rules! outer { () => { inner!(); } }
            outer!();
        "#,
        |db, root| {
            let generated = root
                .expanded_module_items(db)
                .iter()
                .filter(|symbol| {
                    matches!(symbol.data(db),
                        SymbolData::StructSymbol(StructSymbol::Local(item))
                            if item.name(db).text(db) == "Generated")
                })
                .count();
            assert_eq!(generated, 1);
        },
    );
}
}

See more source ↗

Review: Accepted · Codex /root/macro_fix_anchor.

Reviewed both implementation associations, the full recursion_and_fixpoint claim, all three ordinary tests and the explicit TODO test. Captured macro invocation output parsing and fixture/root construction as dependencies. No code was edited.

mods.rs local_expanded_module_items is a Salsa tracked query with an empty cycle-initial value. It enumerates unexpanded items and directly recursively processes output items: expand_macro parses output then calls expand_unexpanded_items_at_depth with depth + 1. The depth limit and active-attribute guard bound/withhold unavailable recursive work. This is separate from same-module query recovery: resolve_bang_macro constructs Resolver::new_for_macro_expansion and lookup_in_module asks for module.expanded_module_items; when that is the module currently expanding, Salsa supplies provisional query results and drives convergence. The resolver still searches named items and globs together in macro-expansion phase. Its in-flight import stack handles import cycles separately, and new identity deduplication collapses repeated routes without changing the fixed-point mechanism. The added final import ambiguity audit is not invoked by this expansion-phase lookup. mods.rs visibility/association changes to symbol_local_item do not change expansion output.

Convergence remains distinct from completeness: failure to resolve a macro yields no emitted entries, but bang_macro_expansion_complete and module_expansion_complete_for_symbol_listing separately return false for that unresolved invocation. Successful output parsing and recursive enumeration do not synthesize a completeness flag from query convergence.

Tests: same_module_macro_resolution_reaches_a_fixed_point defines a macro that emits another macro definition, then invokes that generated definition as a sibling; its assertion requires the Generated struct to appear. directly_emitted_invocations_are_expanded has outer emit an inner invocation and requires exactly one Generated struct, testing recursive output traversal. converged_expansion_can_remain_incomplete calls expanded_module_items twice for missing!(), requires an empty result both times, and separately requires the symbol-listing completeness query to be false. Thus a stable empty result cannot masquerade as exhaustive absence. Source-fixture helpers parse actual input into a local crate, and the invocation helper parses expansion output into item lists.

The modules_expand_recursion_and_fixpoint TODO explicitly retains the missing verification matrix including bounded fixed-point reexecution traces and stable warm reuse. The source scenarios now have ordinary assertions, but the trace/cache claims are not established merely by those passing results or repeated reads. Completing that trace-based evidence is the prerequisite for removing the TODO; this review preserves the deferred classification.

Executed cargo test -p sage-test-harness --test macro_fixpoint_review: 2 passed; cargo test -p sage-test-harness --lib same_module_macro_resolution_reaches_a_fixed_point: 1 passed. All associated ordinary tests executed with no failures. The complete claim and all entries are accounted for by the implementation, substantive tests, and visible trace-coverage deferral; no edits requested.

Browse crates anchors

139 anchors

Specification anchors and declared coverage
AnchorImplementationTests
crates (139)114 Implemented37 TODO2 N/A74 Implemented107 TODO
crates.sage_inspector (15)13 Implemented1 TODO2 N/A3 Implemented15 TODO
crates.sage_inspector.inspection (15)13 Implemented1 TODO2 N/A3 Implemented15 TODO
balanced_tracesImplementedTODO
canonical_ownershipImplementedImplementedTODO
derive_reflectionImplementedImplementedTODO
detail_free_indexImplementedTODO
deterministic_traceImplementedTODO
durable_navigationN/ATODO
generic_browserN/ATODO
owned_reflectionImplementedImplementedTODO
product_availabilityImplementedTODO
revision_and_demandImplementedTODO
semantic_phase_boundaryImplementedTODO
source_evidenceImplementedTODO
typed_serviceImplementedTODO
unknown_workImplementedTODOTODO
workspace_actorImplementedTODO
crates.sage_ir (90)67 Implemented34 TODO40 Implemented88 TODO
crates.sage_ir.checking (12)12 Implemented3 TODO5 Implemented12 TODO
crates.sage_ir.checking.body (5)5 Implemented2 TODO3 Implemented5 TODO
elaborationImplementedImplementedTODO
expected_typesImplementedTODOTODO
interface_dependenciesImplementedImplementedTODO
isolated_completionImplementedImplementedTODO
operator_callsImplementedTODOTODO
identity_mintingImplementedTODO
owned_productsImplementedImplementedTODO
crates.sage_ir.checking.signature (4)4 Implemented1 TODO1 Implemented4 TODO
body_independenceImplementedTODO
narrow_detailImplementedTODOTODO
owner_binderImplementedImplementedTODO
storageImplementedTODO
symbol_keyed_interfacesImplementedTODO
crates.sage_ir.crate (9)9 TODO9 TODO
explicit_restrictionsTODOTODO
identity_before_detailTODOTODO
incremental_evidenceTODOTODO
narrow_demandsTODOTODO
reexecution_and_invalidationTODOTODO
represented_completenessTODOTODO
restrictions_and_gapsTODOTODO
semantic_query_boundariesTODOTODO
terminal_incompletenessTODOTODO
crates.sage_ir.inference (8)8 Implemented6 Implemented8 TODO
atomic_checkingImplementedImplementedTODO
body_local_quiescenceImplementedImplementedTODO
canonical_boundaryImplementedImplementedTODO
completed_body_boundaryImplementedTODO
numeric_domainsImplementedImplementedTODO
subtyping_and_coercionImplementedImplementedTODO
terminal_obligationsImplementedTODO
transaction_isolationImplementedImplementedTODO
crates.sage_ir.metadata (4)4 Implemented1 TODO4 TODO
explicit_incompletenessImplementedTODO
keyed_reuseImplementedTODOTODO
product_boundariesImplementedTODO
provider_authorityImplementedTODO
crates.sage_ir.modules (8)7 Implemented1 TODO4 Implemented8 TODO
crates.sage_ir.modules.expand (4)4 Implemented2 Implemented4 TODO
completenessImplementedImplementedTODO
dependenciesImplementedTODO
direct_membersImplementedTODO
recursion_and_fixpointImplementedImplementedTODO
crates.sage_ir.modules.parse (4)3 Implemented1 TODO2 Implemented4 TODO
dependenciesImplementedTODO
detail_firewallImplementedImplementedTODO
recovery_completenessTODOTODO
syntax_identitiesImplementedImplementedTODO
crates.sage_ir.resolution (5)5 Implemented1 TODO3 Implemented4 TODO
crates.sage_ir.resolution.lookup (5)5 Implemented1 TODO3 Implemented4 TODO
completenessImplementedTODOImplementedTODO
dependenciesImplementedTODO
expansion_import_ambiguityImplementedImplemented
identity_onlyImplementedTODO
precedenceImplementedImplementedTODO
crates.sage_ir.solver (9)7 Implemented7 TODO5 Implemented9 TODO
alternative_isolationImplementedTODOImplementedTODO
bounded_completenessImplementedTODOTODO
candidate_completenessImplementedTODO
canonical_cyclesTODOTODO
canonical_outputsImplementedImplementedTODO
local_index_firewallTODOTODO
normalization_demandImplementedTODOImplementedTODO
schedule_independenceImplementedTODOImplementedTODO
shared_final_resultImplementedTODOImplementedTODO
crates.sage_ir.symbols (8)8 Implemented4 Implemented7 TODO
associated_identityImplementedImplemented
associated_interfacesImplementedTODO
body_interfacesImplementedImplementedTODO
definition_identityImplementedTODO
external_fact_queriesImplementedTODO
external_identityImplementedTODO
kind_wrappersImplementedImplementedTODO
local_identityImplementedImplementedTODO
crates.sage_ir.types (27)16 Implemented12 TODO13 Implemented27 TODO
crates.sage_ir.types.aliases (2)1 Implemented1 TODO1 Implemented2 TODO
identityImplementedImplementedTODO
revelationTODOTODO
crates.sage_ir.types.binder (1)1 Implemented1 TODO1 Implemented1 TODO
owner_parametersImplementedTODOImplementedTODO
crates.sage_ir.types.body (13)4 Implemented9 TODO3 Implemented13 TODO
awaitTODOTODO
closuresTODOTODO
conditional_patternsTODOTODO
coroutinesTODOTODO
diagnosed_recoveryImplementedImplementedTODO
elaboratedTODOImplementedTODO
for_iterationTODOTODO
indexingTODOTODO
macro_expansionTODOTODO
no_inferenceImplementedImplementedTODO
resolved_referencesImplementedTODO
try_residualTODOTODO
typed_provenanceImplementedTODO
crates.sage_ir.types.calls (2)1 Implemented1 TODO1 Implemented2 TODO
dispatch_familiesTODOTODO
selected_semanticsImplementedImplementedTODO
crates.sage_ir.types.lifetimes (2)2 Implemented2 Implemented2 TODO
dummyImplementedImplementedTODO
unchecked_borrowsImplementedImplementedTODO
crates.sage_ir.types.operators (2)2 Implemented1 Implemented2 TODO
lazy_control_flowImplementedTODO
trait_callsImplementedImplementedTODO
scoped_identitiesImplementedTODO
crates.sage_ir.types.spans (4)4 Implemented4 Implemented4 TODO
generated_identityImplementedImplementedTODO
item_originImplementedImplementedTODO
offset_reuseImplementedImplementedTODO
relative_compositionImplementedImplementedTODO
crates.sage_oracle_harness (4)4 Implemented2 TODO1 Implemented4 TODO
crates.sage_oracle_harness.crate (4)4 Implemented2 TODO1 Implemented4 TODO
deterministic_emissionImplementedTODO
exact_comparisonImplementedTODOImplementedTODO
fixed_projectionImplementedTODO
independent_coverageImplementedTODOTODO
crates.sage_stash (5)5 Implemented5 Implemented
crates.sage_stash.storage (5)5 Implemented5 Implemented
handle_ownershipImplementedImplemented
immutable_entriesImplementedImplemented
query_valueImplementedImplemented
rooted_equalityImplementedImplemented
typed_interningImplementedImplemented
crates.sage_test_harness (25)25 Implemented25 Implemented
crates.sage_test_harness.compile_tests (25)25 Implemented25 Implemented
annotation_validationImplementedImplemented
blessing_gateImplementedImplemented
callsite_updatesImplementedImplemented
checking_scopeImplementedImplemented
compiler_conditionsImplementedImplemented
completed_typesImplementedImplemented
coordinatesImplementedImplemented
dependenciesImplementedImplemented
diagnostic_countsImplementedImplemented
diagnostic_locationsImplementedImplemented
editionImplementedImplemented
fixturesImplementedImplemented
grouped_observationsImplementedImplemented
invocationImplementedImplemented
production_executionImplementedImplemented
project_isolationImplementedImplemented
query_captureImplementedImplemented
query_projectionImplementedImplemented
renderingImplementedImplemented
resolved_symbolsImplementedImplemented
review_visibilityImplementedImplemented
rustc_executionImplementedImplemented
rustc_lintsImplementedImplemented
starting_expressionsImplementedImplemented
target_lineImplementedImplemented