Make 'set -ql' search up to function scope

Previously 'set -ql' would only look for variables in the
immediate local scope. This was not very useful. It's also
arguably surprising, since a 'set -l' in a function, followed
by a 'set -ql' in a child block, would fail. There was also no
way to check for a function-scoped variable, since omitting the
scope would also pull in global variables.

We could revisit this and introduce an explicit function scope.

Fixes #2502
This commit is contained in:
ridiculousfish 2015-10-23 15:15:39 -07:00
parent 036a29acf5
commit d5f3a09ce9
3 changed files with 31 additions and 19 deletions

View File

@ -93,7 +93,8 @@ struct env_node_t
const var_entry_t *find_entry(const wcstring &key);
/* Returns the next scope to search in order, respecting the new_scope flag, or NULL if we're done. */
env_node_t *next_scope_to_search(void);
env_node_t *next_scope_to_search();
const env_node_t *next_scope_to_search() const;
};
class variable_entry_t
@ -195,11 +196,17 @@ const var_entry_t *env_node_t::find_entry(const wcstring &key)
return result;
}
env_node_t *env_node_t::next_scope_to_search(void)
env_node_t *env_node_t::next_scope_to_search()
{
return this->new_scope ? global_env : this->next;
}
const env_node_t *env_node_t::next_scope_to_search() const
{
return this->new_scope ? global_env : this->next;
}
/**
Return the current umask value.
*/
@ -1010,8 +1017,6 @@ env_var_t env_get_string(const wcstring &key, env_mode_flags_t mode)
bool env_exist(const wchar_t *key, env_mode_flags_t mode)
{
env_node_t *env;
CHECK(key, false);
const bool has_scope = mode & (ENV_LOCAL | ENV_GLOBAL | ENV_UNIVERSAL);
@ -1037,27 +1042,21 @@ bool env_exist(const wchar_t *key, env_mode_flags_t mode)
if (test_local || test_global)
{
env = test_local ? top : global_env;
while (env)
const env_node_t *env = test_local ? top : global_env;
while (env != NULL)
{
var_table_t::iterator result = env->env.find(key);
if (env == global_env && ! test_global)
{
break;
}
var_table_t::const_iterator result = env->env.find(key);
if (result != env->env.end())
{
const var_entry_t &res = result->second;
return res.exportv ? test_exported : test_unexported;
}
if (has_scope)
{
if (!test_global || env == global_env) break;
env = global_env;
}
else
{
env = env->next_scope_to_search();
}
env = env->next_scope_to_search();
}
}

View File

@ -177,3 +177,14 @@ true ; set -NOT_AN_OPTION 2> /dev/null ; echo 9 $status # no passthrough
false ; set foo (echo A; true) ; echo 10 $status $foo
true ; set foo (echo B; false) ; echo 11 $status $foo
true
echo "Verify set -ql behavior" # see 2502
function setql_check
set -l setql_foo val
if set -ql setql_foo
echo Pass
else
echo Fail
end
end
setql_check

View File

@ -34,3 +34,5 @@ Verify that set passes through exit status, except when passed -n or -q or -e
9 1
10 0 A
11 1 B
Verify set -ql behavior
Pass