Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
[PATCH] Drop some reference specific code from typeset
- X-seq: zsh-workers 55032
- From: Philippe Altherr <philippe.altherr@xxxxxxxxx>
- To: Zsh hackers list <zsh-workers@xxxxxxx>
- Subject: [PATCH] Drop some reference specific code from typeset
- Date: Sat, 25 Jul 2026 15:46:02 +0200
- Arc-authentication-results: i=1; mx.google.com; arc=none
- Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20260327; h=to:subject:message-id:date:from:mime-version:dkim-signature; bh=NlwGEtJdgALX+PCOOMgCWIYLGUf5yCAQEnPNtksmsmw=; fh=BgAYDYpL6Ne/A5nWEMVJiHiBtrz8Imz3uf26RDwgQX4=; b=GwexXcZ9UkkKjeceoZnuWWuH0oFfL4nWCwcNaXz6+b9b5JsG16M+595yMmMgGt+b9I OoiMMVm29BUhJqHTGNoy4al7LYUBMmOEpWuDbHVYEEI4iF4wYH375TkE42DRMSS4IfV3 CMiuwOVeQLtGuPYgH/1e6C0GOU+GuAeZjcxxHGA/EcTMGBxn8Sss0z1E6utMjgtN9jw+ GJx/T8smcOSvy5q1bQwV/gHD+4kicn/s47aKAFwS8GVRBn8KdYsxXfNIYuemm74OGJux XEgK4j5XABzf813pbvl29pmOBm4oNyEKnqDsWG3qoTCetwYfxjJkDqJwB0RwFW3vmN4d Qddw==; darn=zsh.org
- Arc-seal: i=1; a=rsa-sha256; t=1784987175; cv=none; d=google.com; s=arc-20260327; b=j62nRjukTDn44/RVOkHSeKW3BwlzhO2tNNYTe4+DPbE+EA7cypQxo7hCyC7WqK1jeg Cjuxkh4zV06Q6j1ikklhZwwfWmZrqWLLCx7PpjM+k3ah9wjOGOtfs8O/HOcLWqX4fkDc 4r2lhYf3NAQOSZx657fba7Y+0sFJG9Yi+6tKiC89mPzYq2Md1x376g4jSgy8pGQi2aOu 2Wc+Zh/rAlrYUJaMFbJpF8qxXBmWUb63rOQy6Pwjnr3UuLStGhFvvDcdjkqBGgicw1m8 9k/o8wAmp5scJYHz9vYdQ5A3HeGiWubw2lxdFY86qAJJPAO6rYn58hzebQaYr1SEZWTR e9MQ==
- Archived-at: <https://zsh.org/workers/55032>
- List-id: <zsh-workers.zsh.org>
(this is the patch I mentioned in
workers/55027)
The
first part prevents the creation of references to placeholder references that are flagged with PM_SPECIAL. That restriction makes no sense to me.
There are no predefined special references. The only predefined references are in the ksh93 module and none are flagged as special. It turns out that private parameters are flagged with PM_SPECIAL. Thus, "() { private -n ref1; typeset -n ref2=ref1 }" fails because of this restriction
. However, the restriction is easily worked around by replacing "typeset -n ref2=ref1" with "typeset -n ref2; ref2=ref1". The definition of "ref2" is also happily accepted if "ref1" is already initialized. I fail to see what's the point of the restriction. Once removed, references to private references work as expected when accessed from within the same scope as the private reference. They don't work when accessed from a nested scope (expansions return an empty string and assignments fail with an error), which I think is what is expected given that private parameters are only visible and usable from within their scope.
The
second part unsets under some conditions any existing parameter with the same name as the parameter being defined. This has the consequence that for reference definitions, single_typeset is called with pm=NULL, which is different from what happens with all other types of parameters in the same conditions. This is why "typeset -n" fails to detect that an autoloaded or special parameter is being erased or hidden. It's also why "typeset -n -r ref=foo; typeset -n +r ref=bar" fails to update "ref" and instead assigns "foo" with "bar".
The patch also fixes four assignments to usepm that could inadvertently set it to 2, which has a special meaning.
There are only two existing tests (in V10private.zest) affected by the removal of the first part. The other changes in V10private.zest are cleanups and additions.
There is only one existing test (in K01nameref.ztst) affected by the removal of the second part (because of the "typeset -n -r ref=foo; typeset -n +r ref=bar" issue). The tests affected in B02typeset.zest are new ones added in this patch to the issues described above.
For more details, I highly recommend looking at the successive steps on GitHub:
Philippe
diff --git a/Src/builtin.c b/Src/builtin.c
index 2e3e5752a..7b88f6c2f 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -2104,22 +2104,22 @@ typeset_single(char *cname, char *pname, Param pm, int func,
}
tc = 1;
if (OPT_MINUS(ops,'p'))
- usepm = (on & pm->node.flags);
+ usepm = !!(on & pm->node.flags);
else if (OPT_PLUS(ops,'p'))
- usepm = (off & pm->node.flags);
+ usepm = !!(off & pm->node.flags);
else
usepm = 0;
}
else if (usepm || newspecial != NS_NONE) {
int chflags = ((off & pm->node.flags) | (on & ~pm->node.flags)) &
(PM_INTEGER|PM_EFLOAT|PM_FFLOAT|PM_HASHED|
- PM_ARRAY|PM_TIED|PM_AUTOLOAD);
+ PM_ARRAY|PM_NAMEREF|PM_TIED|PM_AUTOLOAD);
/* keep the parameter if just switching between floating types */
if ((tc = chflags && chflags != (PM_EFLOAT|PM_FFLOAT))) {
if (OPT_MINUS(ops,'p'))
- usepm = (on & pm->node.flags);
+ usepm = !!(on & pm->node.flags);
else if (OPT_PLUS(ops,'p'))
- usepm = (off & pm->node.flags);
+ usepm = !!(off & pm->node.flags);
else
usepm = 0;
}
@@ -2220,6 +2220,7 @@ typeset_single(char *cname, char *pname, Param pm, int func,
* ii. we are creating a new local parameter
*/
if (usepm) {
+ int flags = (on & PM_NAMEREF) ? ASSPM_NONAMEREF : 0;
if (OPT_MINUS(ops,'p') && on &&
!((on & pm->node.flags) || ((on & PM_LOCAL) && pm->level)))
return NULL;
@@ -2314,10 +2315,10 @@ typeset_single(char *cname, char *pname, Param pm, int func,
DPUTS(!tdp, "BUG: no join character to update");
}
if (asg->value.scalar &&
- !(pm = assignsparam(pname, ztrdup(asg->value.scalar), 0)))
+ !(pm = assignsparam(pname, ztrdup(asg->value.scalar), flags)))
return NULL;
} else if (asg->flags & ASG_ARRAY) {
- int flags = (asg->flags & ASG_KEY_VALUE) ? ASSPM_KEY_VALUE : 0;
+ flags |= (asg->flags & ASG_KEY_VALUE) ? ASSPM_KEY_VALUE : 0;
if (!(pm = assignaparam(pname, asg->value.array ?
zlinklist2array(asg->value.array, 1) :
mkarray(NULL), flags)))
@@ -2348,6 +2349,9 @@ typeset_single(char *cname, char *pname, Param pm, int func,
on |= ~off & (PM_READONLY|PM_EXPORTED) & pm->node.flags;
/* ...but turn off existing readonly so we can delete it */
pm->node.flags &= ~PM_READONLY;
+ /* Hack to force getsparam below to use the reference's own value */
+ if (off & PM_NAMEREF)
+ pm->node.flags &= ~PM_NAMEREF;
/*
* If we're just changing the type, we should keep the
* variable at the current level of localness.
@@ -2361,6 +2365,12 @@ typeset_single(char *cname, char *pname, Param pm, int func,
* implications.)
*/
if (!ASG_VALUEP(asg) && !((pm->node.flags|on) & (PM_ARRAY|PM_HASHED))) {
+ /*
+ * Relying on pname is fundamentally wrong. If the original pm was
+ * a reference, the resolved pname may refer to a hidden parameter.
+ * In that case, getsparam wrongly returns the value of the hiding
+ * parameter.
+ */
asg->value.scalar = dupstring(getsparam(pname));
asg->flags = 0;
}
@@ -3105,42 +3115,6 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func)
continue;
}
- if (on & PM_NAMEREF) {
- if (asg->value.scalar &&
- ((pm = (Param)paramtab->getnode(paramtab, asg->value.scalar)) &&
- (pm->node.flags & PM_NAMEREF))) {
- if (pm->node.flags & PM_SPECIAL) {
- zwarnnam(name, "%s: invalid reference", pm->node.nam);
- returnval = 1;
- continue;
- }
- }
- if (hn) {
- /* namerefs always start over fresh */
- if (((Param)hn)->level >= locallevel ||
- (!(on & PM_LOCAL) && ((Param)hn)->level < locallevel)) {
- Param oldpm = (Param)hn;
- if (!asg->value.scalar &&
- PM_TYPE(oldpm->node.flags) == PM_SCALAR &&
- oldpm->u.str)
- asg->value.scalar = dupstring(oldpm->u.str);
- /* Defer read-only error to typeset_single() */
- if (!(hn->flags & PM_READONLY)) {
- unsetparam_pm(oldpm, 0, 1);
- hn = NULL;
- }
- }
- /* Passing a NULL pm to typeset_single() makes the
- * nameref read-only before assignment, which breaks
- * typeset -rn ref=var
- * so this is special-cased to permit that action
- * like assign-at-create for other parameter types.
- */
- if (hn && !(hn->flags & PM_READONLY))
- hn = NULL;
- }
- }
-
if (!typeset_single(name, asg->name, (Param)hn,
func, on, off, roff, asg, NULL,
ops, 0))
diff --git a/Src/params.c b/Src/params.c
index 716dd66c3..1a4638b69 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -3143,6 +3143,7 @@ assignsparam(char *s, char *val, int flags)
size_t lvar;
mnumber lhs, rhs;
int sstart, created = 0;
+ int scanflags = flags & ASSPM_NONAMEREF ? SCANPM_NONAMEREF : 0;
if (!isident(s)) {
zerr("not an identifier: %s", s);
@@ -3153,7 +3154,7 @@ assignsparam(char *s, char *val, int flags)
queue_signals();
if ((ss = strchr(s, '['))) {
*ss = '\0';
- if (!(v = getvalue(&vbuf, &s, 1))) {
+ if (!(v = fetchvalue(&vbuf, &s, 1, scanflags))) {
createparam(t, PM_ARRAY);
created = 1;
} else {
@@ -3174,7 +3175,7 @@ assignsparam(char *s, char *val, int flags)
*ss = '[';
v = NULL;
} else {
- if (!(v = getvalue(&vbuf, &s, 1))) {
+ if (!(v = fetchvalue(&vbuf, &s, 1, scanflags))) {
createparam(t, PM_SCALAR);
created = 1;
} else if ((((v->pm->node.flags & PM_ARRAY) &&
@@ -3192,7 +3193,7 @@ assignsparam(char *s, char *val, int flags)
v = NULL;
}
}
- if (!v && !(v = getvalue(&vbuf, &t, 1))) {
+ if (!v && !(v = fetchvalue(&vbuf, &t, 1, scanflags))) {
zsfree(val);
unqueue_signals();
/* errflag |= ERRFLAG_ERROR; */
@@ -3305,6 +3306,7 @@ assignaparam(char *s, char **val, int flags)
char *ss;
int created = 0;
int may_warn_about_nested_vars = 1;
+ int scanflags = flags & ASSPM_NONAMEREF ? SCANPM_NONAMEREF : 0;
if (!isident(s)) {
zerr("not an identifier: %s", s);
@@ -3315,7 +3317,7 @@ assignaparam(char *s, char **val, int flags)
queue_signals();
if ((ss = strchr(s, '['))) {
*ss = '\0';
- if (!(v = getvalue(&vbuf, &s, 1))) {
+ if (!(v = fetchvalue(&vbuf, &s, 1, scanflags))) {
createparam(t, PM_ARRAY);
created = 1;
} else {
@@ -3332,7 +3334,7 @@ assignaparam(char *s, char **val, int flags)
}
v = NULL;
} else {
- if (!(v = fetchvalue(&vbuf, &s, 1, SCANPM_ASSIGNING))) {
+ if (!(v = fetchvalue(&vbuf, &s, 1, scanflags | SCANPM_ASSIGNING))) {
createparam(t, PM_ARRAY);
created = 1;
} else if (v->pm->node.flags & PM_NAMEREF) {
@@ -3363,7 +3365,7 @@ assignaparam(char *s, char **val, int flags)
}
}
if (!v)
- if (!(v = fetchvalue(&vbuf, &t, 1, SCANPM_ASSIGNING))) {
+ if (!(v = fetchvalue(&vbuf, &t, 1, scanflags | SCANPM_ASSIGNING))) {
unqueue_signals();
freearray(val);
/* errflag |= ERRFLAG_ERROR; */
diff --git a/Src/zsh.h b/Src/zsh.h
index 5a989ff47..d45403e0b 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -2141,7 +2141,9 @@ enum {
* This is normal for associative arrays but variant behaviour for
* normal arrays.
*/
- ASSPM_KEY_VALUE = 1 << 4
+ ASSPM_KEY_VALUE = 1 << 4,
+ /* Named references are not followed */
+ ASSPM_NONAMEREF = 1 << 5
};
/* node for named directory hash table (nameddirtab) */
diff --git a/Test/B02typeset.ztst b/Test/B02typeset.ztst
index fe9eb55eb..4c7864893 100644
--- a/Test/B02typeset.ztst
+++ b/Test/B02typeset.ztst
@@ -1194,6 +1194,99 @@ F:This is a bug, the non -h variable should not hide the autoload variable
>z=
>v=
+ zmodload -u zsh/random
+ () { { typeset -g -i SRANDOM 2>&1 } always { TRY_BLOCK_ERROR=0 } }
+ () { { typeset -g -a SRANDOM 2>&1 } always { TRY_BLOCK_ERROR=0 } }
+ () { { typeset -g -n SRANDOM 2>&1 } always { TRY_BLOCK_ERROR=0 } }
+ echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*}
+0:Global parameter can't change type of autoloaded parameter
+>(anon):typeset: SRANDOM: can't change type of autoloaded parameter
+>(anon):typeset: SRANDOM: can't change type of autoloaded parameter
+>(anon):typeset: SRANDOM: can't change type of autoloaded parameter
+>z=SRANDOM (zsh/random)
+
+ zmodload -u zsh/random
+ () { { typeset SRANDOM 2>&1 } always { TRY_BLOCK_ERROR=0 } }
+ () { { typeset -i SRANDOM 2>&1 } always { TRY_BLOCK_ERROR=0 } }
+ () { { typeset -a SRANDOM 2>&1 } always { TRY_BLOCK_ERROR=0 } }
+ () { { typeset -n SRANDOM 2>&1 } always { TRY_BLOCK_ERROR=0 } }
+ echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*}
+0:Local non -h parameter can hide autoloaded parameter
+>z=SRANDOM (zsh/random)
+
+ () { { typeset -g +i EUID 2>&1 } always { TRY_BLOCK_ERROR=0 } }
+ () { { typeset -g -i HOME 2>&1 } always { TRY_BLOCK_ERROR=0 } }
+ () { { typeset -g -a HOME 2>&1 } always { TRY_BLOCK_ERROR=0 } }
+ ( () { { typeset -g -n HOME 2>&1 } always { TRY_BLOCK_ERROR=0 } } )
+ typeset -p EUID HOME
+0q:Global parameter can't change type of special parameter
+>(anon):typeset: EUID: can't change type of a special parameter
+>(anon):typeset: HOME: can't change type of a special parameter
+>(anon):typeset: HOME: can't change type of a special parameter
+>(anon):typeset: HOME: can't change type of a special parameter
+>typeset -g -i10 EUID=$EUID
+>export HOME=$HOME
+
+ () { { typeset +i EUID 2>&1 } always { TRY_BLOCK_ERROR=0 } }
+ () { { typeset -i HOME 2>&1 } always { TRY_BLOCK_ERROR=0 } }
+ () { { typeset -a HOME 2>&1 } always { TRY_BLOCK_ERROR=0 } }
+ () { { typeset -n HOME 2>&1 } always { TRY_BLOCK_ERROR=0 } }
+ typeset -p EUID HOME
+0q:Local non -h parameter can't hide special parameter
+>(anon):typeset: EUID: can't change type of a special parameter
+>(anon):typeset: HOME: can't change type of a special parameter
+>(anon):typeset: HOME: can't change type of a special parameter
+>(anon):typeset: HOME: can't change type of a special parameter
+>typeset -g -i10 EUID=$EUID
+>export HOME=$HOME
+
+ () { typeset -h +i EUID 2>&1; typeset -p EUID }
+ () { typeset -h -i HOME 2>&1; typeset -p HOME }
+ () { typeset -h -a HOME 2>&1; typeset -p HOME }
+ () { typeset -h -n HOME 2>&1; typeset -p HOME }
+ typeset -p EUID HOME
+0q:Local -h parameter can hide special parameter
+>typeset -h EUID=''
+>typeset -ih HOME=0
+>typeset -ah HOME=( )
+F:BUG:"typeset -h -n HOME" should be allowed
+>(anon):typeset: -h not allowed with -n
+>export HOME=$HOME
+>typeset -g -i10 EUID=$EUID
+>export HOME=$HOME
+
+ check() {
+ echo "Testing \"local $1 $2=${3}<N>\""
+ { local $1 -r $2=${3}1 2>&1 && typeset -p $2 } always { TRY_BLOCK_ERROR=0 }
+ { local -r $2=${3}2 2>&1 && typeset -p $2 } always { TRY_BLOCK_ERROR=0 }
+ { local $1 $2=${3}3 2>&1 && typeset -p $2 } always { TRY_BLOCK_ERROR=0 }
+ { local $1 -r $2=${3}4 2>&1 && typeset -p $2 } always { TRY_BLOCK_ERROR=0 }
+ { local $1 +r $2=${3}5 2>&1 && typeset -p $2 } always { TRY_BLOCK_ERROR=0 }
+ }
+ check "" str s
+ check -i int 1
+ check -n ref v
+0:Non +r parameter definition can't change/replace readonly parameter
+>Testing "local str=s<N>"
+>typeset -r str=s1
+>check:3: read-only variable: str
+>check:4: read-only variable: str
+>check:5: read-only variable: str
+>typeset str=s5
+>Testing "local -i int=1<N>"
+>typeset -ir int=11
+>check:3: read-only variable: int
+>check:4: read-only variable: int
+>check:5: read-only variable: int
+>typeset -i int=15
+>Testing "local -n ref=v<N>"
+>typeset -rn ref=v1
+>typeset -rn ref=v1
+F:"typeset -r ref=v2" succeeds because it dereferences "ref" and assigns "v1" with "v2"
+>check:local:4: ref: read-only reference
+>check:local:5: ref: read-only reference
+>typeset -n ref=v5
+
() {
typeset -F f1=nan f2=inf f3=-inf
typeset -p f1 f2 f3
diff --git a/Test/K01nameref.ztst b/Test/K01nameref.ztst
index 5082d1011..77b1e1803 100644
--- a/Test/K01nameref.ztst
+++ b/Test/K01nameref.ztst
@@ -1107,32 +1107,30 @@ F:Checking for a bug in zmodload that affects later tests
unset -n ref
typeset -rn ref=RO
typeset -p ref
- (typeset -n ref=RW)
+ (typeset -n ref=RW 2>&1 && typeset -p ref)
print status: $? expected: 1
typeset +r -n ref
typeset -p ref
typeset -r +n ref
typeset -p ref
- (typeset -rn ref)
- print status: $? expected: 1
- typeset +r -n ref=RW # Assignment occurs after type change,
- typeset -p ref RO # so RO=RW here. Potentially confusing.
- typeset -r -n ref=RX # No type change, so referent changes ...
- typeset -p ref RO # ... and previous refererent does not.
- typeset +rn ref=RW # Here ref=RW, again type changed first.
+ (typeset -rn ref 2>&1 && typeset -p ref)
+ print status: $? expected: 0
+ typeset +r -n ref=RW
+ typeset -p ref
+ typeset -r -n ref=RX
+ typeset -p ref
+ typeset +rn ref=RW
typeset -p ref
0:add and remove readonly attribute with references
>typeset -rn ref=RO
-*?*: ref: read-only reference
+>(eval):typeset:4: ref: read-only reference
>status: 1 expected: 1
>typeset -n ref=RO
>typeset -r ref=RO
-*?*: ref: read-only variable
->status: 1 expected: 1
->typeset -n ref=RO
->typeset -g RO=RW
+>typeset -rn ref=RO
+>status: 0 expected: 0
+>typeset -n ref=RW
>typeset -rn ref=RX
->typeset -g RO=RW
>typeset ref=RW
() {
diff --git a/Test/V10private.ztst b/Test/V10private.ztst
index 256844be1..f3ad7b6b9 100644
--- a/Test/V10private.ztst
+++ b/Test/V10private.ztst
@@ -304,39 +304,44 @@ F:future revision will create a global with this assignment
typeset top=TOP
() {
local -P -n test=top
- print $top
+ print $test
+ test=top
+ print $test
() { print UP: $test }
}
+ print $top
0:nameref can be declared private
>TOP
+>top
>UP:
+>top
() {
typeset -a ary
local -P -n ref=ary
{
- (){
- ref=XX # Should be an error
- typeset -p ary ref
+ () {
+ ref=XX 2>&1 # Should be an error
+ echo NOT REACHED
}
} always {
TRY_BLOCK_ERROR=0
typeset -p ary ref
}
}
- typeset -p ary
+ typeset -p ary 2>&1
1:assignment to private nameref in wrong scope, part 1
+>(anon):1: ref: can't modify read-only parameter
>typeset -a ary
>typeset -hn ref=ary
-*?*ref: can't modify read-only parameter
-*?*no such variable: ary
+>(eval):typeset:14: no such variable: ary
() {
typeset -a ary
local -P -n ref=ary
{
(){
- typeset ref=XX # Should create a local
+ typeset ref=XX 2>&1 # Should create a local
typeset -p ary ref
}
} always {
@@ -344,53 +349,89 @@ F:future revision will create a global with this assignment
typeset -p ary ref
}
}
- typeset -p ary
+ typeset -p ary 2>&1
1:assignment to private nameref in wrong scope, part 2
>typeset -g -a ary
>typeset ref=XX
>typeset -a ary
>typeset -hn ref=ary
-*?*no such variable: ary
+>(eval):typeset:14: no such variable: ary
() {
+ typeset val=LOCAL
typeset -n ptr1=ptr2
private -n ptr2 # TYPESET_TO_UNSET makes this not a "placeholder"
typeset -p ptr1 ptr2
- typeset val=LOCAL
() {
- ptr1=val # Test dies here as ptr2 is private and unset
- typeset -n
- printf "%s=%s\n" ptr1 "$ptr1" ptr2 "$ptr2"
+ ptr1=val 2>&1 # Test dies here as ptr2 is private
+ echo NOT REACHED
}
- typeset -p ptr1 ptr2
+ echo NOT REACHED
}
- typeset -p ptr2
+ echo NOT REACHED
1:up-reference for private namerefs, end unset and not in scope
F:See K01nameref.ztst up-reference part 5
F:Here ptr1 finds private ptr2 by scope mismatch
>typeset -n ptr1=ptr2
>typeset -hn ptr2
-?(anon):1: read-only variable: ptr2
+>(anon):1: read-only variable: ptr2
() {
+ typeset val=LOCAL
typeset -n ptr1=ptr2
private -n ptr2= # Assignment makes this a placeholder, not unset
typeset -p ptr1 ptr2
+ () {
+ ptr1=val 2>&1 # Test dies here as ptr2 is private
+ echo NOT REACHED
+ }
+ echo NOT REACHED
+ }
+ echo NOT REACHED
+1:up-reference for private namerefs, end is placeholder and not in scope
+F:See K01nameref.ztst up-reference part 5
+F:Here ptr1 finds private ptr2 by scope mismatch
+>typeset -n ptr1=ptr2
+>typeset -hn ptr2=''
+>(anon):1: ptr1: can't modify read-only parameter
+
+ () {
typeset val=LOCAL
+ typeset -n ptr1=ptr2
+ private -n ptr2=val # Assignment makes this a reference to existing val
+ typeset -p ptr1 ptr2
() {
- ptr1=val # Test dies here as ptr2 is private and uninitialized
- typeset -n
- printf "%s=%s\n" ptr1 "$ptr1" ptr2 "$ptr2"
+ ptr1=val 2>&1 # Test dies here as ptr2 is private
+ echo NOT REACHED
}
+ echo NOT REACHED
+ }
+ echo NOT REACHED
+1:up-reference for private namerefs, end refers existing variable and not in scope
+F:See K01nameref.ztst up-reference part 5
+F:Here ptr1 finds private ptr2 by scope mismatch
+>typeset -n ptr1=ptr2
+>typeset -hn ptr2=val
+>(anon):1: ptr1: can't modify read-only parameter
+
+ () {
+ typeset val=LOCAL
+ typeset -n ptr1=ptr2
+ private -n ptr2=foo # Assignment makes this a reference to not-yet-defined foo
typeset -p ptr1 ptr2
+ () {
+ ptr1=val 2>&1 # Test dies here as ptr2 is private
+ echo NOT REACHED
+ }
+ echo NOT REACHED
}
- typeset -p ptr2
-1:up-reference for private namerefs, end not in scope
+ echo NOT REACHED
+1:up-reference for private namerefs, end refers not-yet-defined variable and not in scope
F:See K01nameref.ztst up-reference part 5
F:Here ptr1 finds private ptr2 by scope mismatch
>typeset -n ptr1=ptr2
->typeset -hn ptr2=''
-?(anon):1: ptr1: can't modify read-only parameter
+>typeset -hn ptr2=foo
+>(anon):1: ptr1: can't modify read-only parameter
typeset ptr2
() {
@@ -401,7 +442,7 @@ F:Here ptr1 finds private ptr2 by scope mismatch
() {
ptr1=val
typeset -n
- printf "%s=%s\n" ptr1 "$ptr1" ptr2 "$ptr2"
+ printf "print:%s=%s\n" ptr1 "$ptr1" ptr2 "$ptr2"
}
typeset -p ptr1 ptr2
}
@@ -413,24 +454,38 @@ F:Here ptr1 points to global ptr2 so assignment succeeds
>typeset -hn ptr2
>ptr1=ptr2
>ptr2=val
->ptr1=val
->ptr2=val
+>print:ptr1=val
+>print:ptr2=val
>typeset -n ptr1=ptr2
>typeset -hn ptr2
>typeset ptr2=val
+ () {
+ setopt localoptions errreturn
+ private -n ptr2=val
+ typeset -n ptr1=ptr2 2>&1
+ ptr1=foo
+ typeset -p ptr1 ptr2 val
+ }
+ unset val
+0:up-reference for private namerefs, end is set and in scope but private
+>typeset -n ptr1=ptr2
+>typeset -hn ptr2=val
+>typeset -g val=foo
+
() {
setopt localoptions errreturn
private -n ptr2
- typeset -n ptr1=ptr2
- echo NOT REACHED
+ typeset -n ptr1=ptr2 2>&1
+ ptr1=val
+ ptr1=foo
+ typeset -p ptr1 ptr2 val
}
- typeset -p ptr1 ptr2
-1:up-reference for private namerefs, end is in scope but private
-F:Should we allow "public" namerefs to private parameters?
-*?*ptr2: invalid reference
-*?*no such variable: ptr1
-*?*no such variable: ptr2
+ unset val
+0:up-reference for private namerefs, end is unset and in scope but private
+>typeset -n ptr1=ptr2
+>typeset -hn ptr2=val
+>typeset -g val=foo
() {
typeset ptr2=foo
@@ -438,13 +493,13 @@ F:Should we allow "public" namerefs to private parameters?
() {
setopt localoptions errreturn
private -n ptr2
- typeset -n ptr1=ptr2
- echo NOT REACHED
+ typeset -n ptr1=ptr2 2>&1
+ typeset -p ptr1 ptr2
}
}
-1:regression test for invalid reference detection
-F:Should we allow "public" namerefs to private parameters?
-*?*ptr2: invalid reference
+0:regression test for invalid reference detection
+>typeset -n ptr1=ptr2
+>typeset -hn ptr2
() {
private x=1
Messages sorted by:
Reverse Date,
Date,
Thread,
Author