Skip to content

Commit a4d5d39

Browse files
authored
Rollup merge of rust-lang#77640 - ethanboxx:int_error_matching_attempt_2, r=KodrAus
Refactor IntErrorKind to avoid "underflow" terminology This PR is a continuation of rust-lang#76455 # Changes - `Overflow` renamed to `PosOverflow` and `Underflow` renamed to `NegOverflow` after discussion in rust-lang#76455 - Changed some of the parsing code to return `InvalidDigit` rather than `Empty` for strings "+" and "-". https://users.rust-lang.org/t/misleading-error-in-str-parse-for-int-types/49178 - Carry the problem `char` with the `InvalidDigit` variant. - Necessary changes were made to the compiler as it depends on `int_error_matching`. - Redid tests to match on specific errors. r? `@KodrAus`
2 parents e22a27f + e750238 commit a4d5d39

File tree

6 files changed

+69
-46
lines changed

6 files changed

+69
-46
lines changed

compiler/rustc_middle/src/middle/limits.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,12 @@ fn update_limit(
4848
.unwrap_or(attr.span);
4949

5050
let error_str = match e.kind() {
51-
IntErrorKind::Overflow => "`limit` is too large",
51+
IntErrorKind::PosOverflow => "`limit` is too large",
5252
IntErrorKind::Empty => "`limit` must be a non-negative integer",
5353
IntErrorKind::InvalidDigit => "not a valid integer",
54-
IntErrorKind::Underflow => bug!("`limit` should never underflow"),
54+
IntErrorKind::NegOverflow => {
55+
bug!("`limit` should never negatively overflow")
56+
}
5557
IntErrorKind::Zero => bug!("zero is a valid `limit`"),
5658
kind => bug!("unimplemented IntErrorKind variant: {:?}", kind),
5759
};

library/core/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@
158158
#![feature(slice_ptr_get)]
159159
#![feature(no_niche)] // rust-lang/rust#68303
160160
#![feature(unsafe_block_in_unsafe_fn)]
161+
#![feature(int_error_matching)]
161162
#![deny(unsafe_op_in_unsafe_fn)]
162163

163164
#[prelude_import]

library/core/src/num/error.rs

+10-7
Original file line numberDiff line numberDiff line change
@@ -98,15 +98,18 @@ pub enum IntErrorKind {
9898
///
9999
/// Among other causes, this variant will be constructed when parsing an empty string.
100100
Empty,
101-
/// Contains an invalid digit.
101+
/// Contains an invalid digit in its context.
102102
///
103103
/// Among other causes, this variant will be constructed when parsing a string that
104-
/// contains a letter.
104+
/// contains a non-ASCII char.
105+
///
106+
/// This variant is also constructed when a `+` or `-` is misplaced within a string
107+
/// either on its own or in the middle of a number.
105108
InvalidDigit,
106109
/// Integer is too large to store in target integer type.
107-
Overflow,
110+
PosOverflow,
108111
/// Integer is too small to store in target integer type.
109-
Underflow,
112+
NegOverflow,
110113
/// Value was Zero
111114
///
112115
/// This variant will be emitted when the parsing string has a value of zero, which
@@ -119,7 +122,7 @@ impl ParseIntError {
119122
#[unstable(
120123
feature = "int_error_matching",
121124
reason = "it can be useful to match errors when making error messages \
122-
for integer parsing",
125+
for integer parsing",
123126
issue = "22639"
124127
)]
125128
pub fn kind(&self) -> &IntErrorKind {
@@ -136,8 +139,8 @@ impl ParseIntError {
136139
match self.kind {
137140
IntErrorKind::Empty => "cannot parse integer from empty string",
138141
IntErrorKind::InvalidDigit => "invalid digit found in string",
139-
IntErrorKind::Overflow => "number too large to fit in target type",
140-
IntErrorKind::Underflow => "number too small to fit in target type",
142+
IntErrorKind::PosOverflow => "number too large to fit in target type",
143+
IntErrorKind::NegOverflow => "number too small to fit in target type",
141144
IntErrorKind::Zero => "number would be zero for non-zero type",
142145
}
143146
}

library/core/src/num/mod.rs

+13-9
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,12 @@ pub use nonzero::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, No
6363
#[stable(feature = "try_from", since = "1.34.0")]
6464
pub use error::TryFromIntError;
6565

66-
#[unstable(feature = "int_error_matching", issue = "22639")]
66+
#[unstable(
67+
feature = "int_error_matching",
68+
reason = "it can be useful to match errors when making error messages \
69+
for integer parsing",
70+
issue = "22639"
71+
)]
6772
pub use error::IntErrorKind;
6873

