Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
579fe93
Advance the for-loop index on continue
micahscopes Sep 25, 2026
ceb4ec8
Parse generic arguments that start with a qualified type
micahscopes Sep 25, 2026
80ee1f1
Test generic trait parameters on Self associated types in impls
micahscopes Sep 25, 2026
27b4acb
Resolve Self associated types declared by a supertrait
micahscopes Sep 25, 2026
e15f10a
Test shifts compared against a qualified associated constant
micahscopes Sep 26, 2026
53b847b
Skip the for-loop advance block when nothing reaches it
sbillig Sep 28, 2026
fd291c8
Parse `<<` as generic arguments only before a qualified path
sbillig Sep 28, 2026
a2a1699
Keep a bare qualified first generic argument spaced when formatting
sbillig Sep 28, 2026
938b152
Merge inherited and contextual associated-type candidates
sbillig Sep 28, 2026
6b69446
Normalize associated-type candidates with their implied bounds
sbillig Sep 28, 2026
ccd46d3
Reuse speculative parse outcomes per position
sbillig Sep 29, 2026
a1b41e2
Accept a qualified first generic argument on a method call
sbillig Sep 29, 2026
14f04dd
Consult the dry run error flag before caching a probe
sbillig Sep 29, 2026
cd37d81
Parse a qualified first generic argument in the grammar too
sbillig Sep 29, 2026
392092b
Skip strings and comments in the generic-argument lookahead
sbillig Sep 29, 2026
0acbfa0
Confine probe recovery to the scopes the probe opened
sbillig Sep 29, 2026
8ad84af
Emit the for-loop advance only when something reaches it
sbillig Sep 29, 2026
879e74b
Test for loops that continue from an if or match arm next to an exit
micahscopes Sep 29, 2026
6ab7110
Resolve a parameter's associated type only from its own bounds
micahscopes Sep 28, 2026
8d7b392
Name trait arguments in ambiguous associated item hints
micahscopes Sep 28, 2026
097f84e
Test packed record layout through raw pointer projections
micahscopes Sep 22, 2026
cc15956
Distinguish finite nested layouts from expanding types
micahscopes Sep 21, 2026
fd3a0d9
Test that layout growth through wrappers is rejected in bounded time
micahscopes Sep 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions crates/codegen/tests/fixtures/sonatina_ir/for_array.snap
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,32 @@ func private %for_array_sum() -> i64 {
jump block2;

block2:
v51.i64 = phi (0.i64 block1) (v37 block7);
v30.i256 = phi (0.i256 block1) (v45 block7);
v51.i64 = phi (0.i64 block1) (v37 block8);
v30.i256 = phi (0.i256 block1) (v45 block8);
v32.i1 = lt v30 v29;
br v32 block3 block4;
br v32 block3 block5;

block3:
v35.i64 = call %get v26 v30;
(v37.i64, v38.i1) = uaddo v51 v35;
br v38 block5 block6;
br v38 block6 block7;

block4:
return v51;
(v45.i256, v46.i1) = uaddo v30 1.i256;
br v46 block6 block8;

block5:
return v51;

block6:
mstore 0.i256 35408467139433450592217433187231851964531694900788300625387963629091585785856.i256 i256;
mstore 4.i256 17.i256 i256;
evm_revert 0.i256 36.i256;

block6:
(v45.i256, v46.i1) = uaddo v30 1.i256;
br v46 block5 block7;

block7:
jump block4;

block8:
jump block2;
}

