refactor(tvix/eval): refactor locals to use an enum for phantoms

Instead of using sentinel values and an additional bool, this tracks
the identifier of a local as an enum that is either a statically known
name, or a phantom.

To make this work correctly some more locals related logic has been
encapsulated in the `scope` module, which is a good thing (that's the
goal).

Phantom values are now not initialised by default, but the only
current call site of phantoms (`with` expression compilation) performs
the initialisation right away.

This commit changes no actual functionality right now, but paves the
way for fixing an issue related to `let` bodies.

Change-Id: I679f93a59a4daeacfe40f4012263cfb7bc05034e
Reviewed-on: https://cl.tvl.fyi/c/depot/+/6421
Reviewed-by: sterni <sternenseemann@systemli.org>
Tested-by: BuildkiteCI
This commit is contained in:
Vincent Ambo 2022-09-03 00:26:32 +03:00 committed by tazjin
parent 7bc6e5984d
commit 9973ddfcba
2 changed files with 48 additions and 22 deletions

View file

@ -29,7 +29,7 @@ use crate::opcode::{CodeIdx, Count, JumpOffset, OpCode, UpvalueIdx};
use crate::value::{Closure, Lambda, Thunk, Value};
use crate::warnings::{EvalWarning, WarningKind};
use self::scope::{Local, LocalIdx, LocalPosition, Scope, Upvalue, UpvalueKind};
use self::scope::{LocalIdx, LocalPosition, Scope, Upvalue, UpvalueKind};
/// Represents the result of compiling a piece of Nix code. If
/// compilation was successful, the resulting bytecode can be passed
@ -842,7 +842,14 @@ impl Compiler<'_> {
self.emit_force(&node.namespace().unwrap());
let span = self.span_for(&node.namespace().unwrap());
// The attribute set from which `with` inherits values
// occupies a slot on the stack, but this stack slot is not
// directly accessible. As it must be accounted for to
// calculate correct offsets, what we call a "phantom" local
// is declared here.
let local_idx = self.scope_mut().declare_phantom(span);
self.scope_mut().mark_initialised(local_idx);
let with_idx = self.scope().stack_index(local_idx);
self.scope_mut().push_with();
@ -1058,12 +1065,9 @@ impl Compiler<'_> {
// While removing the local, analyse whether it has been
// accessed while it existed and emit a warning to the
// user otherwise.
if let Some(Local {
span, used, name, ..
}) = self.scope_mut().locals.pop()
{
if !used && !name.starts_with('_') {
self.emit_warning(span, WarningKind::UnusedBinding);
if let Some(local) = self.scope_mut().locals.pop() {
if !local.used && !local.is_ignored() {
self.emit_warning(local.span, WarningKind::UnusedBinding);
}
}
}
@ -1106,7 +1110,7 @@ impl Compiler<'_> {
let mut shadowed = false;
for other in self.scope().locals.iter().rev() {
if other.name == name && other.depth == depth {
if other.has_name(&name) && other.depth == depth {
shadowed = true;
break;
}