6974
macro_rules! usize_isize_to_xe_bytes_doc {
@@ -830,15 +835,14 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
830835
let src = src.as_bytes();
831836

832837
let (is_positive, digits) = match src[0] {
838+
b'+' | b'-' if src[1..].is_empty() => {
839+
return Err(PIE { kind: InvalidDigit });
840+
}
833841
b'+' => (true, &src[1..]),
834842
b'-' if is_signed_ty => (false, &src[1..]),
835843
_ => (true, src),
836844
};
837845

838-
if digits.is_empty() {
839-
return Err(PIE { kind: Empty });
840-
}
841-
842846
let mut result = T::from_u32(0);
843847
if is_positive {
844848
// The number is positive
@@ -849,11 +853,11 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
849853
};
850854
result = match result.checked_mul(radix) {
851855
Some(result) => result,
852-
None => return Err(PIE { kind: Overflow }),
856+
None => return Err(PIE { kind: PosOverflow }),
853857
};
854858
result = match result.checked_add(x) {
855859
Some(result) => result,
856-
None => return Err(PIE { kind: Overflow }),
860+
None => return Err(PIE { kind: PosOverflow }),
857861
};
858862
}
859863
} else {
@@ -865,11 +869,11 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
865869
};
866870
result = match result.checked_mul(radix) {
867871
Some(result) => result,
868-
None => return Err(PIE { kind: Underflow }),
872+
None => return Err(PIE { kind: NegOverflow }),
869873
};
870874
result = match result.checked_sub(x) {
871875
Some(result) => result,
872-
None => return Err(PIE { kind: Underflow }),
876+
None => return Err(PIE { kind: NegOverflow }),
873877
};
874878
}
875879
}

library/core/tests/nonzero.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -135,11 +135,11 @@ fn test_from_str() {
135135
);
136136
assert_eq!(
137137
"-129".parse::<NonZeroI8>().err().map(|e| e.kind().clone()),
138-
Some(IntErrorKind::Underflow)
138+
Some(IntErrorKind::NegOverflow)
139139
);
140140
assert_eq!(
141141
"257".parse::<NonZeroU8>().err().map(|e| e.kind().clone()),
142-
Some(IntErrorKind::Overflow)
142+
Some(IntErrorKind::PosOverflow)
143143
);
144144
}
145145

library/core/tests/num/mod.rs

+39-26
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ use core::cmp::PartialEq;
22
use core::convert::{TryFrom, TryInto};
33
use core::fmt::Debug;
44
use core::marker::Copy;
5-
use core::num::TryFromIntError;
5+
use core::num::{IntErrorKind, ParseIntError, TryFromIntError};
66
use core::ops::{Add, Div, Mul, Rem, Sub};
77
use core::option::Option;
8-
use core::option::Option::{None, Some};
8+
use core::option::Option::None;
9+
use core::str::FromStr;
910

1011
#[macro_use]
1112
mod int_macros;
@@ -67,6 +68,15 @@ where
6768
assert_eq!(ten.rem(two), ten % two);
6869
}
6970

