diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyStarExpression.java b/python/psi-api/src/com/jetbrains/python/psi/PyStarExpression.java index 1702efcc50b0..54eb30daaa2c 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/PyStarExpression.java +++ b/python/psi-api/src/com/jetbrains/python/psi/PyStarExpression.java @@ -23,4 +23,6 @@ import org.jetbrains.annotations.Nullable; public interface PyStarExpression extends PyExpression { @Nullable PyExpression getExpression(); + boolean isAssignmentTarget(); + boolean isUnpacking(); } diff --git a/python/src/com/jetbrains/python/psi/impl/PyStarExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyStarExpressionImpl.java index 2dc478528e48..64fb8aa8c452 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyStarExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyStarExpressionImpl.java @@ -16,10 +16,9 @@ package com.jetbrains.python.psi.impl; import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; import com.intellij.psi.util.PsiTreeUtil; -import com.jetbrains.python.psi.PyElementVisitor; -import com.jetbrains.python.psi.PyExpression; -import com.jetbrains.python.psi.PyStarExpression; +import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.types.PyType; import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; @@ -48,4 +47,19 @@ public class PyStarExpressionImpl extends PyElementImpl implements PyStarExpress public void acceptPyVisitor(PyElementVisitor visitor) { visitor.visitPyStarExpression(this); } + + public boolean isAssignmentTarget() { + return getExpression() instanceof PyTargetExpression; + } + + public boolean isUnpacking() { + if (isAssignmentTarget()) { + return false; + } + PsiElement parent = getParent(); + while (parent instanceof PyParenthesizedExpression) { + parent = parent.getParent(); + } + return parent instanceof PyTupleExpression || parent instanceof PyListLiteralExpression; + } } diff --git a/python/src/com/jetbrains/python/validation/CompatibilityVisitor.java b/python/src/com/jetbrains/python/validation/CompatibilityVisitor.java index ddc12854d316..4a54685dc4fa 100644 --- a/python/src/com/jetbrains/python/validation/CompatibilityVisitor.java +++ b/python/src/com/jetbrains/python/validation/CompatibilityVisitor.java @@ -170,16 +170,32 @@ public abstract class CompatibilityVisitor extends PyAnnotator { @Override public void visitPyStarExpression(PyStarExpression node) { super.visitPyStarExpression(node); - int len = 0; - StringBuilder message = new StringBuilder(myCommonMessage); - for (int i = 0; i != myVersionsToProcess.size(); ++i) { - LanguageLevel languageLevel = myVersionsToProcess.get(i); - if (!languageLevel.isPy3K()) { - len = appendLanguageLevel(message, len, languageLevel); + + if (node.isAssignmentTarget()) { + boolean problem = false; + for (LanguageLevel level : myVersionsToProcess) { + if (level.isOlderThan(LanguageLevel.PYTHON30)) { + problem = true; + break; + } + } + if (problem) { + registerProblem(node, "Python versions < 3.0 do not support starred expressions as assignment targets"); + } + } + + if (node.isUnpacking()) { + boolean problem = false; + for (LanguageLevel level : myVersionsToProcess) { + if (level.isOlderThan(LanguageLevel.PYTHON35)) { + problem = true; + break; + } + } + if (problem) { + registerProblem(node, "Python version < 3.5 do not support starred expressions in tuples, lists, and sets"); } } - commonRegisterProblem(message, " not support this syntax. Starred expressions are not allowed as assignment targets in Python 2", - len, node, null); } @Override diff --git a/python/src/com/jetbrains/python/validation/StarAnnotator.java b/python/src/com/jetbrains/python/validation/StarAnnotator.java index 0b6dd5372737..1a0e01b415e1 100644 --- a/python/src/com/jetbrains/python/validation/StarAnnotator.java +++ b/python/src/com/jetbrains/python/validation/StarAnnotator.java @@ -15,9 +15,7 @@ */ package com.jetbrains.python.validation; -import com.intellij.psi.PsiElement; -import com.jetbrains.python.psi.*; -import org.jetbrains.annotations.NotNull; +import com.jetbrains.python.psi.PyStarExpression; /** * @author yole @@ -26,20 +24,8 @@ public class StarAnnotator extends PyAnnotator { @Override public void visitPyStarExpression(PyStarExpression node) { super.visitPyStarExpression(node); - if (!isAssignmentTarget(node) && !isStarUnpacking(node)) { + if (!node.isAssignmentTarget() && !node.isUnpacking()) { getHolder().createErrorAnnotation(node, "Can't use starred expression here"); } } - - private static boolean isStarUnpacking(@NotNull PyStarExpression node) { - PsiElement parent = node.getParent(); - while (parent instanceof PyParenthesizedExpression) { - parent = parent.getParent(); - } - return parent instanceof PyTupleExpression || parent instanceof PyListLiteralExpression; - } - - private static boolean isAssignmentTarget(@NotNull PyStarExpression node) { - return node.getExpression() instanceof PyTargetExpression; - } } diff --git a/python/testData/inspections/PyCompatibilityInspection/starExpression.py b/python/testData/inspections/PyCompatibilityInspection/starExpression.py index 19333a1ab8cb..1858b6269208 100644 --- a/python/testData/inspections/PyCompatibilityInspection/starExpression.py +++ b/python/testData/inspections/PyCompatibilityInspection/starExpression.py @@ -1,2 +1,2 @@ -t = (1, 2, 3) -a, *b, c = t \ No newline at end of file +t = (1, *(2, 3)) +a, *b, c = t diff --git a/python/testData/inspections/PyUnusedVariableTupleUnpacking/test.py b/python/testData/inspections/PyUnusedVariableTupleUnpacking/test.py index 70a64d22ef03..1e504dff73bb 100644 --- a/python/testData/inspections/PyUnusedVariableTupleUnpacking/test.py +++ b/python/testData/inspections/PyUnusedVariableTupleUnpacking/test.py @@ -3,8 +3,8 @@ def foo(): print x def test_vlu(): - *h, t = [1, 2, 3] # fail + *h, t = [1, 2, 3] # fail def test_vlu(): - *h, t = [1, 2, 3] # pass + *h, t = [1, 2, 3] # pass print(t) \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/inspections/PyCompatibilityInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyCompatibilityInspectionTest.java index 49e9acb6929f..f1617e8be29c 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyCompatibilityInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyCompatibilityInspectionTest.java @@ -55,7 +55,7 @@ public class PyCompatibilityInspectionTest extends PyTestCase { } public void testStarExpression() { - setLanguageLevel(LanguageLevel.PYTHON30); + setLanguageLevel(LanguageLevel.PYTHON35); doTest(); }