diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index 6794f9e55..a5dcc185a 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -1079,7 +1079,8 @@ thread_local! { /// Creates an iterator over the captures in a query within the given range, /// re-using a cursor from the pool if available. -fn query_captures<'a, 'tree>( +/// SAFETY: The `QueryCaptures` must be droped before the `QueryCursor` is dropped. +unsafe fn query_captures<'a, 'tree>( query: &'a Query, root: Node<'tree>, source: RopeSlice<'a>, @@ -1094,10 +1095,11 @@ fn query_captures<'a, 'tree>( highlighter.cursors.pop().unwrap_or_default() }); + // This is the unsafe line: // The `captures` iterator borrows the `Tree` and the `QueryCursor`, which // prevents them from being moved. But both of these values are really just // pointers, so it's actually ok to move them. - let cursor_ref = unsafe { mem::transmute::<_, &'static mut QueryCursor>(&mut cursor) }; + let cursor_ref = mem::transmute::<_, &'static mut QueryCursor>(&mut cursor); // if reusing cursors & no range this resets to whole range cursor_ref.set_byte_range(range.unwrap_or(0..usize::MAX)); @@ -1460,12 +1462,14 @@ impl Syntax { .layers .iter() .filter_map(|(_, layer)| { - let (cursor, captures) = query_captures( - query_fn(&layer.config), - layer.tree().root_node(), - source, - range.clone(), - ); + let (cursor, captures) = unsafe { + query_captures( + query_fn(&layer.config), + layer.tree().root_node(), + source, + range.clone(), + ) + }; let mut captures = captures.peekable(); // If there aren't any captures for this layer, skip the layer. @@ -1497,12 +1501,14 @@ impl Syntax { .filter_map(|(_, layer)| { // TODO: if range doesn't overlap layer range, skip it - let (cursor, captures) = query_captures( - &layer.config.query, - layer.tree().root_node(), - source, - range.clone(), - ); + let (cursor, captures) = unsafe { + query_captures( + &layer.config.query, + layer.tree().root_node(), + source, + range.clone(), + ) + }; let mut captures = captures.peekable(); // If there are no captures, skip the layer