Skip to content

[Feature] Implement array slicing and concatenation.#29061

Draft
d0cd wants to merge 2 commits into
masterfrom
feat/array-slicing-refresh
Draft

[Feature] Implement array slicing and concatenation.#29061
d0cd wants to merge 2 commits into
masterfrom
feat/array-slicing-refresh

Conversation

@d0cd

@d0cd d0cd commented Jan 12, 2026

Copy link
Copy Markdown
Contributor

Motivation

This PR adds array slicing and concatenation support to Leo, enabling more expressive and convenient array manipulation.

Array Slicing allows extracting a contiguous portion of an array using Rust-like syntax:

let arr: [u32; 8] = [0u32, 1u32, 2u32, 3u32, 4u32, 5u32, 6u32, 7u32];
let a: [u32; 3] = arr[2..5];    // [2, 3, 4] - exclusive end
let b: [u32; 4] = arr[2..=5];   // [2, 3, 4, 5] - inclusive end
let c: [u32; 5] = arr[3..];     // [3, 4, 5, 6, 7] - slice to end
let d: [u32; 4] = arr[..4];     // [0, 1, 2, 3] - slice from start
let e: [u32; 8] = arr[..];      // full copy

Array Concatenation allows combining two arrays with matching element types using the + operator:

let a: [u32; 2] = [1u32, 2u32];
let b: [u32; 2] = [3u32, 4u32];
let c: [u32; 4] = a + b;        // [1, 2, 3, 4]
let d: [u32; 6] = a + b + a;    // chained concatenation
let e: [u32; 4] = a[0..1] + b;  // slice then concatenate

Both features are resolved at compile time - slices and concatenations are expanded to individual element accesses, ensuring no runtime overhead.

Test Plan

Slicing Tests:

Test Description
slice_basic.leo Basic arr[2..5] exclusive end slice
slice_inclusive.leo Inclusive arr[2..=5] slice
slice_from_start.leo Open-start arr[..5] slice
slice_to_end.leo Open-end arr[3..] slice
slice_full.leo Full slice arr[..]
slice_with_variables.leo Const variable bounds
slice_out_of_bounds_fail.leo Error: bounds exceed array length
slice_invalid_range_fail.leo Error: start > end

Concatenation Tests:

Test Description
array_concat.leo Basic a + b, nested arrays, different sizes
array_concat_chained.leo Chained a + b + c
array_concat_with_slice.leo Combined a[0..2] + b[2..4]
array_concat_type_mismatch_fail.leo Error: mismatched element types

Related PRs

@d0cd

d0cd commented Jan 16, 2026

Copy link
Copy Markdown
Contributor Author

Self-Review Finding

Found one bug that should be fixed:

BUG: Empty slices pass type checking but fail at runtime

Location: compiler/passes/src/type_checking/ast.rs (around line 536)

Empty slices like arr[5..5] pass type checking but fail in the interpreter due to inconsistent boundary checks:

Component Check Allows start == end?
Type checker end < start Yes (produces 0-length slice)
Interpreter end <= start No (returns None, causing runtime error)

Fix: Change the type checker to reject start == end:

// Before
if end < start {
    self.emit_err(TypeCheckerError::slice_range_invalid(start, end, input.span()));

// After  
if end <= start {
    self.emit_err(TypeCheckerError::slice_range_invalid(start, end, input.span()));

Consider adding a test case like slice_empty_fail.leo with arr[5..5] to verify the fix.

@d0cd d0cd force-pushed the feat/array-slicing-refresh branch from 5a85da2 to cfeaad0 Compare February 16, 2026 05:19
Comment thread errors/src/errors/type_checker/type_checker_error.rs Outdated
@d0cd d0cd force-pushed the feat/array-slicing-refresh branch from 9c5a06c to 39539b1 Compare February 27, 2026 00:29

@mohammadfawaz mohammadfawaz left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall no concerns! Just a few comments. There area a bunch of CLAUDE.md files.. do these need to be checked in?

@@ -0,0 +1,3 @@
<claude-mem-context>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this file intentional?

@@ -0,0 +1,3 @@
<claude-mem-context>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same

Comment thread crates/fmt/src/CLAUDE.md
@@ -0,0 +1,3 @@
<claude-mem-context>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same

@@ -0,0 +1,5 @@
Error [ETYC0372176]: Slice range `5..5` is invalid: end must be greater than start.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do allow zero-sized types and zero ranges (in loops). Should we allow the same here?

return Err(CompilerError::repeat_count_not_evaluated(not_evaluated_span).into());
}

if let Some(not_evaluated_span) = const_prop_output.slice_bounds_not_evaluated {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if, in something like arr[start..end], we're only able to const evaluate start in iteration i but end can only be evaluated in iteration i+1 (think nested loops etc.)? Will we error out early and keep iterating?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants