From ea62fc9baf2178deb0e761da11d64e7dff9c7c72 Mon Sep 17 00:00:00 2001 From: Max Mynter Date: Wed, 30 Apr 2025 23:23:44 -0400 Subject: [PATCH 1/3] (tests) Add integration tests for Python Semantic Syntax for `InvalidStarExpression`, `DuplicateMatchKey`, and `DuplicateMatchClassAttribue` --- crates/ruff_linter/src/linter.rs | 47 +++++++++++++++++++ ..._duplicate_match_class_attribute_3.10.snap | 10 ++++ ...cateMatchKey_duplicate_match_key_3.10.snap | 10 ++++ ...pression_invalid_star_expression_3.10.snap | 9 ++++ ...sion_invalid_star_expression_for_3.10.snap | 9 ++++ ...on_invalid_star_expression_yield_3.10.snap | 9 ++++ .../diagnostics/semantic_syntax_errors.md | 42 +++++++++++++++++ 7 files changed, 136 insertions(+) create mode 100644 crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__semantic_syntax_error_DuplicateMatchClassAttribute_duplicate_match_class_attribute_3.10.snap create mode 100644 crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__semantic_syntax_error_DuplicateMatchKey_duplicate_match_key_3.10.snap create mode 100644 crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__semantic_syntax_error_InvalidStarExpression_invalid_star_expression_3.10.snap create mode 100644 crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__semantic_syntax_error_InvalidStarExpression_invalid_star_expression_for_3.10.snap create mode 100644 crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__semantic_syntax_error_InvalidStarExpression_invalid_star_expression_yield_3.10.snap diff --git a/crates/ruff_linter/src/linter.rs b/crates/ruff_linter/src/linter.rs index 4b23e99c89a24..f2445b128caf8 100644 --- a/crates/ruff_linter/src/linter.rs +++ b/crates/ruff_linter/src/linter.rs @@ -1063,6 +1063,53 @@ mod tests { PythonVersion::PY310, "MultipleCaseAssignment" )] + #[test_case( + "duplicate_match_key", + " + match x: + case {'key': 1, 'key': 2}: + pass + ", + PythonVersion::PY310, + "DuplicateMatchKey" + )] + #[test_case( + "duplicate_match_class_attribute", + " + match x: + case Point(x=1, x=2): + pass + ", + PythonVersion::PY310, + "DuplicateMatchClassAttribute" + )] + #[test_case( + "invalid_star_expression", + " + def func(): + return *x + ", + PythonVersion::PY310, + "InvalidStarExpression" + )] + #[test_case( + "invalid_star_expression_for", + " + for *x in range(10): + pass + ", + PythonVersion::PY310, + "InvalidStarExpression" + )] + #[test_case( + "invalid_star_expression_yield", + " + def func(): + yield *x + ", + PythonVersion::PY310, + "InvalidStarExpression" + )] fn test_semantic_errors( name: &str, contents: &str, diff --git a/crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__semantic_syntax_error_DuplicateMatchClassAttribute_duplicate_match_class_attribute_3.10.snap b/crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__semantic_syntax_error_DuplicateMatchClassAttribute_duplicate_match_class_attribute_3.10.snap new file mode 100644 index 0000000000000..bac3111de0219 --- /dev/null +++ b/crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__semantic_syntax_error_DuplicateMatchClassAttribute_duplicate_match_class_attribute_3.10.snap @@ -0,0 +1,10 @@ +--- +source: crates/ruff_linter/src/linter.rs +--- +:3:21: SyntaxError: attribute name `x` repeated in class pattern + | +2 | match x: +3 | case Point(x=1, x=2): + | ^ +4 | pass + | diff --git a/crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__semantic_syntax_error_DuplicateMatchKey_duplicate_match_key_3.10.snap b/crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__semantic_syntax_error_DuplicateMatchKey_duplicate_match_key_3.10.snap new file mode 100644 index 0000000000000..f877e86e31013 --- /dev/null +++ b/crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__semantic_syntax_error_DuplicateMatchKey_duplicate_match_key_3.10.snap @@ -0,0 +1,10 @@ +--- +source: crates/ruff_linter/src/linter.rs +--- +:3:21: SyntaxError: mapping pattern checks duplicate key `'key'` + | +2 | match x: +3 | case {'key': 1, 'key': 2}: + | ^^^^^ +4 | pass + | diff --git a/crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__semantic_syntax_error_InvalidStarExpression_invalid_star_expression_3.10.snap b/crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__semantic_syntax_error_InvalidStarExpression_invalid_star_expression_3.10.snap new file mode 100644 index 0000000000000..cf3e091dc350a --- /dev/null +++ b/crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__semantic_syntax_error_InvalidStarExpression_invalid_star_expression_3.10.snap @@ -0,0 +1,9 @@ +--- +source: crates/ruff_linter/src/linter.rs +--- +:3:12: SyntaxError: can't use starred expression here + | +2 | def func(): +3 | return *x + | ^^ + | diff --git a/crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__semantic_syntax_error_InvalidStarExpression_invalid_star_expression_for_3.10.snap b/crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__semantic_syntax_error_InvalidStarExpression_invalid_star_expression_for_3.10.snap new file mode 100644 index 0000000000000..1f088e8616b3a --- /dev/null +++ b/crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__semantic_syntax_error_InvalidStarExpression_invalid_star_expression_for_3.10.snap @@ -0,0 +1,9 @@ +--- +source: crates/ruff_linter/src/linter.rs +--- +:2:5: SyntaxError: can't use starred expression here + | +2 | for *x in range(10): + | ^^ +3 | pass + | diff --git a/crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__semantic_syntax_error_InvalidStarExpression_invalid_star_expression_yield_3.10.snap b/crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__semantic_syntax_error_InvalidStarExpression_invalid_star_expression_yield_3.10.snap new file mode 100644 index 0000000000000..c7a8feb356466 --- /dev/null +++ b/crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__semantic_syntax_error_InvalidStarExpression_invalid_star_expression_yield_3.10.snap @@ -0,0 +1,9 @@ +--- +source: crates/ruff_linter/src/linter.rs +--- +:3:11: SyntaxError: can't use starred expression here + | +2 | def func(): +3 | yield *x + | ^^ + | diff --git a/crates/ty_python_semantic/resources/mdtest/diagnostics/semantic_syntax_errors.md b/crates/ty_python_semantic/resources/mdtest/diagnostics/semantic_syntax_errors.md index e380e10018c67..9be19b0e36184 100644 --- a/crates/ty_python_semantic/resources/mdtest/diagnostics/semantic_syntax_errors.md +++ b/crates/ty_python_semantic/resources/mdtest/diagnostics/semantic_syntax_errors.md @@ -100,6 +100,26 @@ match 2: ... ``` +## Duplicate `match` class attribute + +Attribute names in class patterns must be unique: + +```toml +[environment] +python-version = "3.10" +``` + +```py +class Point: + pass + +obj = Point() +match obj: + # error: [invalid-syntax] "attribute name `x` repeated in class pattern" + case Point(x=1, x=2): + pass +``` + ## `return`, `yield`, `yield from`, and `await` outside function ```py @@ -186,6 +206,28 @@ def f[X, Y, X](): pass ``` +## Invalid star expression + +Star expressions can't be used in certain contexts: + +```py +def func(): + # error: [invalid-syntax] "can't use starred expression here" + return *[1, 2, 3] + +def gen(): + # error: [invalid-syntax] "can't use starred expression here" + yield * [1, 2, 3] + +# error: [invalid-syntax] "can't use starred expression here" +for *x in range(10): + pass + +# error: [invalid-syntax] "can't use starred expression here" +for x in *range(10): + pass +``` + ## `await` outside async function This error includes `await`, `async for`, `async with`, and `async` comprehensions. From bf8ca036ae7a6867723bb55ce4491f41ff49f1fc Mon Sep 17 00:00:00 2001 From: Brent Westbrook Date: Mon, 5 May 2025 12:27:30 -0400 Subject: [PATCH 2/3] update error message after #17772 --- .../mdtest/diagnostics/semantic_syntax_errors.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/ty_python_semantic/resources/mdtest/diagnostics/semantic_syntax_errors.md b/crates/ty_python_semantic/resources/mdtest/diagnostics/semantic_syntax_errors.md index 9be19b0e36184..7063c58dda1cd 100644 --- a/crates/ty_python_semantic/resources/mdtest/diagnostics/semantic_syntax_errors.md +++ b/crates/ty_python_semantic/resources/mdtest/diagnostics/semantic_syntax_errors.md @@ -212,18 +212,18 @@ Star expressions can't be used in certain contexts: ```py def func(): - # error: [invalid-syntax] "can't use starred expression here" + # error: [invalid-syntax] "Starred expression cannot be used here" return *[1, 2, 3] def gen(): - # error: [invalid-syntax] "can't use starred expression here" + # error: [invalid-syntax] "Starred expression cannot be used here" yield * [1, 2, 3] -# error: [invalid-syntax] "can't use starred expression here" +# error: [invalid-syntax] "Starred expression cannot be used here" for *x in range(10): pass -# error: [invalid-syntax] "can't use starred expression here" +# error: [invalid-syntax] "Starred expression cannot be used here" for x in *range(10): pass ``` From 5642cae326659cf54bdaebc4f1f5767d9e1ae056 Mon Sep 17 00:00:00 2001 From: Brent Westbrook Date: Mon, 5 May 2025 13:26:23 -0400 Subject: [PATCH 3/3] update ruff tests too --- ...rror_InvalidStarExpression_invalid_star_expression_3.10.snap | 2 +- ..._InvalidStarExpression_invalid_star_expression_for_3.10.snap | 2 +- ...nvalidStarExpression_invalid_star_expression_yield_3.10.snap | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__semantic_syntax_error_InvalidStarExpression_invalid_star_expression_3.10.snap b/crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__semantic_syntax_error_InvalidStarExpression_invalid_star_expression_3.10.snap index cf3e091dc350a..81bc057071a74 100644 --- a/crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__semantic_syntax_error_InvalidStarExpression_invalid_star_expression_3.10.snap +++ b/crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__semantic_syntax_error_InvalidStarExpression_invalid_star_expression_3.10.snap @@ -1,7 +1,7 @@ --- source: crates/ruff_linter/src/linter.rs --- -:3:12: SyntaxError: can't use starred expression here +:3:12: SyntaxError: Starred expression cannot be used here | 2 | def func(): 3 | return *x diff --git a/crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__semantic_syntax_error_InvalidStarExpression_invalid_star_expression_for_3.10.snap b/crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__semantic_syntax_error_InvalidStarExpression_invalid_star_expression_for_3.10.snap index 1f088e8616b3a..811caf59bb708 100644 --- a/crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__semantic_syntax_error_InvalidStarExpression_invalid_star_expression_for_3.10.snap +++ b/crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__semantic_syntax_error_InvalidStarExpression_invalid_star_expression_for_3.10.snap @@ -1,7 +1,7 @@ --- source: crates/ruff_linter/src/linter.rs --- -:2:5: SyntaxError: can't use starred expression here +:2:5: SyntaxError: Starred expression cannot be used here | 2 | for *x in range(10): | ^^ diff --git a/crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__semantic_syntax_error_InvalidStarExpression_invalid_star_expression_yield_3.10.snap b/crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__semantic_syntax_error_InvalidStarExpression_invalid_star_expression_yield_3.10.snap index c7a8feb356466..ee1549b0cddd9 100644 --- a/crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__semantic_syntax_error_InvalidStarExpression_invalid_star_expression_yield_3.10.snap +++ b/crates/ruff_linter/src/snapshots/ruff_linter__linter__tests__semantic_syntax_error_InvalidStarExpression_invalid_star_expression_yield_3.10.snap @@ -1,7 +1,7 @@ --- source: crates/ruff_linter/src/linter.rs --- -:3:11: SyntaxError: can't use starred expression here +:3:11: SyntaxError: Starred expression cannot be used here | 2 | def func(): 3 | yield *x