refactor(tvix/eval): Drop LightSpan entirely
This was made unnecessary in c92d06271
(feat(tvix/eval): drop
LightSpan::Delayed, 2023-12-08) because it didn't improve benchmarks as
much as expected and has been vestigial since; this continues the
cleanup by just removing it altogether
Change-Id: I21ec7ae9b52a5cccd2092696a5a87f658194d672
Reviewed-on: https://cl.tvl.fyi/c/depot/+/11949
Autosubmit: aspen <root@gws.fyi>
Tested-by: BuildkiteCI
Reviewed-by: flokli <flokli@flokli.de>
This commit is contained in:
parent
8e31088a01
commit
6037888e18
8 changed files with 109 additions and 175 deletions
|
@ -525,11 +525,7 @@ mod pure_builtins {
|
||||||
let span = generators::request_span(&co).await;
|
let span = generators::request_span(&co).await;
|
||||||
|
|
||||||
for i in 0..len {
|
for i in 0..len {
|
||||||
let val = Value::Thunk(Thunk::new_suspended_call(
|
let val = Value::Thunk(Thunk::new_suspended_call(generator.clone(), i.into(), span));
|
||||||
generator.clone(),
|
|
||||||
i.into(),
|
|
||||||
span.clone(),
|
|
||||||
));
|
|
||||||
out.push_back(val);
|
out.push_back(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -983,7 +979,7 @@ mod pure_builtins {
|
||||||
let span = generators::request_span(&co).await;
|
let span = generators::request_span(&co).await;
|
||||||
|
|
||||||
for val in list.to_list()? {
|
for val in list.to_list()? {
|
||||||
let result = Value::Thunk(Thunk::new_suspended_call(f.clone(), val, span.clone()));
|
let result = Value::Thunk(Thunk::new_suspended_call(f.clone(), val, span));
|
||||||
out.push_back(result)
|
out.push_back(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1006,9 +1002,9 @@ mod pure_builtins {
|
||||||
let result = Value::Thunk(Thunk::new_suspended_call(
|
let result = Value::Thunk(Thunk::new_suspended_call(
|
||||||
f.clone(),
|
f.clone(),
|
||||||
key.clone().into(),
|
key.clone().into(),
|
||||||
span.clone(),
|
span,
|
||||||
));
|
));
|
||||||
let result = Value::Thunk(Thunk::new_suspended_call(result, value, span.clone()));
|
let result = Value::Thunk(Thunk::new_suspended_call(result, value, span));
|
||||||
|
|
||||||
out.insert(key, result);
|
out.insert(key, result);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,6 @@ use crate::chunk::Chunk;
|
||||||
use crate::errors::{CatchableErrorKind, Error, ErrorKind, EvalResult};
|
use crate::errors::{CatchableErrorKind, Error, ErrorKind, EvalResult};
|
||||||
use crate::observer::CompilerObserver;
|
use crate::observer::CompilerObserver;
|
||||||
use crate::opcode::{CodeIdx, ConstantIdx, Count, JumpOffset, OpCode, UpvalueIdx};
|
use crate::opcode::{CodeIdx, ConstantIdx, Count, JumpOffset, OpCode, UpvalueIdx};
|
||||||
use crate::spans::LightSpan;
|
|
||||||
use crate::spans::ToSpan;
|
use crate::spans::ToSpan;
|
||||||
use crate::value::{Closure, Formals, Lambda, NixAttrs, Thunk, Value};
|
use crate::value::{Closure, Formals, Lambda, NixAttrs, Thunk, Value};
|
||||||
use crate::warnings::{EvalWarning, WarningKind};
|
use crate::warnings::{EvalWarning, WarningKind};
|
||||||
|
@ -1257,7 +1256,7 @@ impl Compiler<'_, '_> {
|
||||||
if lambda.upvalue_count == 0 {
|
if lambda.upvalue_count == 0 {
|
||||||
self.emit_constant(
|
self.emit_constant(
|
||||||
if is_suspended_thunk {
|
if is_suspended_thunk {
|
||||||
Value::Thunk(Thunk::new_suspended(lambda, LightSpan::new_actual(span)))
|
Value::Thunk(Thunk::new_suspended(lambda, span))
|
||||||
} else {
|
} else {
|
||||||
Value::Closure(Rc::new(Closure::new(lambda)))
|
Value::Closure(Rc::new(Closure::new(lambda)))
|
||||||
},
|
},
|
||||||
|
@ -1565,10 +1564,7 @@ fn compile_src_builtin(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::Thunk(Thunk::new_suspended(
|
Ok(Value::Thunk(Thunk::new_suspended(result.lambda, file.span)))
|
||||||
result.lambda,
|
|
||||||
LightSpan::Actual { span: file.span },
|
|
||||||
)))
|
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,37 +5,6 @@ use codemap::{File, Span};
|
||||||
use rnix::ast;
|
use rnix::ast;
|
||||||
use rowan::ast::AstNode;
|
use rowan::ast::AstNode;
|
||||||
|
|
||||||
/// Helper struct to carry information required for making a span, but
|
|
||||||
/// without actually performing the (expensive) span lookup.
|
|
||||||
///
|
|
||||||
/// This is used for tracking spans across thunk boundaries, as they
|
|
||||||
/// are frequently instantiated but spans are only used in error or
|
|
||||||
/// warning cases.
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub enum LightSpan {
|
|
||||||
/// The span has already been computed and can just be used right
|
|
||||||
/// away.
|
|
||||||
Actual { span: Span },
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LightSpan {
|
|
||||||
pub fn new_actual(span: Span) -> Self {
|
|
||||||
Self::Actual { span }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn span(&self) -> Span {
|
|
||||||
match self {
|
|
||||||
LightSpan::Actual { span } => *span,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Span> for LightSpan {
|
|
||||||
fn from(span: Span) -> Self {
|
|
||||||
LightSpan::Actual { span }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Trait implemented by all types from which we can retrieve a span.
|
/// Trait implemented by all types from which we can retrieve a span.
|
||||||
pub trait ToSpan {
|
pub trait ToSpan {
|
||||||
fn span_for(&self, file: &File) -> Span;
|
fn span_for(&self, file: &File) -> Span;
|
||||||
|
|
|
@ -7,6 +7,7 @@ use std::path::PathBuf;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use bstr::{BString, ByteVec};
|
use bstr::{BString, ByteVec};
|
||||||
|
use codemap::Span;
|
||||||
use lexical_core::format::CXX_LITERAL;
|
use lexical_core::format::CXX_LITERAL;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
@ -23,7 +24,6 @@ mod thunk;
|
||||||
|
|
||||||
use crate::errors::{CatchableErrorKind, ErrorKind};
|
use crate::errors::{CatchableErrorKind, ErrorKind};
|
||||||
use crate::opcode::StackIdx;
|
use crate::opcode::StackIdx;
|
||||||
use crate::spans::LightSpan;
|
|
||||||
use crate::vm::generators::{self, GenCo};
|
use crate::vm::generators::{self, GenCo};
|
||||||
use crate::AddContext;
|
use crate::AddContext;
|
||||||
pub use attrs::NixAttrs;
|
pub use attrs::NixAttrs;
|
||||||
|
@ -224,7 +224,7 @@ impl Value {
|
||||||
/// their contents, too.
|
/// their contents, too.
|
||||||
///
|
///
|
||||||
/// This is a generator function.
|
/// This is a generator function.
|
||||||
pub(super) async fn deep_force(self, co: GenCo, span: LightSpan) -> Result<Value, ErrorKind> {
|
pub(super) async fn deep_force(self, co: GenCo, span: Span) -> Result<Value, ErrorKind> {
|
||||||
if let Some(v) = Self::deep_force_(self.clone(), co, span).await? {
|
if let Some(v) = Self::deep_force_(self.clone(), co, span).await? {
|
||||||
Ok(v)
|
Ok(v)
|
||||||
} else {
|
} else {
|
||||||
|
@ -233,11 +233,7 @@ impl Value {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns Some(v) or None to indicate the returned value is myself
|
/// Returns Some(v) or None to indicate the returned value is myself
|
||||||
async fn deep_force_(
|
async fn deep_force_(myself: Value, co: GenCo, span: Span) -> Result<Option<Value>, ErrorKind> {
|
||||||
myself: Value,
|
|
||||||
co: GenCo,
|
|
||||||
span: LightSpan,
|
|
||||||
) -> Result<Option<Value>, ErrorKind> {
|
|
||||||
// This is a stack of values which still remain to be forced.
|
// This is a stack of values which still remain to be forced.
|
||||||
let mut vals = vec![myself];
|
let mut vals = vec![myself];
|
||||||
|
|
||||||
|
@ -256,7 +252,7 @@ impl Value {
|
||||||
if !thunk_set.insert(t) {
|
if !thunk_set.insert(t) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Thunk::force_(t.clone(), &co, span.clone()).await?
|
Thunk::force_(t.clone(), &co, span).await?
|
||||||
} else {
|
} else {
|
||||||
v
|
v
|
||||||
};
|
};
|
||||||
|
@ -307,7 +303,7 @@ impl Value {
|
||||||
self,
|
self,
|
||||||
co: GenCo,
|
co: GenCo,
|
||||||
kind: CoercionKind,
|
kind: CoercionKind,
|
||||||
span: LightSpan,
|
span: Span,
|
||||||
) -> Result<Value, ErrorKind> {
|
) -> Result<Value, ErrorKind> {
|
||||||
self.coerce_to_string_(&co, kind, span).await
|
self.coerce_to_string_(&co, kind, span).await
|
||||||
}
|
}
|
||||||
|
@ -318,7 +314,7 @@ impl Value {
|
||||||
self,
|
self,
|
||||||
co: &GenCo,
|
co: &GenCo,
|
||||||
kind: CoercionKind,
|
kind: CoercionKind,
|
||||||
span: LightSpan,
|
span: Span,
|
||||||
) -> Result<Value, ErrorKind> {
|
) -> Result<Value, ErrorKind> {
|
||||||
let mut result = BString::default();
|
let mut result = BString::default();
|
||||||
let mut vals = vec![self];
|
let mut vals = vec![self];
|
||||||
|
@ -331,7 +327,7 @@ impl Value {
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let value = if let Some(v) = vals.pop() {
|
let value = if let Some(v) = vals.pop() {
|
||||||
v.force(co, span.clone()).await?
|
v.force(co, span).await?
|
||||||
} else {
|
} else {
|
||||||
return Ok(Value::String(NixString::new_context_from(context, result)));
|
return Ok(Value::String(NixString::new_context_from(context, result)));
|
||||||
};
|
};
|
||||||
|
@ -377,7 +373,7 @@ impl Value {
|
||||||
// `__toString` is preferred.
|
// `__toString` is preferred.
|
||||||
(Value::Attrs(attrs), kind) => {
|
(Value::Attrs(attrs), kind) => {
|
||||||
if let Some(to_string) = attrs.select("__toString") {
|
if let Some(to_string) = attrs.select("__toString") {
|
||||||
let callable = to_string.clone().force(co, span.clone()).await?;
|
let callable = to_string.clone().force(co, span).await?;
|
||||||
|
|
||||||
// Leave the attribute set on the stack as an argument
|
// Leave the attribute set on the stack as an argument
|
||||||
// to the function call.
|
// to the function call.
|
||||||
|
@ -467,7 +463,7 @@ impl Value {
|
||||||
other: Value,
|
other: Value,
|
||||||
co: GenCo,
|
co: GenCo,
|
||||||
ptr_eq: PointerEquality,
|
ptr_eq: PointerEquality,
|
||||||
span: LightSpan,
|
span: Span,
|
||||||
) -> Result<Value, ErrorKind> {
|
) -> Result<Value, ErrorKind> {
|
||||||
self.nix_eq(other, &co, ptr_eq, span).await
|
self.nix_eq(other, &co, ptr_eq, span).await
|
||||||
}
|
}
|
||||||
|
@ -487,7 +483,7 @@ impl Value {
|
||||||
other: Value,
|
other: Value,
|
||||||
co: &GenCo,
|
co: &GenCo,
|
||||||
ptr_eq: PointerEquality,
|
ptr_eq: PointerEquality,
|
||||||
span: LightSpan,
|
span: Span,
|
||||||
) -> Result<Value, ErrorKind> {
|
) -> Result<Value, ErrorKind> {
|
||||||
// this is a stack of ((v1,v2),peq) triples to be compared;
|
// this is a stack of ((v1,v2),peq) triples to be compared;
|
||||||
// after each triple is popped off of the stack, v1 is
|
// after each triple is popped off of the stack, v1 is
|
||||||
|
@ -513,13 +509,13 @@ impl Value {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Thunk::force_(thunk, co, span.clone()).await?
|
Thunk::force_(thunk, co, span).await?
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => a,
|
_ => a,
|
||||||
};
|
};
|
||||||
|
|
||||||
let b = b.force(co, span.clone()).await?;
|
let b = b.force(co, span).await?;
|
||||||
|
|
||||||
debug_assert!(!matches!(a, Value::Thunk(_)));
|
debug_assert!(!matches!(a, Value::Thunk(_)));
|
||||||
debug_assert!(!matches!(b, Value::Thunk(_)));
|
debug_assert!(!matches!(b, Value::Thunk(_)));
|
||||||
|
@ -568,11 +564,11 @@ impl Value {
|
||||||
#[allow(clippy::single_match)] // might need more match arms later
|
#[allow(clippy::single_match)] // might need more match arms later
|
||||||
match (a1.select("type"), a2.select("type")) {
|
match (a1.select("type"), a2.select("type")) {
|
||||||
(Some(v1), Some(v2)) => {
|
(Some(v1), Some(v2)) => {
|
||||||
let s1 = v1.clone().force(co, span.clone()).await?;
|
let s1 = v1.clone().force(co, span).await?;
|
||||||
if s1.is_catchable() {
|
if s1.is_catchable() {
|
||||||
return Ok(s1);
|
return Ok(s1);
|
||||||
}
|
}
|
||||||
let s2 = v2.clone().force(co, span.clone()).await?;
|
let s2 = v2.clone().force(co, span).await?;
|
||||||
if s2.is_catchable() {
|
if s2.is_catchable() {
|
||||||
return Ok(s2);
|
return Ok(s2);
|
||||||
}
|
}
|
||||||
|
@ -593,8 +589,8 @@ impl Value {
|
||||||
.context("comparing derivations")?
|
.context("comparing derivations")?
|
||||||
.clone();
|
.clone();
|
||||||
|
|
||||||
let out1 = out1.clone().force(co, span.clone()).await?;
|
let out1 = out1.clone().force(co, span).await?;
|
||||||
let out2 = out2.clone().force(co, span.clone()).await?;
|
let out2 = out2.clone().force(co, span).await?;
|
||||||
|
|
||||||
if out1.is_catchable() {
|
if out1.is_catchable() {
|
||||||
return Ok(out1);
|
return Ok(out1);
|
||||||
|
@ -745,7 +741,7 @@ impl Value {
|
||||||
self,
|
self,
|
||||||
other: Self,
|
other: Self,
|
||||||
co: GenCo,
|
co: GenCo,
|
||||||
span: LightSpan,
|
span: Span,
|
||||||
) -> Result<Result<Ordering, CatchableErrorKind>, ErrorKind> {
|
) -> Result<Result<Ordering, CatchableErrorKind>, ErrorKind> {
|
||||||
Self::nix_cmp_ordering_(self, other, co, span).await
|
Self::nix_cmp_ordering_(self, other, co, span).await
|
||||||
}
|
}
|
||||||
|
@ -754,7 +750,7 @@ impl Value {
|
||||||
myself: Self,
|
myself: Self,
|
||||||
other: Self,
|
other: Self,
|
||||||
co: GenCo,
|
co: GenCo,
|
||||||
span: LightSpan,
|
span: Span,
|
||||||
) -> Result<Result<Ordering, CatchableErrorKind>, ErrorKind> {
|
) -> Result<Result<Ordering, CatchableErrorKind>, ErrorKind> {
|
||||||
// this is a stack of ((v1,v2),peq) triples to be compared;
|
// this is a stack of ((v1,v2),peq) triples to be compared;
|
||||||
// after each triple is popped off of the stack, v1 is
|
// after each triple is popped off of the stack, v1 is
|
||||||
|
@ -770,14 +766,14 @@ impl Value {
|
||||||
};
|
};
|
||||||
if ptr_eq == PointerEquality::AllowAll {
|
if ptr_eq == PointerEquality::AllowAll {
|
||||||
if a.clone()
|
if a.clone()
|
||||||
.nix_eq(b.clone(), &co, PointerEquality::AllowAll, span.clone())
|
.nix_eq(b.clone(), &co, PointerEquality::AllowAll, span)
|
||||||
.await?
|
.await?
|
||||||
.as_bool()?
|
.as_bool()?
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
a = a.force(&co, span.clone()).await?;
|
a = a.force(&co, span).await?;
|
||||||
b = b.force(&co, span.clone()).await?;
|
b = b.force(&co, span).await?;
|
||||||
}
|
}
|
||||||
let result = match (a, b) {
|
let result = match (a, b) {
|
||||||
(Value::Catchable(c), _) => return Ok(Err(*c)),
|
(Value::Catchable(c), _) => return Ok(Err(*c)),
|
||||||
|
@ -820,7 +816,7 @@ impl Value {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(amjoseph): de-asyncify this (when called directly by the VM)
|
// TODO(amjoseph): de-asyncify this (when called directly by the VM)
|
||||||
pub async fn force(self, co: &GenCo, span: LightSpan) -> Result<Value, ErrorKind> {
|
pub async fn force(self, co: &GenCo, span: Span) -> Result<Value, ErrorKind> {
|
||||||
if let Value::Thunk(thunk) = self {
|
if let Value::Thunk(thunk) = self {
|
||||||
// TODO(amjoseph): use #[tailcall::mutual]
|
// TODO(amjoseph): use #[tailcall::mutual]
|
||||||
return Thunk::force_(thunk, co, span).await;
|
return Thunk::force_(thunk, co, span).await;
|
||||||
|
@ -829,7 +825,7 @@ impl Value {
|
||||||
}
|
}
|
||||||
|
|
||||||
// need two flavors, because async
|
// need two flavors, because async
|
||||||
pub async fn force_owned_genco(self, co: GenCo, span: LightSpan) -> Result<Value, ErrorKind> {
|
pub async fn force_owned_genco(self, co: GenCo, span: Span) -> Result<Value, ErrorKind> {
|
||||||
if let Value::Thunk(thunk) = self {
|
if let Value::Thunk(thunk) = self {
|
||||||
// TODO(amjoseph): use #[tailcall::mutual]
|
// TODO(amjoseph): use #[tailcall::mutual]
|
||||||
return Thunk::force_(thunk, &co, span).await;
|
return Thunk::force_(thunk, &co, span).await;
|
||||||
|
|
|
@ -28,7 +28,6 @@ use std::{
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::ErrorKind,
|
errors::ErrorKind,
|
||||||
opcode::OpCode,
|
opcode::OpCode,
|
||||||
spans::LightSpan,
|
|
||||||
upvalues::Upvalues,
|
upvalues::Upvalues,
|
||||||
value::Closure,
|
value::Closure,
|
||||||
vm::generators::{self, GenCo},
|
vm::generators::{self, GenCo},
|
||||||
|
@ -59,7 +58,7 @@ enum ThunkRepr {
|
||||||
Suspended {
|
Suspended {
|
||||||
lambda: Rc<Lambda>,
|
lambda: Rc<Lambda>,
|
||||||
upvalues: Rc<Upvalues>,
|
upvalues: Rc<Upvalues>,
|
||||||
light_span: LightSpan,
|
span: Span,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Thunk is a suspended native computation.
|
/// Thunk is a suspended native computation.
|
||||||
|
@ -69,10 +68,10 @@ enum ThunkRepr {
|
||||||
/// value means that infinite recursion has occured.
|
/// value means that infinite recursion has occured.
|
||||||
Blackhole {
|
Blackhole {
|
||||||
/// Span at which the thunk was first forced.
|
/// Span at which the thunk was first forced.
|
||||||
forced_at: LightSpan,
|
forced_at: Span,
|
||||||
|
|
||||||
/// Span at which the thunk was originally suspended.
|
/// Span at which the thunk was originally suspended.
|
||||||
suspended_at: Option<LightSpan>,
|
suspended_at: Option<Span>,
|
||||||
|
|
||||||
/// Span of the first instruction of the actual code inside
|
/// Span of the first instruction of the actual code inside
|
||||||
/// the thunk.
|
/// the thunk.
|
||||||
|
@ -143,11 +142,11 @@ impl Thunk {
|
||||||
)))))
|
)))))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_suspended(lambda: Rc<Lambda>, light_span: LightSpan) -> Self {
|
pub fn new_suspended(lambda: Rc<Lambda>, span: Span) -> Self {
|
||||||
Thunk(Rc::new(RefCell::new(ThunkRepr::Suspended {
|
Thunk(Rc::new(RefCell::new(ThunkRepr::Suspended {
|
||||||
upvalues: Rc::new(Upvalues::with_capacity(lambda.upvalue_count)),
|
upvalues: Rc::new(Upvalues::with_capacity(lambda.upvalue_count)),
|
||||||
lambda: lambda.clone(),
|
lambda: lambda.clone(),
|
||||||
light_span,
|
span,
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,9 +161,8 @@ impl Thunk {
|
||||||
/// particularly useful in builtin implementations if the result of calling
|
/// particularly useful in builtin implementations if the result of calling
|
||||||
/// a function does not need to be forced immediately, because e.g. it is
|
/// a function does not need to be forced immediately, because e.g. it is
|
||||||
/// stored in an attribute set.
|
/// stored in an attribute set.
|
||||||
pub fn new_suspended_call(callee: Value, arg: Value, light_span: LightSpan) -> Self {
|
pub fn new_suspended_call(callee: Value, arg: Value, span: Span) -> Self {
|
||||||
let mut lambda = Lambda::default();
|
let mut lambda = Lambda::default();
|
||||||
let span = light_span.span();
|
|
||||||
|
|
||||||
let arg_idx = lambda.chunk().push_constant(arg);
|
let arg_idx = lambda.chunk().push_constant(arg);
|
||||||
let f_idx = lambda.chunk().push_constant(callee);
|
let f_idx = lambda.chunk().push_constant(callee);
|
||||||
|
@ -183,17 +181,15 @@ impl Thunk {
|
||||||
Thunk(Rc::new(RefCell::new(ThunkRepr::Suspended {
|
Thunk(Rc::new(RefCell::new(ThunkRepr::Suspended {
|
||||||
upvalues: Rc::new(Upvalues::with_capacity(0)),
|
upvalues: Rc::new(Upvalues::with_capacity(0)),
|
||||||
lambda: Rc::new(lambda),
|
lambda: Rc::new(lambda),
|
||||||
light_span,
|
span,
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_blackhole(&self, forced_at: LightSpan) -> ThunkRepr {
|
fn prepare_blackhole(&self, forced_at: Span) -> ThunkRepr {
|
||||||
match &*self.0.borrow() {
|
match &*self.0.borrow() {
|
||||||
ThunkRepr::Suspended {
|
ThunkRepr::Suspended { span, lambda, .. } => ThunkRepr::Blackhole {
|
||||||
light_span, lambda, ..
|
|
||||||
} => ThunkRepr::Blackhole {
|
|
||||||
forced_at,
|
forced_at,
|
||||||
suspended_at: Some(light_span.clone()),
|
suspended_at: Some(*span),
|
||||||
content_span: Some(lambda.chunk.first_span()),
|
content_span: Some(lambda.chunk.first_span()),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -205,14 +201,10 @@ impl Thunk {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn force(myself: Thunk, co: GenCo, span: LightSpan) -> Result<Value, ErrorKind> {
|
pub async fn force(myself: Thunk, co: GenCo, span: Span) -> Result<Value, ErrorKind> {
|
||||||
Self::force_(myself, &co, span).await
|
Self::force_(myself, &co, span).await
|
||||||
}
|
}
|
||||||
pub async fn force_(
|
pub async fn force_(mut myself: Thunk, co: &GenCo, span: Span) -> Result<Value, ErrorKind> {
|
||||||
mut myself: Thunk,
|
|
||||||
co: &GenCo,
|
|
||||||
span: LightSpan,
|
|
||||||
) -> Result<Value, ErrorKind> {
|
|
||||||
// This vector of "thunks which point to the thunk-being-forced", to
|
// This vector of "thunks which point to the thunk-being-forced", to
|
||||||
// be updated along with it, is necessary in order to write this
|
// be updated along with it, is necessary in order to write this
|
||||||
// function in iterative (and later, mutual-tail-call) form.
|
// function in iterative (and later, mutual-tail-call) form.
|
||||||
|
@ -232,7 +224,7 @@ impl Thunk {
|
||||||
// Begin evaluation of this thunk by marking it as a blackhole, meaning
|
// Begin evaluation of this thunk by marking it as a blackhole, meaning
|
||||||
// that any other forcing frame encountering this thunk before its
|
// that any other forcing frame encountering this thunk before its
|
||||||
// evaluation is completed detected an evaluation cycle.
|
// evaluation is completed detected an evaluation cycle.
|
||||||
let inner = myself.0.replace(myself.prepare_blackhole(span.clone()));
|
let inner = myself.0.replace(myself.prepare_blackhole(span));
|
||||||
|
|
||||||
match inner {
|
match inner {
|
||||||
// If there was already a blackhole in the thunk, this is an
|
// If there was already a blackhole in the thunk, this is an
|
||||||
|
@ -243,8 +235,8 @@ impl Thunk {
|
||||||
content_span,
|
content_span,
|
||||||
} => {
|
} => {
|
||||||
return Err(ErrorKind::InfiniteRecursion {
|
return Err(ErrorKind::InfiniteRecursion {
|
||||||
first_force: forced_at.span(),
|
first_force: forced_at,
|
||||||
suspended_at: suspended_at.map(|s| s.span()),
|
suspended_at,
|
||||||
content_span,
|
content_span,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -262,13 +254,12 @@ impl Thunk {
|
||||||
ThunkRepr::Suspended {
|
ThunkRepr::Suspended {
|
||||||
lambda,
|
lambda,
|
||||||
upvalues,
|
upvalues,
|
||||||
light_span,
|
span,
|
||||||
} => {
|
} => {
|
||||||
// TODO(amjoseph): use #[tailcall::mutual] here. This can
|
// TODO(amjoseph): use #[tailcall::mutual] here. This can
|
||||||
// be turned into a tailcall to vm::execute_bytecode() by
|
// be turned into a tailcall to vm::execute_bytecode() by
|
||||||
// passing `also_update` to it.
|
// passing `also_update` to it.
|
||||||
let value =
|
let value = generators::request_enter_lambda(co, lambda, upvalues, span).await;
|
||||||
generators::request_enter_lambda(co, lambda, upvalues, light_span).await;
|
|
||||||
myself.0.replace(ThunkRepr::Evaluated(value));
|
myself.0.replace(ThunkRepr::Evaluated(value));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,7 @@ pub enum VMRequest {
|
||||||
EnterLambda {
|
EnterLambda {
|
||||||
lambda: Rc<Lambda>,
|
lambda: Rc<Lambda>,
|
||||||
upvalues: Rc<Upvalues>,
|
upvalues: Rc<Upvalues>,
|
||||||
light_span: LightSpan,
|
span: Span,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Emit a runtime warning (already containing a span) through the VM.
|
/// Emit a runtime warning (already containing a span) through the VM.
|
||||||
|
@ -198,7 +198,7 @@ pub enum VMResponse {
|
||||||
Directory(Vec<(bytes::Bytes, FileType)>),
|
Directory(Vec<(bytes::Bytes, FileType)>),
|
||||||
|
|
||||||
/// VM response with a span to use at the current point.
|
/// VM response with a span to use at the current point.
|
||||||
Span(LightSpan),
|
Span(Span),
|
||||||
|
|
||||||
/// [std::io::Reader] produced by the VM in response to some IO operation.
|
/// [std::io::Reader] produced by the VM in response to some IO operation.
|
||||||
Reader(Box<dyn std::io::Read>),
|
Reader(Box<dyn std::io::Read>),
|
||||||
|
@ -234,7 +234,7 @@ where
|
||||||
{
|
{
|
||||||
/// Helper function to re-enqueue the current generator while it
|
/// Helper function to re-enqueue the current generator while it
|
||||||
/// is awaiting a value.
|
/// is awaiting a value.
|
||||||
fn reenqueue_generator(&mut self, name: &'static str, span: LightSpan, generator: Generator) {
|
fn reenqueue_generator(&mut self, name: &'static str, span: Span, generator: Generator) {
|
||||||
self.frames.push(Frame::Generator {
|
self.frames.push(Frame::Generator {
|
||||||
name,
|
name,
|
||||||
generator,
|
generator,
|
||||||
|
@ -244,7 +244,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function to enqueue a new generator.
|
/// Helper function to enqueue a new generator.
|
||||||
pub(super) fn enqueue_generator<F, G>(&mut self, name: &'static str, span: LightSpan, gen: G)
|
pub(super) fn enqueue_generator<F, G>(&mut self, name: &'static str, span: Span, gen: G)
|
||||||
where
|
where
|
||||||
F: Future<Output = Result<Value, ErrorKind>> + 'static,
|
F: Future<Output = Result<Value, ErrorKind>> + 'static,
|
||||||
G: FnOnce(GenCo) -> F,
|
G: FnOnce(GenCo) -> F,
|
||||||
|
@ -265,7 +265,7 @@ where
|
||||||
pub(crate) fn run_generator(
|
pub(crate) fn run_generator(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
span: LightSpan,
|
span: Span,
|
||||||
frame_id: usize,
|
frame_id: usize,
|
||||||
state: GeneratorState,
|
state: GeneratorState,
|
||||||
mut generator: Generator,
|
mut generator: Generator,
|
||||||
|
@ -302,8 +302,8 @@ where
|
||||||
// this function prepares the frame stack and yields
|
// this function prepares the frame stack and yields
|
||||||
// back to the outer VM loop.
|
// back to the outer VM loop.
|
||||||
VMRequest::ForceValue(value) => {
|
VMRequest::ForceValue(value) => {
|
||||||
self.reenqueue_generator(name, span.clone(), generator);
|
self.reenqueue_generator(name, span, generator);
|
||||||
self.enqueue_generator("force", span.clone(), |co| {
|
self.enqueue_generator("force", span, |co| {
|
||||||
value.force_owned_genco(co, span)
|
value.force_owned_genco(co, span)
|
||||||
});
|
});
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
|
@ -311,8 +311,8 @@ where
|
||||||
|
|
||||||
// Generator has requested a deep-force.
|
// Generator has requested a deep-force.
|
||||||
VMRequest::DeepForceValue(value) => {
|
VMRequest::DeepForceValue(value) => {
|
||||||
self.reenqueue_generator(name, span.clone(), generator);
|
self.reenqueue_generator(name, span, generator);
|
||||||
self.enqueue_generator("deep_force", span.clone(), |co| {
|
self.enqueue_generator("deep_force", span, |co| {
|
||||||
value.deep_force(co, span)
|
value.deep_force(co, span)
|
||||||
});
|
});
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
|
@ -322,10 +322,10 @@ where
|
||||||
// Logic is similar to `ForceValue`, except with the
|
// Logic is similar to `ForceValue`, except with the
|
||||||
// value being taken from that stack.
|
// value being taken from that stack.
|
||||||
VMRequest::WithValue(idx) => {
|
VMRequest::WithValue(idx) => {
|
||||||
self.reenqueue_generator(name, span.clone(), generator);
|
self.reenqueue_generator(name, span, generator);
|
||||||
|
|
||||||
let value = self.stack[self.with_stack[idx]].clone();
|
let value = self.stack[self.with_stack[idx]].clone();
|
||||||
self.enqueue_generator("force", span.clone(), |co| {
|
self.enqueue_generator("force", span, |co| {
|
||||||
value.force_owned_genco(co, span)
|
value.force_owned_genco(co, span)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -336,13 +336,13 @@ where
|
||||||
// with-stack. Logic is same as above, except for the
|
// with-stack. Logic is same as above, except for the
|
||||||
// value being from that stack.
|
// value being from that stack.
|
||||||
VMRequest::CapturedWithValue(idx) => {
|
VMRequest::CapturedWithValue(idx) => {
|
||||||
self.reenqueue_generator(name, span.clone(), generator);
|
self.reenqueue_generator(name, span, generator);
|
||||||
|
|
||||||
let call_frame = self.last_call_frame()
|
let call_frame = self.last_call_frame()
|
||||||
.expect("Tvix bug: generator requested captured with-value, but there is no call frame");
|
.expect("Tvix bug: generator requested captured with-value, but there is no call frame");
|
||||||
|
|
||||||
let value = call_frame.upvalues.with_stack().unwrap()[idx].clone();
|
let value = call_frame.upvalues.with_stack().unwrap()[idx].clone();
|
||||||
self.enqueue_generator("force", span.clone(), |co| {
|
self.enqueue_generator("force", span, |co| {
|
||||||
value.force_owned_genco(co, span)
|
value.force_owned_genco(co, span)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -351,23 +351,23 @@ where
|
||||||
|
|
||||||
VMRequest::NixEquality(values, ptr_eq) => {
|
VMRequest::NixEquality(values, ptr_eq) => {
|
||||||
let values = *values;
|
let values = *values;
|
||||||
self.reenqueue_generator(name, span.clone(), generator);
|
self.reenqueue_generator(name, span, generator);
|
||||||
self.enqueue_generator("nix_eq", span.clone(), |co| {
|
self.enqueue_generator("nix_eq", span, |co| {
|
||||||
values.0.nix_eq_owned_genco(values.1, co, ptr_eq, span)
|
values.0.nix_eq_owned_genco(values.1, co, ptr_eq, span)
|
||||||
});
|
});
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
VMRequest::StringCoerce(val, kind) => {
|
VMRequest::StringCoerce(val, kind) => {
|
||||||
self.reenqueue_generator(name, span.clone(), generator);
|
self.reenqueue_generator(name, span, generator);
|
||||||
self.enqueue_generator("coerce_to_string", span.clone(), |co| {
|
self.enqueue_generator("coerce_to_string", span, |co| {
|
||||||
val.coerce_to_string(co, kind, span)
|
val.coerce_to_string(co, kind, span)
|
||||||
});
|
});
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
VMRequest::Call(callable) => {
|
VMRequest::Call(callable) => {
|
||||||
self.reenqueue_generator(name, span.clone(), generator);
|
self.reenqueue_generator(name, span, generator);
|
||||||
self.call_value(span, None, callable)?;
|
self.call_value(span, None, callable)?;
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
@ -375,12 +375,12 @@ where
|
||||||
VMRequest::EnterLambda {
|
VMRequest::EnterLambda {
|
||||||
lambda,
|
lambda,
|
||||||
upvalues,
|
upvalues,
|
||||||
light_span,
|
span,
|
||||||
} => {
|
} => {
|
||||||
self.reenqueue_generator(name, span, generator);
|
self.reenqueue_generator(name, span, generator);
|
||||||
|
|
||||||
self.frames.push(Frame::CallFrame {
|
self.frames.push(Frame::CallFrame {
|
||||||
span: light_span,
|
span,
|
||||||
call_frame: CallFrame {
|
call_frame: CallFrame {
|
||||||
lambda,
|
lambda,
|
||||||
upvalues,
|
upvalues,
|
||||||
|
@ -424,7 +424,7 @@ where
|
||||||
path: Some(path),
|
path: Some(path),
|
||||||
error: e.into(),
|
error: e.into(),
|
||||||
})
|
})
|
||||||
.with_span(&span, self)?;
|
.with_span(span, self)?;
|
||||||
|
|
||||||
message = VMResponse::Path(imported);
|
message = VMResponse::Path(imported);
|
||||||
}
|
}
|
||||||
|
@ -438,7 +438,7 @@ where
|
||||||
path: Some(path),
|
path: Some(path),
|
||||||
error: e.into(),
|
error: e.into(),
|
||||||
})
|
})
|
||||||
.with_span(&span, self)?;
|
.with_span(span, self)?;
|
||||||
|
|
||||||
message = VMResponse::Reader(reader)
|
message = VMResponse::Reader(reader)
|
||||||
}
|
}
|
||||||
|
@ -453,7 +453,7 @@ where
|
||||||
error: e.into(),
|
error: e.into(),
|
||||||
})
|
})
|
||||||
.map(Value::Bool)
|
.map(Value::Bool)
|
||||||
.with_span(&span, self)?;
|
.with_span(span, self)?;
|
||||||
|
|
||||||
message = VMResponse::Value(exists);
|
message = VMResponse::Value(exists);
|
||||||
}
|
}
|
||||||
|
@ -467,31 +467,31 @@ where
|
||||||
path: Some(path),
|
path: Some(path),
|
||||||
error: e.into(),
|
error: e.into(),
|
||||||
})
|
})
|
||||||
.with_span(&span, self)?;
|
.with_span(span, self)?;
|
||||||
message = VMResponse::Directory(dir);
|
message = VMResponse::Directory(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
VMRequest::Span => {
|
VMRequest::Span => {
|
||||||
message = VMResponse::Span(self.reasonable_light_span());
|
message = VMResponse::Span(self.reasonable_span);
|
||||||
}
|
}
|
||||||
|
|
||||||
VMRequest::TryForce(value) => {
|
VMRequest::TryForce(value) => {
|
||||||
self.try_eval_frames.push(frame_id);
|
self.try_eval_frames.push(frame_id);
|
||||||
self.reenqueue_generator(name, span.clone(), generator);
|
self.reenqueue_generator(name, span, generator);
|
||||||
|
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
self.frames.len() == frame_id + 1,
|
self.frames.len() == frame_id + 1,
|
||||||
"generator should be reenqueued with the same frame ID"
|
"generator should be reenqueued with the same frame ID"
|
||||||
);
|
);
|
||||||
|
|
||||||
self.enqueue_generator("force", span.clone(), |co| {
|
self.enqueue_generator("force", span, |co| {
|
||||||
value.force_owned_genco(co, span)
|
value.force_owned_genco(co, span)
|
||||||
});
|
});
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
VMRequest::ToJson(value) => {
|
VMRequest::ToJson(value) => {
|
||||||
self.reenqueue_generator(name, span.clone(), generator);
|
self.reenqueue_generator(name, span, generator);
|
||||||
self.enqueue_generator("to_json", span, |co| {
|
self.enqueue_generator("to_json", span, |co| {
|
||||||
value.into_contextful_json_generator(co)
|
value.into_contextful_json_generator(co)
|
||||||
});
|
});
|
||||||
|
@ -503,7 +503,7 @@ where
|
||||||
// Generator has completed, and its result value should
|
// Generator has completed, and its result value should
|
||||||
// be left on the stack.
|
// be left on the stack.
|
||||||
genawaiter::GeneratorState::Complete(result) => {
|
genawaiter::GeneratorState::Complete(result) => {
|
||||||
let value = result.with_span(&span, self)?;
|
let value = result.with_span(span, self)?;
|
||||||
self.stack.push(value);
|
self.stack.push(value);
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
@ -683,12 +683,12 @@ pub(crate) async fn request_enter_lambda(
|
||||||
co: &GenCo,
|
co: &GenCo,
|
||||||
lambda: Rc<Lambda>,
|
lambda: Rc<Lambda>,
|
||||||
upvalues: Rc<Upvalues>,
|
upvalues: Rc<Upvalues>,
|
||||||
light_span: LightSpan,
|
span: Span,
|
||||||
) -> Value {
|
) -> Value {
|
||||||
let msg = VMRequest::EnterLambda {
|
let msg = VMRequest::EnterLambda {
|
||||||
lambda,
|
lambda,
|
||||||
upvalues,
|
upvalues,
|
||||||
light_span,
|
span,
|
||||||
};
|
};
|
||||||
|
|
||||||
match co.yield_(msg).await {
|
match co.yield_(msg).await {
|
||||||
|
@ -767,7 +767,7 @@ pub(crate) async fn request_read_dir(co: &GenCo, path: PathBuf) -> Vec<(bytes::B
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn request_span(co: &GenCo) -> LightSpan {
|
pub(crate) async fn request_span(co: &GenCo) -> Span {
|
||||||
match co.yield_(VMRequest::Span).await {
|
match co.yield_(VMRequest::Span).await {
|
||||||
VMResponse::Span(span) => span,
|
VMResponse::Span(span) => span,
|
||||||
msg => panic!(
|
msg => panic!(
|
||||||
|
|
|
@ -49,7 +49,7 @@ macro_rules! cmp_op {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let gen_span = $frame.current_light_span();
|
let gen_span = $frame.current_span();
|
||||||
$vm.push_call_frame($span, $frame);
|
$vm.push_call_frame($span, $frame);
|
||||||
$vm.enqueue_generator("compare", gen_span, |co| compare(a, b, co));
|
$vm.enqueue_generator("compare", gen_span, |co| compare(a, b, co));
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
|
|
|
@ -28,7 +28,6 @@ use crate::{
|
||||||
nix_search_path::NixSearchPath,
|
nix_search_path::NixSearchPath,
|
||||||
observer::RuntimeObserver,
|
observer::RuntimeObserver,
|
||||||
opcode::{CodeIdx, Count, JumpOffset, OpCode, StackIdx, UpvalueIdx},
|
opcode::{CodeIdx, Count, JumpOffset, OpCode, StackIdx, UpvalueIdx},
|
||||||
spans::LightSpan,
|
|
||||||
upvalues::Upvalues,
|
upvalues::Upvalues,
|
||||||
value::{
|
value::{
|
||||||
Builtin, BuiltinResult, Closure, CoercionKind, Lambda, NixAttrs, NixContext, NixList,
|
Builtin, BuiltinResult, Closure, CoercionKind, Lambda, NixAttrs, NixContext, NixList,
|
||||||
|
@ -51,7 +50,7 @@ trait GetSpan {
|
||||||
|
|
||||||
impl<'o, IO> GetSpan for &VM<'o, IO> {
|
impl<'o, IO> GetSpan for &VM<'o, IO> {
|
||||||
fn get_span(self) -> Span {
|
fn get_span(self) -> Span {
|
||||||
self.reasonable_span.span()
|
self.reasonable_span
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,9 +60,9 @@ impl GetSpan for &CallFrame {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GetSpan for &LightSpan {
|
impl GetSpan for &Span {
|
||||||
fn get_span(self) -> Span {
|
fn get_span(self) -> Span {
|
||||||
self.span()
|
*self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,7 +93,7 @@ impl<T, S: GetSpan, IO> WithSpan<T, S, IO> for Result<T, ErrorKind> {
|
||||||
Frame::CallFrame { span, .. } => {
|
Frame::CallFrame { span, .. } => {
|
||||||
error = Error::new(
|
error = Error::new(
|
||||||
ErrorKind::BytecodeError(Box::new(error)),
|
ErrorKind::BytecodeError(Box::new(error)),
|
||||||
span.span(),
|
*span,
|
||||||
vm.source.clone(),
|
vm.source.clone(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -104,7 +103,7 @@ impl<T, S: GetSpan, IO> WithSpan<T, S, IO> for Result<T, ErrorKind> {
|
||||||
err: Box::new(error),
|
err: Box::new(error),
|
||||||
gen_type: name,
|
gen_type: name,
|
||||||
},
|
},
|
||||||
span.span(),
|
*span,
|
||||||
vm.source.clone(),
|
vm.source.clone(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -163,13 +162,6 @@ impl CallFrame {
|
||||||
pub fn current_span(&self) -> Span {
|
pub fn current_span(&self) -> Span {
|
||||||
self.chunk().get_span(self.ip - 1)
|
self.chunk().get_span(self.ip - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the information needed to calculate the current span,
|
|
||||||
/// but without performing that calculation.
|
|
||||||
// TODO: why pub?
|
|
||||||
pub(crate) fn current_light_span(&self) -> LightSpan {
|
|
||||||
LightSpan::new_actual(self.current_span())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A frame represents an execution state of the VM. The VM has a stack of
|
/// A frame represents an execution state of the VM. The VM has a stack of
|
||||||
|
@ -187,7 +179,7 @@ enum Frame {
|
||||||
call_frame: CallFrame,
|
call_frame: CallFrame,
|
||||||
|
|
||||||
/// Span from which the call frame was launched.
|
/// Span from which the call frame was launched.
|
||||||
span: LightSpan,
|
span: Span,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Generator represents a frame that can yield further
|
/// Generator represents a frame that can yield further
|
||||||
|
@ -201,7 +193,7 @@ enum Frame {
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
|
|
||||||
/// Span from which the generator was launched.
|
/// Span from which the generator was launched.
|
||||||
span: LightSpan,
|
span: Span,
|
||||||
|
|
||||||
state: GeneratorState,
|
state: GeneratorState,
|
||||||
|
|
||||||
|
@ -211,9 +203,9 @@ enum Frame {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Frame {
|
impl Frame {
|
||||||
pub fn span(&self) -> LightSpan {
|
pub fn span(&self) -> Span {
|
||||||
match self {
|
match self {
|
||||||
Frame::CallFrame { span, .. } | Frame::Generator { span, .. } => span.clone(),
|
Frame::CallFrame { span, .. } | Frame::Generator { span, .. } => *span,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -309,7 +301,7 @@ struct VM<'o, IO> {
|
||||||
///
|
///
|
||||||
/// The VM should update this whenever control flow changes take place (i.e.
|
/// The VM should update this whenever control flow changes take place (i.e.
|
||||||
/// entering or exiting a frame to yield control somewhere).
|
/// entering or exiting a frame to yield control somewhere).
|
||||||
reasonable_span: LightSpan,
|
reasonable_span: Span,
|
||||||
|
|
||||||
/// This field is responsible for handling `builtins.tryEval`. When that
|
/// This field is responsible for handling `builtins.tryEval`. When that
|
||||||
/// builtin is encountered, it sends a special message to the VM which
|
/// builtin is encountered, it sends a special message to the VM which
|
||||||
|
@ -343,7 +335,7 @@ where
|
||||||
observer: &'o mut dyn RuntimeObserver,
|
observer: &'o mut dyn RuntimeObserver,
|
||||||
source: SourceCode,
|
source: SourceCode,
|
||||||
globals: Rc<GlobalsMap>,
|
globals: Rc<GlobalsMap>,
|
||||||
reasonable_span: LightSpan,
|
reasonable_span: Span,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
nix_search_path,
|
nix_search_path,
|
||||||
|
@ -362,7 +354,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Push a call frame onto the frame stack.
|
/// Push a call frame onto the frame stack.
|
||||||
fn push_call_frame(&mut self, span: LightSpan, call_frame: CallFrame) {
|
fn push_call_frame(&mut self, span: Span, call_frame: CallFrame) {
|
||||||
self.frames.push(Frame::CallFrame { span, call_frame })
|
self.frames.push(Frame::CallFrame { span, call_frame })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -444,7 +436,7 @@ where
|
||||||
///
|
///
|
||||||
/// The return value indicates whether the bytecode has been executed to
|
/// The return value indicates whether the bytecode has been executed to
|
||||||
/// completion, or whether it has been suspended in favour of a generator.
|
/// completion, or whether it has been suspended in favour of a generator.
|
||||||
fn execute_bytecode(&mut self, span: LightSpan, mut frame: CallFrame) -> EvalResult<bool> {
|
fn execute_bytecode(&mut self, span: Span, mut frame: CallFrame) -> EvalResult<bool> {
|
||||||
loop {
|
loop {
|
||||||
let op = frame.inc_ip();
|
let op = frame.inc_ip();
|
||||||
self.observer.observe_execute_op(frame.ip, &op, &self.stack);
|
self.observer.observe_execute_op(frame.ip, &op, &self.stack);
|
||||||
|
@ -464,7 +456,7 @@ where
|
||||||
);
|
);
|
||||||
Thunk::new_closure(blueprint)
|
Thunk::new_closure(blueprint)
|
||||||
} else {
|
} else {
|
||||||
Thunk::new_suspended(blueprint, frame.current_light_span())
|
Thunk::new_suspended(blueprint, frame.current_span())
|
||||||
};
|
};
|
||||||
let upvalues = thunk.upvalues_mut();
|
let upvalues = thunk.upvalues_mut();
|
||||||
self.stack.push(Value::Thunk(thunk.clone()));
|
self.stack.push(Value::Thunk(thunk.clone()));
|
||||||
|
@ -484,10 +476,10 @@ where
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let gen_span = frame.current_light_span();
|
let gen_span = frame.current_span();
|
||||||
|
|
||||||
self.push_call_frame(span, frame);
|
self.push_call_frame(span, frame);
|
||||||
self.enqueue_generator("force", gen_span.clone(), |co| {
|
self.enqueue_generator("force", gen_span, |co| {
|
||||||
Thunk::force(thunk, co, gen_span)
|
Thunk::force(thunk, co, gen_span)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -515,7 +507,7 @@ where
|
||||||
|
|
||||||
OpCode::OpCall => {
|
OpCode::OpCall => {
|
||||||
let callable = self.stack_pop();
|
let callable = self.stack_pop();
|
||||||
self.call_value(frame.current_light_span(), Some((span, frame)), callable)?;
|
self.call_value(frame.current_span(), Some((span, frame)), callable)?;
|
||||||
|
|
||||||
// exit this loop and let the outer loop enter the new call
|
// exit this loop and let the outer loop enter the new call
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
|
@ -640,9 +632,9 @@ where
|
||||||
|
|
||||||
OpCode::OpEqual => lifted_pop! {
|
OpCode::OpEqual => lifted_pop! {
|
||||||
self(b, a) => {
|
self(b, a) => {
|
||||||
let gen_span = frame.current_light_span();
|
let gen_span = frame.current_span();
|
||||||
self.push_call_frame(span, frame);
|
self.push_call_frame(span, frame);
|
||||||
self.enqueue_generator("nix_eq", gen_span.clone(), |co| {
|
self.enqueue_generator("nix_eq", gen_span, |co| {
|
||||||
a.nix_eq_owned_genco(b, co, PointerEquality::ForbidAll, gen_span)
|
a.nix_eq_owned_genco(b, co, PointerEquality::ForbidAll, gen_span)
|
||||||
});
|
});
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
|
@ -739,7 +731,7 @@ where
|
||||||
let ident = self.stack_pop().to_str().with_span(&frame, self)?;
|
let ident = self.stack_pop().to_str().with_span(&frame, self)?;
|
||||||
|
|
||||||
// Re-enqueue this frame.
|
// Re-enqueue this frame.
|
||||||
let op_span = frame.current_light_span();
|
let op_span = frame.current_span();
|
||||||
self.push_call_frame(span, frame);
|
self.push_call_frame(span, frame);
|
||||||
|
|
||||||
// Construct a generator frame doing the lookup in constant
|
// Construct a generator frame doing the lookup in constant
|
||||||
|
@ -770,10 +762,10 @@ where
|
||||||
|
|
||||||
OpCode::OpCoerceToString(kind) => {
|
OpCode::OpCoerceToString(kind) => {
|
||||||
let value = self.stack_pop();
|
let value = self.stack_pop();
|
||||||
let gen_span = frame.current_light_span();
|
let gen_span = frame.current_span();
|
||||||
self.push_call_frame(span, frame);
|
self.push_call_frame(span, frame);
|
||||||
|
|
||||||
self.enqueue_generator("coerce_to_string", gen_span.clone(), |co| {
|
self.enqueue_generator("coerce_to_string", gen_span, |co| {
|
||||||
value.coerce_to_string(co, kind, gen_span)
|
value.coerce_to_string(co, kind, gen_span)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -808,7 +800,7 @@ where
|
||||||
|
|
||||||
OpCode::OpAdd => lifted_pop! {
|
OpCode::OpAdd => lifted_pop! {
|
||||||
self(b, a) => {
|
self(b, a) => {
|
||||||
let gen_span = frame.current_light_span();
|
let gen_span = frame.current_span();
|
||||||
self.push_call_frame(span, frame);
|
self.push_call_frame(span, frame);
|
||||||
|
|
||||||
// OpAdd can add not just numbers, but also string-like
|
// OpAdd can add not just numbers, but also string-like
|
||||||
|
@ -1004,12 +996,6 @@ where
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a reasonable light span for the current situation that the VM is
|
|
||||||
/// in.
|
|
||||||
pub fn reasonable_light_span(&self) -> LightSpan {
|
|
||||||
self.reasonable_span.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Apply an argument from the stack to a builtin, and attempt to call it.
|
/// Apply an argument from the stack to a builtin, and attempt to call it.
|
||||||
///
|
///
|
||||||
/// All calls are tail-calls in Tvix, as every function application is a
|
/// All calls are tail-calls in Tvix, as every function application is a
|
||||||
|
@ -1017,7 +1003,7 @@ where
|
||||||
///
|
///
|
||||||
/// Due to this, once control flow exits this function, the generator will
|
/// Due to this, once control flow exits this function, the generator will
|
||||||
/// automatically be run by the VM.
|
/// automatically be run by the VM.
|
||||||
fn call_builtin(&mut self, span: LightSpan, mut builtin: Builtin) -> EvalResult<()> {
|
fn call_builtin(&mut self, span: Span, mut builtin: Builtin) -> EvalResult<()> {
|
||||||
let builtin_name = builtin.name();
|
let builtin_name = builtin.name();
|
||||||
self.observer.observe_enter_builtin(builtin_name);
|
self.observer.observe_enter_builtin(builtin_name);
|
||||||
|
|
||||||
|
@ -1041,8 +1027,8 @@ where
|
||||||
|
|
||||||
fn call_value(
|
fn call_value(
|
||||||
&mut self,
|
&mut self,
|
||||||
span: LightSpan,
|
span: Span,
|
||||||
parent: Option<(LightSpan, CallFrame)>,
|
parent: Option<(Span, CallFrame)>,
|
||||||
callable: Value,
|
callable: Value,
|
||||||
) -> EvalResult<()> {
|
) -> EvalResult<()> {
|
||||||
match callable {
|
match callable {
|
||||||
|
@ -1098,7 +1084,7 @@ where
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
v => Err(ErrorKind::NotCallable(v.type_of())).with_span(&span, self),
|
v => Err(ErrorKind::NotCallable(v.type_of())).with_span(span, self),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1345,17 +1331,17 @@ where
|
||||||
observer,
|
observer,
|
||||||
source,
|
source,
|
||||||
globals,
|
globals,
|
||||||
root_span.into(),
|
root_span,
|
||||||
);
|
);
|
||||||
|
|
||||||
// When evaluating strictly, synthesise a frame that will instruct
|
// When evaluating strictly, synthesise a frame that will instruct
|
||||||
// the VM to deep-force the final value before returning it.
|
// the VM to deep-force the final value before returning it.
|
||||||
if strict {
|
if strict {
|
||||||
vm.enqueue_generator("final_deep_force", root_span.into(), final_deep_force);
|
vm.enqueue_generator("final_deep_force", root_span, final_deep_force);
|
||||||
}
|
}
|
||||||
|
|
||||||
vm.frames.push(Frame::CallFrame {
|
vm.frames.push(Frame::CallFrame {
|
||||||
span: root_span.into(),
|
span: root_span,
|
||||||
call_frame: CallFrame {
|
call_frame: CallFrame {
|
||||||
lambda,
|
lambda,
|
||||||
upvalues: Rc::new(Upvalues::with_capacity(0)),
|
upvalues: Rc::new(Upvalues::with_capacity(0)),
|
||||||
|
|
Loading…
Reference in a new issue