feat(stash): alias storage + name resolution for *Dst:: = *Src::#543
Closed
fglock wants to merge 2 commits intofix/sub-name-b-gv-introspectionfrom
Closed
feat(stash): alias storage + name resolution for *Dst:: = *Src::#543fglock wants to merge 2 commits intofix/sub-name-b-gv-introspectionfrom
fglock wants to merge 2 commits intofix/sub-name-b-gv-introspectionfrom
Conversation
Documents the architecture, fix strategy, and staged implementation plan for making typeglob-to-stash assignment unify the target's namespace with the source's, as Perl 5 does. Referenced from the PR body of this same branch; keeping it co-located with the Sub::Name fix commit for context. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Implements Commits 1-3 of dev/prompts/stash-aliasing-plan.md:
1. Infrastructure in GlobalVariable:
- resolveAliasedFqn(fqn): resolves the pkg prefix of an FQN through
stashAliases. Fast path when the alias map is empty (no hashing,
no substring).
- resolvedStashAliasCache: memoised transitive resolution with cycle
cap. Invalidated on setStashAlias/clearStashAlias/resetAllGlobals.
Returns the input String identity for non-aliased packages so
callers can fast-path with `==`.
2. Hash storage unification in RuntimeGlob.set(RuntimeGlob):
When both names end with "::", also put the source's RuntimeStash
into globalHashes under the destination key. This makes
`\%Dst:: == \%Src::` true and `*Dst::{HASH} == *Src::{HASH}` true,
matching Perl 5.
3. Route NameNormalizer.normalizeVariableName through resolveAliasedFqn:
Applied after the existing normalisation cache so cached entries
still participate in alias resolution. Covers symbolic refs,
runtime-compiled subs (`sub Dst::foo {}` via eval), and qualified
variable references.
4. Fix caller()-style package/name splitting in SubroutineParser:
The placeholder.subName was previously set from the raw `subName`
parameter, which may contain "::" (e.g. parsing `sub Dst::foo {}`
arrives with subName="Dst::foo"). Combined with resolveAliasedFqn
rewriting the full name to "Src::foo", this produced `code.subName
= "Dst::foo"` and `code.packageName = "Src"` and caller() reported
"Src::Dst::foo". Derive both halves from the resolved fullName
instead.
Unit test added: src/test/resources/unit/stash_aliasing.t — covers
hash identity, sub installation through alias, caller() name,
symbolic refs, and chained aliases.
Impact on Sub-Name-0.28 t/exotic_names.t (stacked on #541):
- Before #541: 0/1558 pass
- After #541: 1038/1560 pass
- With this PR: 1168/1560 pass (+130)
Remaining 392 failures are all in the "natively compiled sub" subtest
which uses GV-level aliasing:
*palatable:: = *{"aliased::native::${pkg}::"};
${"palatable::"}{"sub"} = ${"palatable::"}{$encoded_sub};
That second line stores a GV named $encoded_sub under the hash key
"sub", so `sub palatable::sub{}` should install under the
$encoded_sub name. Supporting this requires first-class GV objects
with their own `name` field independent of the stash slot, which is
a larger architectural change tracked separately.
Verification:
- make: all unit tests pass (including new stash_aliasing.t)
- perl5_t/t/op/stash.t + perl5_t/t/uni/stash.t: 75/105, unchanged
- Sub-Name-0.28 t/exotic_names.t: 0 -> 1168/1560 cumulative
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
299848a to
b195dee
Compare
Owner
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements Commits 1–3 of
dev/prompts/stash-aliasing-plan.mdto make*Dst:: = *Src::;actually alias the namespaces, matching Perl 5 semantics.What now works
Changes
GlobalVariableinfrastructure. NewresolveAliasedFqn(fqn)plus a memoised transitive-resolution cacheresolvedStashAliasCachewith cycle cap. Fast path whenstashAliases.isEmpty(); non-alias hits return the input string identity so callers can skip the substring+concat via==. Invalidated on everysetStashAlias/clearStashAlias/resetAllGlobals.Hash unification in
RuntimeGlob.set(RuntimeGlob). When both glob names end with::, alsoglobalHashes.put(this.globName, getGlobalHash(value.globName))so the two stash-view hashes share storage.NameNormalizer.normalizeVariableNameappliesresolveAliasedFqnafter the existing cache, covering symbolic refs,eval "sub Dst::foo {}", and${"Dst::var"}.SubroutineParserpackage/name split bugfix.placeholder.subNamewas being set from the raw parser token (may contain::, e.g."Dst::foo"), whilepackageNamewas derived from the alias-resolvedfullName.caller()then concatenated toSrc::Dst::foo. Now both halves are derived from the resolvedfullName.Caching strategy
resolveAliasedFqnis on the hot path for every global symbol access. Two layers protect it:if (stashAliases.isEmpty()) return fqn;— O(1) for programs that never use stash aliasing (i.e. almost all programs)."Pkg::"maps inresolvedStashAliasCacheto its terminal target. Chains collapsed once, reused forever (until a mutation clears the cache). Non-aliased packages map to their own string instance so the caller uses reference equality to shortcut the concat.Test Impact
Sub-Name-0.28 t/exotic_names.t(the test that surfaced this): 1038 → 1168 passing (out of 1560) cumulative since fix: Sub::Name B::GV introspection + stash aliasing for *Dst:: = *Src:: #541.${"palatable::"}{"sub"} = ${"palatable::"}{$encoded_sub}) — requires GVs with their ownnamefield independent of the stash slot; deeper refactor, tracked in the plan doc.perl5_t/t/op/stash.t+perl5_t/t/uni/stash.t: 75/105 → 75/105 — no regression.makeunit tests: all pass, including a newsrc/test/resources/unit/stash_aliasing.tcovering hash identity, sub installation through alias, caller() reporting, symbolic refs, and chained aliases.Test plan
make(unit tests)src/test/resources/unit/stash_aliasing.t— 5 subtests, all passperl dev/tools/perl_test_runner.pl perl5_t/t/op/stash.t perl5_t/t/uni/stash.t— 75/105, unchangedjcpan -t Sub::Name— exotic_names.t 1038→1168 passingGenerated with Devin