Skip to content

Commit 2b6e1f5

Browse files
committed
Encode in parent
1 parent 5cfd581 commit 2b6e1f5

5 files changed

Lines changed: 33 additions & 21 deletions

File tree

crates/ruff_python_formatter/src/expression/expr_await.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
use ruff_formatter::write;
22
use ruff_python_ast::AnyNodeRef;
33
use ruff_python_ast::ExprAwait;
4+
use ruff_text_size::Ranged;
45

56
use crate::expression::maybe_parenthesize_expression;
67
use crate::expression::parentheses::{
78
NeedsParentheses, OptionalParentheses, Parenthesize, is_expression_parenthesized,
9+
is_type_annotation_of,
810
};
911
use crate::prelude::*;
1012

@@ -36,7 +38,7 @@ impl NeedsParentheses for ExprAwait {
3638
parent: AnyNodeRef,
3739
context: &PyFormatContext,
3840
) -> OptionalParentheses {
39-
if parent.is_expr_await() {
41+
if parent.is_expr_await() || is_type_annotation_of(self.range(), parent) {
4042
OptionalParentheses::Always
4143
} else if is_expression_parenthesized(
4244
self.value.as_ref().into(),

crates/ruff_python_formatter/src/expression/expr_yield.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use ruff_text_size::{Ranged, TextRange};
66
use crate::expression::maybe_parenthesize_expression;
77
use crate::expression::parentheses::{
88
NeedsParentheses, OptionalParentheses, Parenthesize, is_expression_parenthesized,
9+
is_type_annotation_of,
910
};
1011
use crate::prelude::*;
1112

@@ -42,6 +43,10 @@ impl NeedsParentheses for AnyExpressionYield<'_> {
4243
parent: AnyNodeRef,
4344
context: &PyFormatContext,
4445
) -> OptionalParentheses {
46+
if is_type_annotation_of(self.range(), parent) {
47+
return OptionalParentheses::Always;
48+
}
49+
4550
// According to https://docs.python.org/3/reference/grammar.html There are two situations
4651
// where we do not want to always parenthesize a yield expression:
4752
// 1. Right hand side of an assignment, e.g. `x = yield y`

crates/ruff_python_formatter/src/expression/parentheses.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use ruff_python_trivia::CommentRanges;
66
use ruff_python_trivia::{
77
BackwardsTokenizer, SimpleToken, SimpleTokenKind, first_non_trivia_token,
88
};
9-
use ruff_text_size::Ranged;
9+
use ruff_text_size::{Ranged, TextRange};
1010

1111
use crate::comments::{
1212
SourceComment, dangling_comments, dangling_open_parenthesis_comments, trailing_comments,
@@ -42,6 +42,19 @@ pub(crate) trait NeedsParentheses {
4242
) -> OptionalParentheses;
4343
}
4444

45+
/// Returns `true` if `expr_range` identifies a type annotation child of `parent`,
46+
/// i.e. the annotation of a [`StmtAnnAssign`] or the return annotation of a [`StmtFunctionDef`].
47+
pub(crate) fn is_type_annotation_of(expr_range: TextRange, parent: AnyNodeRef) -> bool {
48+
match parent {
49+
AnyNodeRef::StmtAnnAssign(stmt) => stmt.annotation.range() == expr_range,
50+
AnyNodeRef::StmtFunctionDef(stmt) => stmt
51+
.returns
52+
.as_deref()
53+
.is_some_and(|r| r.range() == expr_range),
54+
_ => false,
55+
}
56+
}
57+
4558
/// From the perspective of the parent statement or expression, when should the child expression
4659
/// get parentheses?
4760
#[derive(Copy, Clone, Debug, PartialEq)]

crates/ruff_python_formatter/src/statement/stmt_ann_assign.rs

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use ruff_formatter::write;
22
use ruff_python_ast::StmtAnnAssign;
33

4+
use crate::expression::is_splittable_expression;
45
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses, Parentheses};
5-
use crate::expression::{is_invalid_type_expression, is_splittable_expression};
66
use crate::prelude::*;
77
use crate::statement::stmt_assign::{
88
AnyAssignmentOperator, AnyBeforeOperator, FormatStatementsLastExpression,
@@ -23,12 +23,15 @@ impl FormatNodeRule<StmtAnnAssign> for FormatStmtAnnAssign {
2323
simple: _,
2424
} = item;
2525
let comments = f.context().comments().clone();
26-
let preserve_annotation_parentheses = is_invalid_type_expression(annotation);
26+
let annotation_parentheses = annotation
27+
.as_ref()
28+
.needs_parentheses(item.into(), f.context());
2729

2830
write!(f, [target.format(), token(":"), space()])?;
2931

3032
if let Some(value) = value {
31-
if !preserve_annotation_parentheses && is_splittable_expression(annotation, f.context())
33+
if annotation_parentheses != OptionalParentheses::Always
34+
&& is_splittable_expression(annotation, f.context())
3235
{
3336
FormatStatementsLastExpression::RightToLeft {
3437
before_operator: AnyBeforeOperator::Expression(annotation),
@@ -42,15 +45,9 @@ impl FormatNodeRule<StmtAnnAssign> for FormatStmtAnnAssign {
4245
// Ensure we keep the parentheses if the annotation has any comments.
4346
let parentheses = if comments.has_leading(annotation.as_ref())
4447
|| comments.has_trailing(annotation.as_ref())
45-
|| matches!(
46-
annotation
47-
.as_ref()
48-
.needs_parentheses(item.into(), f.context()),
49-
OptionalParentheses::Always
50-
) {
48+
|| annotation_parentheses == OptionalParentheses::Always
49+
{
5150
Parentheses::Always
52-
} else if preserve_annotation_parentheses {
53-
Parentheses::Preserve
5451
} else {
5552
Parentheses::Never
5653
};
@@ -67,10 +64,10 @@ impl FormatNodeRule<StmtAnnAssign> for FormatStmtAnnAssign {
6764
]
6865
)?;
6966
}
70-
} else if preserve_annotation_parentheses {
67+
} else if annotation_parentheses == OptionalParentheses::Always {
7168
annotation
7269
.format()
73-
.with_options(Parentheses::Preserve)
70+
.with_options(Parentheses::Always)
7471
.fmt(f)?;
7572
} else {
7673
// Parenthesize the value and inline the comment if it is a "simple" type annotation, similar

crates/ruff_python_formatter/src/statement/stmt_function_def.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use crate::comments::format::{
22
empty_lines_after_leading_comments, empty_lines_before_trailing_comments,
33
};
4+
use crate::expression::maybe_parenthesize_expression;
45
use crate::expression::parentheses::{Parentheses, Parenthesize};
5-
use crate::expression::{is_invalid_type_expression, maybe_parenthesize_expression};
66
use crate::prelude::*;
77
use crate::statement::clause::{ClauseHeader, clause};
88
use crate::statement::stmt_class_def::FormatDecorators;
@@ -162,11 +162,6 @@ fn format_function_header(f: &mut PyFormatter, item: &StmtFunctionDef) -> Format
162162
.format()
163163
.with_options(Parentheses::Always)
164164
.fmt(f)
165-
} else if is_invalid_type_expression(return_annotation) {
166-
return_annotation
167-
.format()
168-
.with_options(Parentheses::Preserve)
169-
.fmt(f)
170165
} else {
171166
let parenthesize = if parameters.is_empty() && !comments.has(parameters.as_ref()) {
172167
// If the parameters are empty, add parentheses around literal expressions

0 commit comments

Comments
 (0)