Skip to content

Commit c246ad3

Browse files
authored
fix(interpreter): resolve namerefs in parameter expansion for assoc array subscripts (#869)
`resolve_param_expansion_name` didn't resolve namerefs before looking up array names for subscript access and bulk operations (`[@]`, `[*]`). This caused `${ref[key]:-default}` and `${ref[key]:+alt}` to always treat the value as unset when `ref` was a nameref to an associative array. ## Changes - Resolve namerefs for `arr_name` in the `[@]`/`[*]` bulk access path - Resolve namerefs for `arr_name` in the individual `[key]` subscript path - Add 4 spec tests covering `:-`, `:+`, and `[@]:-` through namerefs ## Test plan - [x] 4 new spec tests in `nameref.test.sh` (3 were failing before fix, all pass after) - [x] All 1814 bash spec tests pass (0 failures, 23 skips) - [x] Full harness compatibility suite: 98/98 pass - [x] Issue #801 test cases: 16/16 pass - [x] `cargo clippy --all-features -- -D warnings` clean - [x] `cargo fmt --check` clean Closes #801
1 parent db454e5 commit c246ad3

File tree

2 files changed

+62
-4
lines changed

2 files changed

+62
-4
lines changed

crates/bashkit/src/interpreter/mod.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6312,20 +6312,22 @@ impl Interpreter {
63126312
.strip_suffix("[@]")
63136313
.or_else(|| name.strip_suffix("[*]"))
63146314
{
6315+
// Resolve nameref: if arr_name is a nameref, follow it to the target
6316+
let resolved_arr_name = self.resolve_nameref(arr_name);
63156317
let sep = if is_star {
63166318
self.get_ifs_separator()
63176319
} else {
63186320
" ".to_string()
63196321
};
6320-
if let Some(arr) = self.assoc_arrays.get(arr_name) {
6322+
if let Some(arr) = self.assoc_arrays.get(resolved_arr_name) {
63216323
let is_set = !arr.is_empty();
63226324
let mut keys: Vec<_> = arr.keys().collect();
63236325
keys.sort();
63246326
let values: Vec<String> =
63256327
keys.iter().filter_map(|k| arr.get(*k).cloned()).collect();
63266328
return (is_set, values.join(&sep));
63276329
}
6328-
if let Some(arr) = self.arrays.get(arr_name) {
6330+
if let Some(arr) = self.arrays.get(resolved_arr_name) {
63296331
let is_set = !arr.is_empty();
63306332
let mut indices: Vec<_> = arr.keys().collect();
63316333
indices.sort();
@@ -6343,15 +6345,17 @@ impl Interpreter {
63436345
&& name.ends_with(']')
63446346
{
63456347
let arr_name = &name[..bracket];
6348+
// Resolve nameref: if arr_name is a nameref, follow it to the target
6349+
let resolved_arr_name = self.resolve_nameref(arr_name);
63466350
let key = &name[bracket + 1..name.len() - 1];
6347-
if let Some(arr) = self.assoc_arrays.get(arr_name) {
6351+
if let Some(arr) = self.assoc_arrays.get(resolved_arr_name) {
63486352
let expanded_key = self.expand_variable_or_literal(key);
63496353
return match arr.get(&expanded_key) {
63506354
Some(v) => (true, v.clone()),
63516355
None => (false, String::new()),
63526356
};
63536357
}
6354-
if let Some(arr) = self.arrays.get(arr_name)
6358+
if let Some(arr) = self.arrays.get(resolved_arr_name)
63556359
&& let Ok(idx) = key.parse::<usize>()
63566360
{
63576361
return match arr.get(&idx) {

crates/bashkit/tests/spec_cases/bash/nameref.test.sh

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,3 +264,57 @@ echo "$result"
264264
### expect
265265
computed
266266
### end
267+
268+
### nameref_assoc_default_value
269+
# ${ref[key]:-default} through nameref to assoc array (issue #801)
270+
declare -A m=([x]=1 [y]=2)
271+
f() {
272+
local -n ref="$1"
273+
echo "${ref[x]:-EMPTY}"
274+
echo "${ref[y]:-EMPTY}"
275+
echo "${ref[z]:-EMPTY}"
276+
}
277+
f m
278+
### expect
279+
1
280+
2
281+
EMPTY
282+
### end
283+
284+
### nameref_assoc_replacement
285+
# ${ref[key]:+alt} through nameref to assoc array
286+
declare -A m=([a]=val)
287+
f() {
288+
local -n ref="$1"
289+
echo "${ref[a]:+found}"
290+
echo "${ref[missing]:+found}"
291+
}
292+
f m
293+
### expect
294+
found
295+
296+
### end
297+
298+
### nameref_assoc_subscript_at_default
299+
# ${ref[@]:-default} through nameref to assoc array
300+
declare -A m=([k]=v)
301+
f() {
302+
local -n ref="$1"
303+
echo "${ref[@]:-EMPTY}"
304+
}
305+
f m
306+
### expect
307+
v
308+
### end
309+
310+
### nameref_assoc_subscript_at_empty
311+
# ${ref[@]:-default} through nameref to empty assoc array
312+
declare -A m
313+
f() {
314+
local -n ref="$1"
315+
echo "${ref[@]:-EMPTY}"
316+
}
317+
f m
318+
### expect
319+
EMPTY
320+
### end

0 commit comments

Comments
 (0)