feat(tvix/eval): add builtins to builtins
This is a somewhat terrifying hack that enables us to support `builtins.builtins`, by running a "fake compilation" inside of a suspended native thunk that can resolve the weak pointer to the globals. With this implementation, the thunk at `builtins.builtins` actually resolves to the "real" `builtins` (verified with a new test). This is kind of ugly, and it's something users shouldn't use, but bubbling a warning out of this is difficult at the moment due to a little bit of trickery with how the spans in suspended native thunks work (they don't) (see b/237, b/238) Change-Id: I67d0e93246dd5b279c960aeda00402031aa12af3 Reviewed-on: https://cl.tvl.fyi/c/depot/+/7748 Tested-by: BuildkiteCI Reviewed-by: flokli <flokli@flokli.de>
This commit is contained in:
parent
79e54f46ce
commit
b9646ab40c
3 changed files with 34 additions and 2 deletions
|
@ -28,7 +28,7 @@ use std::sync::Arc;
|
|||
|
||||
use crate::chunk::Chunk;
|
||||
use crate::errors::{Error, ErrorKind, EvalResult};
|
||||
use crate::observer::CompilerObserver;
|
||||
use crate::observer::{CompilerObserver, NoOpObserver};
|
||||
use crate::opcode::{CodeIdx, Count, JumpOffset, OpCode, UpvalueIdx};
|
||||
use crate::spans::LightSpan;
|
||||
use crate::spans::ToSpan;
|
||||
|
@ -1261,7 +1261,7 @@ pub fn prepare_globals(
|
|||
// to instantiate its compiler, the `Weak` reference is passed
|
||||
// here.
|
||||
if enable_import {
|
||||
let import = Value::Builtin(import::builtins_import(weak, source));
|
||||
let import = Value::Builtin(import::builtins_import(weak, source.clone()));
|
||||
builtins_under_construction.insert("import", import);
|
||||
}
|
||||
|
||||
|
@ -1278,6 +1278,36 @@ pub fn prepare_globals(
|
|||
}
|
||||
}
|
||||
|
||||
// builtins contain themselves (`builtins.builtins`), which we
|
||||
// can resolve by manually constructing a suspended thunk that
|
||||
// dereferences the same weak pointer as above.
|
||||
//
|
||||
// This is an inefficient hack, but *if* anyone was to use
|
||||
// `builtins.builtins`, it would only happen once as the thunk
|
||||
// is then resolved.
|
||||
let weak_globals = weak.clone();
|
||||
builtins_under_construction.insert(
|
||||
"builtins",
|
||||
Value::Thunk(Thunk::new_suspended_native(Rc::new(Box::new(move |_| {
|
||||
let file = source.add_file("builtins-dot-builtins.nix".into(), "builtins".into());
|
||||
let span = file.span;
|
||||
let mut observer = NoOpObserver::default();
|
||||
|
||||
let mut compiler = Compiler::new(
|
||||
None,
|
||||
file,
|
||||
weak_globals
|
||||
.upgrade()
|
||||
.expect("globals dropped while still in use"),
|
||||
&mut observer,
|
||||
)?;
|
||||
|
||||
weak_globals.upgrade().unwrap().get("builtins").unwrap()(&mut compiler, span);
|
||||
|
||||
Ok(compiler.chunk().constants[0].clone())
|
||||
})))),
|
||||
);
|
||||
|
||||
// This is followed by the actual `builtins` attribute set
|
||||
// being constructed and inserted in the global scope.
|
||||
let builtins_set =
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
true
|
|
@ -0,0 +1 @@
|
|||
[ builtins ] == [ builtins.builtins ]
|
Loading…
Reference in a new issue