Refactor the ExprDict node (#11267)

Co-authored-by: Micha Reiser <micha@reiser.io>
This commit is contained in:
Alex Waygood 2024-05-07 12:46:10 +01:00 committed by GitHub
parent de270154a1
commit 6774f27f4b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
52 changed files with 2425 additions and 2240 deletions

View file

@ -1172,8 +1172,8 @@ impl<'a> Visitor<'a> for Checker<'a> {
let Keyword { arg, value, .. } = keyword; let Keyword { arg, value, .. } = keyword;
match (arg.as_ref(), value) { match (arg.as_ref(), value) {
// Ex) NamedTuple("a", **{"a": int}) // Ex) NamedTuple("a", **{"a": int})
(None, Expr::Dict(ast::ExprDict { keys, values, .. })) => { (None, Expr::Dict(ast::ExprDict { items, .. })) => {
for (key, value) in keys.iter().zip(values) { for ast::DictItem { key, value } in items {
if let Some(key) = key.as_ref() { if let Some(key) = key.as_ref() {
self.visit_non_type_definition(key); self.visit_non_type_definition(key);
self.visit_type_definition(value); self.visit_type_definition(value);
@ -1200,16 +1200,11 @@ impl<'a> Visitor<'a> for Checker<'a> {
self.visit_non_type_definition(arg); self.visit_non_type_definition(arg);
} }
for arg in args { for arg in args {
if let Expr::Dict(ast::ExprDict { if let Expr::Dict(ast::ExprDict { items, range: _ }) = arg {
keys, for ast::DictItem { key, value } in items {
values, if let Some(key) = key {
range: _, self.visit_non_type_definition(key);
}) = arg }
{
for key in keys.iter().flatten() {
self.visit_non_type_definition(key);
}
for value in values {
self.visit_type_definition(value); self.visit_type_definition(value);
} }
} else { } else {

View file

@ -54,11 +54,12 @@ fn is_call_insecure(call: &ast::ExprCall) -> bool {
if let Some(argument) = call.arguments.find_argument(argument_name, position) { if let Some(argument) = call.arguments.find_argument(argument_name, position) {
match argument_name { match argument_name {
"select" => match argument { "select" => match argument {
Expr::Dict(ExprDict { keys, values, .. }) => { Expr::Dict(ExprDict { items, .. }) => {
if !keys.iter().flatten().all(Expr::is_string_literal_expr) { if items.iter().any(|ast::DictItem { key, value }| {
return true; key.as_ref()
} .is_some_and(|key| !key.is_string_literal_expr())
if !values.iter().all(Expr::is_string_literal_expr) { || !value.is_string_literal_expr()
}) {
return true; return true;
} }
} }

View file

@ -89,18 +89,19 @@ fn check_msg(checker: &mut Checker, msg: &Expr) {
/// Check contents of the `extra` argument to logging calls. /// Check contents of the `extra` argument to logging calls.
fn check_log_record_attr_clash(checker: &mut Checker, extra: &Keyword) { fn check_log_record_attr_clash(checker: &mut Checker, extra: &Keyword) {
match &extra.value { match &extra.value {
Expr::Dict(ast::ExprDict { keys, .. }) => { Expr::Dict(dict) => {
for key in keys { for invalid_key in dict.iter_keys().filter_map(|key| {
if let Some(key) = &key { let string_key = key?.as_string_literal_expr()?;
if let Expr::StringLiteral(ast::ExprStringLiteral { value: attr, .. }) = key { if is_reserved_attr(string_key.value.to_str()) {
if is_reserved_attr(attr.to_str()) { Some(string_key)
checker.diagnostics.push(Diagnostic::new( } else {
LoggingExtraAttrClash(attr.to_string()), None
key.range(),
));
}
}
} }
}) {
checker.diagnostics.push(Diagnostic::new(
LoggingExtraAttrClash(invalid_key.value.to_string()),
invalid_key.range(),
));
} }
} }
Expr::Call(ast::ExprCall { Expr::Call(ast::ExprCall {

View file

@ -71,7 +71,7 @@ pub(crate) fn reimplemented_container_builtin(checker: &mut Checker, expr: &Expr
let container = match &**body { let container = match &**body {
Expr::List(ast::ExprList { elts, .. }) if elts.is_empty() => Container::List, Expr::List(ast::ExprList { elts, .. }) if elts.is_empty() => Container::List,
Expr::Dict(ast::ExprDict { values, .. }) if values.is_empty() => Container::Dict, Expr::Dict(ast::ExprDict { items, .. }) if items.is_empty() => Container::Dict,
_ => return, _ => return,
}; };
let mut diagnostic = Diagnostic::new(ReimplementedContainerBuiltin { container }, expr.range()); let mut diagnostic = Diagnostic::new(ReimplementedContainerBuiltin { container }, expr.range());

View file

@ -65,36 +65,36 @@ pub(crate) fn unnecessary_dict_kwargs(checker: &mut Checker, call: &ast::ExprCal
continue; continue;
} }
let Expr::Dict(ast::ExprDict { keys, values, .. }) = &keyword.value else { let Expr::Dict(dict) = &keyword.value else {
continue; continue;
}; };
// Ex) `foo(**{**bar})` // Ex) `foo(**{**bar})`
if matches!(keys.as_slice(), [None]) { if let [ast::DictItem { key: None, value }] = dict.items.as_slice() {
let mut diagnostic = Diagnostic::new(UnnecessaryDictKwargs, keyword.range()); let diagnostic = Diagnostic::new(UnnecessaryDictKwargs, keyword.range());
let edit = Edit::range_replacement(
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( format!("**{}", checker.locator().slice(value)),
format!("**{}", checker.locator().slice(values[0].range())),
keyword.range(), keyword.range(),
))); );
checker
checker.diagnostics.push(diagnostic); .diagnostics
.push(diagnostic.with_fix(Fix::safe_edit(edit)));
continue; continue;
} }
// Ensure that every keyword is a valid keyword argument (e.g., avoid errors for cases like // Ensure that every keyword is a valid keyword argument (e.g., avoid errors for cases like
// `foo(**{"bar-bar": 1})`). // `foo(**{"bar-bar": 1})`).
let kwargs = keys let kwargs: Vec<&str> = dict
.iter() .iter_keys()
.filter_map(|key| key.as_ref().and_then(as_kwarg)) .filter_map(|key| key.and_then(as_kwarg))
.collect::<Vec<_>>(); .collect();
if kwargs.len() != keys.len() { if kwargs.len() != dict.items.len() {
continue; continue;
} }
let mut diagnostic = Diagnostic::new(UnnecessaryDictKwargs, keyword.range()); let mut diagnostic = Diagnostic::new(UnnecessaryDictKwargs, keyword.range());
if values.is_empty() { if dict.items.is_empty() {
diagnostic.try_set_fix(|| { diagnostic.try_set_fix(|| {
remove_argument( remove_argument(
keyword, keyword,
@ -119,7 +119,7 @@ pub(crate) fn unnecessary_dict_kwargs(checker: &mut Checker, call: &ast::ExprCal
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement( diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
kwargs kwargs
.iter() .iter()
.zip(values.iter()) .zip(dict.iter_values())
.map(|(kwarg, value)| { .map(|(kwarg, value)| {
format!("{}={}", kwarg, checker.locator().slice(value.range())) format!("{}={}", kwarg, checker.locator().slice(value.range()))
}) })
@ -150,9 +150,9 @@ fn duplicates(call: &ast::ExprCall) -> FxHashSet<&str> {
if !seen.insert(name.as_str()) { if !seen.insert(name.as_str()) {
duplicates.insert(name.as_str()); duplicates.insert(name.as_str());
} }
} else if let Expr::Dict(ast::ExprDict { keys, .. }) = &keyword.value { } else if let Expr::Dict(dict) = &keyword.value {
for key in keys { for key in dict.iter_keys() {
if let Some(name) = key.as_ref().and_then(as_kwarg) { if let Some(name) = key.and_then(as_kwarg) {
if !seen.insert(name) { if !seen.insert(name) {
duplicates.insert(name); duplicates.insert(name);
} }

View file

@ -49,8 +49,8 @@ impl Violation for UnnecessarySpread {
pub(crate) fn unnecessary_spread(checker: &mut Checker, dict: &ast::ExprDict) { pub(crate) fn unnecessary_spread(checker: &mut Checker, dict: &ast::ExprDict) {
// The first "end" is the start of the dictionary, immediately following the open bracket. // The first "end" is the start of the dictionary, immediately following the open bracket.
let mut prev_end = dict.start() + TextSize::from(1); let mut prev_end = dict.start() + TextSize::from(1);
for item in dict.keys.iter().zip(dict.values.iter()) { for ast::DictItem { key, value } in &dict.items {
if let (None, value) = item { if key.is_none() {
// We only care about when the key is None which indicates a spread `**` // We only care about when the key is None which indicates a spread `**`
// inside a dict. // inside a dict.
if let Expr::Dict(inner) = value { if let Expr::Dict(inner) = value {
@ -61,7 +61,7 @@ pub(crate) fn unnecessary_spread(checker: &mut Checker, dict: &ast::ExprDict) {
checker.diagnostics.push(diagnostic); checker.diagnostics.push(diagnostic);
} }
} }
prev_end = item.1.end(); prev_end = value.end();
} }
} }
@ -75,7 +75,7 @@ fn unnecessary_spread_fix(
let doublestar = SimpleTokenizer::starts_at(prev_end, locator.contents()) let doublestar = SimpleTokenizer::starts_at(prev_end, locator.contents())
.find(|tok| matches!(tok.kind(), SimpleTokenKind::DoubleStar))?; .find(|tok| matches!(tok.kind(), SimpleTokenKind::DoubleStar))?;
if let Some(last) = dict.values.last() { if let Some(last) = dict.iter_values().last() {
// Ex) `**{a: 1, b: 2}` // Ex) `**{a: 1, b: 2}`
let mut edits = vec![]; let mut edits = vec![];
for tok in SimpleTokenizer::starts_at(last.end(), locator.contents()).skip_trivia() { for tok in SimpleTokenizer::starts_at(last.end(), locator.contents()).skip_trivia() {

View file

@ -298,17 +298,13 @@ fn is_valid_default_value_with_annotation(
.iter() .iter()
.all(|e| is_valid_default_value_with_annotation(e, false, locator, semantic)); .all(|e| is_valid_default_value_with_annotation(e, false, locator, semantic));
} }
Expr::Dict(ast::ExprDict { Expr::Dict(ast::ExprDict { items, range: _ }) => {
keys,
values,
range: _,
}) => {
return allow_container return allow_container
&& keys.len() <= 10 && items.len() <= 10
&& keys.iter().zip(values).all(|(k, v)| { && items.iter().all(|ast::DictItem { key, value }| {
k.as_ref().is_some_and(|k| { key.as_ref().is_some_and(|key| {
is_valid_default_value_with_annotation(k, false, locator, semantic) is_valid_default_value_with_annotation(key, false, locator, semantic)
}) && is_valid_default_value_with_annotation(v, false, locator, semantic) }) && is_valid_default_value_with_annotation(value, false, locator, semantic)
}); });
} }
Expr::UnaryOp(ast::ExprUnaryOp { Expr::UnaryOp(ast::ExprUnaryOp {

View file

@ -113,8 +113,8 @@ impl ConstantLikelihood {
.map(|expr| ConstantLikelihood::from_expression(expr, preview)) .map(|expr| ConstantLikelihood::from_expression(expr, preview))
.min() .min()
.unwrap_or(ConstantLikelihood::Definitely), .unwrap_or(ConstantLikelihood::Definitely),
Expr::Dict(ast::ExprDict { values: vs, .. }) if preview.is_enabled() => { Expr::Dict(ast::ExprDict { items, .. }) if preview.is_enabled() => {
if vs.is_empty() { if items.is_empty() {
ConstantLikelihood::Definitely ConstantLikelihood::Definitely
} else { } else {
ConstantLikelihood::Probably ConstantLikelihood::Probably

View file

@ -132,10 +132,10 @@ impl Violation for MultiValueRepeatedKeyVariable {
pub(crate) fn repeated_keys(checker: &mut Checker, dict: &ast::ExprDict) { pub(crate) fn repeated_keys(checker: &mut Checker, dict: &ast::ExprDict) {
// Generate a map from key to (index, value). // Generate a map from key to (index, value).
let mut seen: FxHashMap<ComparableExpr, FxHashSet<ComparableExpr>> = let mut seen: FxHashMap<ComparableExpr, FxHashSet<ComparableExpr>> =
FxHashMap::with_capacity_and_hasher(dict.keys.len(), BuildHasherDefault::default()); FxHashMap::with_capacity_and_hasher(dict.items.len(), BuildHasherDefault::default());
// Detect duplicate keys. // Detect duplicate keys.
for (i, (key, value)) in dict.keys.iter().zip(dict.values.iter()).enumerate() { for (i, ast::DictItem { key, value }) in dict.items.iter().enumerate() {
let Some(key) = key else { let Some(key) = key else {
continue; continue;
}; };
@ -167,20 +167,20 @@ pub(crate) fn repeated_keys(checker: &mut Checker, dict: &ast::ExprDict) {
if !seen_values.insert(comparable_value) { if !seen_values.insert(comparable_value) {
diagnostic.set_fix(Fix::unsafe_edit(Edit::deletion( diagnostic.set_fix(Fix::unsafe_edit(Edit::deletion(
parenthesized_range( parenthesized_range(
(&dict.values[i - 1]).into(), dict.value(i - 1).into(),
dict.into(), dict.into(),
checker.indexer().comment_ranges(), checker.indexer().comment_ranges(),
checker.locator().contents(), checker.locator().contents(),
) )
.unwrap_or(dict.values[i - 1].range()) .unwrap_or_else(|| dict.value(i - 1).range())
.end(), .end(),
parenthesized_range( parenthesized_range(
(&dict.values[i]).into(), dict.value(i).into(),
dict.into(), dict.into(),
checker.indexer().comment_ranges(), checker.indexer().comment_ranges(),
checker.locator().contents(), checker.locator().contents(),
) )
.unwrap_or(dict.values[i].range()) .unwrap_or_else(|| dict.value(i).range())
.end(), .end(),
))); )));
} }
@ -195,24 +195,24 @@ pub(crate) fn repeated_keys(checker: &mut Checker, dict: &ast::ExprDict) {
}, },
key.range(), key.range(),
); );
let comparable_value: ComparableExpr = (&dict.values[i]).into(); let comparable_value: ComparableExpr = dict.value(i).into();
if !seen_values.insert(comparable_value) { if !seen_values.insert(comparable_value) {
diagnostic.set_fix(Fix::unsafe_edit(Edit::deletion( diagnostic.set_fix(Fix::unsafe_edit(Edit::deletion(
parenthesized_range( parenthesized_range(
(&dict.values[i - 1]).into(), dict.value(i - 1).into(),
dict.into(), dict.into(),
checker.indexer().comment_ranges(), checker.indexer().comment_ranges(),
checker.locator().contents(), checker.locator().contents(),
) )
.unwrap_or(dict.values[i - 1].range()) .unwrap_or_else(|| dict.value(i - 1).range())
.end(), .end(),
parenthesized_range( parenthesized_range(
(&dict.values[i]).into(), dict.value(i).into(),
dict.into(), dict.into(),
checker.indexer().comment_ranges(), checker.indexer().comment_ranges(),
checker.locator().contents(), checker.locator().contents(),
) )
.unwrap_or(dict.values[i].range()) .unwrap_or_else(|| dict.value(i).range())
.end(), .end(),
))); )));
} }

View file

@ -573,13 +573,12 @@ pub(crate) fn percent_format_extra_named_arguments(
return; return;
}; };
// If any of the keys are spread, abort. // If any of the keys are spread, abort.
if dict.keys.iter().any(Option::is_none) { if dict.iter_keys().any(|key| key.is_none()) {
return; return;
} }
let missing: Vec<(usize, &str)> = dict let missing: Vec<(usize, &str)> = dict
.keys .iter_keys()
.iter()
.enumerate() .enumerate()
.filter_map(|(index, key)| match key { .filter_map(|(index, key)| match key {
Some(Expr::StringLiteral(ast::ExprStringLiteral { value, .. })) => { Some(Expr::StringLiteral(ast::ExprStringLiteral { value, .. })) => {
@ -629,16 +628,16 @@ pub(crate) fn percent_format_missing_arguments(
return; return;
} }
let Expr::Dict(ast::ExprDict { keys, .. }) = &right else { let Expr::Dict(dict) = &right else {
return; return;
}; };
if keys.iter().any(Option::is_none) { if dict.iter_keys().any(|key| key.is_none()) {
return; // contains **x splat return; // contains **x splat
} }
let mut keywords = FxHashSet::default(); let mut keywords = FxHashSet::default();
for key in keys.iter().flatten() { for key in dict.iter_keys().flatten() {
match key { match key {
Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => { Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => {
keywords.insert(value.to_str()); keywords.insert(value.to_str());

View file

@ -170,16 +170,12 @@ fn is_valid_tuple(formats: &[CFormatStrOrBytes<String>], elts: &[Expr]) -> bool
} }
/// Return `true` if the dictionary values align with the format types. /// Return `true` if the dictionary values align with the format types.
fn is_valid_dict( fn is_valid_dict(formats: &[CFormatStrOrBytes<String>], items: &[ast::DictItem]) -> bool {
formats: &[CFormatStrOrBytes<String>],
keys: &[Option<Expr>],
values: &[Expr],
) -> bool {
let formats = collect_specs(formats); let formats = collect_specs(formats);
// If there are more formats that values, the statement is invalid. Avoid // If there are more formats that values, the statement is invalid. Avoid
// checking the values. // checking the values.
if formats.len() > values.len() { if formats.len() > items.len() {
return true; return true;
} }
@ -192,7 +188,7 @@ fn is_valid_dict(
.map(|mapping_key| (mapping_key.as_str(), format)) .map(|mapping_key| (mapping_key.as_str(), format))
}) })
.collect(); .collect();
for (key, value) in keys.iter().zip(values) { for ast::DictItem { key, value } in items {
let Some(key) = key else { let Some(key) = key else {
return true; return true;
}; };
@ -252,11 +248,7 @@ pub(crate) fn bad_string_format_type(checker: &mut Checker, expr: &Expr, right:
// Parse the parameters. // Parse the parameters.
let is_valid = match right { let is_valid = match right {
Expr::Tuple(ast::ExprTuple { elts, .. }) => is_valid_tuple(&format_strings, elts), Expr::Tuple(ast::ExprTuple { elts, .. }) => is_valid_tuple(&format_strings, elts),
Expr::Dict(ast::ExprDict { Expr::Dict(ast::ExprDict { items, range: _ }) => is_valid_dict(&format_strings, items),
keys,
values,
range: _,
}) => is_valid_dict(&format_strings, keys, values),
_ => is_valid_constant(&format_strings, right), _ => is_valid_constant(&format_strings, right),
}; };
if !is_valid { if !is_valid {

View file

@ -99,10 +99,10 @@ fn is_dict_key_tuple_with_two_elements(semantic: &SemanticModel, binding: &Bindi
return false; return false;
}; };
dict_expr.keys.iter().all(|elt| { dict_expr.iter_keys().all(|elt| {
elt.as_ref().is_some_and(|x| { elt.is_some_and(|x| {
if let Some(tuple) = x.as_tuple_expr() { if let Expr::Tuple(ExprTuple { elts, .. }) = x {
return tuple.elts.len() == 2; return elts.len() == 2;
} }
false false
}) })

View file

@ -229,7 +229,7 @@ fn slots_attributes(expr: &Expr) -> impl Iterator<Item = &str> {
// Ex) `__slots__ = {"name": ...}` // Ex) `__slots__ = {"name": ...}`
let keys_iter = match expr { let keys_iter = match expr {
Expr::Dict(ast::ExprDict { keys, .. }) => Some(keys.iter().filter_map(|key| match key { Expr::Dict(dict) => Some(dict.iter_keys().filter_map(|key| match key {
Some(Expr::StringLiteral(ast::ExprStringLiteral { value, .. })) => Some(value.to_str()), Some(Expr::StringLiteral(ast::ExprStringLiteral { value, .. })) => Some(value.to_str()),
_ => None, _ => None,
})), })),

View file

@ -4,7 +4,7 @@ use rustc_hash::FxHashSet;
use ruff_diagnostics::{Diagnostic, Violation}; use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::{Expr, ExprCall, ExprDict, ExprStringLiteral}; use ruff_python_ast::{Expr, ExprCall, ExprStringLiteral};
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
@ -56,9 +56,9 @@ pub(crate) fn repeated_keyword_argument(checker: &mut Checker, call: &ExprCall)
keyword.range(), keyword.range(),
)); ));
} }
} else if let Expr::Dict(ExprDict { keys, .. }) = &keyword.value { } else if let Expr::Dict(dict) = &keyword.value {
// Ex) `func(**{"a": 1, "a": 2})` // Ex) `func(**{"a": 1, "a": 2})`
for key in keys.iter().flatten() { for key in dict.iter_keys().flatten() {
if let Expr::StringLiteral(ExprStringLiteral { value, .. }) = key { if let Expr::StringLiteral(ExprStringLiteral { value, .. }) = key {
if !seen.insert(value.to_str()) { if !seen.insert(value.to_str()) {
checker.diagnostics.push(Diagnostic::new( checker.diagnostics.push(Diagnostic::new(

View file

@ -163,16 +163,16 @@ fn create_class_def_stmt(
.into() .into()
} }
fn fields_from_dict_literal(keys: &[Option<Expr>], values: &[Expr]) -> Option<Vec<Stmt>> { fn fields_from_dict_literal(items: &[ast::DictItem]) -> Option<Vec<Stmt>> {
if keys.is_empty() { if items.is_empty() {
let node = Stmt::Pass(ast::StmtPass { let node = Stmt::Pass(ast::StmtPass {
range: TextRange::default(), range: TextRange::default(),
}); });
Some(vec![node]) Some(vec![node])
} else { } else {
keys.iter() items
.zip(values.iter()) .iter()
.map(|(key, value)| match key { .map(|ast::DictItem { key, value }| match key {
Some(Expr::StringLiteral(ast::ExprStringLiteral { value: field, .. })) => { Some(Expr::StringLiteral(ast::ExprStringLiteral { value: field, .. })) => {
if !is_identifier(field.to_str()) { if !is_identifier(field.to_str()) {
return None; return None;
@ -231,11 +231,9 @@ fn match_fields_and_total(arguments: &Arguments) -> Option<(Vec<Stmt>, Option<&K
([_typename, fields], [..]) => { ([_typename, fields], [..]) => {
let total = arguments.find_keyword("total"); let total = arguments.find_keyword("total");
match fields { match fields {
Expr::Dict(ast::ExprDict { Expr::Dict(ast::ExprDict { items, range: _ }) => {
keys, Some((fields_from_dict_literal(items)?, total))
values, }
range: _,
}) => Some((fields_from_dict_literal(keys, values)?, total)),
Expr::Call(ast::ExprCall { Expr::Call(ast::ExprCall {
func, func,
arguments: Arguments { keywords, .. }, arguments: Arguments { keywords, .. },

View file

@ -212,16 +212,11 @@ fn clean_params_tuple<'a>(right: &Expr, locator: &Locator<'a>) -> Cow<'a, str> {
fn clean_params_dictionary(right: &Expr, locator: &Locator, stylist: &Stylist) -> Option<String> { fn clean_params_dictionary(right: &Expr, locator: &Locator, stylist: &Stylist) -> Option<String> {
let is_multi_line = locator.contains_line_break(right.range()); let is_multi_line = locator.contains_line_break(right.range());
let mut contents = String::new(); let mut contents = String::new();
if let Expr::Dict(ast::ExprDict { if let Expr::Dict(ast::ExprDict { items, range: _ }) = &right {
keys,
values,
range: _,
}) = &right
{
let mut arguments: Vec<String> = vec![]; let mut arguments: Vec<String> = vec![];
let mut seen: Vec<&str> = vec![]; let mut seen: Vec<&str> = vec![];
let mut indent = None; let mut indent = None;
for (key, value) in keys.iter().zip(values.iter()) { for ast::DictItem { key, value } in items {
match key { match key {
Some(key) => { Some(key) => {
if let Expr::StringLiteral(ast::ExprStringLiteral { if let Expr::StringLiteral(ast::ExprStringLiteral {

View file

@ -174,13 +174,9 @@ impl<'a> StringLiteralDisplay<'a> {
display_kind, display_kind,
} }
} }
ast::Expr::Dict(ast::ExprDict { ast::Expr::Dict(dict @ ast::ExprDict { items, range }) => {
keys, let mut narrowed_keys = Vec::with_capacity(items.len());
values, for key in dict.iter_keys() {
range,
}) => {
let mut narrowed_keys = Vec::with_capacity(values.len());
for key in keys {
if let Some(key) = key { if let Some(key) = key {
// This is somewhat unfortunate, // This is somewhat unfortunate,
// *but* using a dict for __slots__ is very rare // *but* using a dict for __slots__ is very rare
@ -193,12 +189,11 @@ impl<'a> StringLiteralDisplay<'a> {
// `__slots__ = {"foo": "bar", **other_dict}` // `__slots__ = {"foo": "bar", **other_dict}`
// If `None` wasn't present in the keys, // If `None` wasn't present in the keys,
// the length of the keys should always equal the length of the values // the length of the keys should always equal the length of the values
assert_eq!(narrowed_keys.len(), values.len()); assert_eq!(narrowed_keys.len(), items.len());
let display_kind = DisplayKind::Dict { values };
Self { Self {
elts: Cow::Owned(narrowed_keys), elts: Cow::Owned(narrowed_keys),
range: *range, range: *range,
display_kind, display_kind: DisplayKind::Dict { items },
} }
} }
_ => return None, _ => return None,
@ -206,7 +201,7 @@ impl<'a> StringLiteralDisplay<'a> {
Some(result) Some(result)
} }
fn generate_fix(&self, items: &[&str], checker: &Checker) -> Option<Fix> { fn generate_fix(&self, elements: &[&str], checker: &Checker) -> Option<Fix> {
let locator = checker.locator(); let locator = checker.locator();
let is_multiline = locator.contains_line_break(self.range()); let is_multiline = locator.contains_line_break(self.range());
let sorted_source_code = match (&self.display_kind, is_multiline) { let sorted_source_code = match (&self.display_kind, is_multiline) {
@ -224,12 +219,12 @@ impl<'a> StringLiteralDisplay<'a> {
(DisplayKind::Sequence(sequence_kind), false) => sort_single_line_elements_sequence( (DisplayKind::Sequence(sequence_kind), false) => sort_single_line_elements_sequence(
*sequence_kind, *sequence_kind,
&self.elts, &self.elts,
items, elements,
locator, locator,
SORTING_STYLE, SORTING_STYLE,
), ),
(DisplayKind::Dict { values }, false) => { (DisplayKind::Dict { items }, false) => {
sort_single_line_elements_dict(&self.elts, items, values, locator) sort_single_line_elements_dict(&self.elts, elements, items, locator)
} }
}; };
Some(Fix::safe_edit(Edit::range_replacement( Some(Fix::safe_edit(Edit::range_replacement(
@ -245,7 +240,7 @@ impl<'a> StringLiteralDisplay<'a> {
#[derive(Debug)] #[derive(Debug)]
enum DisplayKind<'a> { enum DisplayKind<'a> {
Sequence(SequenceKind), Sequence(SequenceKind),
Dict { values: &'a [ast::Expr] }, Dict { items: &'a [ast::DictItem] },
} }
/// A newtype that zips together three iterables: /// A newtype that zips together three iterables:
@ -262,14 +257,14 @@ enum DisplayKind<'a> {
struct DictElements<'a>(Vec<(&'a &'a str, &'a ast::Expr, &'a ast::Expr)>); struct DictElements<'a>(Vec<(&'a &'a str, &'a ast::Expr, &'a ast::Expr)>);
impl<'a> DictElements<'a> { impl<'a> DictElements<'a> {
fn new(elements: &'a [&str], key_elts: &'a [ast::Expr], value_elts: &'a [ast::Expr]) -> Self { fn new(elements: &'a [&str], key_elts: &'a [ast::Expr], items: &'a [ast::DictItem]) -> Self {
assert_eq!(key_elts.len(), elements.len()); assert_eq!(key_elts.len(), elements.len());
assert_eq!(elements.len(), value_elts.len()); assert_eq!(elements.len(), items.len());
assert!( assert!(
elements.len() >= 2, elements.len() >= 2,
"A sequence with < 2 elements cannot be unsorted" "A sequence with < 2 elements cannot be unsorted"
); );
Self(izip!(elements, key_elts, value_elts).collect()) Self(izip!(elements, key_elts, items.iter().map(|item| &item.value)).collect())
} }
fn last_item_index(&self) -> usize { fn last_item_index(&self) -> usize {
@ -294,13 +289,13 @@ impl<'a> DictElements<'a> {
/// `sequence_sorting.rs` if any other modules need it, /// `sequence_sorting.rs` if any other modules need it,
/// but stays here for now, since this is currently the /// but stays here for now, since this is currently the
/// only module that needs it /// only module that needs it
fn sort_single_line_elements_dict( fn sort_single_line_elements_dict<'a>(
key_elts: &[ast::Expr], key_elts: &'a [ast::Expr],
elements: &[&str], elements: &'a [&str],
value_elts: &[ast::Expr], original_items: &'a [ast::DictItem],
locator: &Locator, locator: &Locator,
) -> String { ) -> String {
let element_trios = DictElements::new(elements, key_elts, value_elts); let element_trios = DictElements::new(elements, key_elts, original_items);
let last_item_index = element_trios.last_item_index(); let last_item_index = element_trios.last_item_index();
let mut result = String::from('{'); let mut result = String::from('{');
// We grab the original source-code ranges using `locator.slice()` // We grab the original source-code ranges using `locator.slice()`

View file

@ -687,10 +687,24 @@ pub struct ExprIf<'a> {
orelse: Box<ComparableExpr<'a>>, orelse: Box<ComparableExpr<'a>>,
} }
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct ComparableDictItem<'a> {
key: Option<ComparableExpr<'a>>,
value: ComparableExpr<'a>,
}
impl<'a> From<&'a ast::DictItem> for ComparableDictItem<'a> {
fn from(ast::DictItem { key, value }: &'a ast::DictItem) -> Self {
Self {
key: key.as_ref().map(ComparableExpr::from),
value: value.into(),
}
}
}
#[derive(Debug, PartialEq, Eq, Hash)] #[derive(Debug, PartialEq, Eq, Hash)]
pub struct ExprDict<'a> { pub struct ExprDict<'a> {
keys: Vec<Option<ComparableExpr<'a>>>, items: Vec<ComparableDictItem<'a>>,
values: Vec<ComparableExpr<'a>>,
} }
#[derive(Debug, PartialEq, Eq, Hash)] #[derive(Debug, PartialEq, Eq, Hash)]
@ -933,16 +947,8 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> {
body: body.into(), body: body.into(),
orelse: orelse.into(), orelse: orelse.into(),
}), }),
ast::Expr::Dict(ast::ExprDict { ast::Expr::Dict(ast::ExprDict { items, range: _ }) => Self::Dict(ExprDict {
keys, items: items.iter().map(ComparableDictItem::from).collect(),
values,
range: _,
}) => Self::Dict(ExprDict {
keys: keys
.iter()
.map(|expr| expr.as_ref().map(Into::into))
.collect(),
values: values.iter().map(Into::into).collect(),
}), }),
ast::Expr::Set(ast::ExprSet { elts, range: _ }) => Self::Set(ExprSet { ast::Expr::Set(ast::ExprSet { elts, range: _ }) => Self::Set(ExprSet {
elts: elts.iter().map(Into::into).collect(), elts: elts.iter().map(Into::into).collect(),

View file

@ -155,14 +155,12 @@ pub fn any_over_expr(expr: &Expr, func: &dyn Fn(&Expr) -> bool) -> bool {
orelse, orelse,
range: _, range: _,
}) => any_over_expr(test, func) || any_over_expr(body, func) || any_over_expr(orelse, func), }) => any_over_expr(test, func) || any_over_expr(body, func) || any_over_expr(orelse, func),
Expr::Dict(ast::ExprDict { Expr::Dict(ast::ExprDict { items, range: _ }) => {
keys, items.iter().any(|ast::DictItem { key, value }| {
values, any_over_expr(value, func)
range: _, || key.as_ref().is_some_and(|key| any_over_expr(key, func))
}) => values })
.iter() }
.chain(keys.iter().flatten())
.any(|expr| any_over_expr(expr, func)),
Expr::Set(ast::ExprSet { elts, range: _ }) Expr::Set(ast::ExprSet { elts, range: _ })
| Expr::List(ast::ExprList { elts, range: _, .. }) | Expr::List(ast::ExprList { elts, range: _, .. })
| Expr::Tuple(ast::ExprTuple { elts, range: _, .. }) => { | Expr::Tuple(ast::ExprTuple { elts, range: _, .. }) => {
@ -1188,8 +1186,8 @@ impl Truthiness {
Self::Truthy Self::Truthy
} }
} }
Expr::Dict(ast::ExprDict { keys, .. }) => { Expr::Dict(ast::ExprDict { items, .. }) => {
if keys.is_empty() { if items.is_empty() {
Self::Falsey Self::Falsey
} else { } else {
Self::Truthy Self::Truthy

View file

@ -2301,13 +2301,9 @@ impl AstNode for ast::ExprDict {
where where
V: PreorderVisitor<'a> + ?Sized, V: PreorderVisitor<'a> + ?Sized,
{ {
let ast::ExprDict { let ast::ExprDict { items, range: _ } = self;
keys,
values,
range: _,
} = self;
for (key, value) in keys.iter().zip(values) { for ast::DictItem { key, value } in items {
if let Some(key) = key { if let Some(key) = key {
visitor.visit_expr(key); visitor.visit_expr(key);
} }

View file

@ -767,12 +767,89 @@ impl From<ExprIf> for Expr {
} }
} }
/// Represents an item in a [dictionary literal display][1].
///
/// Consider the following Python dictionary literal:
/// ```python
/// {key1: value1, **other_dictionary}
/// ```
///
/// In our AST, this would be represented using an `ExprDict` node containing
/// two `DictItem` nodes inside it:
/// ```ignore
/// [
/// DictItem {
/// key: Some(Expr::Name(ExprName { id: "key1" })),
/// value: Expr::Name(ExprName { id: "value1" }),
/// },
/// DictItem {
/// key: None,
/// value: Expr::Name(ExprName { id: "other_dictionary" }),
/// }
/// ]
/// ```
///
/// [1]: https://docs.python.org/3/reference/expressions.html#displays-for-lists-sets-and-dictionaries
#[derive(Debug, Clone, PartialEq)]
pub struct DictItem {
pub key: Option<Expr>,
pub value: Expr,
}
impl DictItem {
fn key(&self) -> Option<&Expr> {
self.key.as_ref()
}
fn value(&self) -> &Expr {
&self.value
}
}
impl Ranged for DictItem {
fn range(&self) -> TextRange {
TextRange::new(
self.key.as_ref().map_or(self.value.start(), Ranged::start),
self.value.end(),
)
}
}
/// See also [Dict](https://docs.python.org/3/library/ast.html#ast.Dict) /// See also [Dict](https://docs.python.org/3/library/ast.html#ast.Dict)
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct ExprDict { pub struct ExprDict {
pub range: TextRange, pub range: TextRange,
pub keys: Vec<Option<Expr>>, pub items: Vec<DictItem>,
pub values: Vec<Expr>, }
impl ExprDict {
/// Returns an `Iterator` over the AST nodes representing the
/// dictionary's keys.
pub fn iter_keys(&self) -> DictKeyIterator {
DictKeyIterator::new(&self.items)
}
/// Returns an `Iterator` over the AST nodes representing the
/// dictionary's values.
pub fn iter_values(&self) -> DictValueIterator {
DictValueIterator::new(&self.items)
}
/// Returns the AST node representing the *n*th key of this
/// dictionary.
///
/// Panics: If the index `n` is out of bounds.
pub fn key(&self, n: usize) -> Option<&Expr> {
self.items[n].key()
}
/// Returns the AST node representing the *n*th value of this
/// dictionary.
///
/// Panics: If the index `n` is out of bounds.
pub fn value(&self, n: usize) -> &Expr {
self.items[n].value()
}
} }
impl From<ExprDict> for Expr { impl From<ExprDict> for Expr {
@ -781,6 +858,90 @@ impl From<ExprDict> for Expr {
} }
} }
#[derive(Debug, Clone)]
pub struct DictKeyIterator<'a> {
items: Iter<'a, DictItem>,
}
impl<'a> DictKeyIterator<'a> {
fn new(items: &'a [DictItem]) -> Self {
Self {
items: items.iter(),
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl<'a> Iterator for DictKeyIterator<'a> {
type Item = Option<&'a Expr>;
fn next(&mut self) -> Option<Self::Item> {
self.items.next().map(DictItem::key)
}
fn last(mut self) -> Option<Self::Item> {
self.next_back()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.items.size_hint()
}
}
impl<'a> DoubleEndedIterator for DictKeyIterator<'a> {
fn next_back(&mut self) -> Option<Self::Item> {
self.items.next_back().map(DictItem::key)
}
}
impl<'a> FusedIterator for DictKeyIterator<'a> {}
impl<'a> ExactSizeIterator for DictKeyIterator<'a> {}
#[derive(Debug, Clone)]
pub struct DictValueIterator<'a> {
items: Iter<'a, DictItem>,
}
impl<'a> DictValueIterator<'a> {
fn new(items: &'a [DictItem]) -> Self {
Self {
items: items.iter(),
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl<'a> Iterator for DictValueIterator<'a> {
type Item = &'a Expr;
fn next(&mut self) -> Option<Self::Item> {
self.items.next().map(DictItem::value)
}
fn last(mut self) -> Option<Self::Item> {
self.next_back()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.items.size_hint()
}
}
impl<'a> DoubleEndedIterator for DictValueIterator<'a> {
fn next_back(&mut self) -> Option<Self::Item> {
self.items.next_back().map(DictItem::value)
}
}
impl<'a> FusedIterator for DictValueIterator<'a> {}
impl<'a> ExactSizeIterator for DictValueIterator<'a> {}
/// See also [Set](https://docs.python.org/3/library/ast.html#ast.Set) /// See also [Set](https://docs.python.org/3/library/ast.html#ast.Set)
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct ExprSet { pub struct ExprSet {
@ -4358,7 +4519,7 @@ mod tests {
assert_eq!(std::mem::size_of::<ExprBytesLiteral>(), 40); assert_eq!(std::mem::size_of::<ExprBytesLiteral>(), 40);
assert_eq!(std::mem::size_of::<ExprCall>(), 56); assert_eq!(std::mem::size_of::<ExprCall>(), 56);
assert_eq!(std::mem::size_of::<ExprCompare>(), 48); assert_eq!(std::mem::size_of::<ExprCompare>(), 48);
assert_eq!(std::mem::size_of::<ExprDict>(), 56); assert_eq!(std::mem::size_of::<ExprDict>(), 32);
assert_eq!(std::mem::size_of::<ExprDictComp>(), 48); assert_eq!(std::mem::size_of::<ExprDictComp>(), 48);
assert_eq!(std::mem::size_of::<ExprEllipsisLiteral>(), 8); assert_eq!(std::mem::size_of::<ExprEllipsisLiteral>(), 8);
// 56 for Rustc < 1.76 // 56 for Rustc < 1.76

View file

@ -389,16 +389,12 @@ pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) {
visitor.visit_expr(body); visitor.visit_expr(body);
visitor.visit_expr(orelse); visitor.visit_expr(orelse);
} }
Expr::Dict(ast::ExprDict { Expr::Dict(ast::ExprDict { items, range: _ }) => {
keys, for ast::DictItem { key, value } in items {
values, if let Some(key) = key {
range: _, visitor.visit_expr(key);
}) => { }
for expr in keys.iter().flatten() { visitor.visit_expr(value);
visitor.visit_expr(expr);
}
for expr in values {
visitor.visit_expr(expr);
} }
} }
Expr::Set(ast::ExprSet { elts, range: _ }) => { Expr::Set(ast::ExprSet { elts, range: _ }) => {

View file

@ -376,16 +376,12 @@ pub fn walk_expr<V: Transformer + ?Sized>(visitor: &V, expr: &mut Expr) {
visitor.visit_expr(body); visitor.visit_expr(body);
visitor.visit_expr(orelse); visitor.visit_expr(orelse);
} }
Expr::Dict(ast::ExprDict { Expr::Dict(ast::ExprDict { items, range: _ }) => {
keys, for ast::DictItem { key, value } in items {
values, if let Some(key) = key {
range: _, visitor.visit_expr(key);
}) => { }
for expr in keys.iter_mut().flatten() { visitor.visit_expr(value);
visitor.visit_expr(expr);
}
for expr in values {
visitor.visit_expr(expr);
} }
} }
Expr::Set(ast::ExprSet { elts, range: _ }) => { Expr::Set(ast::ExprSet { elts, range: _ }) => {

View file

@ -919,22 +919,18 @@ impl<'a> Generator<'a> {
self.unparse_expr(orelse, precedence::IF_EXP); self.unparse_expr(orelse, precedence::IF_EXP);
}); });
} }
Expr::Dict(ast::ExprDict { Expr::Dict(ast::ExprDict { items, range: _ }) => {
keys,
values,
range: _,
}) => {
self.p("{"); self.p("{");
let mut first = true; let mut first = true;
for (k, v) in keys.iter().zip(values) { for ast::DictItem { key, value } in items {
self.p_delim(&mut first, ", "); self.p_delim(&mut first, ", ");
if let Some(k) = k { if let Some(key) = key {
self.unparse_expr(k, precedence::COMMA); self.unparse_expr(key, precedence::COMMA);
self.p(": "); self.p(": ");
self.unparse_expr(v, precedence::COMMA); self.unparse_expr(value, precedence::COMMA);
} else { } else {
self.p("**"); self.p("**");
self.unparse_expr(v, precedence::MAX); self.unparse_expr(value, precedence::MAX);
} }
} }
self.p("}"); self.p("}");

View file

@ -1,6 +1,5 @@
use ruff_formatter::{format_args, write}; use ruff_formatter::{format_args, write};
use ruff_python_ast::AnyNodeRef; use ruff_python_ast::{AnyNodeRef, DictItem, Expr, ExprDict};
use ruff_python_ast::{Expr, ExprDict};
use ruff_text_size::{Ranged, TextRange}; use ruff_text_size::{Ranged, TextRange};
use crate::comments::{dangling_comments, leading_comments, SourceComment}; use crate::comments::{dangling_comments, leading_comments, SourceComment};
@ -14,18 +13,12 @@ pub struct FormatExprDict;
impl FormatNodeRule<ExprDict> for FormatExprDict { impl FormatNodeRule<ExprDict> for FormatExprDict {
fn fmt_fields(&self, item: &ExprDict, f: &mut PyFormatter) -> FormatResult<()> { fn fmt_fields(&self, item: &ExprDict, f: &mut PyFormatter) -> FormatResult<()> {
let ExprDict { let ExprDict { range: _, items } = item;
range: _,
keys,
values,
} = item;
debug_assert_eq!(keys.len(), values.len());
let comments = f.context().comments().clone(); let comments = f.context().comments().clone();
let dangling = comments.dangling(item); let dangling = comments.dangling(item);
let (Some(key), Some(value)) = (keys.first(), values.first()) else { let Some(first_dict_item) = items.first() else {
return empty_parenthesized("{", dangling, "}").fmt(f); return empty_parenthesized("{", dangling, "}").fmt(f);
}; };
@ -37,17 +30,17 @@ impl FormatNodeRule<ExprDict> for FormatExprDict {
// y // y
// } // }
// ``` // ```
let (open_parenthesis_comments, key_value_comments) = dangling.split_at( let (open_parenthesis_comments, key_value_comments) =
dangling dangling.split_at(dangling.partition_point(|comment| {
.partition_point(|comment| comment.end() < KeyValuePair::new(key, value).start()), comment.end() < KeyValuePair::new(first_dict_item).start()
); }));
let format_pairs = format_with(|f| { let format_pairs = format_with(|f| {
let mut joiner = f.join_comma_separated(item.end()); let mut joiner = f.join_comma_separated(item.end());
let mut key_value_comments = key_value_comments; let mut key_value_comments = key_value_comments;
for (key, value) in keys.iter().zip(values) { for dict_item in items {
let mut key_value_pair = KeyValuePair::new(key, value); let mut key_value_pair = KeyValuePair::new(dict_item);
let partition = key_value_comments let partition = key_value_comments
.partition_point(|comment| comment.start() < key_value_pair.end()); .partition_point(|comment| comment.start() < key_value_pair.end());
@ -84,10 +77,10 @@ struct KeyValuePair<'a> {
} }
impl<'a> KeyValuePair<'a> { impl<'a> KeyValuePair<'a> {
fn new(key: &'a Option<Expr>, value: &'a Expr) -> Self { fn new(item: &'a DictItem) -> Self {
Self { Self {
key, key: &item.key,
value, value: &item.value,
comments: &[], comments: &[],
} }
} }

View file

@ -1059,8 +1059,8 @@ pub(crate) fn has_own_parentheses(
} }
} }
Expr::Dict(ast::ExprDict { keys, .. }) => { Expr::Dict(ast::ExprDict { items, .. }) => {
if !keys.is_empty() || context.comments().has_dangling(AnyNodeRef::from(expr)) { if !items.is_empty() || context.comments().has_dangling(AnyNodeRef::from(expr)) {
Some(OwnParentheses::NonEmpty) Some(OwnParentheses::NonEmpty)
} else { } else {
Some(OwnParentheses::Empty) Some(OwnParentheses::Empty)
@ -1217,7 +1217,7 @@ pub(crate) fn is_splittable_expression(expr: &Expr, context: &PyFormatContext) -
// Sequence types can split if they contain at least one element. // Sequence types can split if they contain at least one element.
Expr::Tuple(tuple) => !tuple.elts.is_empty(), Expr::Tuple(tuple) => !tuple.elts.is_empty(),
Expr::Dict(dict) => !dict.values.is_empty(), Expr::Dict(dict) => !dict.items.is_empty(),
Expr::Set(set) => !set.elts.is_empty(), Expr::Set(set) => !set.elts.is_empty(),
Expr::List(list) => !list.elts.is_empty(), Expr::List(list) => !list.elts.is_empty(),

View file

@ -1544,8 +1544,7 @@ impl<'src> Parser<'src> {
// Return an empty `DictExpr` when finding a `}` right after the `{` // Return an empty `DictExpr` when finding a `}` right after the `{`
if self.eat(TokenKind::Rbrace) { if self.eat(TokenKind::Rbrace) {
return Expr::Dict(ast::ExprDict { return Expr::Dict(ast::ExprDict {
keys: vec![], items: vec![],
values: vec![],
range: self.node_range(start), range: self.node_range(start),
}); });
} }
@ -1794,21 +1793,24 @@ impl<'src> Parser<'src> {
self.expect(TokenKind::Comma); self.expect(TokenKind::Comma);
} }
let mut keys = vec![key]; let mut items = vec![ast::DictItem { key, value }];
let mut values = vec![value];
self.parse_comma_separated_list(RecoveryContextKind::DictElements, |parser| { self.parse_comma_separated_list(RecoveryContextKind::DictElements, |parser| {
if parser.eat(TokenKind::DoubleStar) { if parser.eat(TokenKind::DoubleStar) {
keys.push(None);
// Handle dictionary unpacking. Here, the grammar is `'**' bitwise_or` // Handle dictionary unpacking. Here, the grammar is `'**' bitwise_or`
// which requires limiting the expression. // which requires limiting the expression.
values.push(parser.parse_expression_with_bitwise_or_precedence().expr); items.push(ast::DictItem {
key: None,
value: parser.parse_expression_with_bitwise_or_precedence().expr,
});
} else { } else {
keys.push(Some(parser.parse_conditional_expression_or_higher().expr)); let key = parser.parse_conditional_expression_or_higher().expr;
parser.expect(TokenKind::Colon); parser.expect(TokenKind::Colon);
values.push(parser.parse_conditional_expression_or_higher().expr); items.push(ast::DictItem {
key: Some(key),
value: parser.parse_conditional_expression_or_higher().expr,
});
} }
}); });
@ -1816,8 +1818,7 @@ impl<'src> Parser<'src> {
ast::ExprDict { ast::ExprDict {
range: self.node_range(start), range: self.node_range(start),
keys, items,
values,
} }
} }

View file

@ -51,24 +51,23 @@ pub(super) fn pattern_to_expr(pattern: Pattern) -> Expr {
patterns, patterns,
rest, rest,
}) => { }) => {
let mut keys = keys.into_iter().map(Option::Some).collect::<Vec<_>>(); let mut items: Vec<ast::DictItem> = keys
let mut values = patterns
.into_iter() .into_iter()
.map(pattern_to_expr) .zip(patterns)
.collect::<Vec<_>>(); .map(|(key, pattern)| ast::DictItem {
key: Some(key),
value: pattern_to_expr(pattern),
})
.collect();
if let Some(rest) = rest { if let Some(rest) = rest {
keys.push(None); let value = Expr::Name(ast::ExprName {
values.push(Expr::Name(ast::ExprName {
range: rest.range, range: rest.range,
id: rest.id, id: rest.id,
ctx: ExprContext::Store, ctx: ExprContext::Store,
})); });
items.push(ast::DictItem { key: None, value });
} }
Expr::Dict(ast::ExprDict { Expr::Dict(ast::ExprDict { range, items })
range,
keys,
values,
})
} }
Pattern::MatchClass(ast::PatternMatchClass { Pattern::MatchClass(ast::PatternMatchClass {
range, range,

View file

@ -15,34 +15,36 @@ Module(
value: Dict( value: Dict(
ExprDict { ExprDict {
range: 125..135, range: 125..135,
keys: [ items: [
None, DictItem {
Some( key: None,
NumberLiteral( value: Name(
ExprNumberLiteral { ExprName {
range: 133..134, range: 128..129,
value: Int( id: "x",
1, ctx: Load,
),
}, },
), ),
), },
], DictItem {
values: [ key: Some(
Name( NumberLiteral(
ExprName { ExprNumberLiteral {
range: 128..129, range: 133..134,
id: "x", value: Int(
ctx: Load, 1,
}, ),
), },
Name( ),
ExprName { ),
range: 134..134, value: Name(
id: "", ExprName {
ctx: Invalid, range: 134..134,
}, id: "",
), ctx: Invalid,
},
),
},
], ],
}, },
), ),
@ -54,52 +56,54 @@ Module(
value: Dict( value: Dict(
ExprDict { ExprDict {
range: 136..162, range: 136..162,
keys: [ items: [
Some( DictItem {
Name( key: Some(
ExprName { Name(
range: 137..138, ExprName {
id: "a", range: 137..138,
ctx: Load, id: "a",
ctx: Load,
},
),
),
value: NumberLiteral(
ExprNumberLiteral {
range: 140..141,
value: Int(
1,
),
}, },
), ),
), },
None, DictItem {
], key: None,
values: [ value: If(
NumberLiteral( ExprIf {
ExprNumberLiteral { range: 145..161,
range: 140..141, test: BooleanLiteral(
value: Int( ExprBooleanLiteral {
1, range: 150..154,
), value: true,
}, },
), ),
If( body: Name(
ExprIf { ExprName {
range: 145..161, range: 145..146,
test: BooleanLiteral( id: "x",
ExprBooleanLiteral { ctx: Load,
range: 150..154, },
value: true, ),
}, orelse: Name(
), ExprName {
body: Name( range: 160..161,
ExprName { id: "y",
range: 145..146, ctx: Load,
id: "x", },
ctx: Load, ),
}, },
), ),
orelse: Name( },
ExprName {
range: 160..161,
id: "y",
ctx: Load,
},
),
},
),
], ],
}, },
), ),
@ -111,62 +115,64 @@ Module(
value: Dict( value: Dict(
ExprDict { ExprDict {
range: 163..184, range: 163..184,
keys: [ items: [
None, DictItem {
Some( key: None,
Name( value: Lambda(
ExprName { ExprLambda {
range: 179..180, range: 166..177,
id: "b", parameters: Some(
ctx: Load, Parameters {
range: 173..174,
posonlyargs: [],
args: [
ParameterWithDefault {
range: 173..174,
parameter: Parameter {
range: 173..174,
name: Identifier {
id: "x",
range: 173..174,
},
annotation: None,
},
default: None,
},
],
vararg: None,
kwonlyargs: [],
kwarg: None,
},
),
body: Name(
ExprName {
range: 176..177,
id: "x",
ctx: Load,
},
),
}, },
), ),
), },
], DictItem {
values: [ key: Some(
Lambda( Name(
ExprLambda {
range: 166..177,
parameters: Some(
Parameters {
range: 173..174,
posonlyargs: [],
args: [
ParameterWithDefault {
range: 173..174,
parameter: Parameter {
range: 173..174,
name: Identifier {
id: "x",
range: 173..174,
},
annotation: None,
},
default: None,
},
],
vararg: None,
kwonlyargs: [],
kwarg: None,
},
),
body: Name(
ExprName { ExprName {
range: 176..177, range: 179..180,
id: "x", id: "b",
ctx: Load, ctx: Load,
}, },
), ),
}, ),
), value: NumberLiteral(
NumberLiteral( ExprNumberLiteral {
ExprNumberLiteral { range: 182..183,
range: 182..183, value: Int(
value: Int( 2,
2, ),
), },
}, ),
), },
], ],
}, },
), ),
@ -178,49 +184,51 @@ Module(
value: Dict( value: Dict(
ExprDict { ExprDict {
range: 185..201, range: 185..201,
keys: [ items: [
Some( DictItem {
Name( key: Some(
ExprName { Name(
range: 186..187, ExprName {
id: "a", range: 186..187,
ctx: Load, id: "a",
ctx: Load,
},
),
),
value: NumberLiteral(
ExprNumberLiteral {
range: 189..190,
value: Int(
1,
),
}, },
), ),
), },
None, DictItem {
], key: None,
values: [ value: BoolOp(
NumberLiteral( ExprBoolOp {
ExprNumberLiteral { range: 194..200,
range: 189..190, op: Or,
value: Int( values: [
1, Name(
), ExprName {
}, range: 194..195,
), id: "x",
BoolOp( ctx: Load,
ExprBoolOp { },
range: 194..200, ),
op: Or, Name(
values: [ ExprName {
Name( range: 199..200,
ExprName { id: "y",
range: 194..195, ctx: Load,
id: "x", },
ctx: Load, ),
}, ],
), },
Name( ),
ExprName { },
range: 199..200,
id: "y",
ctx: Load,
},
),
],
},
),
], ],
}, },
), ),
@ -232,49 +240,51 @@ Module(
value: Dict( value: Dict(
ExprDict { ExprDict {
range: 202..219, range: 202..219,
keys: [ items: [
None, DictItem {
Some( key: None,
Name( value: BoolOp(
ExprName { ExprBoolOp {
range: 214..215, range: 205..212,
id: "b", op: And,
ctx: Load, values: [
Name(
ExprName {
range: 205..206,
id: "x",
ctx: Load,
},
),
Name(
ExprName {
range: 211..212,
id: "y",
ctx: Load,
},
),
],
}, },
), ),
), },
], DictItem {
values: [ key: Some(
BoolOp( Name(
ExprBoolOp { ExprName {
range: 205..212, range: 214..215,
op: And, id: "b",
values: [ ctx: Load,
Name( },
ExprName {
range: 205..206,
id: "x",
ctx: Load,
},
),
Name(
ExprName {
range: 211..212,
id: "y",
ctx: Load,
},
),
],
},
),
NumberLiteral(
ExprNumberLiteral {
range: 217..218,
value: Int(
2,
), ),
}, ),
), value: NumberLiteral(
ExprNumberLiteral {
range: 217..218,
value: Int(
2,
),
},
),
},
], ],
}, },
), ),
@ -286,57 +296,61 @@ Module(
value: Dict( value: Dict(
ExprDict { ExprDict {
range: 220..241, range: 220..241,
keys: [ items: [
Some( DictItem {
Name( key: Some(
ExprName { Name(
range: 221..222,
id: "a",
ctx: Load,
},
),
),
None,
Some(
Name(
ExprName {
range: 236..237,
id: "b",
ctx: Load,
},
),
),
],
values: [
NumberLiteral(
ExprNumberLiteral {
range: 224..225,
value: Int(
1,
),
},
),
UnaryOp(
ExprUnaryOp {
range: 229..234,
op: Not,
operand: Name(
ExprName { ExprName {
range: 233..234, range: 221..222,
id: "x", id: "a",
ctx: Load, ctx: Load,
}, },
), ),
}, ),
), value: NumberLiteral(
NumberLiteral( ExprNumberLiteral {
ExprNumberLiteral { range: 224..225,
range: 239..240, value: Int(
value: Int( 1,
2, ),
},
),
},
DictItem {
key: None,
value: UnaryOp(
ExprUnaryOp {
range: 229..234,
op: Not,
operand: Name(
ExprName {
range: 233..234,
id: "x",
ctx: Load,
},
),
},
),
},
DictItem {
key: Some(
Name(
ExprName {
range: 236..237,
id: "b",
ctx: Load,
},
), ),
}, ),
), value: NumberLiteral(
ExprNumberLiteral {
range: 239..240,
value: Int(
2,
),
},
),
},
], ],
}, },
), ),
@ -348,34 +362,34 @@ Module(
value: Dict( value: Dict(
ExprDict { ExprDict {
range: 242..252, range: 242..252,
keys: [ items: [
None, DictItem {
], key: None,
values: [ value: Compare(
Compare( ExprCompare {
ExprCompare { range: 245..251,
range: 245..251, left: Name(
left: Name(
ExprName {
range: 245..246,
id: "x",
ctx: Load,
},
),
ops: [
In,
],
comparators: [
Name(
ExprName { ExprName {
range: 250..251, range: 245..246,
id: "y", id: "x",
ctx: Load, ctx: Load,
}, },
), ),
], ops: [
}, In,
), ],
comparators: [
Name(
ExprName {
range: 250..251,
id: "y",
ctx: Load,
},
),
],
},
),
},
], ],
}, },
), ),
@ -387,34 +401,34 @@ Module(
value: Dict( value: Dict(
ExprDict { ExprDict {
range: 253..267, range: 253..267,
keys: [ items: [
None, DictItem {
], key: None,
values: [ value: Compare(
Compare( ExprCompare {
ExprCompare { range: 256..266,
range: 256..266, left: Name(
left: Name(
ExprName {
range: 256..257,
id: "x",
ctx: Load,
},
),
ops: [
NotIn,
],
comparators: [
Name(
ExprName { ExprName {
range: 265..266, range: 256..257,
id: "y", id: "x",
ctx: Load, ctx: Load,
}, },
), ),
], ops: [
}, NotIn,
), ],
comparators: [
Name(
ExprName {
range: 265..266,
id: "y",
ctx: Load,
},
),
],
},
),
},
], ],
}, },
), ),
@ -426,34 +440,34 @@ Module(
value: Dict( value: Dict(
ExprDict { ExprDict {
range: 268..277, range: 268..277,
keys: [ items: [
None, DictItem {
], key: None,
values: [ value: Compare(
Compare( ExprCompare {
ExprCompare { range: 271..276,
range: 271..276, left: Name(
left: Name(
ExprName {
range: 271..272,
id: "x",
ctx: Load,
},
),
ops: [
Lt,
],
comparators: [
Name(
ExprName { ExprName {
range: 275..276, range: 271..272,
id: "y", id: "x",
ctx: Load, ctx: Load,
}, },
), ),
], ops: [
}, Lt,
), ],
comparators: [
Name(
ExprName {
range: 275..276,
id: "y",
ctx: Load,
},
),
],
},
),
},
], ],
}, },
), ),

View file

@ -15,82 +15,88 @@ Module(
value: Dict( value: Dict(
ExprDict { ExprDict {
range: 122..147, range: 122..147,
keys: [ items: [
None, DictItem {
Some( key: None,
Name( value: Name(
ExprName { ExprName {
range: 128..129, range: 125..126,
id: "y",
ctx: Load,
},
),
),
Some(
Name(
ExprName {
range: 134..135,
id: "x", id: "x",
ctx: Load, ctx: Load,
}, },
), ),
), },
Some( DictItem {
Compare( key: Some(
ExprCompare { Name(
range: 137..146, ExprName {
left: Name( range: 128..129,
ExprName { id: "y",
range: 137..138, ctx: Load,
id: "y", },
ctx: Load, ),
}, ),
), value: Name(
ops: [ ExprName {
In, range: 130..133,
], id: "for",
comparators: [ ctx: Load,
Name( },
),
},
DictItem {
key: Some(
Name(
ExprName {
range: 134..135,
id: "x",
ctx: Load,
},
),
),
value: Name(
ExprName {
range: 135..135,
id: "",
ctx: Invalid,
},
),
},
DictItem {
key: Some(
Compare(
ExprCompare {
range: 137..146,
left: Name(
ExprName { ExprName {
range: 142..146, range: 137..138,
id: "data", id: "y",
ctx: Load, ctx: Load,
}, },
), ),
], ops: [
In,
],
comparators: [
Name(
ExprName {
range: 142..146,
id: "data",
ctx: Load,
},
),
],
},
),
),
value: Name(
ExprName {
range: 146..146,
id: "",
ctx: Invalid,
}, },
), ),
), },
],
values: [
Name(
ExprName {
range: 125..126,
id: "x",
ctx: Load,
},
),
Name(
ExprName {
range: 130..133,
id: "for",
ctx: Load,
},
),
Name(
ExprName {
range: 135..135,
id: "",
ctx: Invalid,
},
),
Name(
ExprName {
range: 146..146,
id: "",
ctx: Invalid,
},
),
], ],
}, },
), ),

View file

@ -15,51 +15,53 @@ Module(
value: Dict( value: Dict(
ExprDict { ExprDict {
range: 0..24, range: 0..24,
keys: [ items: [
Some( DictItem {
Name( key: Some(
Name(
ExprName {
range: 1..2,
id: "x",
ctx: Load,
},
),
),
value: Name(
ExprName { ExprName {
range: 1..2, range: 5..8,
id: "x", id: "def",
ctx: Load, ctx: Load,
}, },
), ),
), },
Some( DictItem {
Call( key: Some(
ExprCall { Call(
range: 9..14, ExprCall {
func: Name( range: 9..14,
ExprName { func: Name(
range: 9..12, ExprName {
id: "foo", range: 9..12,
ctx: Load, id: "foo",
ctx: Load,
},
),
arguments: Arguments {
range: 12..14,
args: [],
keywords: [],
}, },
),
arguments: Arguments {
range: 12..14,
args: [],
keywords: [],
}, },
),
),
value: Name(
ExprName {
range: 20..24,
id: "pass",
ctx: Load,
}, },
), ),
), },
],
values: [
Name(
ExprName {
range: 5..8,
id: "def",
ctx: Load,
},
),
Name(
ExprName {
range: 20..24,
id: "pass",
ctx: Load,
},
),
], ],
}, },
), ),

View file

@ -15,40 +15,40 @@ Module(
value: Dict( value: Dict(
ExprDict { ExprDict {
range: 0..10, range: 0..10,
keys: [ items: [
Some( DictItem {
Name( key: Some(
ExprName { Name(
range: 1..2, ExprName {
id: "x", range: 1..2,
ctx: Load, id: "x",
ctx: Load,
},
),
),
value: BinOp(
ExprBinOp {
range: 5..10,
left: NumberLiteral(
ExprNumberLiteral {
range: 5..6,
value: Int(
1,
),
},
),
op: Add,
right: NumberLiteral(
ExprNumberLiteral {
range: 9..10,
value: Int(
2,
),
},
),
}, },
), ),
), },
],
values: [
BinOp(
ExprBinOp {
range: 5..10,
left: NumberLiteral(
ExprNumberLiteral {
range: 5..6,
value: Int(
1,
),
},
),
op: Add,
right: NumberLiteral(
ExprNumberLiteral {
range: 9..10,
value: Int(
2,
),
},
),
},
),
], ],
}, },
), ),

View file

@ -15,26 +15,26 @@ Module(
value: Dict( value: Dict(
ExprDict { ExprDict {
range: 0..6, range: 0..6,
keys: [ items: [
Some( DictItem {
Name( key: Some(
ExprName { Name(
range: 1..2, ExprName {
id: "x", range: 1..2,
ctx: Load, id: "x",
ctx: Load,
},
),
),
value: NumberLiteral(
ExprNumberLiteral {
range: 4..5,
value: Int(
1,
),
}, },
), ),
), },
],
values: [
NumberLiteral(
ExprNumberLiteral {
range: 4..5,
value: Int(
1,
),
},
),
], ],
}, },
), ),

View file

@ -15,71 +15,75 @@ Module(
value: Dict( value: Dict(
ExprDict { ExprDict {
range: 55..77, range: 55..77,
keys: [ items: [
Some( DictItem {
Named( key: Some(
ExprNamed { Named(
range: 56..62, ExprNamed {
target: Name( range: 56..62,
ExprName { target: Name(
range: 56..57, ExprName {
id: "x", range: 56..57,
ctx: Store, id: "x",
}, ctx: Store,
), },
value: NumberLiteral( ),
ExprNumberLiteral { value: NumberLiteral(
range: 61..62, ExprNumberLiteral {
value: Int( range: 61..62,
1, value: Int(
), 1,
}, ),
), },
}, ),
},
),
), ),
), value: Name(
Some(
Name(
ExprName { ExprName {
range: 67..68, range: 64..65,
id: "z", id: "y",
ctx: Load, ctx: Load,
}, },
), ),
), },
Some( DictItem {
NumberLiteral( key: Some(
ExprNumberLiteral { Name(
range: 72..73, ExprName {
value: Int( range: 67..68,
2, id: "z",
), ctx: Load,
},
),
),
value: Name(
ExprName {
range: 68..68,
id: "",
ctx: Invalid,
}, },
), ),
), },
], DictItem {
values: [ key: Some(
Name( NumberLiteral(
ExprName { ExprNumberLiteral {
range: 64..65, range: 72..73,
id: "y", value: Int(
ctx: Load, 2,
}, ),
), },
Name( ),
ExprName { ),
range: 68..68, value: Name(
id: "", ExprName {
ctx: Invalid, range: 75..76,
}, id: "a",
), ctx: Load,
Name( },
ExprName { ),
range: 75..76, },
id: "a",
ctx: Load,
},
),
], ],
}, },
), ),

View file

@ -15,75 +15,81 @@ Module(
value: Dict( value: Dict(
ExprDict { ExprDict {
range: 57..79, range: 57..79,
keys: [ items: [
Some( DictItem {
Name( key: Some(
Name(
ExprName {
range: 58..59,
id: "x",
ctx: Load,
},
),
),
value: Name(
ExprName { ExprName {
range: 58..59, range: 61..62,
id: "x", id: "y",
ctx: Load, ctx: Load,
}, },
), ),
), },
Some( DictItem {
NumberLiteral( key: Some(
ExprNumberLiteral { NumberLiteral(
range: 66..67, ExprNumberLiteral {
value: Int( range: 66..67,
1, value: Int(
), 1,
),
},
),
),
value: Name(
ExprName {
range: 67..67,
id: "",
ctx: Invalid,
}, },
), ),
), },
Some( DictItem {
Name( key: Some(
Name(
ExprName {
range: 69..70,
id: "z",
ctx: Load,
},
),
),
value: Name(
ExprName { ExprName {
range: 69..70, range: 72..73,
id: "z", id: "a",
ctx: Load, ctx: Load,
}, },
), ),
), },
Some( DictItem {
NumberLiteral( key: Some(
ExprNumberLiteral { NumberLiteral(
range: 77..78, ExprNumberLiteral {
value: Int( range: 77..78,
2, value: Int(
), 2,
),
},
),
),
value: Name(
ExprName {
range: 78..78,
id: "",
ctx: Invalid,
}, },
), ),
), },
],
values: [
Name(
ExprName {
range: 61..62,
id: "y",
ctx: Load,
},
),
Name(
ExprName {
range: 67..67,
id: "",
ctx: Invalid,
},
),
Name(
ExprName {
range: 72..73,
id: "a",
ctx: Load,
},
),
Name(
ExprName {
range: 78..78,
id: "",
ctx: Invalid,
},
),
], ],
}, },
), ),

View file

@ -34,45 +34,47 @@ Module(
value: Dict( value: Dict(
ExprDict { ExprDict {
range: 93..105, range: 93..105,
keys: [ items: [
Some( DictItem {
NumberLiteral( key: Some(
NumberLiteral(
ExprNumberLiteral {
range: 94..95,
value: Int(
1,
),
},
),
),
value: NumberLiteral(
ExprNumberLiteral { ExprNumberLiteral {
range: 94..95, range: 97..98,
value: Int( value: Int(
1, 2,
), ),
}, },
), ),
), },
Some( DictItem {
NumberLiteral( key: Some(
NumberLiteral(
ExprNumberLiteral {
range: 100..101,
value: Int(
3,
),
},
),
),
value: NumberLiteral(
ExprNumberLiteral { ExprNumberLiteral {
range: 100..101, range: 103..104,
value: Int( value: Int(
3, 4,
), ),
}, },
), ),
), },
],
values: [
NumberLiteral(
ExprNumberLiteral {
range: 97..98,
value: Int(
2,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 103..104,
value: Int(
4,
),
},
),
], ],
}, },
), ),
@ -84,27 +86,27 @@ Module(
value: Dict( value: Dict(
ExprDict { ExprDict {
range: 107..115, range: 107..115,
keys: [ items: [
Some( DictItem {
NumberLiteral( key: Some(
NumberLiteral(
ExprNumberLiteral {
range: 108..109,
value: Int(
1,
),
},
),
),
value: NumberLiteral(
ExprNumberLiteral { ExprNumberLiteral {
range: 108..109, range: 111..112,
value: Int( value: Int(
1, 2,
), ),
}, },
), ),
), },
],
values: [
NumberLiteral(
ExprNumberLiteral {
range: 111..112,
value: Int(
2,
),
},
),
], ],
}, },
), ),
@ -116,45 +118,47 @@ Module(
value: Dict( value: Dict(
ExprDict { ExprDict {
range: 133..144, range: 133..144,
keys: [ items: [
Some( DictItem {
NumberLiteral( key: Some(
NumberLiteral(
ExprNumberLiteral {
range: 134..135,
value: Int(
1,
),
},
),
),
value: NumberLiteral(
ExprNumberLiteral { ExprNumberLiteral {
range: 134..135, range: 137..138,
value: Int( value: Int(
1, 2,
), ),
}, },
), ),
), },
Some( DictItem {
NumberLiteral( key: Some(
NumberLiteral(
ExprNumberLiteral {
range: 139..140,
value: Int(
3,
),
},
),
),
value: NumberLiteral(
ExprNumberLiteral { ExprNumberLiteral {
range: 139..140, range: 142..143,
value: Int( value: Int(
3, 4,
), ),
}, },
), ),
), },
],
values: [
NumberLiteral(
ExprNumberLiteral {
range: 137..138,
value: Int(
2,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 142..143,
value: Int(
4,
),
},
),
], ],
}, },
), ),
@ -166,26 +170,26 @@ Module(
value: Dict( value: Dict(
ExprDict { ExprDict {
range: 157..162, range: 157..162,
keys: [ items: [
Some( DictItem {
NumberLiteral( key: Some(
ExprNumberLiteral { NumberLiteral(
range: 158..159, ExprNumberLiteral {
value: Int( range: 158..159,
1, value: Int(
), 1,
),
},
),
),
value: Name(
ExprName {
range: 160..160,
id: "",
ctx: Invalid,
}, },
), ),
), },
],
values: [
Name(
ExprName {
range: 160..160,
id: "",
ctx: Invalid,
},
),
], ],
}, },
), ),
@ -197,17 +201,17 @@ Module(
value: Dict( value: Dict(
ExprDict { ExprDict {
range: 201..205, range: 201..205,
keys: [ items: [
None, DictItem {
], key: None,
values: [ value: Name(
Name( ExprName {
ExprName { range: 204..204,
range: 204..204, id: "",
id: "", ctx: Invalid,
ctx: Invalid, },
}, ),
), },
], ],
}, },
), ),
@ -219,49 +223,53 @@ Module(
value: Dict( value: Dict(
ExprDict { ExprDict {
range: 206..222, range: 206..222,
keys: [ items: [
Some( DictItem {
Name( key: Some(
Name(
ExprName {
range: 207..208,
id: "x",
ctx: Load,
},
),
),
value: Name(
ExprName { ExprName {
range: 207..208, range: 210..211,
id: "x", id: "y",
ctx: Load, ctx: Load,
}, },
), ),
), },
None, DictItem {
Some( key: None,
Name( value: Name(
ExprName { ExprName {
range: 217..218, range: 215..215,
id: "a", id: "",
ctx: Invalid,
},
),
},
DictItem {
key: Some(
Name(
ExprName {
range: 217..218,
id: "a",
ctx: Load,
},
),
),
value: Name(
ExprName {
range: 220..221,
id: "b",
ctx: Load, ctx: Load,
}, },
), ),
), },
],
values: [
Name(
ExprName {
range: 210..211,
id: "y",
ctx: Load,
},
),
Name(
ExprName {
range: 215..215,
id: "",
ctx: Invalid,
},
),
Name(
ExprName {
range: 220..221,
id: "b",
ctx: Load,
},
),
], ],
}, },
), ),
@ -273,69 +281,73 @@ Module(
value: Dict( value: Dict(
ExprDict { ExprDict {
range: 310..330, range: 310..330,
keys: [ items: [
Some( DictItem {
Starred( key: Some(
ExprStarred { Starred(
range: 311..313, ExprStarred {
value: Name( range: 311..313,
ExprName { value: Name(
range: 312..313, ExprName {
id: "x", range: 312..313,
ctx: Load, id: "x",
}, ctx: Load,
), },
ctx: Load, ),
}, ctx: Load,
},
),
), ),
), value: Name(
Some(
Name(
ExprName { ExprName {
range: 318..319, range: 315..316,
id: "z", id: "y",
ctx: Load, ctx: Load,
}, },
), ),
), },
Some( DictItem {
Starred( key: Some(
ExprStarred { Name(
range: 324..326, ExprName {
value: Name( range: 318..319,
ExprName { id: "z",
range: 325..326, ctx: Load,
id: "b", },
ctx: Load, ),
}, ),
), value: Name(
ExprName {
range: 321..322,
id: "a",
ctx: Load, ctx: Load,
}, },
), ),
), },
], DictItem {
values: [ key: Some(
Name( Starred(
ExprName { ExprStarred {
range: 315..316, range: 324..326,
id: "y", value: Name(
ctx: Load, ExprName {
}, range: 325..326,
), id: "b",
Name( ctx: Load,
ExprName { },
range: 321..322, ),
id: "a", ctx: Load,
ctx: Load, },
}, ),
), ),
Name( value: Name(
ExprName { ExprName {
range: 328..329, range: 328..329,
id: "c", id: "c",
ctx: Load, ctx: Load,
}, },
), ),
},
], ],
}, },
), ),
@ -347,53 +359,55 @@ Module(
value: Dict( value: Dict(
ExprDict { ExprDict {
range: 331..345, range: 331..345,
keys: [ items: [
Some( DictItem {
Name( key: Some(
ExprName { Name(
range: 332..333,
id: "x",
ctx: Load,
},
),
),
Some(
Name(
ExprName {
range: 339..340,
id: "z",
ctx: Load,
},
),
),
],
values: [
Starred(
ExprStarred {
range: 335..337,
value: Name(
ExprName { ExprName {
range: 336..337, range: 332..333,
id: "y", id: "x",
ctx: Load, ctx: Load,
}, },
), ),
ctx: Load, ),
}, value: Starred(
), ExprStarred {
Starred( range: 335..337,
ExprStarred { value: Name(
range: 342..344, ExprName {
value: Name( range: 336..337,
id: "y",
ctx: Load,
},
),
ctx: Load,
},
),
},
DictItem {
key: Some(
Name(
ExprName { ExprName {
range: 343..344, range: 339..340,
id: "a", id: "z",
ctx: Load, ctx: Load,
}, },
), ),
ctx: Load, ),
}, value: Starred(
), ExprStarred {
range: 342..344,
value: Name(
ExprName {
range: 343..344,
id: "a",
ctx: Load,
},
),
ctx: Load,
},
),
},
], ],
}, },
), ),

View file

@ -110,27 +110,27 @@ Module(
value: Dict( value: Dict(
ExprDict { ExprDict {
range: 271..277, range: 271..277,
keys: [ items: [
Some( DictItem {
NumberLiteral( key: Some(
NumberLiteral(
ExprNumberLiteral {
range: 272..273,
value: Int(
1,
),
},
),
),
value: NumberLiteral(
ExprNumberLiteral { ExprNumberLiteral {
range: 272..273, range: 275..276,
value: Int( value: Int(
1, 2,
), ),
}, },
), ),
), },
],
values: [
NumberLiteral(
ExprNumberLiteral {
range: 275..276,
value: Int(
2,
),
},
),
], ],
}, },
), ),

View file

@ -44,37 +44,37 @@ Module(
Dict( Dict(
ExprDict { ExprDict {
range: 14..22, range: 14..22,
keys: [ items: [
Some( DictItem {
StringLiteral( key: Some(
ExprStringLiteral { StringLiteral(
range: 15..18, ExprStringLiteral {
value: StringLiteralValue { range: 15..18,
inner: Single( value: StringLiteralValue {
StringLiteral { inner: Single(
range: 15..18, StringLiteral {
value: "x", range: 15..18,
flags: StringLiteralFlags { value: "x",
quote_style: Single, flags: StringLiteralFlags {
prefix: Empty, quote_style: Single,
triple_quoted: false, prefix: Empty,
triple_quoted: false,
},
}, },
}, ),
), },
}, },
),
),
value: NumberLiteral(
ExprNumberLiteral {
range: 20..21,
value: Int(
1,
),
}, },
), ),
), },
],
values: [
NumberLiteral(
ExprNumberLiteral {
range: 20..21,
value: Int(
1,
),
},
),
], ],
}, },
), ),

View file

@ -57,65 +57,67 @@ Module(
value: Dict( value: Dict(
ExprDict { ExprDict {
range: 20..36, range: 20..36,
keys: [ items: [
Some( DictItem {
StringLiteral( key: Some(
ExprStringLiteral { StringLiteral(
range: 21..24, ExprStringLiteral {
value: StringLiteralValue { range: 21..24,
inner: Single( value: StringLiteralValue {
StringLiteral { inner: Single(
range: 21..24, StringLiteral {
value: "b", range: 21..24,
flags: StringLiteralFlags { value: "b",
quote_style: Single, flags: StringLiteralFlags {
prefix: Empty, quote_style: Single,
triple_quoted: false, prefix: Empty,
triple_quoted: false,
},
}, },
}, ),
), },
}, },
),
),
value: NumberLiteral(
ExprNumberLiteral {
range: 26..27,
value: Int(
1,
),
}, },
), ),
), },
Some( DictItem {
StringLiteral( key: Some(
ExprStringLiteral { StringLiteral(
range: 29..32, ExprStringLiteral {
value: StringLiteralValue { range: 29..32,
inner: Single( value: StringLiteralValue {
StringLiteral { inner: Single(
range: 29..32, StringLiteral {
value: "c", range: 29..32,
flags: StringLiteralFlags { value: "c",
quote_style: Single, flags: StringLiteralFlags {
prefix: Empty, quote_style: Single,
triple_quoted: false, prefix: Empty,
triple_quoted: false,
},
}, },
}, ),
), },
}, },
),
),
value: NumberLiteral(
ExprNumberLiteral {
range: 34..35,
value: Int(
2,
),
}, },
), ),
), },
],
values: [
NumberLiteral(
ExprNumberLiteral {
range: 26..27,
value: Int(
1,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 34..35,
value: Int(
2,
),
},
),
], ],
}, },
), ),

View file

@ -319,37 +319,37 @@ Module(
Dict( Dict(
ExprDict { ExprDict {
range: 386..394, range: 386..394,
keys: [ items: [
Some( DictItem {
StringLiteral( key: Some(
ExprStringLiteral { StringLiteral(
range: 387..390, ExprStringLiteral {
value: StringLiteralValue { range: 387..390,
inner: Single( value: StringLiteralValue {
StringLiteral { inner: Single(
range: 387..390, StringLiteral {
value: "a", range: 387..390,
flags: StringLiteralFlags { value: "a",
quote_style: Double, flags: StringLiteralFlags {
prefix: Empty, quote_style: Double,
triple_quoted: false, prefix: Empty,
triple_quoted: false,
},
}, },
}, ),
), },
}, },
),
),
value: NumberLiteral(
ExprNumberLiteral {
range: 392..393,
value: Int(
5,
),
}, },
), ),
), },
],
values: [
NumberLiteral(
ExprNumberLiteral {
range: 392..393,
value: Int(
5,
),
},
),
], ],
}, },
), ),

View file

@ -236,37 +236,37 @@ Module(
target: Dict( target: Dict(
ExprDict { ExprDict {
range: 186..194, range: 186..194,
keys: [ items: [
Some( DictItem {
StringLiteral( key: Some(
ExprStringLiteral { StringLiteral(
range: 187..190, ExprStringLiteral {
value: StringLiteralValue { range: 187..190,
inner: Single( value: StringLiteralValue {
StringLiteral { inner: Single(
range: 187..190, StringLiteral {
value: "a", range: 187..190,
flags: StringLiteralFlags { value: "a",
quote_style: Double, flags: StringLiteralFlags {
prefix: Empty, quote_style: Double,
triple_quoted: false, prefix: Empty,
triple_quoted: false,
},
}, },
}, ),
), },
}, },
),
),
value: NumberLiteral(
ExprNumberLiteral {
range: 192..193,
value: Int(
5,
),
}, },
), ),
), },
],
values: [
NumberLiteral(
ExprNumberLiteral {
range: 192..193,
value: Int(
5,
),
},
),
], ],
}, },
), ),

View file

@ -28,8 +28,7 @@ Module(
cls: Dict( cls: Dict(
ExprDict { ExprDict {
range: 108..109, range: 108..109,
keys: [], items: [],
values: [],
}, },
), ),
arguments: PatternArguments { arguments: PatternArguments {

View file

@ -263,25 +263,25 @@ Module(
left: Dict( left: Dict(
ExprDict { ExprDict {
range: 201..210, range: 201..210,
keys: [ items: [
Some( DictItem {
BooleanLiteral( key: Some(
ExprBooleanLiteral { BooleanLiteral(
range: 202..206, ExprBooleanLiteral {
value: true, range: 202..206,
value: true,
},
),
),
value: NumberLiteral(
ExprNumberLiteral {
range: 208..209,
value: Int(
1,
),
}, },
), ),
), },
],
values: [
NumberLiteral(
ExprNumberLiteral {
range: 208..209,
value: Int(
1,
),
},
),
], ],
}, },
), ),
@ -711,25 +711,25 @@ Module(
right: Dict( right: Dict(
ExprDict { ExprDict {
range: 534..543, range: 534..543,
keys: [ items: [
Some( DictItem {
BooleanLiteral( key: Some(
ExprBooleanLiteral { BooleanLiteral(
range: 535..539, ExprBooleanLiteral {
value: true, range: 535..539,
value: true,
},
),
),
value: NumberLiteral(
ExprNumberLiteral {
range: 541..542,
value: Int(
1,
),
}, },
), ),
), },
],
values: [
NumberLiteral(
ExprNumberLiteral {
range: 541..542,
value: Int(
1,
),
},
),
], ],
}, },
), ),

View file

@ -192,26 +192,26 @@ Module(
value: Dict( value: Dict(
ExprDict { ExprDict {
range: 76..82, range: 76..82,
keys: [ items: [
Some( DictItem {
Name( key: Some(
ExprName { Name(
range: 77..78, ExprName {
id: "i", range: 77..78,
ctx: Load, id: "i",
ctx: Load,
},
),
),
value: NumberLiteral(
ExprNumberLiteral {
range: 80..81,
value: Int(
5,
),
}, },
), ),
), },
],
values: [
NumberLiteral(
ExprNumberLiteral {
range: 80..81,
value: Int(
5,
),
},
),
], ],
}, },
), ),

View file

@ -360,45 +360,47 @@ Module(
func: Dict( func: Dict(
ExprDict { ExprDict {
range: 219..231, range: 219..231,
keys: [ items: [
Some( DictItem {
NumberLiteral( key: Some(
NumberLiteral(
ExprNumberLiteral {
range: 220..221,
value: Int(
1,
),
},
),
),
value: NumberLiteral(
ExprNumberLiteral { ExprNumberLiteral {
range: 220..221, range: 223..224,
value: Int( value: Int(
1, 2,
), ),
}, },
), ),
), },
Some( DictItem {
NumberLiteral( key: Some(
NumberLiteral(
ExprNumberLiteral {
range: 226..227,
value: Int(
3,
),
},
),
),
value: NumberLiteral(
ExprNumberLiteral { ExprNumberLiteral {
range: 226..227, range: 229..230,
value: Int( value: Int(
3, 4,
), ),
}, },
), ),
), },
],
values: [
NumberLiteral(
ExprNumberLiteral {
range: 223..224,
value: Int(
2,
),
},
),
NumberLiteral(
ExprNumberLiteral {
range: 229..230,
value: Int(
4,
),
},
),
], ],
}, },
), ),

View file

@ -823,104 +823,104 @@ Module(
value: Dict( value: Dict(
ExprDict { ExprDict {
range: 219..253, range: 219..253,
keys: [ items: [
Some( DictItem {
FString( key: Some(
ExprFString { FString(
range: 220..248, ExprFString {
value: FStringValue { range: 220..248,
inner: Concatenated( value: FStringValue {
[ inner: Concatenated(
Literal( [
StringLiteral { Literal(
range: 220..226, StringLiteral {
value: "foo ", range: 220..226,
flags: StringLiteralFlags { value: "foo ",
quote_style: Double, flags: StringLiteralFlags {
prefix: Empty, quote_style: Double,
triple_quoted: false, prefix: Empty,
triple_quoted: false,
},
}, },
}, ),
), FString(
FString( FString {
FString { range: 227..242,
range: 227..242, elements: [
elements: [ Literal(
Literal( FStringLiteralElement {
FStringLiteralElement { range: 229..233,
range: 229..233, value: "bar ",
value: "bar ", },
}, ),
), Expression(
Expression( FStringExpressionElement {
FStringExpressionElement { range: 233..240,
range: 233..240, expression: BinOp(
expression: BinOp( ExprBinOp {
ExprBinOp { range: 234..239,
range: 234..239, left: Name(
left: Name( ExprName {
ExprName { range: 234..235,
range: 234..235, id: "x",
id: "x", ctx: Load,
ctx: Load, },
}, ),
), op: Add,
op: Add, right: Name(
right: Name( ExprName {
ExprName { range: 238..239,
range: 238..239, id: "y",
id: "y", ctx: Load,
ctx: Load, },
}, ),
), },
}, ),
), debug_text: None,
debug_text: None, conversion: None,
conversion: None, format_spec: None,
format_spec: None, },
}, ),
), Literal(
Literal( FStringLiteralElement {
FStringLiteralElement { range: 240..241,
range: 240..241, value: " ",
value: " ", },
}, ),
), ],
], flags: FStringFlags {
flags: FStringFlags { quote_style: Double,
quote_style: Double, prefix: Regular,
prefix: Regular, triple_quoted: false,
triple_quoted: false, },
}, },
}, ),
), Literal(
Literal( StringLiteral {
StringLiteral { range: 243..248,
range: 243..248, value: "baz",
value: "baz", flags: StringLiteralFlags {
flags: StringLiteralFlags { quote_style: Double,
quote_style: Double, prefix: Empty,
prefix: Empty, triple_quoted: false,
triple_quoted: false, },
}, },
}, ),
), ],
], ),
), },
}, },
),
),
value: NumberLiteral(
ExprNumberLiteral {
range: 250..252,
value: Int(
10,
),
}, },
), ),
), },
],
values: [
NumberLiteral(
ExprNumberLiteral {
range: 250..252,
value: Int(
10,
),
},
),
], ],
}, },
), ),

View file

@ -652,26 +652,26 @@ Module(
Dict( Dict(
ExprDict { ExprDict {
range: 319..325, range: 319..325,
keys: [ items: [
Some( DictItem {
Name( key: Some(
ExprName { Name(
range: 320..321, ExprName {
id: "a", range: 320..321,
ctx: Load, id: "a",
ctx: Load,
},
),
),
value: NumberLiteral(
ExprNumberLiteral {
range: 323..324,
value: Int(
1,
),
}, },
), ),
), },
],
values: [
NumberLiteral(
ExprNumberLiteral {
range: 323..324,
value: Int(
1,
),
},
),
], ],
}, },
), ),

View file

@ -15,8 +15,7 @@ Module(
value: Dict( value: Dict(
ExprDict { ExprDict {
range: 14..16, range: 14..16,
keys: [], items: [],
values: [],
}, },
), ),
}, },
@ -139,8 +138,7 @@ Module(
value: Dict( value: Dict(
ExprDict { ExprDict {
range: 74..77, range: 74..77,
keys: [], items: [],
values: [],
}, },
), ),
}, },
@ -579,33 +577,35 @@ Module(
Dict( Dict(
ExprDict { ExprDict {
range: 300..311, range: 300..311,
keys: [ items: [
Some( DictItem {
Name( key: Some(
Name(
ExprName {
range: 301..302,
id: "a",
ctx: Load,
},
),
),
value: Name(
ExprName { ExprName {
range: 301..302, range: 304..305,
id: "a", id: "b",
ctx: Load, ctx: Load,
}, },
), ),
), },
None, DictItem {
], key: None,
values: [ value: Name(
Name( ExprName {
ExprName { range: 309..310,
range: 304..305, id: "d",
id: "b", ctx: Load,
ctx: Load, },
}, ),
), },
Name(
ExprName {
range: 309..310,
id: "d",
ctx: Load,
},
),
], ],
}, },
), ),

View file

@ -216,26 +216,26 @@ Module(
Dict( Dict(
ExprDict { ExprDict {
range: 85..91, range: 85..91,
keys: [ items: [
Some( DictItem {
Name( key: Some(
ExprName { Name(
range: 86..87, ExprName {
id: "x", range: 86..87,
ctx: Load, id: "x",
ctx: Load,
},
),
),
value: NumberLiteral(
ExprNumberLiteral {
range: 89..90,
value: Int(
5,
),
}, },
), ),
), },
],
values: [
NumberLiteral(
ExprNumberLiteral {
range: 89..90,
value: Int(
5,
),
},
),
], ],
}, },
), ),

View file

@ -192,26 +192,26 @@ Module(
value: Dict( value: Dict(
ExprDict { ExprDict {
range: 114..120, range: 114..120,
keys: [ items: [
Some( DictItem {
Name( key: Some(
ExprName { Name(
range: 115..116, ExprName {
id: "x", range: 115..116,
ctx: Load, id: "x",
ctx: Load,
},
),
),
value: NumberLiteral(
ExprNumberLiteral {
range: 118..119,
value: Int(
5,
),
}, },
), ),
), },
],
values: [
NumberLiteral(
ExprNumberLiteral {
range: 118..119,
value: Int(
5,
),
},
),
], ],
}, },
), ),

View file

@ -3814,37 +3814,37 @@ Module(
subject: Dict( subject: Dict(
ExprDict { ExprDict {
range: 2959..2970, range: 2959..2970,
keys: [ items: [
Some( DictItem {
StringLiteral( key: Some(
ExprStringLiteral { StringLiteral(
range: 2960..2966, ExprStringLiteral {
value: StringLiteralValue { range: 2960..2966,
inner: Single( value: StringLiteralValue {
StringLiteral { inner: Single(
range: 2960..2966, StringLiteral {
value: "test", range: 2960..2966,
flags: StringLiteralFlags { value: "test",
quote_style: Double, flags: StringLiteralFlags {
prefix: Empty, quote_style: Double,
triple_quoted: false, prefix: Empty,
triple_quoted: false,
},
}, },
}, ),
), },
}, },
),
),
value: NumberLiteral(
ExprNumberLiteral {
range: 2968..2969,
value: Int(
1,
),
}, },
), ),
), },
],
values: [
NumberLiteral(
ExprNumberLiteral {
range: 2968..2969,
value: Int(
1,
),
},
),
], ],
}, },
), ),
@ -3907,16 +3907,36 @@ Module(
subject: Dict( subject: Dict(
ExprDict { ExprDict {
range: 3032..3049, range: 3032..3049,
keys: [ items: [
Some( DictItem {
StringLiteral( key: Some(
StringLiteral(
ExprStringLiteral {
range: 3033..3040,
value: StringLiteralValue {
inner: Single(
StringLiteral {
range: 3033..3040,
value: "label",
flags: StringLiteralFlags {
quote_style: Double,
prefix: Empty,
triple_quoted: false,
},
},
),
},
},
),
),
value: StringLiteral(
ExprStringLiteral { ExprStringLiteral {
range: 3033..3040, range: 3042..3048,
value: StringLiteralValue { value: StringLiteralValue {
inner: Single( inner: Single(
StringLiteral { StringLiteral {
range: 3033..3040, range: 3042..3048,
value: "label", value: "test",
flags: StringLiteralFlags { flags: StringLiteralFlags {
quote_style: Double, quote_style: Double,
prefix: Empty, prefix: Empty,
@ -3927,27 +3947,7 @@ Module(
}, },
}, },
), ),
), },
],
values: [
StringLiteral(
ExprStringLiteral {
range: 3042..3048,
value: StringLiteralValue {
inner: Single(
StringLiteral {
range: 3042..3048,
value: "test",
flags: StringLiteralFlags {
quote_style: Double,
prefix: Empty,
triple_quoted: false,
},
},
),
},
},
),
], ],
}, },
), ),