Expand Down
21 changes: 12 additions & 9 deletions crates/codegen/tests/fixtures/sonatina_ir/for_array_large.snap
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,32 @@ func private %for_array_large_sum() -> i64 {
jump block2;

block2:
v36.i64 = phi (0.i64 block1) (v22 block7);
v15.i256 = phi (0.i256 block1) (v30 block7);
v36.i64 = phi (0.i64 block1) (v22 block8);
v15.i256 = phi (0.i256 block1) (v30 block8);
v17.i1 = lt v15 v14;
br v17 block3 block4;
br v17 block3 block5;

block3:
v20.i64 = call %get v11 v15;
(v22.i64, v23.i1) = uaddo v36 v20;
br v23 block5 block6;
br v23 block6 block7;

block4:
return v36;
(v30.i256, v31.i1) = uaddo v15 1.i256;
br v31 block6 block8;

block5:
return v36;

block6:
mstore 0.i256 35408467139433450592217433187231851964531694900788300625387963629091585785856.i256 i256;
mstore 4.i256 17.i256 i256;
evm_revert 0.i256 36.i256;

block6:
(v30.i256, v31.i1) = uaddo v15 1.i256;
br v31 block5 block7;

block7:
jump block4;

block8:
jump block2;
}

Expand Down
21 changes: 12 additions & 9 deletions crates/codegen/tests/fixtures/sonatina_ir/for_range.snap
Original file line number Diff line number Diff line change
Expand Up @@ -19,29 +19,32 @@ func private %for_range_sum() -> i256 {
jump block2;

block2:
v25.i256 = phi (0.i256 block1) (v11 block7);
v4.i256 = phi (0.i256 block1) (v19 block7);
v25.i256 = phi (0.i256 block1) (v11 block8);
v4.i256 = phi (0.i256 block1) (v19 block8);
v6.i1 = lt v4 v3;
br v6 block3 block4;
br v6 block3 block5;

block3:
v9.i256 = call %get v2 v4;
(v11.i256, v12.i1) = uaddo v25 v9;
br v12 block5 block6;
br v12 block6 block7;

block4:
return v25;
(v19.i256, v20.i1) = uaddo v4 1.i256;
br v20 block6 block8;

block5:
return v25;

block6:
mstore 0.i256 35408467139433450592217433187231851964531694900788300625387963629091585785856.i256 i256;
mstore 4.i256 17.i256 i256;
evm_revert 0.i256 36.i256;

block6:
(v19.i256, v20.i1) = uaddo v4 1.i256;
br v20 block5 block7;

block7:
jump block4;

block8:
jump block2;
}

Expand Down
21 changes: 12 additions & 9 deletions crates/codegen/tests/fixtures/sonatina_ir/range_bounds.snap
Original file line number Diff line number Diff line change
Expand Up @@ -58,29 +58,32 @@ func private %sum_const() -> i256 {
jump block2;

block2:
v20.i256 = phi (0.i256 block1) (v9 block7);
v3.i256 = phi (0.i256 block1) (v16 block7);
v20.i256 = phi (0.i256 block1) (v9 block8);
v3.i256 = phi (0.i256 block1) (v16 block8);
v5.i1 = lt v3 v2;
br v5 block3 block4;
br v5 block3 block5;

block3:
v7.i256 = call %get v3;
(v9.i256, v10.i1) = uaddo v20 v7;
br v10 block5 block6;
br v10 block6 block7;

block4:
return v20;
(v16.i256, v17.i1) = uaddo v3 1.i256;
br v17 block6 block8;

block5:
return v20;

block6:
mstore 0.i256 35408467139433450592217433187231851964531694900788300625387963629091585785856.i256 i256;
mstore 4.i256 17.i256 i256;
evm_revert 0.i256 36.i256;

block6:
(v16.i256, v17.i1) = uaddo v3 1.i256;
br v17 block5 block7;

block7:
jump block4;

block8:
jump block2;
}

Expand Down
Binary file modified crates/fe-web/vendor/tree-sitter-fe.wasm
Binary file not shown.
2 changes: 1 addition & 1 deletion crates/fe-web/vendor/tree-sitter-fe.wasm.inputs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

162 changes: 162 additions & 0 deletions crates/fe/tests/fixtures/fe_test/for_continue_advances.fe
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
#[test]
fn unconditional_continue_advances_sequence() {
let mut visits: usize = 0
for i in 0..5 {
visits += 1
assert!(visits <= 5)
continue
}
assert!(visits == 5)
}

