diff --git a/Cargo.lock b/Cargo.lock index d28cc0a8fb..888071464e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -172,6 +172,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + [[package]] name = "base64" version = "0.21.3" @@ -214,6 +220,15 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "bstr" version = "1.6.2" @@ -495,6 +510,15 @@ version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636" +[[package]] +name = "cpufeatures" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +dependencies = [ + "libc", +] + [[package]] name = "crc32fast" version = "1.3.2" @@ -587,6 +611,16 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "darling" version = "0.20.3" @@ -634,6 +668,16 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + [[package]] name = "dirs" version = "4.0.0" @@ -720,6 +764,18 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +[[package]] +name = "embed-doc-image" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af36f591236d9d822425cb6896595658fa558fcebf5ee8accac1d4b92c47166e" +dependencies = [ + "base64 0.13.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "ena" version = "0.14.2" @@ -872,6 +928,16 @@ dependencies = [ "libc", ] +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.2.10" @@ -1167,6 +1233,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "keccak" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" +dependencies = [ + "cpufeatures", +] + [[package]] name = "kqueue" version = "1.0.8" @@ -1320,6 +1395,41 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +[[package]] +name = "malachite" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9fa232412d927f518cd873073911726943f432bac1bbc1288316d240635dc51" +dependencies = [ + "malachite-base", + "malachite-nz", +] + +[[package]] +name = "malachite-base" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "606a61b226dc58b8b283399b74754460433c193b193f26eaaad92f7966abd72b" +dependencies = [ + "getrandom", + "itertools 0.11.0", + "rand", + "rand_chacha", + "ryu", + "sha3", +] + +[[package]] +name = "malachite-nz" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "863d06218c83cc2269c425186cc15094d6284b1333a1184d0890aecfddb8916b" +dependencies = [ + "embed-doc-image", + "itertools 0.11.0", + "malachite-base", +] + [[package]] name = "matchers" version = "0.1.0" @@ -1454,27 +1564,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "num-bigint" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.16" @@ -2047,9 +2136,9 @@ dependencies = [ "itertools 0.11.0", "libcst", "log", + "malachite", "memchr", "natord", - "num-bigint", "num-traits", "once_cell", "path-absolutize", @@ -2298,9 +2387,8 @@ dependencies = [ "insta", "is-macro", "itertools 0.11.0", + "malachite", "memchr", - "num-bigint", - "num-traits", "once_cell", "ruff_python_parser", "ruff_python_trivia", @@ -2389,8 +2477,7 @@ dependencies = [ "itertools 0.11.0", "lalrpop", "lalrpop-util", - "num-bigint", - "num-traits", + "malachite", "ruff_python_ast", "ruff_text_size", "rustc-hash", @@ -2416,7 +2503,6 @@ version = "0.0.0" dependencies = [ "bitflags 2.4.0", "is-macro", - "num-traits", "ruff_index", "ruff_python_ast", "ruff_python_parser", @@ -2764,6 +2850,16 @@ dependencies = [ "syn 2.0.37", ] +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + [[package]] name = "sharded-slab" version = "0.1.4" @@ -3176,6 +3272,12 @@ version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + [[package]] name = "unic-char-property" version = "0.9.0" @@ -3271,7 +3373,7 @@ version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b11c96ac7ee530603dcdf68ed1557050f374ce55a5a07193ebf8cbc9f8927e9" dependencies = [ - "base64", + "base64 0.21.3", "flate2", "log", "once_cell", diff --git a/Cargo.toml b/Cargo.toml index d59a6a5c20..20b38f990c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,8 +25,8 @@ insta = { version = "1.31.0", feature = ["filters", "glob"] } is-macro = { version = "0.3.0" } itertools = { version = "0.11.0" } log = { version = "0.4.17" } +malachite = { version = "0.4.0", default-features = false, features = ["naturals_and_integers"] } memchr = "2.6.3" -num-bigint = { version = "0.4.3" } num-traits = { version = "0.2.15" } once_cell = { version = "1.17.1" } path-absolutize = { version = "3.1.1" } diff --git a/crates/ruff/Cargo.toml b/crates/ruff/Cargo.toml index d9a464b785..d8d69f7c28 100644 --- a/crates/ruff/Cargo.toml +++ b/crates/ruff/Cargo.toml @@ -45,9 +45,9 @@ is-macro = { workspace = true } itertools = { workspace = true } libcst = { workspace = true } log = { workspace = true } +malachite = { workspace = true } memchr = { workspace = true } natord = { version = "1.0.9" } -num-bigint = { workspace = true } num-traits = { workspace = true } once_cell = { workspace = true } path-absolutize = { workspace = true, features = [ diff --git a/crates/ruff/src/rules/flake8_2020/rules/compare.rs b/crates/ruff/src/rules/flake8_2020/rules/compare.rs index 58a8f80838..debb88697e 100644 --- a/crates/ruff/src/rules/flake8_2020/rules/compare.rs +++ b/crates/ruff/src/rules/flake8_2020/rules/compare.rs @@ -1,8 +1,6 @@ -use num_bigint::BigInt; -use ruff_python_ast::{self as ast, CmpOp, Constant, Expr}; - use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; +use ruff_python_ast::{self as ast, CmpOp, Constant, Expr}; use ruff_text_size::Ranged; use crate::checkers::ast::Checker; @@ -237,7 +235,7 @@ pub(crate) fn compare(checker: &mut Checker, left: &Expr, ops: &[CmpOp], compara .. }) = slice.as_ref() { - if *i == BigInt::from(0) { + if *i == 0 { if let ( [CmpOp::Eq | CmpOp::NotEq], [Expr::Constant(ast::ExprConstant { @@ -246,13 +244,13 @@ pub(crate) fn compare(checker: &mut Checker, left: &Expr, ops: &[CmpOp], compara })], ) = (ops, comparators) { - if *n == BigInt::from(3) && checker.enabled(Rule::SysVersionInfo0Eq3) { + if *n == 3 && checker.enabled(Rule::SysVersionInfo0Eq3) { checker .diagnostics .push(Diagnostic::new(SysVersionInfo0Eq3, left.range())); } } - } else if *i == BigInt::from(1) { + } else if *i == 1 { if let ( [CmpOp::Lt | CmpOp::LtE | CmpOp::Gt | CmpOp::GtE], [Expr::Constant(ast::ExprConstant { diff --git a/crates/ruff/src/rules/flake8_2020/rules/subscript.rs b/crates/ruff/src/rules/flake8_2020/rules/subscript.rs index 9c21064ce0..f8e707f75f 100644 --- a/crates/ruff/src/rules/flake8_2020/rules/subscript.rs +++ b/crates/ruff/src/rules/flake8_2020/rules/subscript.rs @@ -1,4 +1,3 @@ -use num_bigint::BigInt; use ruff_python_ast::{self as ast, Constant, Expr}; use ruff_diagnostics::{Diagnostic, Violation}; @@ -184,11 +183,11 @@ pub(crate) fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) { .. }) = upper.as_ref() { - if *i == BigInt::from(1) && checker.enabled(Rule::SysVersionSlice1) { + if *i == 1 && checker.enabled(Rule::SysVersionSlice1) { checker .diagnostics .push(Diagnostic::new(SysVersionSlice1, value.range())); - } else if *i == BigInt::from(3) && checker.enabled(Rule::SysVersionSlice3) { + } else if *i == 3 && checker.enabled(Rule::SysVersionSlice3) { checker .diagnostics .push(Diagnostic::new(SysVersionSlice3, value.range())); @@ -200,11 +199,11 @@ pub(crate) fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) { value: Constant::Int(i), .. }) => { - if *i == BigInt::from(2) && checker.enabled(Rule::SysVersion2) { + if *i == 2 && checker.enabled(Rule::SysVersion2) { checker .diagnostics .push(Diagnostic::new(SysVersion2, value.range())); - } else if *i == BigInt::from(0) && checker.enabled(Rule::SysVersion0) { + } else if *i == 0 && checker.enabled(Rule::SysVersion0) { checker .diagnostics .push(Diagnostic::new(SysVersion0, value.range())); diff --git a/crates/ruff/src/rules/flake8_bandit/rules/bad_file_permissions.rs b/crates/ruff/src/rules/flake8_bandit/rules/bad_file_permissions.rs index 0fdf07cd12..5b13665843 100644 --- a/crates/ruff/src/rules/flake8_bandit/rules/bad_file_permissions.rs +++ b/crates/ruff/src/rules/flake8_bandit/rules/bad_file_permissions.rs @@ -1,4 +1,4 @@ -use num_traits::ToPrimitive; +use malachite::Integer; use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; @@ -36,7 +36,7 @@ use crate::checkers::ast::Checker; /// - [Common Weakness Enumeration: CWE-732](https://cwe.mitre.org/data/definitions/732.html) #[violation] pub struct BadFilePermissions { - mask: u16, + mask: Integer, } impl Violation for BadFilePermissions { @@ -56,7 +56,9 @@ pub(crate) fn bad_file_permissions(checker: &mut Checker, call: &ast::ExprCall) { if let Some(mode_arg) = call.arguments.find_argument("mode", 1) { if let Some(int_value) = int_value(mode_arg, checker.semantic()) { - if (int_value & WRITE_WORLD > 0) || (int_value & EXECUTE_GROUP > 0) { + if (int_value.clone() & Integer::from(WRITE_WORLD) > 0) + || (int_value.clone() & Integer::from(EXECUTE_GROUP) > 0) + { checker.diagnostics.push(Diagnostic::new( BadFilePermissions { mask: int_value }, mode_arg.range(), @@ -113,13 +115,17 @@ fn py_stat(call_path: &CallPath) -> Option { } } -fn int_value(expr: &Expr, semantic: &SemanticModel) -> Option { +fn int_value(expr: &Expr, semantic: &SemanticModel) -> Option { match expr { Expr::Constant(ast::ExprConstant { value: Constant::Int(value), .. - }) => value.to_u16(), - Expr::Attribute(_) => semantic.resolve_call_path(expr).as_ref().and_then(py_stat), + }) => Some(value.clone()), + Expr::Attribute(_) => semantic + .resolve_call_path(expr) + .as_ref() + .and_then(py_stat) + .map(Integer::from), Expr::BinOp(ast::ExprBinOp { left, op, diff --git a/crates/ruff/src/rules/flake8_bandit/rules/snmp_insecure_version.rs b/crates/ruff/src/rules/flake8_bandit/rules/snmp_insecure_version.rs index 6e6b2b8aed..2e895d4107 100644 --- a/crates/ruff/src/rules/flake8_bandit/rules/snmp_insecure_version.rs +++ b/crates/ruff/src/rules/flake8_bandit/rules/snmp_insecure_version.rs @@ -1,5 +1,3 @@ -use num_traits::{One, Zero}; - use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::{self as ast, Constant, Expr}; @@ -57,7 +55,7 @@ pub(crate) fn snmp_insecure_version(checker: &mut Checker, call: &ast::ExprCall) .. }) = &keyword.value { - if value.is_zero() || value.is_one() { + if *value == 0 || *value == 1 { checker .diagnostics .push(Diagnostic::new(SnmpInsecureVersion, keyword.range())); diff --git a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_subscript_reversal.rs b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_subscript_reversal.rs index ab00f7892d..d17bf24b30 100644 --- a/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_subscript_reversal.rs +++ b/crates/ruff/src/rules/flake8_comprehensions/rules/unnecessary_subscript_reversal.rs @@ -1,5 +1,3 @@ -use num_bigint::BigInt; - use ruff_diagnostics::{Diagnostic, Violation}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::{self as ast, Constant, Expr, UnaryOp}; @@ -93,7 +91,7 @@ pub(crate) fn unnecessary_subscript_reversal( else { return; }; - if *val != BigInt::from(1) { + if *val != 1 { return; }; checker.diagnostics.push(Diagnostic::new( diff --git a/crates/ruff/src/rules/flake8_pie/rules/unnecessary_range_start.rs b/crates/ruff/src/rules/flake8_pie/rules/unnecessary_range_start.rs index a6275ac602..e2d1c7fe7f 100644 --- a/crates/ruff/src/rules/flake8_pie/rules/unnecessary_range_start.rs +++ b/crates/ruff/src/rules/flake8_pie/rules/unnecessary_range_start.rs @@ -1,5 +1,3 @@ -use num_bigint::BigInt; - use ruff_diagnostics::Diagnostic; use ruff_diagnostics::{AlwaysAutofixableViolation, Fix}; use ruff_macros::{derive_message_formats, violation}; @@ -75,7 +73,7 @@ pub(crate) fn unnecessary_range_start(checker: &mut Checker, call: &ast::ExprCal else { return; }; - if *value != BigInt::from(0) { + if *value != 0 { return; }; diff --git a/crates/ruff/src/rules/flake8_pyi/rules/unrecognized_version_info.rs b/crates/ruff/src/rules/flake8_pyi/rules/unrecognized_version_info.rs index 4df6441d93..be1a0d3a2b 100644 --- a/crates/ruff/src/rules/flake8_pyi/rules/unrecognized_version_info.rs +++ b/crates/ruff/src/rules/flake8_pyi/rules/unrecognized_version_info.rs @@ -1,5 +1,3 @@ -use num_bigint::BigInt; -use num_traits::{One, Zero}; use ruff_python_ast::{self as ast, CmpOp, Constant, Expr}; use ruff_diagnostics::{Diagnostic, Violation}; @@ -249,10 +247,10 @@ impl ExpectedComparator { .. }) = upper.as_ref() { - if *upper == BigInt::one() { + if *upper == 1 { return Some(ExpectedComparator::MajorTuple); } - if *upper == BigInt::from(2) { + if *upper == 2 { return Some(ExpectedComparator::MajorMinorTuple); } } @@ -260,7 +258,7 @@ impl ExpectedComparator { Expr::Constant(ast::ExprConstant { value: Constant::Int(n), .. - }) if n.is_zero() => { + }) if *n == 0 => { return Some(ExpectedComparator::MajorDigit); } _ => (), diff --git a/crates/ruff/src/rules/pandas_vet/rules/nunique_constant_series_check.rs b/crates/ruff/src/rules/pandas_vet/rules/nunique_constant_series_check.rs index 6147f18a87..be2bbdace0 100644 --- a/crates/ruff/src/rules/pandas_vet/rules/nunique_constant_series_check.rs +++ b/crates/ruff/src/rules/pandas_vet/rules/nunique_constant_series_check.rs @@ -1,4 +1,3 @@ -use num_traits::One; use ruff_python_ast::{self as ast, CmpOp, Constant, Expr}; use ruff_diagnostics::Diagnostic; @@ -115,7 +114,7 @@ pub(crate) fn nunique_constant_series_check( fn is_constant_one(expr: &Expr) -> bool { match expr { Expr::Constant(constant) => match &constant.value { - Constant::Int(int) => int.is_one(), + Constant::Int(int) => *int == 1, _ => false, }, _ => false, diff --git a/crates/ruff/src/rules/pyupgrade/rules/native_literals.rs b/crates/ruff/src/rules/pyupgrade/rules/native_literals.rs index 18b9670acb..553a4c90a9 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/native_literals.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/native_literals.rs @@ -1,8 +1,7 @@ +use malachite::Integer; use std::fmt; use std::str::FromStr; -use num_bigint::BigInt; - use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::{self as ast, Constant, Expr}; @@ -47,7 +46,7 @@ impl From for Constant { value: Vec::new(), implicit_concatenated: false, }), - LiteralType::Int => Constant::Int(BigInt::from(0)), + LiteralType::Int => Constant::Int(Integer::from(0)), LiteralType::Float => Constant::Float(0.0), LiteralType::Bool => Constant::Bool(false), } diff --git a/crates/ruff/src/rules/pyupgrade/rules/outdated_version_block.rs b/crates/ruff/src/rules/pyupgrade/rules/outdated_version_block.rs index 1e8c94abd7..32aa093114 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/outdated_version_block.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/outdated_version_block.rs @@ -1,6 +1,6 @@ use std::cmp::Ordering; -use num_bigint::{BigInt, Sign}; +use malachite::Integer; use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; @@ -122,31 +122,24 @@ pub(crate) fn outdated_version_block(checker: &mut Checker, stmt_if: &StmtIf) { .. }) => { if op == &CmpOp::Eq { - match bigint_to_u32(number) { - 2 => { - let mut diagnostic = - Diagnostic::new(OutdatedVersionBlock, branch.test.range()); - if checker.patch(diagnostic.kind.rule()) { - if let Some(fix) = - fix_always_false_branch(checker, stmt_if, &branch) - { - diagnostic.set_fix(fix); - } + if *number == 2 { + let mut diagnostic = + Diagnostic::new(OutdatedVersionBlock, branch.test.range()); + if checker.patch(diagnostic.kind.rule()) { + if let Some(fix) = fix_always_false_branch(checker, stmt_if, &branch) { + diagnostic.set_fix(fix); } - checker.diagnostics.push(diagnostic); } - 3 => { - let mut diagnostic = - Diagnostic::new(OutdatedVersionBlock, branch.test.range()); - if checker.patch(diagnostic.kind.rule()) { - if let Some(fix) = fix_always_true_branch(checker, stmt_if, &branch) - { - diagnostic.set_fix(fix); - } + checker.diagnostics.push(diagnostic); + } else if *number == 3 { + let mut diagnostic = + Diagnostic::new(OutdatedVersionBlock, branch.test.range()); + if checker.patch(diagnostic.kind.rule()) { + if let Some(fix) = fix_always_true_branch(checker, stmt_if, &branch) { + diagnostic.set_fix(fix); } - checker.diagnostics.push(diagnostic); } - _ => {} + checker.diagnostics.push(diagnostic); } } } @@ -156,7 +149,7 @@ pub(crate) fn outdated_version_block(checker: &mut Checker, stmt_if: &StmtIf) { } /// Returns true if the `target_version` is always less than the [`PythonVersion`]. -fn compare_version(target_version: &[u32], py_version: PythonVersion, or_equal: bool) -> bool { +fn compare_version(target_version: &[Integer], py_version: PythonVersion, or_equal: bool) -> bool { let mut target_version_iter = target_version.iter(); let Some(if_major) = target_version_iter.next() else { @@ -165,7 +158,7 @@ fn compare_version(target_version: &[u32], py_version: PythonVersion, or_equal: let (py_major, py_minor) = py_version.as_tuple(); - match if_major.cmp(&py_major) { + match if_major.cmp(&Integer::from(py_major)) { Ordering::Less => true, Ordering::Greater => false, Ordering::Equal => { @@ -353,26 +346,16 @@ fn fix_always_true_branch( } } -/// Converts a `BigInt` to a `u32`. If the number is negative, it will return 0. -fn bigint_to_u32(number: &BigInt) -> u32 { - let the_number = number.to_u32_digits(); - match the_number.0 { - Sign::Minus | Sign::NoSign => 0, - Sign::Plus => *the_number.1.first().unwrap(), - } -} - /// Gets the version from the tuple -fn extract_version(elts: &[Expr]) -> Vec { - let mut version: Vec = vec![]; +fn extract_version(elts: &[Expr]) -> Vec { + let mut version = Vec::new(); for elt in elts { if let Expr::Constant(ast::ExprConstant { - value: Constant::Int(item), + value: Constant::Int(number), .. }) = &elt { - let number = bigint_to_u32(item); - version.push(number); + version.push(number.clone()); } else { return version; } @@ -403,6 +386,13 @@ mod tests { or_equal: bool, expected: bool, ) { - assert_eq!(compare_version(version_vec, version, or_equal), expected); + let version_integers = version_vec + .iter() + .map(|x| Integer::from(*x)) + .collect::>(); + assert_eq!( + compare_version(&version_integers, version, or_equal), + expected + ); } } diff --git a/crates/ruff/src/rules/ruff/rules/pairwise_over_zipped.rs b/crates/ruff/src/rules/ruff/rules/pairwise_over_zipped.rs index cd366d64fa..5004c83c31 100644 --- a/crates/ruff/src/rules/ruff/rules/pairwise_over_zipped.rs +++ b/crates/ruff/src/rules/ruff/rules/pairwise_over_zipped.rs @@ -1,4 +1,4 @@ -use num_traits::ToPrimitive; +use malachite::Integer; use ruff_python_ast::{self as ast, Constant, Expr, UnaryOp}; use ruff_diagnostics::{Diagnostic, Violation}; @@ -46,11 +46,11 @@ impl Violation for PairwiseOverZipped { #[derive(Debug)] struct SliceInfo { arg_name: String, - slice_start: Option, + slice_start: Option, } impl SliceInfo { - pub(crate) fn new(arg_name: String, slice_start: Option) -> Self { + pub(crate) fn new(arg_name: String, slice_start: Option) -> Self { Self { arg_name, slice_start, @@ -89,12 +89,12 @@ fn match_slice_info(expr: &Expr) -> Option { )) } -fn to_bound(expr: &Expr) -> Option { +fn to_bound(expr: &Expr) -> Option { match expr { Expr::Constant(ast::ExprConstant { value: Constant::Int(value), .. - }) => value.to_i64(), + }) => Some(value.clone()), Expr::UnaryOp(ast::ExprUnaryOp { op: UnaryOp::USub | UnaryOp::Invert, operand, @@ -105,7 +105,7 @@ fn to_bound(expr: &Expr) -> Option { .. }) = operand.as_ref() { - value.to_i64().map(|v| -v) + Some(-value.clone()) } else { None } @@ -155,7 +155,10 @@ pub(crate) fn pairwise_over_zipped(checker: &mut Checker, func: &Expr, args: &[E } // Verify that the arguments are successive. - if second_arg_info.slice_start.unwrap_or(0) - first_arg_info.slice_start.unwrap_or(0) != 1 { + if second_arg_info.slice_start.unwrap_or(Integer::from(0)) + - first_arg_info.slice_start.unwrap_or(Integer::from(0)) + != 1 + { return; } diff --git a/crates/ruff/src/rules/ruff/rules/unnecessary_iterable_allocation_for_first_element.rs b/crates/ruff/src/rules/ruff/rules/unnecessary_iterable_allocation_for_first_element.rs index fe574e09a6..094f194cdd 100644 --- a/crates/ruff/src/rules/ruff/rules/unnecessary_iterable_allocation_for_first_element.rs +++ b/crates/ruff/src/rules/ruff/rules/unnecessary_iterable_allocation_for_first_element.rs @@ -1,7 +1,5 @@ use std::borrow::Cow; -use num_traits::Zero; - use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::{self as ast, Arguments, Comprehension, Constant, Expr}; @@ -115,7 +113,7 @@ fn is_head_slice(expr: &Expr) -> bool { .. }) = expr { - value.is_zero() + *value == 0 } else { false } diff --git a/crates/ruff_python_ast/Cargo.toml b/crates/ruff_python_ast/Cargo.toml index b98a00ca23..4ba67380cb 100644 --- a/crates/ruff_python_ast/Cargo.toml +++ b/crates/ruff_python_ast/Cargo.toml @@ -20,9 +20,8 @@ ruff_text_size = { path = "../ruff_text_size" } bitflags = { workspace = true } is-macro = { workspace = true } itertools = { workspace = true } +malachite = { workspace = true } memchr = { workspace = true } -num-bigint = { workspace = true } -num-traits = { workspace = true } once_cell = { workspace = true } rustc-hash = { workspace = true } serde = { workspace = true, optional = true } diff --git a/crates/ruff_python_ast/src/comparable.rs b/crates/ruff_python_ast/src/comparable.rs index 1c4f01967b..35da43c434 100644 --- a/crates/ruff_python_ast/src/comparable.rs +++ b/crates/ruff_python_ast/src/comparable.rs @@ -15,9 +15,8 @@ //! an implicit concatenation of string literals, as these expressions are considered to //! have the same shape in that they evaluate to the same value. -use num_bigint::BigInt; - use crate as ast; +use malachite::Integer; #[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] pub enum ComparableBoolOp { @@ -334,7 +333,7 @@ pub enum ComparableConstant<'a> { Bool(&'a bool), Str { value: &'a str, unicode: bool }, Bytes(&'a [u8]), - Int(&'a BigInt), + Int(&'a Integer), Tuple(Vec>), Float(u64), Complex { real: u64, imag: u64 }, diff --git a/crates/ruff_python_ast/src/helpers.rs b/crates/ruff_python_ast/src/helpers.rs index 9e9ce3179c..f8ff714ff3 100644 --- a/crates/ruff_python_ast/src/helpers.rs +++ b/crates/ruff_python_ast/src/helpers.rs @@ -1,7 +1,6 @@ use std::borrow::Cow; use std::path::Path; -use num_traits::Zero; use smallvec::SmallVec; use ruff_text_size::{Ranged, TextRange}; @@ -1073,7 +1072,7 @@ impl Truthiness { Constant::None => Some(false), Constant::Str(ast::StringConstant { value, .. }) => Some(!value.is_empty()), Constant::Bytes(bytes) => Some(!bytes.is_empty()), - Constant::Int(int) => Some(!int.is_zero()), + Constant::Int(int) => Some(*int != 0), Constant::Float(float) => Some(*float != 0.0), Constant::Complex { real, imag } => Some(*real != 0.0 || *imag != 0.0), Constant::Ellipsis => Some(true), diff --git a/crates/ruff_python_ast/src/nodes.rs b/crates/ruff_python_ast/src/nodes.rs index 9c4d8b594a..4a4fc75627 100644 --- a/crates/ruff_python_ast/src/nodes.rs +++ b/crates/ruff_python_ast/src/nodes.rs @@ -1,12 +1,11 @@ #![allow(clippy::derive_partial_eq_without_eq)] use itertools::Itertools; +use malachite::Integer; use std::fmt; use std::fmt::Debug; use std::ops::Deref; -use num_bigint::BigInt; - use ruff_text_size::{Ranged, TextRange, TextSize}; /// See also [mod](https://docs.python.org/3/library/ast.html#ast.mod) @@ -2604,7 +2603,7 @@ pub enum Constant { Bool(bool), Str(StringConstant), Bytes(BytesConstant), - Int(BigInt), + Int(Integer), Float(f64), Complex { real: f64, imag: f64 }, Ellipsis, diff --git a/crates/ruff_python_literal/src/float.rs b/crates/ruff_python_literal/src/float.rs index 763d652445..7ec2534ba9 100644 --- a/crates/ruff_python_literal/src/float.rs +++ b/crates/ruff_python_literal/src/float.rs @@ -1,5 +1,5 @@ use crate::Case; -use num_traits::{Float, Zero}; +use num_traits::Float; use std::f64; pub fn parse_str(literal: &str) -> Option { @@ -248,7 +248,7 @@ pub fn to_hex(value: f64) -> String { let (mantissa, exponent, sign) = value.integer_decode(); let sign_fmt = if sign < 0 { "-" } else { "" }; match value { - value if value.is_zero() => format!("{sign_fmt}0x0.0p+0"), + value if value == 0.0 => format!("{sign_fmt}0x0.0p+0"), value if value.is_infinite() => format!("{sign_fmt}inf"), value if value.is_nan() => "nan".to_owned(), _ => { diff --git a/crates/ruff_python_parser/Cargo.toml b/crates/ruff_python_parser/Cargo.toml index a4bb8f6c50..2851ccc5c9 100644 --- a/crates/ruff_python_parser/Cargo.toml +++ b/crates/ruff_python_parser/Cargo.toml @@ -21,8 +21,7 @@ anyhow = { workspace = true } is-macro = { workspace = true } itertools = { workspace = true } lalrpop-util = { version = "0.20.0", default-features = false } -num-bigint = { workspace = true } -num-traits = { workspace = true } +malachite = { workspace = true } unicode-ident = { workspace = true } unicode_names2 = { version = "0.6.0", git = "https://github.com/youknowone/unicode_names2.git", rev = "4ce16aa85cbcdd9cc830410f1a72ef9a235f2fde" } rustc-hash = { workspace = true } diff --git a/crates/ruff_python_parser/src/lexer.rs b/crates/ruff_python_parser/src/lexer.rs index fca0ba5b90..74064040c8 100644 --- a/crates/ruff_python_parser/src/lexer.rs +++ b/crates/ruff_python_parser/src/lexer.rs @@ -28,11 +28,11 @@ //! //! [Lexical analysis]: https://docs.python.org/3/reference/lexical_analysis.html +use malachite::num::conversion::traits::FromStringBase; +use malachite::Integer; use std::iter::FusedIterator; use std::{char, cmp::Ordering, str::FromStr}; -use num_bigint::BigInt; -use num_traits::{Num, Zero}; use ruff_python_ast::IpyEscapeKind; use ruff_text_size::{TextLen, TextRange, TextSize}; use unicode_ident::{is_xid_continue, is_xid_start}; @@ -264,11 +264,16 @@ impl<'source> Lexer<'source> { let mut number = LexedText::new(self.offset(), self.source); self.radix_run(&mut number, radix); - let value = - BigInt::from_str_radix(number.as_str(), radix.as_u32()).map_err(|e| LexicalError { - error: LexicalErrorType::OtherError(format!("{e:?}")), + + let value = Integer::from_string_base(radix.as_u8(), number.as_str()).ok_or_else(|| { + LexicalError { + error: LexicalErrorType::OtherError(format!( + "'{}' is not a valid integer", + number.as_str() + )), location: self.token_range().start(), - })?; + } + })?; Ok(Tok::Int { value }) } @@ -339,8 +344,19 @@ impl<'source> Lexer<'source> { let imag = f64::from_str(number.as_str()).unwrap(); Ok(Tok::Complex { real: 0.0, imag }) } else { - let value = number.as_str().parse::().unwrap(); - if start_is_zero && !value.is_zero() { + // Optimization: `Natural` and thereby `Integer` add up digits from bytes to convert + // from string. This is much less efficient than the highly optimized std + // string-to-number parser and we know that most numbers are small. + // i32::MAX is 2147483647 (10 digits), so all 9 digit numbers are representable as + // i32. We can't guarantee that `32_bit_limbs` isn't set, so we limit ourselves to + // i32 instead of i64. + let value = if number.as_str().len() < 10 { + Integer::from(i32::from_str(number.as_str()).unwrap()) + } else { + Integer::from_str(number.as_str()).unwrap() + }; + + if start_is_zero && value != 0 { // leading zeros in decimal integer literals are not permitted return Err(LexicalError { error: LexicalErrorType::OtherError("Invalid Token".to_owned()), @@ -1155,7 +1171,7 @@ impl State { } } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] enum Radix { Binary, Octal, @@ -1164,7 +1180,7 @@ enum Radix { } impl Radix { - const fn as_u32(self) -> u32 { + const fn as_u8(self) -> u8 { match self { Radix::Binary => 2, Radix::Octal => 8, diff --git a/crates/ruff_python_parser/src/python.lalrpop b/crates/ruff_python_parser/src/python.lalrpop index 1c0d828393..9d8044b014 100644 --- a/crates/ruff_python_parser/src/python.lalrpop +++ b/crates/ruff_python_parser/src/python.lalrpop @@ -3,7 +3,6 @@ // See also: file:///usr/share/doc/python/html/reference/compound_stmts.html#function-definitions // See also: https://greentreesnakes.readthedocs.io/en/latest/nodes.html#keyword -use num_bigint::BigInt; use ruff_text_size::{Ranged, TextSize}; use ruff_python_ast::{self as ast, IpyEscapeKind}; use crate::{ @@ -15,6 +14,7 @@ use crate::{ token::{self, StringKind}, }; use lalrpop_util::ParseError; +use malachite::Integer; grammar(mode: Mode); @@ -1928,7 +1928,7 @@ extern { "True" => token::Tok::True, "False" => token::Tok::False, "None" => token::Tok::None, - int => token::Tok::Int { value: }, + int => token::Tok::Int { value: }, float => token::Tok::Float { value: }, complex => token::Tok::Complex { real: , imag: }, string => token::Tok::String { diff --git a/crates/ruff_python_parser/src/python.rs b/crates/ruff_python_parser/src/python.rs index 64b4588a21..1194c57e86 100644 --- a/crates/ruff_python_parser/src/python.rs +++ b/crates/ruff_python_parser/src/python.rs @@ -1,6 +1,5 @@ // auto-generated: "lalrpop 0.20.0" -// sha3: e8f3229288c1a13387ea6041355e2d8fe9ab788fbc7229032d2de92beb675944 -use num_bigint::BigInt; +// sha3: 5b982370860d3a79f183bc579ec6f5165211b83573141f4c9ceaec27436c30ad use ruff_text_size::{Ranged, TextSize}; use ruff_python_ast::{self as ast, IpyEscapeKind}; use crate::{ @@ -12,6 +11,7 @@ use crate::{ token::{self, StringKind}, }; use lalrpop_util::ParseError; +use malachite::Integer; #[allow(unused_extern_crates)] extern crate lalrpop_util as __lalrpop_util; #[allow(unused_imports)] @@ -23,7 +23,6 @@ extern crate alloc; #[allow(non_snake_case, non_camel_case_types, unused_mut, unused_variables, unused_imports, unused_parens, clippy::all)] mod __parse__Top { - use num_bigint::BigInt; use ruff_text_size::{Ranged, TextSize}; use ruff_python_ast::{self as ast, IpyEscapeKind}; use crate::{ @@ -35,6 +34,7 @@ mod __parse__Top { token::{self, StringKind}, }; use lalrpop_util::ParseError; + use malachite::Integer; #[allow(unused_extern_crates)] extern crate lalrpop_util as __lalrpop_util; #[allow(unused_imports)] @@ -48,7 +48,7 @@ mod __parse__Top { Variant0(token::Tok), Variant1((f64, f64)), Variant2(f64), - Variant3(BigInt), + Variant3(Integer), Variant4((IpyEscapeKind, String)), Variant5(String), Variant6((String, StringKind, bool)), @@ -17716,7 +17716,7 @@ mod __parse__Top { fn __pop_Variant3< >( __symbols: &mut alloc::vec::Vec<(TextSize,__Symbol<>,TextSize)> - ) -> (TextSize, BigInt, TextSize) + ) -> (TextSize, Integer, TextSize) { match __symbols.pop() { Some((__l, __Symbol::Variant3(__v), __r)) => (__l, __v, __r), @@ -34480,7 +34480,7 @@ fn __action232< fn __action233< >( mode: Mode, - (_, value, _): (TextSize, BigInt, TextSize), + (_, value, _): (TextSize, Integer, TextSize), ) -> ast::Constant { ast::Constant::Int(value) diff --git a/crates/ruff_python_parser/src/token.rs b/crates/ruff_python_parser/src/token.rs index 9bec604b8d..b7771bee5f 100644 --- a/crates/ruff_python_parser/src/token.rs +++ b/crates/ruff_python_parser/src/token.rs @@ -5,7 +5,7 @@ //! //! [CPython source]: https://github.com/python/cpython/blob/dfc2e065a2e71011017077e549cd2f9bf4944c54/Include/internal/pycore_token.h; use crate::Mode; -use num_bigint::BigInt; +use malachite::Integer; use ruff_python_ast::IpyEscapeKind; use ruff_text_size::TextSize; use std::fmt; @@ -21,7 +21,7 @@ pub enum Tok { /// Token value for an integer. Int { /// The integer value. - value: BigInt, + value: Integer, }, /// Token value for a floating point number. Float { diff --git a/crates/ruff_python_semantic/Cargo.toml b/crates/ruff_python_semantic/Cargo.toml index 58484d140d..602a0e27c1 100644 --- a/crates/ruff_python_semantic/Cargo.toml +++ b/crates/ruff_python_semantic/Cargo.toml @@ -21,7 +21,6 @@ ruff_text_size = { path = "../ruff_text_size" } bitflags = { workspace = true } is-macro = { workspace = true } -num-traits = { workspace = true } rustc-hash = { workspace = true } smallvec = { workspace = true } diff --git a/crates/ruff_python_semantic/src/analyze/typing.rs b/crates/ruff_python_semantic/src/analyze/typing.rs index b7847f78da..e8383d8151 100644 --- a/crates/ruff_python_semantic/src/analyze/typing.rs +++ b/crates/ruff_python_semantic/src/analyze/typing.rs @@ -1,6 +1,5 @@ //! Analysis rules for the `typing` module. -use num_traits::identities::Zero; use ruff_python_ast::{ self as ast, Constant, Expr, Operator, ParameterWithDefault, Parameters, Stmt, }; @@ -319,7 +318,7 @@ pub fn is_type_checking_block(stmt: &ast::StmtIf, semantic: &SemanticModel) -> b .. }) = test.as_ref() { - if value.is_zero() { + if *value == 0 { return true; } }