diff options
Diffstat (limited to 'tvix/eval')
-rw-r--r-- | tvix/eval/src/builtins/mod.rs | 12 | ||||
-rw-r--r-- | tvix/eval/src/compiler/mod.rs | 8 | ||||
-rw-r--r-- | tvix/eval/src/spans.rs | 31 | ||||
-rw-r--r-- | tvix/eval/src/value/mod.rs | 50 | ||||
-rw-r--r-- | tvix/eval/src/value/thunk.rs | 43 | ||||
-rw-r--r-- | tvix/eval/src/vm/generators.rs | 64 | ||||
-rw-r--r-- | tvix/eval/src/vm/macros.rs | 2 | ||||
-rw-r--r-- | tvix/eval/src/vm/mod.rs | 74 |
8 files changed, 109 insertions, 175 deletions
diff --git a/tvix/eval/src/builtins/mod.rs b/tvix/eval/src/builtins/mod.rs index 96e9985747f5..88bed35d8a7e 100644 --- a/tvix/eval/src/builtins/mod.rs +++ b/tvix/eval/src/builtins/mod.rs @@ -525,11 +525,7 @@ mod pure_builtins { let span = generators::request_span(&co).await; for i in 0..len { - let val = Value::Thunk(Thunk::new_suspended_call( - generator.clone(), - i.into(), - span.clone(), - )); + let val = Value::Thunk(Thunk::new_suspended_call(generator.clone(), i.into(), span)); out.push_back(val); } @@ -983,7 +979,7 @@ mod pure_builtins { let span = generators::request_span(&co).await; 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) } @@ -1006,9 +1002,9 @@ mod pure_builtins { let result = Value::Thunk(Thunk::new_suspended_call( f.clone(), 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); } diff --git a/tvix/eval/src/compiler/mod.rs b/tvix/eval/src/compiler/mod.rs index 60c55dda27b4..88018cce2fae 100644 --- a/tvix/eval/src/compiler/mod.rs +++ b/tvix/eval/src/compiler/mod.rs @@ -29,7 +29,6 @@ use crate::chunk::Chunk; use crate::errors::{CatchableErrorKind, Error, ErrorKind, EvalResult}; use crate::observer::CompilerObserver; use crate::opcode::{CodeIdx, ConstantIdx, Count, JumpOffset, OpCode, UpvalueIdx}; -use crate::spans::LightSpan; use crate::spans::ToSpan; use crate::value::{Closure, Formals, Lambda, NixAttrs, Thunk, Value}; use crate::warnings::{EvalWarning, WarningKind}; @@ -1257,7 +1256,7 @@ impl Compiler<'_, '_> { if lambda.upvalue_count == 0 { self.emit_constant( if is_suspended_thunk { - Value::Thunk(Thunk::new_suspended(lambda, LightSpan::new_actual(span))) + Value::Thunk(Thunk::new_suspended(lambda, span)) } else { Value::Closure(Rc::new(Closure::new(lambda))) }, @@ -1565,10 +1564,7 @@ fn compile_src_builtin( }); } - Ok(Value::Thunk(Thunk::new_suspended( - result.lambda, - LightSpan::Actual { span: file.span }, - ))) + Ok(Value::Thunk(Thunk::new_suspended(result.lambda, file.span))) }))) } diff --git a/tvix/eval/src/spans.rs b/tvix/eval/src/spans.rs index f422093b0d12..9998e438b220 100644 --- a/tvix/eval/src/spans.rs +++ b/tvix/eval/src/spans.rs @@ -5,37 +5,6 @@ use codemap::{File, Span}; use rnix::ast; 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. pub trait ToSpan { fn span_for(&self, file: &File) -> Span; diff --git a/tvix/eval/src/value/mod.rs b/tvix/eval/src/value/mod.rs index dfad0cd8391b..a5bc17c15294 100644 --- a/tvix/eval/src/value/mod.rs +++ b/tvix/eval/src/value/mod.rs @@ -7,6 +7,7 @@ use std::path::PathBuf; use std::rc::Rc; use bstr::{BString, ByteVec}; +use codemap::Span; use lexical_core::format::CXX_LITERAL; use serde::Deserialize; @@ -23,7 +24,6 @@ mod thunk; use crate::errors::{CatchableErrorKind, ErrorKind}; use crate::opcode::StackIdx; -use crate::spans::LightSpan; use crate::vm::generators::{self, GenCo}; use crate::AddContext; pub use attrs::NixAttrs; @@ -224,7 +224,7 @@ impl Value { /// their contents, too. /// /// 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? { Ok(v) } else { @@ -233,11 +233,7 @@ impl Value { } /// Returns Some(v) or None to indicate the returned value is myself - async fn deep_force_( - myself: Value, - co: GenCo, - span: LightSpan, - ) -> Result<Option<Value>, ErrorKind> { + async fn deep_force_(myself: Value, co: GenCo, span: Span) -> Result<Option<Value>, ErrorKind> { // This is a stack of values which still remain to be forced. let mut vals = vec![myself]; @@ -256,7 +252,7 @@ impl Value { if !thunk_set.insert(t) { continue; } - Thunk::force_(t.clone(), &co, span.clone()).await? + Thunk::force_(t.clone(), &co, span).await? } else { v }; @@ -307,7 +303,7 @@ impl Value { self, co: GenCo, kind: CoercionKind, - span: LightSpan, + span: Span, ) -> Result<Value, ErrorKind> { self.coerce_to_string_(&co, kind, span).await } @@ -318,7 +314,7 @@ impl Value { self, co: &GenCo, kind: CoercionKind, - span: LightSpan, + span: Span, ) -> Result<Value, ErrorKind> { let mut result = BString::default(); let mut vals = vec![self]; @@ -331,7 +327,7 @@ impl Value { loop { let value = if let Some(v) = vals.pop() { - v.force(co, span.clone()).await? + v.force(co, span).await? } else { return Ok(Value::String(NixString::new_context_from(context, result))); }; @@ -377,7 +373,7 @@ impl Value { // `__toString` is preferred. (Value::Attrs(attrs), kind) => { 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 // to the function call. @@ -467,7 +463,7 @@ impl Value { other: Value, co: GenCo, ptr_eq: PointerEquality, - span: LightSpan, + span: Span, ) -> Result<Value, ErrorKind> { self.nix_eq(other, &co, ptr_eq, span).await } @@ -487,7 +483,7 @@ impl Value { other: Value, co: &GenCo, ptr_eq: PointerEquality, - span: LightSpan, + span: Span, ) -> Result<Value, ErrorKind> { // this is a stack of ((v1,v2),peq) triples to be compared; // 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, }; - let b = b.force(co, span.clone()).await?; + let b = b.force(co, span).await?; debug_assert!(!matches!(a, Value::Thunk(_))); debug_assert!(!matches!(b, Value::Thunk(_))); @@ -568,11 +564,11 @@ impl Value { #[allow(clippy::single_match)] // might need more match arms later match (a1.select("type"), a2.select("type")) { (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() { return Ok(s1); } - let s2 = v2.clone().force(co, span.clone()).await?; + let s2 = v2.clone().force(co, span).await?; if s2.is_catchable() { return Ok(s2); } @@ -593,8 +589,8 @@ impl Value { .context("comparing derivations")? .clone(); - let out1 = out1.clone().force(co, span.clone()).await?; - let out2 = out2.clone().force(co, span.clone()).await?; + let out1 = out1.clone().force(co, span).await?; + let out2 = out2.clone().force(co, span).await?; if out1.is_catchable() { return Ok(out1); @@ -745,7 +741,7 @@ impl Value { self, other: Self, co: GenCo, - span: LightSpan, + span: Span, ) -> Result<Result<Ordering, CatchableErrorKind>, ErrorKind> { Self::nix_cmp_ordering_(self, other, co, span).await } @@ -754,7 +750,7 @@ impl Value { myself: Self, other: Self, co: GenCo, - span: LightSpan, + span: Span, ) -> Result<Result<Ordering, CatchableErrorKind>, ErrorKind> { // this is a stack of ((v1,v2),peq) triples to be compared; // after each triple is popped off of the stack, v1 is @@ -770,14 +766,14 @@ impl Value { }; if ptr_eq == PointerEquality::AllowAll { if a.clone() - .nix_eq(b.clone(), &co, PointerEquality::AllowAll, span.clone()) + .nix_eq(b.clone(), &co, PointerEquality::AllowAll, span) .await? .as_bool()? { continue; } - a = a.force(&co, span.clone()).await?; - b = b.force(&co, span.clone()).await?; + a = a.force(&co, span).await?; + b = b.force(&co, span).await?; } let result = match (a, b) { (Value::Catchable(c), _) => return Ok(Err(*c)), @@ -820,7 +816,7 @@ impl Value { } // 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 { // TODO(amjoseph): use #[tailcall::mutual] return Thunk::force_(thunk, co, span).await; @@ -829,7 +825,7 @@ impl Value { } // 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 { // TODO(amjoseph): use #[tailcall::mutual] return Thunk::force_(thunk, &co, span).await; diff --git a/tvix/eval/src/value/thunk.rs b/tvix/eval/src/value/thunk.rs index a67537f945a9..6d1fe1b8a7cc 100644 --- a/tvix/eval/src/value/thunk.rs +++ b/tvix/eval/src/value/thunk.rs @@ -28,7 +28,6 @@ use std::{ use crate::{ errors::ErrorKind, opcode::OpCode, - spans::LightSpan, upvalues::Upvalues, value::Closure, vm::generators::{self, GenCo}, @@ -59,7 +58,7 @@ enum ThunkRepr { Suspended { lambda: Rc<Lambda>, upvalues: Rc<Upvalues>, - light_span: LightSpan, + span: Span, }, /// Thunk is a suspended native computation. @@ -69,10 +68,10 @@ enum ThunkRepr { /// value means that infinite recursion has occured. Blackhole { /// Span at which the thunk was first forced. - forced_at: LightSpan, + forced_at: Span, /// 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 /// 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 { upvalues: Rc::new(Upvalues::with_capacity(lambda.upvalue_count)), lambda: lambda.clone(), - light_span, + span, }))) } @@ -162,9 +161,8 @@ impl Thunk { /// particularly useful in builtin implementations if the result of calling /// a function does not need to be forced immediately, because e.g. it is /// 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 span = light_span.span(); let arg_idx = lambda.chunk().push_constant(arg); let f_idx = lambda.chunk().push_constant(callee); @@ -183,17 +181,15 @@ impl Thunk { Thunk(Rc::new(RefCell::new(ThunkRepr::Suspended { upvalues: Rc::new(Upvalues::with_capacity(0)), 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() { - ThunkRepr::Suspended { - light_span, lambda, .. - } => ThunkRepr::Blackhole { + ThunkRepr::Suspended { span, lambda, .. } => ThunkRepr::Blackhole { forced_at, - suspended_at: Some(light_span.clone()), + suspended_at: Some(*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 } - pub async fn force_( - mut myself: Thunk, - co: &GenCo, - span: LightSpan, - ) -> Result<Value, ErrorKind> { + pub async fn force_(mut myself: Thunk, co: &GenCo, span: Span) -> Result<Value, ErrorKind> { // This vector of "thunks which point to the thunk-being-forced", to // be updated along with it, is necessary in order to write this // 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 // that any other forcing frame encountering this thunk before its // 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 { // If there was already a blackhole in the thunk, this is an @@ -243,8 +235,8 @@ impl Thunk { content_span, } => { return Err(ErrorKind::InfiniteRecursion { - first_force: forced_at.span(), - suspended_at: suspended_at.map(|s| s.span()), + first_force: forced_at, + suspended_at, content_span, }) } @@ -262,13 +254,12 @@ impl Thunk { ThunkRepr::Suspended { lambda, upvalues, - light_span, + span, } => { // TODO(amjoseph): use #[tailcall::mutual] here. This can // be turned into a tailcall to vm::execute_bytecode() by // passing `also_update` to it. - let value = - generators::request_enter_lambda(co, lambda, upvalues, light_span).await; + let value = generators::request_enter_lambda(co, lambda, upvalues, span).await; myself.0.replace(ThunkRepr::Evaluated(value)); continue; } diff --git a/tvix/eval/src/vm/generators.rs b/tvix/eval/src/vm/generators.rs index dbf7703bf002..36b837dbee6e 100644 --- a/tvix/eval/src/vm/generators.rs +++ b/tvix/eval/src/vm/generators.rs @@ -81,7 +81,7 @@ pub enum VMRequest { EnterLambda { lambda: Rc<Lambda>, upvalues: Rc<Upvalues>, - light_span: LightSpan, + span: Span, }, /// Emit a runtime warning (already containing a span) through the VM. @@ -198,7 +198,7 @@ pub enum VMResponse { Directory(Vec<(bytes::Bytes, FileType)>), /// 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. Reader(Box<dyn std::io::Read>), @@ -234,7 +234,7 @@ where { /// Helper function to re-enqueue the current generator while it /// 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 { name, generator, @@ -244,7 +244,7 @@ where } /// 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 F: Future<Output = Result<Value, ErrorKind>> + 'static, G: FnOnce(GenCo) -> F, @@ -265,7 +265,7 @@ where pub(crate) fn run_generator( &mut self, name: &'static str, - span: LightSpan, + span: Span, frame_id: usize, state: GeneratorState, mut generator: Generator, @@ -302,8 +302,8 @@ where // this function prepares the frame stack and yields // back to the outer VM loop. VMRequest::ForceValue(value) => { - self.reenqueue_generator(name, span.clone(), generator); - self.enqueue_generator("force", span.clone(), |co| { + self.reenqueue_generator(name, span, generator); + self.enqueue_generator("force", span, |co| { value.force_owned_genco(co, span) }); return Ok(false); @@ -311,8 +311,8 @@ where // Generator has requested a deep-force. VMRequest::DeepForceValue(value) => { - self.reenqueue_generator(name, span.clone(), generator); - self.enqueue_generator("deep_force", span.clone(), |co| { + self.reenqueue_generator(name, span, generator); + self.enqueue_generator("deep_force", span, |co| { value.deep_force(co, span) }); return Ok(false); @@ -322,10 +322,10 @@ where // Logic is similar to `ForceValue`, except with the // value being taken from that stack. 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(); - self.enqueue_generator("force", span.clone(), |co| { + self.enqueue_generator("force", span, |co| { value.force_owned_genco(co, span) }); @@ -336,13 +336,13 @@ where // with-stack. Logic is same as above, except for the // value being from that stack. VMRequest::CapturedWithValue(idx) => { - self.reenqueue_generator(name, span.clone(), generator); + self.reenqueue_generator(name, span, generator); let call_frame = self.last_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(); - self.enqueue_generator("force", span.clone(), |co| { + self.enqueue_generator("force", span, |co| { value.force_owned_genco(co, span) }); @@ -351,23 +351,23 @@ where VMRequest::NixEquality(values, ptr_eq) => { let values = *values; - self.reenqueue_generator(name, span.clone(), generator); - self.enqueue_generator("nix_eq", span.clone(), |co| { + self.reenqueue_generator(name, span, generator); + self.enqueue_generator("nix_eq", span, |co| { values.0.nix_eq_owned_genco(values.1, co, ptr_eq, span) }); return Ok(false); } VMRequest::StringCoerce(val, kind) => { - self.reenqueue_generator(name, span.clone(), generator); - self.enqueue_generator("coerce_to_string", span.clone(), |co| { + self.reenqueue_generator(name, span, generator); + self.enqueue_generator("coerce_to_string", span, |co| { val.coerce_to_string(co, kind, span) }); return Ok(false); } VMRequest::Call(callable) => { - self.reenqueue_generator(name, span.clone(), generator); + self.reenqueue_generator(name, span, generator); self.call_value(span, None, callable)?; return Ok(false); } @@ -375,12 +375,12 @@ where VMRequest::EnterLambda { lambda, upvalues, - light_span, + span, } => { self.reenqueue_generator(name, span, generator); self.frames.push(Frame::CallFrame { - span: light_span, + span, call_frame: CallFrame { lambda, upvalues, @@ -424,7 +424,7 @@ where path: Some(path), error: e.into(), }) - .with_span(&span, self)?; + .with_span(span, self)?; message = VMResponse::Path(imported); } @@ -438,7 +438,7 @@ where path: Some(path), error: e.into(), }) - .with_span(&span, self)?; + .with_span(span, self)?; message = VMResponse::Reader(reader) } @@ -453,7 +453,7 @@ where error: e.into(), }) .map(Value::Bool) - .with_span(&span, self)?; + .with_span(span, self)?; message = VMResponse::Value(exists); } @@ -467,31 +467,31 @@ where path: Some(path), error: e.into(), }) - .with_span(&span, self)?; + .with_span(span, self)?; message = VMResponse::Directory(dir); } VMRequest::Span => { - message = VMResponse::Span(self.reasonable_light_span()); + message = VMResponse::Span(self.reasonable_span); } VMRequest::TryForce(value) => { self.try_eval_frames.push(frame_id); - self.reenqueue_generator(name, span.clone(), generator); + self.reenqueue_generator(name, span, generator); debug_assert!( self.frames.len() == frame_id + 1, "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) }); return Ok(false); } VMRequest::ToJson(value) => { - self.reenqueue_generator(name, span.clone(), generator); + self.reenqueue_generator(name, span, generator); self.enqueue_generator("to_json", span, |co| { value.into_contextful_json_generator(co) }); @@ -503,7 +503,7 @@ where // Generator has completed, and its result value should // be left on the stack. genawaiter::GeneratorState::Complete(result) => { - let value = result.with_span(&span, self)?; + let value = result.with_span(span, self)?; self.stack.push(value); return Ok(true); } @@ -683,12 +683,12 @@ pub(crate) async fn request_enter_lambda( co: &GenCo, lambda: Rc<Lambda>, upvalues: Rc<Upvalues>, - light_span: LightSpan, + span: Span, ) -> Value { let msg = VMRequest::EnterLambda { lambda, upvalues, - light_span, + span, }; 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 { VMResponse::Span(span) => span, msg => panic!( diff --git a/tvix/eval/src/vm/macros.rs b/tvix/eval/src/vm/macros.rs index d8a09706ab9c..f9c084d41f91 100644 --- a/tvix/eval/src/vm/macros.rs +++ b/tvix/eval/src/vm/macros.rs @@ -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.enqueue_generator("compare", gen_span, |co| compare(a, b, co)); return Ok(false); diff --git a/tvix/eval/src/vm/mod.rs b/tvix/eval/src/vm/mod.rs index 48dcdfc8df47..65117b79a0bc 100644 --- a/tvix/eval/src/vm/mod.rs +++ b/tvix/eval/src/vm/mod.rs @@ -28,7 +28,6 @@ use crate::{ nix_search_path::NixSearchPath, observer::RuntimeObserver, opcode::{CodeIdx, Count, JumpOffset, OpCode, StackIdx, UpvalueIdx}, - spans::LightSpan, upvalues::Upvalues, value::{ Builtin, BuiltinResult, Closure, CoercionKind, Lambda, NixAttrs, NixContext, NixList, @@ -51,7 +50,7 @@ trait GetSpan { impl<'o, IO> GetSpan for &VM<'o, IO> { 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 { - self.span() + *self } } @@ -94,7 +93,7 @@ impl<T, S: GetSpan, IO> WithSpan<T, S, IO> for Result<T, ErrorKind> { Frame::CallFrame { span, .. } => { error = Error::new( ErrorKind::BytecodeError(Box::new(error)), - span.span(), + *span, vm.source.clone(), ); } @@ -104,7 +103,7 @@ impl<T, S: GetSpan, IO> WithSpan<T, S, IO> for Result<T, ErrorKind> { err: Box::new(error), gen_type: name, }, - span.span(), + *span, vm.source.clone(), ); } @@ -163,13 +162,6 @@ impl CallFrame { pub fn current_span(&self) -> Span { 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 @@ -187,7 +179,7 @@ enum Frame { call_frame: CallFrame, /// Span from which the call frame was launched. - span: LightSpan, + span: Span, }, /// Generator represents a frame that can yield further @@ -201,7 +193,7 @@ enum Frame { name: &'static str, /// Span from which the generator was launched. - span: LightSpan, + span: Span, state: GeneratorState, @@ -211,9 +203,9 @@ enum Frame { } impl Frame { - pub fn span(&self) -> LightSpan { + pub fn span(&self) -> Span { 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. /// 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 /// builtin is encountered, it sends a special message to the VM which @@ -343,7 +335,7 @@ where observer: &'o mut dyn RuntimeObserver, source: SourceCode, globals: Rc<GlobalsMap>, - reasonable_span: LightSpan, + reasonable_span: Span, ) -> Self { Self { nix_search_path, @@ -362,7 +354,7 @@ where } /// 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 }) } @@ -444,7 +436,7 @@ where /// /// The return value indicates whether the bytecode has been executed to /// 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 { let op = frame.inc_ip(); self.observer.observe_execute_op(frame.ip, &op, &self.stack); @@ -464,7 +456,7 @@ where ); Thunk::new_closure(blueprint) } else { - Thunk::new_suspended(blueprint, frame.current_light_span()) + Thunk::new_suspended(blueprint, frame.current_span()) }; let upvalues = thunk.upvalues_mut(); self.stack.push(Value::Thunk(thunk.clone())); @@ -484,10 +476,10 @@ where _ => unreachable!(), }; - let gen_span = frame.current_light_span(); + let gen_span = frame.current_span(); 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) }); @@ -515,7 +507,7 @@ where OpCode::OpCall => { 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 return Ok(true); @@ -640,9 +632,9 @@ where OpCode::OpEqual => lifted_pop! { self(b, a) => { - let gen_span = frame.current_light_span(); + let gen_span = frame.current_span(); 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) }); return Ok(false); @@ -739,7 +731,7 @@ where let ident = self.stack_pop().to_str().with_span(&frame, self)?; // Re-enqueue this frame. - let op_span = frame.current_light_span(); + let op_span = frame.current_span(); self.push_call_frame(span, frame); // Construct a generator frame doing the lookup in constant @@ -770,10 +762,10 @@ where OpCode::OpCoerceToString(kind) => { 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.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) }); @@ -808,7 +800,7 @@ where OpCode::OpAdd => lifted_pop! { self(b, a) => { - let gen_span = frame.current_light_span(); + let gen_span = frame.current_span(); self.push_call_frame(span, frame); // OpAdd can add not just numbers, but also string-like @@ -1004,12 +996,6 @@ where 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. /// /// 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 /// 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(); self.observer.observe_enter_builtin(builtin_name); @@ -1041,8 +1027,8 @@ where fn call_value( &mut self, - span: LightSpan, - parent: Option<(LightSpan, CallFrame)>, + span: Span, + parent: Option<(Span, CallFrame)>, callable: Value, ) -> EvalResult<()> { match callable { @@ -1098,7 +1084,7 @@ where 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, source, globals, - root_span.into(), + root_span, ); // When evaluating strictly, synthesise a frame that will instruct // the VM to deep-force the final value before returning it. 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 { - span: root_span.into(), + span: root_span, call_frame: CallFrame { lambda, upvalues: Rc::new(Upvalues::with_capacity(0)), |