From 101e1a5ddd0eacd5bbfc1cb6a7ee18cfd685d7fa Mon Sep 17 00:00:00 2001 From: Max Mynter <32773644+maxmynter@users.noreply.github.com> Date: Mon, 5 May 2025 19:30:16 +0200 Subject: [PATCH] [semantic-syntax-tests] for for `InvalidStarExpression`, `DuplicateMatchKey`, and `DuplicateMatchClassAttribute` (#17754) Re: #17526 ## Summary Add integration tests for Python Semantic Syntax for `InvalidStarExpression`, `DuplicateMatchKey`, and `DuplicateMatchClassAttribute`. ## Note - Red knot integration tests for `DuplicateMatchKey` exist already in line 89-101. ## Test Plan This is a test. --- 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 4b23e99c89..f2445b128c 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 0000000000..bac3111de0 --- /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 0000000000..f877e86e31 --- /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 0000000000..81bc057071 --- /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: 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 new file mode 100644 index 0000000000..811caf59bb --- /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: Starred expression cannot be used 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 0000000000..ee1549b0cd --- /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: Starred expression cannot be used 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 e380e10018..7063c58dda 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] "Starred expression cannot be used here" + return *[1, 2, 3] + +def gen(): + # error: [invalid-syntax] "Starred expression cannot be used here" + yield * [1, 2, 3] + +# error: [invalid-syntax] "Starred expression cannot be used here" +for *x in range(10): + pass + +# error: [invalid-syntax] "Starred expression cannot be used here" +for x in *range(10): + pass +``` + ## `await` outside async function This error includes `await`, `async for`, `async with`, and `async` comprehensions.