Skip to content

Fix itertools.count to take PyNumber instead of PyInt #3822

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

Merged
merged 8 commits into from
Jun 27, 2022

Conversation

yonmilk
Copy link
Contributor

@yonmilk yonmilk commented Jun 26, 2022

No description provided.

Comment on lines 183 to 184
#[pyarg(positional, optional)]
start: OptionalArg<PyIntRef>,
Copy link
Member

Choose a reason for hiding this comment

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

#[pyarg] and OptinoalArg is not expected to be removed.
(See the test results how this change broke tests)

Use OptionalArg<PyObjectRef>

Comment on lines 240 to 242
if let Some(step) = &zelf.step {
*cur = vm._iadd(&*cur, step.as_object())?;
}
Copy link
Member

Choose a reason for hiding this comment

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

Doesn't 1 have to be added when step is None?

stdlib::sys,
types::{Constructor, IterNext, IterNextIterable},
AsObject, Py, PyObjectRef, PyPayload, PyRef, PyResult, PyWeakRef, VirtualMachine,
};
use crossbeam_utils::atomic::AtomicCell;
use num_bigint::BigInt;
use num_traits::{One, Signed, ToPrimitive, Zero};
// use num_bigint::BigInt;
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// use num_bigint::BigInt;

cur: PyRwLock<BigInt>,
step: BigInt,
cur: PyRwLock<PyObjectRef>,
step: Option<PyIntRef>,
Copy link
Contributor

@Snowapril Snowapril Jun 27, 2022

Choose a reason for hiding this comment

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

Can I ask you is there any reason for making step as Option?
And It seems step also need to be checked via PyNumber::check in cpython which means that any type that implements number protocol can be fitted.

Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
step: Option<PyIntRef>,
step: PyObjectRef,

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because step is an optional value as the second argument of count, set it as Option.
And when processing, there is something similar to repeat, so I considered it.
But if I need to set it up differently, I will.
I checked all reviews. thank. I'll fix.

Copy link
Member

Choose a reason for hiding this comment

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

What's different between saving it as a PyIntRef and Option<PyIntRef>?
e.g. Does it affect to repr result? If they act same for everything, we don't need to distinguish them.

Comment on lines 197 to 200
let start = match start.into_option() {
Some(int) => int.as_bigint().clone(),
None => BigInt::zero(),
Some(num) => vm.new_pyobj(num),
None => vm.new_pyobj(0),
};
Copy link
Contributor

Choose a reason for hiding this comment

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

let start: PyObjectRef = start.into_option().unwrap_or_else(|| vm.new_pyobj(0));

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tried but got an error

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry. I was wrong. I'll fix it. Thanks for the suggestion.

Comment on lines 201 to 207
let step = match step.into_option() {
Some(int) => int.as_bigint().clone(),
None => BigInt::one(),
Some(int) => {
let val: isize = int.try_to_primitive(vm)?;
Some(vm.new_pyref(val.to_usize().unwrap_or(0)))
}
None => None,
};
Copy link
Contributor

Choose a reason for hiding this comment

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

let step: PyObjectRef = step.into_option().unwrap_or_else(|| vm.new_pyobj(1));

};
if !PyNumber::check(&start, vm) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
if !PyNumber::check(&start, vm) {
if !PyNumber::check(&start, vm) || !PyNumber::check(&step, vm) {

It seems step also need to be checked via PyNumber::check.
https://github.com/python/cpython/blob/3.10/Modules/itertoolsmodule.c#L4178-L4182

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I didn't because it's a PyIntRef. I'll fix it.

Copy link
Member

Choose a reason for hiding this comment

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

PyIntRef is always a PyNumber.

Comment on lines 243 to 248
if let Some(step) = &zelf.step {
*cur = vm._iadd(&*cur, step.as_object())?;
} else {
let one = vm.new_pyobj(1);
*cur = vm._add(&*cur, &one)?;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
if let Some(step) = &zelf.step {
*cur = vm._iadd(&*cur, step.as_object())?;
} else {
let one = vm.new_pyobj(1);
*cur = vm._add(&*cur, &one)?;
}
*cur = vm._add(&*cur, &zelf.step)?;

If you have interest, this line could be replaced with PyNumber::add which is not yet implemented in rustpython

Copy link
Member

Choose a reason for hiding this comment

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

that will not be easy before #3819

Copy link
Member

Choose a reason for hiding this comment

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

I feel like iadd fits better.

Suggested change
if let Some(step) = &zelf.step {
*cur = vm._iadd(&*cur, step.as_object())?;
} else {
let one = vm.new_pyobj(1);
*cur = vm._add(&*cur, &one)?;
}
vm._iadd(&*cur, step.as_object())?;

@youknowone youknowone changed the title Fix to get number of itertools count Fix itertools.count to take PyNumber instead of PyInt Jun 27, 2022
let result = cur.clone();
*cur += &zelf.step;
*cur = vm._iadd(&*cur, step.as_object())?;
Copy link
Member

Choose a reason for hiding this comment

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

is iadd intended to be used with return value?

Copy link
Member

Choose a reason for hiding this comment

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

oh, it does. I didn't know that.

Copy link
Member

@youknowone youknowone left a comment

Choose a reason for hiding this comment

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

Looks good, thank you for contributing!

@youknowone youknowone merged commit 6ad0e54 into RustPython:main Jun 27, 2022
@yonmilk yonmilk deleted the iter_count_get_number branch July 17, 2022 23:28
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.

3 participants