Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

[PATCH] Drop some reference specific code from typeset



(this is the patch I mentioned in workers/55027)

The function bin_typeset contains code that runs only for references that is more harmful than helpful. The patch below removes all of it.

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:

Drop some reference specific code from typeset

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