Skip to content

Commit 1eb295c

Browse files
cclergetmvdan
authored andcommitted
interp: fix variables scope in functions
Variables declared as exported or readonly in functions without assignment are not correctly propagated to the global scope, this snippet should return a `bar: readonly variable` error: ``` _foo() { bar=foo readonly bar } _foo bar=bar ``` This snippet should also export `bar` variable correctly: ``` _foo() { export bar } _foo bar=foo env | grep ^bar= ```
1 parent 308418e commit 1eb295c

File tree

2 files changed

+27
-1
lines changed

2 files changed

+27
-1
lines changed

interp/interp_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2303,6 +2303,10 @@ set +o pipefail
23032303
{"export foo=(1 2); $ENV_PROG | grep '^foo='", "exit status 1"},
23042304
{"declare -A foo=([a]=b); export foo; $ENV_PROG | grep '^foo='", "exit status 1"},
23052305
{"export foo=(b c); foo=x; $ENV_PROG | grep '^foo='", "exit status 1"},
2306+
{"foo() { bar=foo; export bar; }; foo; $ENV_PROG | grep ^bar=", "bar=foo\n"},
2307+
{"foo() { export bar; }; bar=foo; foo; $ENV_PROG | grep ^bar=", "bar=foo\n"},
2308+
{"foo() { export bar; }; foo; bar=foo; $ENV_PROG | grep ^bar=", "bar=foo\n"},
2309+
{"foo() { export bar=foo; }; foo; readonly bar; $ENV_PROG | grep ^bar=", "bar=foo\n"},
23062310

23072311
// local
23082312
{
@@ -2430,6 +2434,18 @@ set +o pipefail
24302434
"readonly foo=bar; foo=etc",
24312435
"foo: readonly variable\nexit status 1 #JUSTERR",
24322436
},
2437+
{
2438+
"foo() { bar=foo; readonly bar; }; foo; bar=bar",
2439+
"bar: readonly variable\nexit status 1 #JUSTERR",
2440+
},
2441+
{
2442+
"foo() { readonly bar; }; foo; bar=foo",
2443+
"bar: readonly variable\nexit status 1 #JUSTERR",
2444+
},
2445+
{
2446+
"foo() { readonly bar=foo; }; foo; export bar; $ENV_PROG | grep '^bar='",
2447+
"bar=foo\n",
2448+
},
24332449

24342450
// multiple var modes at once
24352451
{

interp/vars.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,14 @@ func (o *overlayEnviron) Get(name string) expand.Variable {
3333
func (o *overlayEnviron) Set(name string, vr expand.Variable) error {
3434
// "foo=bar" in a function updates the global scope, unless the variable
3535
// has been declared as local.
36-
if o.funcScope && vr.IsSet() && !vr.Local && !o.values[name].Local {
36+
if o.funcScope && !vr.Local && !o.values[name].Local {
37+
// "foo=bar" followed by "export foo" or "readonly foo"
38+
if !vr.IsSet() {
39+
prev := o.Get(name)
40+
prev.Exported = prev.Exported || vr.Exported
41+
prev.ReadOnly = prev.ReadOnly || vr.ReadOnly
42+
vr = prev
43+
}
3744
return o.parent.(expand.WriteEnviron).Set(name, vr)
3845
}
3946

@@ -64,6 +71,9 @@ func (o *overlayEnviron) Set(name string, vr expand.Variable) error {
6471
writeEnv.Set(name, vr)
6572
return nil
6673
}
74+
} else if prev.Exported {
75+
// variable is set and was marked as exported
76+
vr.Exported = true
6777
}
6878
// modifying the entire variable
6979
vr.Local = prev.Local || vr.Local

0 commit comments

Comments
 (0)