Fix #2386 - withOptions leaves stale index entries on qualifier/secondary change#2447
Fix #2386 - withOptions leaves stale index entries on qualifier/secondary change#2447arnaudgiuliani wants to merge 1 commit into
Conversation
…dary change withOptions mutates a BeanDefinition in place then re-indexes from the mutated state, but never removed the entries registered under the *previous* coordinates. Changing the qualifier (or secondaryTypes) left the definition reachable under its old qualifier (silent dual-index), and secondary types were indexed only under the new qualifier — asymmetric reachability vs the stale primary. Snapshot the previous qualifier + secondaryTypes before applying the options; when either changes, drop the stale Module.mappings entries (old primary + old secondaries under the old qualifier) before re-indexing with the new coordinates. No-op when nothing index-relevant changed. Tests: - WithOptionsStaleIndexTest (commonTest) — qualifier change drops the stale primary index; primary + secondary reachability stay consistent (RED->GREEN). - NewDSLTest: corrected mappings.size expectations that were counting the stale entry (3->2, 3->2, 4->3) — they encoded the bug. Behavioral note: a definition is no longer reachable under a qualifier it had before withOptions changed it. This removes unintended (undocumented) reachability; resolution by the *current* qualifier is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Root cause of the regression: with two same-type definitions — viewModelOf(::MyViewModel) // (1) indexes MyViewModel:null
viewModelOf(::MyViewModel){ named("bis") } // (2) indexes MyViewModel:null at creation (overwrites (1)!), then withOptions moves it to :bis— the Implication: the clean fix for #2386's single-definition cases is correct (verified by |
Problem
withOptionsmutates aBeanDefinitionin place, then re-indexes from the mutated state — but never removes the entry registered under the previous coordinates. So:leaves both
Foo:a(stale) andFoo:binModule.mappings, pointing at the same factory —get<Foo>(named("a"))still resolves even though the definition's qualifier is nowb. WithsecondaryTypesit gets worse: secondaries are indexed only under the new qualifier, soFoois reachable via old+new butBaronly via new (asymmetry). Fixes #2386.Fix
Snapshot the previous
qualifier+secondaryTypesbefore applying the options; when either changes, drop the stalemappingsentries (old primary + old secondaries under the old qualifier) before re-indexing with the new coordinates:No-op when nothing index-relevant changed.
Behavioral note (resolution semantics)
A definition is no longer reachable under a qualifier it had before
withOptionschanged it — this removes unintended/undocumented reachability (the dual-index). Resolution by the definition's current qualifier is unchanged.Tests
WithOptionsStaleIndexTest(commonTest, RED→GREEN): qualifier change drops the stale primary index; primary + secondary reachability stay consistent.NewDSLTest: corrected threemappings.sizeexpectations that were counting the stale entry (3→2, 3→2, 4→3) — they encoded the bug.Verification
:core:koin-core:jvmTestgreen; wasmJs green except the documented pre-existingcreatedAtStartreds; native validated via JVM+wasmJs (native run hits the known pre-existingServiceMessagesParserbacktick-reporter crash, unrelated)../gradlew apiCheck— pass (no public API change;mappingsis@KoinInternalApi).🤖 Generated with Claude Code