Auto merge of #38066 - bluss:string-slice-error, r=sfackler
Use more specific panic message for &str slicing errors Separate out of bounds errors from character boundary errors, and print more details for character boundary errors. It reports the first error it finds in: 1. begin out of bounds 2. end out of bounds 3. begin <= end violated 3. begin not char boundary 5. end not char boundary. Example: &"abcαβγ"[..4] thread 'str::test_slice_fail_boundary_1' panicked at 'byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of `abcαβγ`' Fixes #38052
This commit is contained in:
commit
468227129d
@ -163,8 +163,8 @@ let hachi = &dog[0..2];
|
||||
with this error:
|
||||
|
||||
```text
|
||||
thread 'main' panicked at 'index 0 and/or 2 in `忠犬ハチ公` do not lie on
|
||||
character boundary'
|
||||
thread 'main' panicked at 'byte index 2 is not a char boundary; it is inside '忠'
|
||||
(bytes 0..3) of `忠犬ハチ公`'
|
||||
```
|
||||
|
||||
## Concatenation
|
||||
|
@ -383,17 +383,29 @@ fn test_is_char_boundary() {
|
||||
|
||||
// check the panic includes the prefix of the sliced string
|
||||
#[test]
|
||||
#[should_panic(expected="Lorem ipsum dolor sit amet")]
|
||||
#[should_panic(expected="byte index 1024 is out of bounds of `Lorem ipsum dolor sit amet")]
|
||||
fn test_slice_fail_truncated_1() {
|
||||
&LOREM_PARAGRAPH[..1024];
|
||||
}
|
||||
// check the truncation in the panic message
|
||||
#[test]
|
||||
#[should_panic(expected="luctus, im`[...] do not lie on character boundary")]
|
||||
#[should_panic(expected="luctus, im`[...]")]
|
||||
fn test_slice_fail_truncated_2() {
|
||||
&LOREM_PARAGRAPH[..1024];
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected="byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of")]
|
||||
fn test_slice_fail_boundary_1() {
|
||||
&"abcαβγ"[4..];
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected="byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of")]
|
||||
fn test_slice_fail_boundary_2() {
|
||||
&"abcαβγ"[2..6];
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_slice_from() {
|
||||
assert_eq!(&"abcd"[0..], "abcd");
|
||||
|
@ -1746,13 +1746,31 @@ fn truncate_to_char_boundary(s: &str, mut max: usize) -> (bool, &str) {
|
||||
#[cold]
|
||||
fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! {
|
||||
const MAX_DISPLAY_LENGTH: usize = 256;
|
||||
let (truncated, s) = truncate_to_char_boundary(s, MAX_DISPLAY_LENGTH);
|
||||
let (truncated, s_trunc) = truncate_to_char_boundary(s, MAX_DISPLAY_LENGTH);
|
||||
let ellipsis = if truncated { "[...]" } else { "" };
|
||||
|
||||
// 1. out of bounds
|
||||
if begin > s.len() || end > s.len() {
|
||||
let oob_index = if begin > s.len() { begin } else { end };
|
||||
panic!("byte index {} is out of bounds of `{}`{}", oob_index, s_trunc, ellipsis);
|
||||
}
|
||||
|
||||
// 2. begin <= end
|
||||
assert!(begin <= end, "begin <= end ({} <= {}) when slicing `{}`{}",
|
||||
begin, end, s, ellipsis);
|
||||
panic!("index {} and/or {} in `{}`{} do not lie on character boundary",
|
||||
begin, end, s, ellipsis);
|
||||
begin, end, s_trunc, ellipsis);
|
||||
|
||||
// 3. character boundary
|
||||
let index = if !s.is_char_boundary(begin) { begin } else { end };
|
||||
// find the character
|
||||
let mut char_start = index;
|
||||
while !s.is_char_boundary(char_start) {
|
||||
char_start -= 1;
|
||||
}
|
||||
// `char_start` must be less than len and a char boundary
|
||||
let ch = s[char_start..].chars().next().unwrap();
|
||||
let char_range = char_start .. char_start + ch.len_utf8();
|
||||
panic!("byte index {} is not a char boundary; it is inside {:?} (bytes {:?}) of `{}`{}",
|
||||
index, ch, char_range, s_trunc, ellipsis);
|
||||
}
|
||||
|
||||
#[stable(feature = "core", since = "1.6.0")]
|
||||
|
Loading…
Reference in New Issue
Block a user