fix(tvix/eval): consider let ... inherit ...
in dynamic scopes
In conditions where no dynamic identifiers exist in a scope, inheriting is usually a no-op - *unless* the identifier is not statically known and the scope has a non-empty `with`-stack. Change-Id: Iff4138d9cd4c56e844bc574203708dacc11c3f73 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6264 Reviewed-by: sterni <sternenseemann@systemli.org> Tested-by: BuildkiteCI
This commit is contained in:
parent
c3b13416b0
commit
2023b8e33f
3 changed files with 40 additions and 3 deletions
|
@ -667,13 +667,34 @@ impl Compiler {
|
||||||
for inherit in node.inherits() {
|
for inherit in node.inherits() {
|
||||||
match inherit.from() {
|
match inherit.from() {
|
||||||
// Within a `let` binding, inheriting from the outer
|
// Within a `let` binding, inheriting from the outer
|
||||||
// scope is practically a no-op.
|
// scope is a no-op *if* the identifier can be
|
||||||
None => {
|
// statically resolved.
|
||||||
|
None if self.scope().with_stack.is_empty() => {
|
||||||
self.emit_warning(inherit.syntax().clone(), WarningKind::UselessInherit);
|
self.emit_warning(inherit.syntax().clone(), WarningKind::UselessInherit);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
None => {
|
||||||
|
for ident in inherit.idents() {
|
||||||
|
// If the identifier resolves statically, it
|
||||||
|
// has precedence over dynamic bindings, and
|
||||||
|
// the inherit is useless.
|
||||||
|
if self
|
||||||
|
.resolve_local(ident.ident_token().unwrap().text())
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
self.emit_warning(ident.syntax().clone(), WarningKind::UselessInherit);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.compile_ident(ident.clone());
|
||||||
|
self.declare_local(
|
||||||
|
ident.syntax().clone(),
|
||||||
|
ident.ident_token().unwrap().text(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Some(from) => {
|
Some(from) => {
|
||||||
for ident in inherit.idents() {
|
for ident in inherit.idents() {
|
||||||
self.compile(from.expr().unwrap());
|
self.compile(from.expr().unwrap());
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
1
|
|
@ -0,0 +1,15 @@
|
||||||
|
# Normally using an `inherit` without a source attribute set within a
|
||||||
|
# `let` is a no-op, *unless* there is a with in-scope that might
|
||||||
|
# provide the value.
|
||||||
|
|
||||||
|
# Provide a dynamic `x` identifier in the scope.
|
||||||
|
with ({ x = 1;});
|
||||||
|
|
||||||
|
# inherit this `x` as a static identifier
|
||||||
|
let inherit x;
|
||||||
|
|
||||||
|
# Provide another dynamic `x` identifier
|
||||||
|
in with ({ x = 3; });
|
||||||
|
|
||||||
|
# Inherited static identifier should have precedence
|
||||||
|
x
|
Loading…
Reference in a new issue