-
Notifications
You must be signed in to change notification settings - Fork 547
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add support for the ..=
RangeInclusive syntax
#6972
base: main
Are you sure you want to change the base?
feat: add support for the ..=
RangeInclusive syntax
#6972
Conversation
17331b6
to
ee47ba0
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed 5 of 16 files at r1, 3 of 4 files at r2.
Reviewable status: 8 of 16 files reviewed, 6 unresolved discussions (waiting on @cairoIover)
corelib/src/ops.cairo
line 16 at r2 (raw file):
// `RangeOp` is used internally by the compiler. #[allow(unused_imports)] use range::RangeOp;
Suggestion:
// `RangeOp` and `RangeInclusiveOp` are used internally by the compiler.
#[allow(unused_imports)]
use range::{RangeOp, RangeInclusiveOp};
crates/cairo-lang-parser/src/lexer.rs
line 282 at r2 (raw file):
_ => TokenKind::DotDot, } }
Suggestion:
Some('.') => self.pick_kind('=', TokenKind::DotDotEq, TokenKind::DotDot),
corelib/src/ops/range.cairo
line 145 at r2 (raw file):
} } }
Suggestion:
impl RangeInclusiveIteratorImpl<
T, +One<T>, +Add<T>, +Copy<T>, +Drop<T>, +PartialEq<T>, +PartialOrd<T>,
> of Iterator<RangeInclusiveIterator<T>> {
type Item = T;
fn next(ref self: RangeInclusiveIterator<T>) -> Option<T> {
let next = self.cur + One::one();
if next != self.end {
let value = self.cur;
self.cur = next;
Option::Some(value)
} else {
Option::None
}
}
}
corelib/src/ops/range.cairo
line 167 at r2 (raw file):
} } }
Suggestion:
pub impl RangeInclusiveIntoIterator<
T,
+One<T>,
+Add<T>,
+Copy<T>,
+Drop<T>,
+PartialEq<T>,
+PartialOrd<T>,
-SierraIntRangeSupport<T>,
> of IntoIterator<RangeInclusive<T>> {
type IntoIter = RangeInclusiveIterator<T>;
fn into_iter(self: RangeInclusive<T>) -> Self::IntoIter {
if self.start <= self.end {
Self::IntoIter { cur: self.start, end: self.end }
} else {
// Since `self.end < self.start` this will never overflow.
let after_end = self.end + One::one();
Self::IntoIter { cur: after_end, end: self.end }
}
}
}
corelib/src/test/range_test.cairo
line 23 at r2 (raw file):
assert!(iter.next() == Option::Some(3)); assert!(iter.next() == Option::None); }
Suggestion:
#[test]
fn test_range_inclusive_iterator() {
let mut iter = (1_usize..=3).into_iter();
assert!(iter.next() == Option::Some(1));
assert!(iter.next() == Option::Some(2));
assert!(iter.next() == Option::Some(3));
assert!(iter.next() == Option::None);
}
#[test]
fn test_range_inclusive_iterator_range_end() {
let mut iter = (253_u8..=255).into_iter();
assert!(iter.next() == Option::Some(253));
assert!(iter.next() == Option::Some(254));
assert!(iter.next() == Option::Some(255));
assert!(iter.next() == Option::None);
}
#[test]
fn test_range_inclusive_empty_ranges() {
let mut iter = (255_u8..=125).into_iter();
assert!(iter.next() == Option::None);
let mut iter = (255_u8..=0).into_iter();
assert!(iter.next() == Option::None);
}
crates/cairo-lang-syntax/src/node/key_fields.rs
line 2 at r2 (raw file):
// Autogenerated file. To regenerate, please run `cargo run --bin generate-syntax`.
use the same rust_fmt.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewable status: 8 of 16 files reviewed, 6 unresolved discussions (waiting on @orizi)
crates/cairo-lang-syntax/src/node/key_fields.rs
line 2 at r2 (raw file):
Previously, orizi wrote…
use the same rust_fmt.
this is what running cargo run --bin generate-syntax gets me 🤔
corelib/src/ops/range.cairo
line 145 at r2 (raw file):
} } }
I don't believe this logic to be valid; counter examples:
1.
starting state: cur = 10
, end=11
=> next=11
=> next == end
=> return Option::None
when this should be returning Some(11)
I am proposing something else; see new code with a boolean flag for exhaustion.
corelib/src/ops/range.cairo
line 167 at r2 (raw file):
} } }
I think this could overflow on integer bounds. see new proposal
corelib/src/test/range_test.cairo
line 23 at r2 (raw file):
assert!(iter.next() == Option::Some(3)); assert!(iter.next() == Option::None); }
Done.
corelib/src/ops.cairo
line 16 at r2 (raw file):
// `RangeOp` is used internally by the compiler. #[allow(unused_imports)] use range::RangeOp;
Done.
crates/cairo-lang-parser/src/lexer.rs
line 282 at r2 (raw file):
_ => TokenKind::DotDot, } }
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed 4 of 16 files at r1, 6 of 6 files at r3, all commit messages.
Reviewable status: all files reviewed, 1 unresolved discussion (waiting on @cairoIover)
a discussion (no related file):
@gilbens-starkware @TomerStarkware @dean-starkware multiple second eyes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewable status: all files reviewed, 5 unresolved discussions (waiting on @cairoIover)
corelib/src/ops/range.cairo
line 115 at r3 (raw file):
#[derive(Clone, Drop)] pub struct RangeInclusiveIterator<T> {
T: PartialOrd + Clone
Code quote:
T
corelib/src/ops/range.cairo
line 133 at r3 (raw file):
pub impl RangeInclusiveOpImpl<T> of RangeInclusiveOp<T> { /// Handles the `..=` operator. Returns the value of the expression `start..=end`. fn range_inclusive(start: T, end: T) -> RangeInclusive<T> {
assert!(start <= end, "start must be less than or equal to end");
corelib/src/ops/range.cairo
line 153 at r3 (raw file):
fn next(ref self: RangeInclusiveIterator<T>) -> Option<T> { if self.exhausted {
Instead of using a manual exhausted
flag, consider leveraging the range bounds directly (e.g., self.cur > self.end
).
If self.cur
or self.end
is mutated outside this struct (e.g., via unsafe code or direct access), the exhausted
flag may no longer correctly represent the iterator's state.
corelib/src/ops/range.cairo
line 184 at r3 (raw file):
fn into_iter(self: RangeInclusive<T>) -> Self::IntoIter { let exhausted = self.start > self.end;
For non-primitive types, this comparison might be expensive.
Maybe try to cache the result of this check during construction if it is used frequently?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewable status: all files reviewed, 5 unresolved discussions (waiting on @dean-starkware)
corelib/src/ops/range.cairo
line 115 at r3 (raw file):
Previously, dean-starkware wrote…
T: PartialOrd + Clone
not sure I understand what you mean here
corelib/src/ops/range.cairo
line 133 at r3 (raw file):
Previously, dean-starkware wrote…
assert!(start <= end, "start must be less than or equal to end");
I don't think the operator should prevent you from building such a range. you can do this with Range
to.
corelib/src/ops/range.cairo
line 153 at r3 (raw file):
self.cur > self.end
I cannot do that as if self.end is T::MAX
then self.cur cannot be incremented by one due to overflow issues
If
self.cur
orself.end
is mutated outside this struct (e.g., via unsafe code or direct access), theexhausted
flag may no longer correctly represent the iterator's state.
the fields are private
corelib/src/ops/range.cairo
line 184 at r3 (raw file):
Previously, dean-starkware wrote…
For non-primitive types, this comparison might be expensive.
Maybe try to cache the result of this check during construction if it is used frequently?
This is only done once during initialization of the iterator. I don't see where this could be cached
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewable status: all files reviewed, 3 unresolved discussions (waiting on @cairoIover)
corelib/src/ops/range.cairo
line 115 at r3 (raw file):
Previously, cairoIover wrote…
not sure I understand what you mean here
While RangeInclusive
is generic over T
, the implementation assumes that T
supports certain operations (PartialOrd
, Clone
, etc.). These bounds are not enforced in the struct definition.
If T
is not comparable (PartialOrd
) or cannot be cloned (Clone
), this code will fail to compile when used.
corelib/src/ops/range.cairo
line 133 at r3 (raw file):
Previously, cairoIover wrote…
I don't think the operator should prevent you from building such a range. you can do this with
Range
to.
If start > end
, the resulting range behaves as an empty range. This behavior doesn't make any sense in my opinion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewable status: all files reviewed, 3 unresolved discussions (waiting on @dean-starkware)
corelib/src/ops/range.cairo
line 115 at r3 (raw file):
Previously, dean-starkware wrote…
While
RangeInclusive
is generic overT
, the implementation assumes thatT
supports certain operations (PartialOrd
,Clone
, etc.). These bounds are not enforced in the struct definition.
IfT
is not comparable (PartialOrd
) or cannot be cloned (Clone
), this code will fail to compile when used.
You cannot enforce bounds in struct definitions in Cairo. If you declare
#[derive(Drop, Clone)]
struct S{}
Then S cannot be instanciated with instances of T that do not derive Drop nor Clone
#[derive(Drop, Clone)]
struct S<T: ParialOrd + Clone>{}
is not a valid syntax
corelib/src/ops/range.cairo
line 133 at r3 (raw file):
Previously, dean-starkware wrote…
If
start > end
, the resulting range behaves as an empty range. This behavior doesn't make any sense in my opinion.
In my opinion, it does make sense. We do not want to trigger runtime errors in such behaviors.
An empty range is not inherently wrong or dangerous. It's just empty.
In set theory, the interval [5,3] contains all the values between 5 and 3. Which means that [5, 3] = {}
Moreover, panicking if start <= end is inconsistent with the behavior of most programming languages, like rust or python.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed 9 of 16 files at r1, 1 of 4 files at r2, 6 of 6 files at r3, all commit messages.
Reviewable status: all files reviewed, 1 unresolved discussion (waiting on @cairoIover)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewable status: all files reviewed, 2 unresolved discussions (waiting on @cairoIover)
corelib/src/ops/range.cairo
line 179 at r3 (raw file):
+PartialEq<T>, +PartialOrd<T>, -SierraIntRangeSupport<T>,
Remove this, as this won't be relevant for inclusive range.
Code quote:
-SierraIntRangeSupport<T>,
5d2c040
to
f6e94ca
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewable status: 6 of 16 files reviewed, 2 unresolved discussions (waiting on @dean-starkware, @gilbens-starkware, and @orizi)
corelib/src/ops/range.cairo
line 179 at r3 (raw file):
Previously, gilbens-starkware (Gil Ben-Shachar) wrote…
Remove this, as this won't be relevant for inclusive range.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed 4 of 16 files at r1, 1 of 4 files at r2, 1 of 6 files at r3, 9 of 10 files at r4, all commit messages.
Reviewable status: 15 of 16 files reviewed, 1 unresolved discussion (waiting on @cairoIover, @dean-starkware, and @orizi)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewable status: 15 of 16 files reviewed, 1 unresolved discussion (waiting on @cairoIover, @dean-starkware, and @orizi)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed 1 of 10 files at r4, all commit messages.
Reviewable status: complete! all files reviewed, all discussions resolved (waiting on @cairoIover)
Adds support for the
DotDotEq
token in the parser, linkBinaryOperator::DotDotEq(_)
toRangeInclusiveOp
and implement it in the core library.