diff --git a/tests/debug.rs b/tests/debug.rs index 3c3f1ab615..057c395a03 100644 --- a/tests/debug.rs +++ b/tests/debug.rs @@ -79,6 +79,43 @@ fn line_hook() { vec![1, 3, 4, 3, 1].into_iter().map(Line::from).collect::>()); } +#[test] +fn implicit_prelude_lines_not_counted() { + let _ = env_logger::init(); + + let thread = new_vm(); + { + let mut context = thread.context(); + context.set_hook(Some(Box::new(move |_, debug_info| { + if debug_info.stack_info(0).unwrap().source_name() == "test" { + Err(vm::Error::Yield) + } else { + Ok(()) + } + }))); + context.set_hook_mask(LINE_FLAG); + } + let mut result = Compiler::new() + .run_expr::(&thread, "test", "1") + .map(|_| ()); + + let mut lines = Vec::new(); + loop { + match result { + Ok(_) => break, + Err(Error::VM(vm::Error::Yield)) => { + let context = thread.context(); + let debug_info = context.debug_info(); + let stack_info = debug_info.stack_info(0).unwrap(); + lines.push(stack_info.line().unwrap()); + } + Err(err) => panic!("{}", err), + } + result = thread.resume().map_err(From::from); + } + + assert_eq!(lines, vec![Line::from(0)]); +} #[test] fn read_variables() { diff --git a/vm/src/compiler.rs b/vm/src/compiler.rs index 44ef51aeae..36a90bb1d2 100644 --- a/vm/src/compiler.rs +++ b/vm/src/compiler.rs @@ -6,7 +6,7 @@ use base::kind::{ArcKind, KindEnv}; use base::types::{self, Alias, ArcType, Type, TypeEnv}; use base::scoped_map::ScopedMap; use base::symbol::{Symbol, SymbolRef, SymbolModule}; -use base::pos::Line; +use base::pos::{Line, NO_EXPANSION}; use base::source::Source; use types::*; use vm::GlobalVmState; @@ -74,8 +74,11 @@ struct FunctionEnv { /// The variables currently in scope in the this function. stack: ScopedMap, /// The current size of the stack. Not the same as `stack.len()`. + /// The current size of the stack. Not the same as `stack.len()`. stack_size: VmIndex, + /// The variables which this function takes from the outer scope free_vars: Vec, + /// The line where instructions are currently being emitted current_line: Line, function: CompiledFunction, } @@ -457,13 +460,19 @@ impl<'a> Compiler<'a> { // Store a stack of expressions which need to be cleaned up after this "tailcall" loop is // done function.stack.enter_scope(); - function.current_line = self.source - .line_number_at_byte(expr.span.start); - while let Some(next) = self.compile_(expr, function, tail_position)? { - expr = next; + // Don't update the current_line for macro expanded code as the lines in that code do not come + // from this module + if expr.span.expansion_id == NO_EXPANSION { function.current_line = self.source .line_number_at_byte(expr.span.start); } + while let Some(next) = self.compile_(expr, function, tail_position)? { + expr = next; + if expr.span.expansion_id == NO_EXPANSION { + function.current_line = self.source + .line_number_at_byte(expr.span.start); + } + } let count = function.exit_scope(self); function.emit(Slide(count)); Ok(()) diff --git a/vm/src/source_map.rs b/vm/src/source_map.rs index 97f3934505..81b88ca277 100644 --- a/vm/src/source_map.rs +++ b/vm/src/source_map.rs @@ -17,8 +17,8 @@ impl SourceMap { /// Defines the instruction at `instruction_index` to be at `current_line`. /// This function must be called with indexes in increasing order pub fn emit(&mut self, instruction_index: usize, current_line: Line) { - let last_emitted_line = self.map.last().map_or(Line::from(0), |&(_, x)| x); - if last_emitted_line != current_line { + let last_emitted_line = self.map.last().map(|&(_, x)| x); + if last_emitted_line != Some(current_line) { self.map.push((instruction_index, current_line)); } }