scope: add inherits_from() to treat inherit clauses specially

This commit is contained in:
Astro 2021-12-08 17:50:41 +01:00
parent 236876b13f
commit 96a06966bc
3 changed files with 42 additions and 0 deletions

View File

@ -159,6 +159,12 @@ fn rec_attrset_shadowed() {
assert_eq!(results[0].binding.name.as_str(), "dead");
}
#[test]
fn let_inherit_in_let_inherit_alive() {
let results = run("let alive = true; in let inherit alive; in alive");
assert_eq!(0, results.len());
}
#[test]
fn let_inherit_in_rec_attrset_alive() {
let results = run("let alive = true; in rec { inherit alive; }");

View File

@ -218,4 +218,36 @@ impl Scope {
),
}
}
/// Check the `inherit (var) ...` and `inherit vars` clauses for a
/// given `name`.
///
/// Although a scope may shadow existing variable bindings, it can
/// `inherit` bindings from the outer scope.
pub fn inherits_from(&self, name: &Ident) -> bool {
match self {
Scope::LambdaPattern(_, _) | Scope::LambdaArg(_, _) =>
false,
Scope::LetIn(let_in) =>
let_in.inherits().any(|inherit|
inherit.from()
.map(|from|
crate::usage::find_usage(name, from.node().clone())
).unwrap_or_else(||
crate::usage::find_usage(name, inherit.node().clone())
)
),
Scope::RecAttrSet(attr_set) =>
attr_set.inherits().any(|inherit|
inherit.from()
.map(|from|
crate::usage::find_usage(name, from.node().clone())
).unwrap_or_else(||
crate::usage::find_usage(name, inherit.node().clone())
)
),
}
}
}

View File

@ -13,6 +13,10 @@ use crate::scope::Scope;
/// find out if `name` is used in `node`
pub fn find_usage(name: &Ident, node: SyntaxNode<NixLanguage>) -> bool {
if let Some(scope) = Scope::new(&node) {
if scope.inherits_from(name) {
return true;
}
for binding in scope.bindings() {
if binding.name.as_str() == name.as_str() {
// shadowed by a a new child scope that redefines the