Add as_slice method for all string nodes (#9111)

This PR adds a `as_slice` method to all the string nodes which returns
all the parts of the nodes as a slice. This will be useful in the next
PR to split the string formatting to use this method to extract the
_single node_ or _implicitly concanated nodes_.
This commit is contained in:
Dhruv Manilawala 2023-12-13 00:31:20 -06:00 committed by GitHub
parent cb99815c3e
commit 18452cf477
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 121 additions and 65 deletions

View file

@ -1277,7 +1277,7 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
} }
Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => { Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => {
if checker.enabled(Rule::UnicodeKindPrefix) { if checker.enabled(Rule::UnicodeKindPrefix) {
for string_part in value.parts() { for string_part in value {
pyupgrade::rules::unicode_kind_prefix(checker, string_part); pyupgrade::rules::unicode_kind_prefix(checker, string_part);
} }
} }

View file

@ -57,7 +57,7 @@ impl Violation for HardcodedSQLExpression {
/// becomes `foobar {x}baz`. /// becomes `foobar {x}baz`.
fn concatenated_f_string(expr: &ast::ExprFString, locator: &Locator) -> String { fn concatenated_f_string(expr: &ast::ExprFString, locator: &Locator) -> String {
expr.value expr.value
.parts() .iter()
.filter_map(|part| { .filter_map(|part| {
raw_contents(locator.slice(part)).map(|s| s.escape_default().to_string()) raw_contents(locator.slice(part)).map(|s| s.escape_default().to_string())
}) })

View file

@ -56,7 +56,7 @@ pub(super) fn is_empty_or_null_string(expr: &Expr) -> bool {
Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => value.is_empty(), Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => value.is_empty(),
Expr::NoneLiteral(_) => true, Expr::NoneLiteral(_) => true,
Expr::FString(ast::ExprFString { value, .. }) => { Expr::FString(ast::ExprFString { value, .. }) => {
value.parts().all(|f_string_part| match f_string_part { value.iter().all(|f_string_part| match f_string_part {
ast::FStringPart::Literal(literal) => literal.is_empty(), ast::FStringPart::Literal(literal) => literal.is_empty(),
ast::FStringPart::FString(f_string) => f_string ast::FStringPart::FString(f_string) => f_string
.elements .elements

View file

@ -70,7 +70,7 @@ pub(crate) fn assert_on_string_literal(checker: &mut Checker, test: &Expr) {
)); ));
} }
Expr::FString(ast::ExprFString { value, .. }) => { Expr::FString(ast::ExprFString { value, .. }) => {
let kind = if value.parts().all(|f_string_part| match f_string_part { let kind = if value.iter().all(|f_string_part| match f_string_part {
ast::FStringPart::Literal(literal) => literal.is_empty(), ast::FStringPart::Literal(literal) => literal.is_empty(),
ast::FStringPart::FString(f_string) => { ast::FStringPart::FString(f_string) => {
f_string.elements.iter().all(|element| match element { f_string.elements.iter().all(|element| match element {
@ -82,7 +82,7 @@ pub(crate) fn assert_on_string_literal(checker: &mut Checker, test: &Expr) {
} }
}) { }) {
Kind::Empty Kind::Empty
} else if value.parts().any(|f_string_part| match f_string_part { } else if value.iter().any(|f_string_part| match f_string_part {
ast::FStringPart::Literal(literal) => !literal.is_empty(), ast::FStringPart::Literal(literal) => !literal.is_empty(),
ast::FStringPart::FString(f_string) => { ast::FStringPart::FString(f_string) => {
f_string.elements.iter().any(|element| match element { f_string.elements.iter().any(|element| match element {

View file

@ -90,7 +90,7 @@ pub(crate) fn raise_vanilla_args(checker: &mut Checker, expr: &Expr) {
fn contains_message(expr: &Expr) -> bool { fn contains_message(expr: &Expr) -> bool {
match expr { match expr {
Expr::FString(ast::ExprFString { value, .. }) => { Expr::FString(ast::ExprFString { value, .. }) => {
for f_string_part in value.parts() { for f_string_part in value {
match f_string_part { match f_string_part {
ast::FStringPart::Literal(literal) => { ast::FStringPart::Literal(literal) => {
if literal.chars().any(char::is_whitespace) { if literal.chars().any(char::is_whitespace) {

View file

@ -583,10 +583,10 @@ impl<'a> From<ast::LiteralExpressionRef<'a>> for ComparableLiteral<'a> {
value, .. value, ..
}) => Self::Bool(value), }) => Self::Bool(value),
ast::LiteralExpressionRef::StringLiteral(ast::ExprStringLiteral { value, .. }) => { ast::LiteralExpressionRef::StringLiteral(ast::ExprStringLiteral { value, .. }) => {
Self::Str(value.parts().map(Into::into).collect()) Self::Str(value.iter().map(Into::into).collect())
} }
ast::LiteralExpressionRef::BytesLiteral(ast::ExprBytesLiteral { value, .. }) => { ast::LiteralExpressionRef::BytesLiteral(ast::ExprBytesLiteral { value, .. }) => {
Self::Bytes(value.parts().map(Into::into).collect()) Self::Bytes(value.iter().map(Into::into).collect())
} }
ast::LiteralExpressionRef::NumberLiteral(ast::ExprNumberLiteral { value, .. }) => { ast::LiteralExpressionRef::NumberLiteral(ast::ExprNumberLiteral { value, .. }) => {
Self::Number(value.into()) Self::Number(value.into())
@ -1012,17 +1012,17 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> {
}), }),
ast::Expr::FString(ast::ExprFString { value, range: _ }) => { ast::Expr::FString(ast::ExprFString { value, range: _ }) => {
Self::FString(ExprFString { Self::FString(ExprFString {
parts: value.parts().map(Into::into).collect(), parts: value.iter().map(Into::into).collect(),
}) })
} }
ast::Expr::StringLiteral(ast::ExprStringLiteral { value, range: _ }) => { ast::Expr::StringLiteral(ast::ExprStringLiteral { value, range: _ }) => {
Self::StringLiteral(ExprStringLiteral { Self::StringLiteral(ExprStringLiteral {
parts: value.parts().map(Into::into).collect(), parts: value.iter().map(Into::into).collect(),
}) })
} }
ast::Expr::BytesLiteral(ast::ExprBytesLiteral { value, range: _ }) => { ast::Expr::BytesLiteral(ast::ExprBytesLiteral { value, range: _ }) => {
Self::BytesLiteral(ExprBytesLiteral { Self::BytesLiteral(ExprBytesLiteral {
parts: value.parts().map(Into::into).collect(), parts: value.iter().map(Into::into).collect(),
}) })
} }
ast::Expr::NumberLiteral(ast::ExprNumberLiteral { value, range: _ }) => { ast::Expr::NumberLiteral(ast::ExprNumberLiteral { value, range: _ }) => {

View file

@ -1326,7 +1326,7 @@ impl Truthiness {
Expr::NoneLiteral(_) => Self::Falsey, Expr::NoneLiteral(_) => Self::Falsey,
Expr::EllipsisLiteral(_) => Self::Truthy, Expr::EllipsisLiteral(_) => Self::Truthy,
Expr::FString(ast::ExprFString { value, .. }) => { Expr::FString(ast::ExprFString { value, .. }) => {
if value.parts().all(|part| match part { if value.iter().all(|part| match part {
ast::FStringPart::Literal(string_literal) => string_literal.is_empty(), ast::FStringPart::Literal(string_literal) => string_literal.is_empty(),
ast::FStringPart::FString(f_string) => f_string.elements.is_empty(), ast::FStringPart::FString(f_string) => f_string.elements.is_empty(),
}) { }) {

View file

@ -2742,7 +2742,7 @@ impl AstNode for ast::ExprFString {
{ {
let ast::ExprFString { value, range: _ } = self; let ast::ExprFString { value, range: _ } = self;
for f_string_part in value.parts() { for f_string_part in value {
match f_string_part { match f_string_part {
ast::FStringPart::Literal(string_literal) => { ast::FStringPart::Literal(string_literal) => {
visitor.visit_string_literal(string_literal); visitor.visit_string_literal(string_literal);
@ -2788,7 +2788,7 @@ impl AstNode for ast::ExprStringLiteral {
{ {
let ast::ExprStringLiteral { value, range: _ } = self; let ast::ExprStringLiteral { value, range: _ } = self;
for string_literal in value.parts() { for string_literal in value {
visitor.visit_string_literal(string_literal); visitor.visit_string_literal(string_literal);
} }
} }
@ -2827,7 +2827,7 @@ impl AstNode for ast::ExprBytesLiteral {
{ {
let ast::ExprBytesLiteral { value, range: _ } = self; let ast::ExprBytesLiteral { value, range: _ } = self;
for bytes_literal in value.parts() { for bytes_literal in value {
visitor.visit_bytes_literal(bytes_literal); visitor.visit_bytes_literal(bytes_literal);
} }
} }

View file

@ -4,8 +4,8 @@ use std::cell::OnceCell;
use std::fmt; use std::fmt;
use std::fmt::Debug; use std::fmt::Debug;
use std::ops::Deref; use std::ops::Deref;
use std::slice::{Iter, IterMut};
use itertools::Either::{Left, Right};
use itertools::Itertools; use itertools::Itertools;
use ruff_text_size::{Ranged, TextRange, TextSize}; use ruff_text_size::{Ranged, TextRange, TextSize};
@ -1051,21 +1051,31 @@ impl FStringValue {
matches!(self.inner, FStringValueInner::Concatenated(_)) matches!(self.inner, FStringValueInner::Concatenated(_))
} }
/// Returns an iterator over all the [`FStringPart`]s contained in this value. /// Returns a slice of all the [`FStringPart`]s contained in this value.
pub fn parts(&self) -> impl Iterator<Item = &FStringPart> { pub fn as_slice(&self) -> &[FStringPart] {
match &self.inner { match &self.inner {
FStringValueInner::Single(part) => Left(std::iter::once(part)), FStringValueInner::Single(part) => std::slice::from_ref(part),
FStringValueInner::Concatenated(parts) => Right(parts.iter()), FStringValueInner::Concatenated(parts) => parts,
} }
} }
/// Returns a mutable slice of all the [`FStringPart`]s contained in this value.
fn as_mut_slice(&mut self) -> &mut [FStringPart] {
match &mut self.inner {
FStringValueInner::Single(part) => std::slice::from_mut(part),
FStringValueInner::Concatenated(parts) => parts,
}
}
/// Returns an iterator over all the [`FStringPart`]s contained in this value.
pub fn iter(&self) -> Iter<FStringPart> {
self.as_slice().iter()
}
/// Returns an iterator over all the [`FStringPart`]s contained in this value /// Returns an iterator over all the [`FStringPart`]s contained in this value
/// that allows modification. /// that allows modification.
pub(crate) fn parts_mut(&mut self) -> impl Iterator<Item = &mut FStringPart> { pub(crate) fn iter_mut(&mut self) -> IterMut<FStringPart> {
match &mut self.inner { self.as_mut_slice().iter_mut()
FStringValueInner::Single(part) => Left(std::iter::once(part)),
FStringValueInner::Concatenated(parts) => Right(parts.iter_mut()),
}
} }
/// Returns an iterator over the [`StringLiteral`] parts contained in this value. /// Returns an iterator over the [`StringLiteral`] parts contained in this value.
@ -1078,7 +1088,7 @@ impl FStringValue {
/// ///
/// Here, the string literal parts returned would be `"foo"` and `"baz"`. /// Here, the string literal parts returned would be `"foo"` and `"baz"`.
pub fn literals(&self) -> impl Iterator<Item = &StringLiteral> { pub fn literals(&self) -> impl Iterator<Item = &StringLiteral> {
self.parts().filter_map(|part| part.as_literal()) self.iter().filter_map(|part| part.as_literal())
} }
/// Returns an iterator over the [`FString`] parts contained in this value. /// Returns an iterator over the [`FString`] parts contained in this value.
@ -1091,7 +1101,7 @@ impl FStringValue {
/// ///
/// Here, the f-string parts returned would be `f"bar {x}"` and `f"qux"`. /// Here, the f-string parts returned would be `f"bar {x}"` and `f"qux"`.
pub fn f_strings(&self) -> impl Iterator<Item = &FString> { pub fn f_strings(&self) -> impl Iterator<Item = &FString> {
self.parts().filter_map(|part| part.as_f_string()) self.iter().filter_map(|part| part.as_f_string())
} }
/// Returns an iterator over all the [`FStringElement`] contained in this value. /// Returns an iterator over all the [`FStringElement`] contained in this value.
@ -1110,6 +1120,15 @@ impl FStringValue {
} }
} }
impl<'a> IntoIterator for &'a FStringValue {
type Item = &'a FStringPart;
type IntoIter = Iter<'a, FStringPart>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
/// An internal representation of [`FStringValue`]. /// An internal representation of [`FStringValue`].
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
enum FStringValueInner { enum FStringValueInner {
@ -1238,24 +1257,34 @@ impl StringLiteralValue {
/// For an implicitly concatenated string, it returns `true` only if the first /// For an implicitly concatenated string, it returns `true` only if the first
/// string literal is a unicode string. /// string literal is a unicode string.
pub fn is_unicode(&self) -> bool { pub fn is_unicode(&self) -> bool {
self.parts().next().map_or(false, |part| part.unicode) self.iter().next().map_or(false, |part| part.unicode)
}
/// Returns a slice of all the [`StringLiteral`] parts contained in this value.
pub fn as_slice(&self) -> &[StringLiteral] {
match &self.inner {
StringLiteralValueInner::Single(value) => std::slice::from_ref(value),
StringLiteralValueInner::Concatenated(value) => value.strings.as_slice(),
}
}
/// Returns a mutable slice of all the [`StringLiteral`] parts contained in this value.
fn as_mut_slice(&mut self) -> &mut [StringLiteral] {
match &mut self.inner {
StringLiteralValueInner::Single(value) => std::slice::from_mut(value),
StringLiteralValueInner::Concatenated(value) => value.strings.as_mut_slice(),
}
} }
/// Returns an iterator over all the [`StringLiteral`] parts contained in this value. /// Returns an iterator over all the [`StringLiteral`] parts contained in this value.
pub fn parts(&self) -> impl Iterator<Item = &StringLiteral> { pub fn iter(&self) -> Iter<StringLiteral> {
match &self.inner { self.as_slice().iter()
StringLiteralValueInner::Single(value) => Left(std::iter::once(value)),
StringLiteralValueInner::Concatenated(value) => Right(value.strings.iter()),
}
} }
/// Returns an iterator over all the [`StringLiteral`] parts contained in this value /// Returns an iterator over all the [`StringLiteral`] parts contained in this value
/// that allows modification. /// that allows modification.
pub(crate) fn parts_mut(&mut self) -> impl Iterator<Item = &mut StringLiteral> { pub(crate) fn iter_mut(&mut self) -> IterMut<StringLiteral> {
match &mut self.inner { self.as_mut_slice().iter_mut()
StringLiteralValueInner::Single(value) => Left(std::iter::once(value)),
StringLiteralValueInner::Concatenated(value) => Right(value.strings.iter_mut()),
}
} }
/// Returns `true` if the string literal value is empty. /// Returns `true` if the string literal value is empty.
@ -1266,12 +1295,12 @@ impl StringLiteralValue {
/// Returns the total length of the string literal value, in bytes, not /// Returns the total length of the string literal value, in bytes, not
/// [`char`]s or graphemes. /// [`char`]s or graphemes.
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.parts().fold(0, |acc, part| acc + part.value.len()) self.iter().fold(0, |acc, part| acc + part.value.len())
} }
/// Returns an iterator over the [`char`]s of each string literal part. /// Returns an iterator over the [`char`]s of each string literal part.
pub fn chars(&self) -> impl Iterator<Item = char> + '_ { pub fn chars(&self) -> impl Iterator<Item = char> + '_ {
self.parts().flat_map(|part| part.value.chars()) self.iter().flat_map(|part| part.value.chars())
} }
/// Returns the concatenated string value as a [`str`]. /// Returns the concatenated string value as a [`str`].
@ -1286,6 +1315,15 @@ impl StringLiteralValue {
} }
} }
impl<'a> IntoIterator for &'a StringLiteralValue {
type Item = &'a StringLiteral;
type IntoIter = Iter<'a, StringLiteral>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl PartialEq<str> for StringLiteralValue { impl PartialEq<str> for StringLiteralValue {
fn eq(&self, other: &str) -> bool { fn eq(&self, other: &str) -> bool {
if self.len() != other.len() { if self.len() != other.len() {
@ -1457,37 +1495,55 @@ impl BytesLiteralValue {
matches!(self.inner, BytesLiteralValueInner::Concatenated(_)) matches!(self.inner, BytesLiteralValueInner::Concatenated(_))
} }
/// Returns an iterator over all the [`BytesLiteral`] parts contained in this value. /// Returns a slice of all the [`BytesLiteral`] parts contained in this value.
pub fn parts(&self) -> impl Iterator<Item = &BytesLiteral> { pub fn as_slice(&self) -> &[BytesLiteral] {
match &self.inner { match &self.inner {
BytesLiteralValueInner::Single(value) => Left(std::iter::once(value)), BytesLiteralValueInner::Single(value) => std::slice::from_ref(value),
BytesLiteralValueInner::Concatenated(values) => Right(values.iter()), BytesLiteralValueInner::Concatenated(value) => value.as_slice(),
} }
} }
/// Returns a mutable slice of all the [`BytesLiteral`] parts contained in this value.
fn as_mut_slice(&mut self) -> &mut [BytesLiteral] {
match &mut self.inner {
BytesLiteralValueInner::Single(value) => std::slice::from_mut(value),
BytesLiteralValueInner::Concatenated(value) => value.as_mut_slice(),
}
}
/// Returns an iterator over all the [`BytesLiteral`] parts contained in this value.
pub fn iter(&self) -> Iter<BytesLiteral> {
self.as_slice().iter()
}
/// Returns an iterator over all the [`BytesLiteral`] parts contained in this value /// Returns an iterator over all the [`BytesLiteral`] parts contained in this value
/// that allows modification. /// that allows modification.
pub(crate) fn parts_mut(&mut self) -> impl Iterator<Item = &mut BytesLiteral> { pub(crate) fn iter_mut(&mut self) -> IterMut<BytesLiteral> {
match &mut self.inner { self.as_mut_slice().iter_mut()
BytesLiteralValueInner::Single(value) => Left(std::iter::once(value)),
BytesLiteralValueInner::Concatenated(values) => Right(values.iter_mut()),
}
} }
/// Returns `true` if the concatenated bytes has a length of zero. /// Returns `true` if the concatenated bytes has a length of zero.
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.parts().all(|part| part.is_empty()) self.iter().all(|part| part.is_empty())
} }
/// Returns the length of the concatenated bytes. /// Returns the length of the concatenated bytes.
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.parts().map(|part| part.len()).sum() self.iter().map(|part| part.len()).sum()
} }
/// Returns an iterator over the bytes of the concatenated bytes. /// Returns an iterator over the bytes of the concatenated bytes.
fn bytes(&self) -> impl Iterator<Item = u8> + '_ { fn bytes(&self) -> impl Iterator<Item = u8> + '_ {
self.parts() self.iter().flat_map(|part| part.as_slice().iter().copied())
.flat_map(|part| part.as_slice().iter().copied()) }
}
impl<'a> IntoIterator for &'a BytesLiteralValue {
type Item = &'a BytesLiteral;
type IntoIter = Iter<'a, BytesLiteral>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
} }
} }

View file

@ -477,7 +477,7 @@ pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) {
visitor.visit_arguments(arguments); visitor.visit_arguments(arguments);
} }
Expr::FString(ast::ExprFString { value, .. }) => { Expr::FString(ast::ExprFString { value, .. }) => {
for part in value.parts() { for part in value {
match part { match part {
FStringPart::Literal(string_literal) => { FStringPart::Literal(string_literal) => {
visitor.visit_string_literal(string_literal); visitor.visit_string_literal(string_literal);
@ -487,12 +487,12 @@ pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) {
} }
} }
Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => { Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => {
for string_literal in value.parts() { for string_literal in value {
visitor.visit_string_literal(string_literal); visitor.visit_string_literal(string_literal);
} }
} }
Expr::BytesLiteral(ast::ExprBytesLiteral { value, .. }) => { Expr::BytesLiteral(ast::ExprBytesLiteral { value, .. }) => {
for bytes_literal in value.parts() { for bytes_literal in value {
visitor.visit_bytes_literal(bytes_literal); visitor.visit_bytes_literal(bytes_literal);
} }
} }

View file

@ -464,7 +464,7 @@ pub fn walk_expr<V: Transformer + ?Sized>(visitor: &V, expr: &mut Expr) {
visitor.visit_arguments(arguments); visitor.visit_arguments(arguments);
} }
Expr::FString(ast::ExprFString { value, .. }) => { Expr::FString(ast::ExprFString { value, .. }) => {
for f_string_part in value.parts_mut() { for f_string_part in value.iter_mut() {
match f_string_part { match f_string_part {
ast::FStringPart::Literal(string_literal) => { ast::FStringPart::Literal(string_literal) => {
visitor.visit_string_literal(string_literal); visitor.visit_string_literal(string_literal);
@ -476,12 +476,12 @@ pub fn walk_expr<V: Transformer + ?Sized>(visitor: &V, expr: &mut Expr) {
} }
} }
Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => { Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => {
for string_literal in value.parts_mut() { for string_literal in value.iter_mut() {
visitor.visit_string_literal(string_literal); visitor.visit_string_literal(string_literal);
} }
} }
Expr::BytesLiteral(ast::ExprBytesLiteral { value, .. }) => { Expr::BytesLiteral(ast::ExprBytesLiteral { value, .. }) => {
for bytes_literal in value.parts_mut() { for bytes_literal in value.iter_mut() {
visitor.visit_bytes_literal(bytes_literal); visitor.visit_bytes_literal(bytes_literal);
} }
} }

View file

@ -1077,7 +1077,7 @@ impl<'a> Generator<'a> {
} }
Expr::BytesLiteral(ast::ExprBytesLiteral { value, .. }) => { Expr::BytesLiteral(ast::ExprBytesLiteral { value, .. }) => {
let mut first = true; let mut first = true;
for bytes_literal in value.parts() { for bytes_literal in value {
self.p_delim(&mut first, " "); self.p_delim(&mut first, " ");
self.p_bytes_repr(&bytes_literal.value); self.p_bytes_repr(&bytes_literal.value);
} }
@ -1273,7 +1273,7 @@ impl<'a> Generator<'a> {
fn unparse_string_literal_value(&mut self, value: &ast::StringLiteralValue) { fn unparse_string_literal_value(&mut self, value: &ast::StringLiteralValue) {
let mut first = true; let mut first = true;
for string_literal in value.parts() { for string_literal in value {
self.p_delim(&mut first, " "); self.p_delim(&mut first, " ");
self.unparse_string_literal(string_literal); self.unparse_string_literal(string_literal);
} }
@ -1281,7 +1281,7 @@ impl<'a> Generator<'a> {
fn unparse_f_string_value(&mut self, value: &ast::FStringValue, is_spec: bool) { fn unparse_f_string_value(&mut self, value: &ast::FStringValue, is_spec: bool) {
let mut first = true; let mut first = true;
for f_string_part in value.parts() { for f_string_part in value {
self.p_delim(&mut first, " "); self.p_delim(&mut first, " ");
match f_string_part { match f_string_part {
ast::FStringPart::Literal(string_literal) => { ast::FStringPart::Literal(string_literal) => {

View file

@ -86,13 +86,13 @@ impl<'a> AnyString<'a> {
fn parts(&self) -> Vec<AnyStringPart<'a>> { fn parts(&self) -> Vec<AnyStringPart<'a>> {
match self { match self {
Self::String(ExprStringLiteral { value, .. }) => { Self::String(ExprStringLiteral { value, .. }) => {
value.parts().map(AnyStringPart::String).collect() value.iter().map(AnyStringPart::String).collect()
} }
Self::Bytes(ExprBytesLiteral { value, .. }) => { Self::Bytes(ExprBytesLiteral { value, .. }) => {
value.parts().map(AnyStringPart::Bytes).collect() value.iter().map(AnyStringPart::Bytes).collect()
} }
Self::FString(ExprFString { value, .. }) => value Self::FString(ExprFString { value, .. }) => value
.parts() .iter()
.map(|f_string_part| match f_string_part { .map(|f_string_part| match f_string_part {
ast::FStringPart::Literal(string_literal) => { ast::FStringPart::Literal(string_literal) => {
AnyStringPart::String(string_literal) AnyStringPart::String(string_literal)