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..81bc057071a74 --- /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 0000000000000..811caf59bb708 --- /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 0000000000000..ee1549b0cddd9 --- /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 e380e10018c67..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 @@ -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.