#[test]
fn nested_continue_advances_only_inner_sequence() {
let mut visits: usize = 0
let mut sum: usize = 0
for outer in 0..3 {
for inner in 0..4 {
visits += 1
assert!(visits <= 12)
if inner % 2 == 0 { continue }
sum += outer + inner
}
}
assert!(visits == 12)
assert!(sum == 18)
}

#[test]
fn continue_and_break_preserve_sequence_order() {
let mut visits: usize = 0
for i in 0..8 {
visits += 1
assert!(visits <= 5)
if i < 4 { continue }
assert!(i == 4)
break
}
assert!(visits == 5)
}

#[test]
fn while_continue_does_not_advance_enclosing_sequence() {
let mut visits: usize = 0
let mut sum: usize = 0
for outer in 0..3 {
let mut inner: usize = 0
while inner < 3 {
inner += 1
visits += 1
assert!(visits <= 9)
if inner < 3 { continue }
sum += outer
}
}
assert!(visits == 9)
assert!(sum == 3)
}

#[test]
fn unconditional_break_leaves_after_first_element() {
let mut visits: usize = 0
for i in 0..5 {
visits += 1
break
}
assert!(visits == 1)
}

fn first(_ values: [usize; 3]) -> usize {
for value in values {
return value
}
0
}

#[test]
fn unconditional_return_yields_first_element() {
assert!(first([7, 8, 9]) == 7)
}

fn leading_zero(_ values: [usize; 3]) -> bool {
for value in values {
if value == 0 { return true } else { break }
}
false
}

#[test]
fn exiting_on_every_branch_inspects_only_first_element() {
assert!(leading_zero([0, 5, 5]))
assert!(!leading_zero([5, 0, 0]))
}

fn abort() -> ! {
let code: u256 = 1
std::evm::revert(code)
}

#[test(should_revert)]
fn diverging_body_reverts() {
for i in 0..3 {
abort()
}
}

fn ignore(_ value: usize, _ other: usize) {}

#[test(should_revert)]
fn continue_after_diverging_argument_is_unreachable() {
for i in 0..3 {
ignore(abort(), { continue })
}
}

fn first_even(_ values: [u256; 5]) -> u256 {
for value in values {
if value % 2 == 1 {
continue
} else {
return value
}
}
return 0
}

#[test]
fn continue_arm_advances_when_other_arms_exit() {
assert!(first_even([1, 3, 6, 5, 8]) == 6)
assert!(first_even([1, 3, 5, 7, 9]) == 0)
}

#[test]
fn continue_or_break_in_every_arm() {
let mut visits: usize = 0
let mut last: usize = 0
for i in 0..8 {
visits += 1
assert!(visits <= 4)
last = i
match i < 3 {
true => { continue }
false => { break }
}
}
assert!(visits == 4)
assert!(last == 3)
}

#[test]
fn only_inner_body_always_exits() {
let mut outer_visits: usize = 0
let mut inner_visits: usize = 0
for outer in 0..3 {
outer_visits += 1
for inner in 0..4 {
inner_visits += 1
break
}
}
assert!(outer_visits == 3)
assert!(inner_visits == 3)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
pub trait T<A> {
type Out
fn f(_ a: A) -> Self::Out
}

pub struct X {}

pub struct Wrap<P> {}

impl T<u256> for X {
type Out = u256
fn f(_ a: u256) -> u256 {
a + 1
}
}

// The impl stays generic over the trait's own parameter `A`.
impl<A: core::marker::Copy, P: T<A>> T<A> for Wrap<P> {
type Out = (<P as T<A>>::Out, A)
fn f(_ a: A) -> Self::Out {
(P::f(a), a)
}
}

pub fn use_it() -> (u256, u256) {
<Wrap<X> as T<u256>>::f(4)
}

#[test]
fn generic_trait_arg_impl_normalizes_self_out() {
let r = use_it()
assert!(r.0 == 5)
assert!(r.1 == 4)
}
Loading
Loading