71+
/// Helper function for asserting number parsing returns a specific error
72+
fn test_parse<T>(num_str: &str, expected: Result<T, IntErrorKind>)
73+
where
74+
T: FromStr<Err = ParseIntError>,
75+
Result<T, IntErrorKind>: PartialEq + Debug,
76+
{
77+
assert_eq!(num_str.parse::<T>().map_err(|e| e.kind().clone()), expected)
78+
}
79+
7080
#[test]
7181
fn from_str_issue7588() {
7282
let u: Option<u8> = u8::from_str_radix("1000", 10).ok();
@@ -77,49 +87,52 @@ fn from_str_issue7588() {
7787

7888
#[test]
7989
fn test_int_from_str_overflow() {
80-
assert_eq!("127".parse::<i8>().ok(), Some(127i8));
81-
assert_eq!("128".parse::<i8>().ok(), None);
90+
test_parse::<i8>("127", Ok(127));
91+
test_parse::<i8>("128", Err(IntErrorKind::PosOverflow));
8292

83-
assert_eq!("-128".parse::<i8>().ok(), Some(-128i8));
84-
assert_eq!("-129".parse::<i8>().ok(), None);
93+
test_parse::<i8>("-128", Ok(-128));
94+
test_parse::<i8>("-129", Err(IntErrorKind::NegOverflow));
8595

86-
assert_eq!("32767".parse::<i16>().ok(), Some(32_767i16));
87-
assert_eq!("32768".parse::<i16>().ok(), None);
96+
test_parse::<i16>("32767", Ok(32_767));
97+
test_parse::<i16>("32768", Err(IntErrorKind::PosOverflow));
8898

89-
assert_eq!("-32768".parse::<i16>().ok(), Some(-32_768i16));
90-
assert_eq!("-32769".parse::<i16>().ok(), None);
99+
test_parse::<i16>("-32768", Ok(-32_768));
100+
test_parse::<i16>("-32769", Err(IntErrorKind::NegOverflow));
91101

92-
assert_eq!("2147483647".parse::<i32>().ok(), Some(2_147_483_647i32));
93-
assert_eq!("2147483648".parse::<i32>().ok(), None);
102+
test_parse::<i32>("2147483647", Ok(2_147_483_647));
103+
test_parse::<i32>("2147483648", Err(IntErrorKind::PosOverflow));
94104

95-
assert_eq!("-2147483648".parse::<i32>().ok(), Some(-2_147_483_648i32));
96-
assert_eq!("-2147483649".parse::<i32>().ok(), None);
105+
test_parse::<i32>("-2147483648", Ok(-2_147_483_648));
106+
test_parse::<i32>("-2147483649", Err(IntErrorKind::NegOverflow));
97107

98-
assert_eq!("9223372036854775807".parse::<i64>().ok(), Some(9_223_372_036_854_775_807i64));
99-
assert_eq!("9223372036854775808".parse::<i64>().ok(), None);
108+
test_parse::<i64>("9223372036854775807", Ok(9_223_372_036_854_775_807));
109+
test_parse::<i64>("9223372036854775808", Err(IntErrorKind::PosOverflow));
100110

101-
assert_eq!("-9223372036854775808".parse::<i64>().ok(), Some(-9_223_372_036_854_775_808i64));
102-
assert_eq!("-9223372036854775809".parse::<i64>().ok(), None);
111+
test_parse::<i64>("-9223372036854775808", Ok(-9_223_372_036_854_775_808));
112+
test_parse::<i64>("-9223372036854775809", Err(IntErrorKind::NegOverflow));
103113
}
104114

105115
#[test]
106116
fn test_leading_plus() {
107-
assert_eq!("+127".parse::<u8>().ok(), Some(127));
108-
assert_eq!("+9223372036854775807".parse::<i64>().ok(), Some(9223372036854775807));
117+
test_parse::<u8>("+127", Ok(127));
118+
test_parse::<i64>("+9223372036854775807", Ok(9223372036854775807));
109119
}
110120

111121
#[test]
112122
fn test_invalid() {
113-
assert_eq!("--129".parse::<i8>().ok(), None);
114-
assert_eq!("++129".parse::<i8>().ok(), None);
115-
assert_eq!("Съешь".parse::<u8>().ok(), None);
123+
test_parse::<i8>("--129", Err(IntErrorKind::InvalidDigit));
124+
test_parse::<i8>("++129", Err(IntErrorKind::InvalidDigit));
125+
test_parse::<u8>("Съешь", Err(IntErrorKind::InvalidDigit));
126+
test_parse::<u8>("123Hello", Err(IntErrorKind::InvalidDigit));
127+
test_parse::<i8>("--", Err(IntErrorKind::InvalidDigit));
128+
test_parse::<i8>("-", Err(IntErrorKind::InvalidDigit));
129+
test_parse::<i8>("+", Err(IntErrorKind::InvalidDigit));
130+
test_parse::<u8>("-1", Err(IntErrorKind::InvalidDigit));
116131
}
117132

118133
#[test]
119134
fn test_empty() {
120-
assert_eq!("-".parse::<i8>().ok(), None);
121-
assert_eq!("+".parse::<i8>().ok(), None);
122-
assert_eq!("".parse::<u8>().ok(), None);
135+
test_parse::<u8>("", Err(IntErrorKind::Empty));
123136
}
124137

125138
#[test]

0 commit comments

Comments
 (0)