From f1c04bb8e98e5cb6a387712b8a0a87b333fb577e Mon Sep 17 00:00:00 2001 From: Tim Fennis Date: Sun, 24 May 2026 12:46:34 +0200 Subject: [PATCH] =?UTF-8?q?perf(vm):=20defer=20GetIterator=20type=20string?= =?UTF-8?q?ification=20to=20error=20path=20=F0=9F=A6=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `OpCode::GetIterator` was eagerly building the "X is not iterable" error message before checking whether the value was iterable. For deeply nested containers (e.g. `List>>>`), `val.static_type()` recursively walks every element and allocates a fresh `StaticType` tree — which was then thrown away in the common case because the value *was* iterable. Moving the call into the actual error branch turns a per-iter O(n) deep walk into a check that only runs when iteration actually fails. Co-Authored-By: Claude Opus 4.7 (1M context) --- ndc_vm/src/vm.rs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/ndc_vm/src/vm.rs b/ndc_vm/src/vm.rs index 4ad660d..2188a3a 100644 --- a/ndc_vm/src/vm.rs +++ b/ndc_vm/src/vm.rs @@ -387,22 +387,16 @@ impl Vm { continue; } - // Get type string before moving val - let type_str = format!("{}", val.static_type()); - - // Try to create an iterator - let iter_val = match val { + let iter_val = match &val { Value::Object(rc) => match rc.as_ref() { - Object::List(_) | Object::Tuple(_) | Object::Deque(_) => { - Some(Value::iterator(Rc::new(RefCell::new(SeqIter::new( - Rc::clone(&rc), - ))))) - } + Object::List(_) | Object::Tuple(_) | Object::Deque(_) => Some( + Value::iterator(Rc::new(RefCell::new(SeqIter::new(Rc::clone(rc))))), + ), Object::String(s) => Some(Value::iterator(Rc::new(RefCell::new( StringIter::new(Rc::clone(s)), )))), Object::Map { .. } => Some(Value::iterator(Rc::new(RefCell::new( - MapIter::new(Rc::clone(&rc)), + MapIter::new(Rc::clone(rc)), )))), Object::MinHeap(h) => { Some(Value::iterator(Rc::new(RefCell::new(HeapIter::new_min(h))))) @@ -419,7 +413,7 @@ impl Vm { Some(iter) => self.stack.push(iter), None => { return Err(VmError::new( - format!("{} is not iterable", type_str), + format!("{} is not iterable", val.static_type()), span, )); }