diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyNoneLiteralExpression.java b/python/psi-api/src/com/jetbrains/python/psi/PyNoneLiteralExpression.java
index ca83704e149d..f5a6f2ad37d5 100644
--- a/python/psi-api/src/com/jetbrains/python/psi/PyNoneLiteralExpression.java
+++ b/python/psi-api/src/com/jetbrains/python/psi/PyNoneLiteralExpression.java
@@ -6,4 +6,5 @@ package com.jetbrains.python.psi;
* @author yole
*/
public interface PyNoneLiteralExpression extends PyLiteralExpression {
+ boolean isEllipsis();
}
diff --git a/python/src/com/jetbrains/python/parsing/ExpressionParsing.java b/python/src/com/jetbrains/python/parsing/ExpressionParsing.java
index e597bf45096e..74ee45358b63 100644
--- a/python/src/com/jetbrains/python/parsing/ExpressionParsing.java
+++ b/python/src/com/jetbrains/python/parsing/ExpressionParsing.java
@@ -72,6 +72,9 @@ public class ExpressionParsing extends Parsing {
parseReprExpression(myBuilder);
return true;
}
+ else if (parseEllipsis()) {
+ return true;
+ }
return false;
}
@@ -97,7 +100,7 @@ public class ExpressionParsing extends Parsing {
expr.done(PyElementTypes.LIST_LITERAL_EXPRESSION);
return;
}
- if (!parseSingleExpression(isTargetExpression, false)) {
+ if (!parseSingleExpression(isTargetExpression)) {
builder.error(message("PARSE.expected.expression"));
}
if (builder.getTokenType() == PyTokenTypes.FOR_KEYWORD) {
@@ -111,7 +114,7 @@ public class ExpressionParsing extends Parsing {
if (atToken(PyTokenTypes.RBRACKET)) {
break;
}
- if (!parseSingleExpression(isTargetExpression, false)) {
+ if (!parseSingleExpression(isTargetExpression)) {
builder.error(message("PARSE.expected.expr.or.comma.or.bracket"));
break;
}
@@ -154,7 +157,7 @@ public class ExpressionParsing extends Parsing {
result = parseORTestExpression(false, false);
}
else {
- result = parseTupleExpression(false, false, true, false);
+ result = parseTupleExpression(false, false, true);
}
if (!result) {
myBuilder.error("expression expected");
@@ -172,7 +175,7 @@ public class ExpressionParsing extends Parsing {
}
final PsiBuilder.Marker firstExprMarker = myBuilder.mark();
- if (!parseSingleExpression(false, false)) {
+ if (!parseSingleExpression(false)) {
myBuilder.error("expression expected");
firstExprMarker.drop();
expr.done(PyElementTypes.DICT_LITERAL_EXPRESSION);
@@ -198,7 +201,7 @@ public class ExpressionParsing extends Parsing {
}
private void parseDictLiteralTail(PsiBuilder.Marker startMarker, PsiBuilder.Marker firstKeyValueMarker) {
- if (!parseSingleExpression(false, false)) {
+ if (!parseSingleExpression(false)) {
myBuilder.error("expression expected");
firstKeyValueMarker.done(PyElementTypes.KEY_VALUE_EXPRESSION);
if (atToken(PyTokenTypes.RBRACE)) {
@@ -225,12 +228,12 @@ public class ExpressionParsing extends Parsing {
private boolean parseKeyValueExpression() {
final PsiBuilder.Marker marker = myBuilder.mark();
- if (!parseSingleExpression(false, false)) {
+ if (!parseSingleExpression(false)) {
marker.drop();
return false;
}
checkMatches(PyTokenTypes.COLON, message("PARSE.expected.colon"));
- if (!parseSingleExpression(false, false)) {
+ if (!parseSingleExpression(false)) {
myBuilder.error("value expression expected");
marker.drop();
return false;
@@ -242,7 +245,7 @@ public class ExpressionParsing extends Parsing {
private void parseSetLiteralTail(PsiBuilder.Marker startMarker) {
while (myBuilder.getTokenType() != PyTokenTypes.RBRACE) {
checkMatches(PyTokenTypes.COMMA, message("PARSE.expected.comma"));
- if (!parseSingleExpression(false, false)) {
+ if (!parseSingleExpression(false)) {
break;
}
}
@@ -325,7 +328,7 @@ public class ExpressionParsing extends Parsing {
parseSliceEnd(expr, sliceItemStart);
}
else {
- boolean hadExpression = parseSingleExpression(false, true);
+ boolean hadExpression = parseSingleExpression(false);
if (atToken(PyTokenTypes.COLON)) {
sliceOrTupleStart.drop();
parseSliceEnd(expr, sliceItemStart);
@@ -334,7 +337,7 @@ public class ExpressionParsing extends Parsing {
sliceItemStart.done(PyElementTypes.SLICE_ITEM);
if (!parseSliceListTail(expr, sliceOrTupleStart)) {
sliceOrTupleStart.rollbackTo();
- if (!parseTupleExpression(false, false, false, true)) {
+ if (!parseTupleExpression(false, false, false)) {
myBuilder.error("tuple expression expected");
}
checkMatches(PyTokenTypes.RBRACKET, message("PARSE.expected.rbracket"));
@@ -404,13 +407,13 @@ public class ExpressionParsing extends Parsing {
sliceMarker.done(PyElementTypes.EMPTY_EXPRESSION);
}
else {
- parseSingleExpression(false, true);
+ parseSingleExpression(false);
}
if (!BRACKET_COLON_COMMA.contains(myBuilder.getTokenType())) {
myBuilder.error(message("PARSE.expected.colon.or.rbracket"));
}
if (matchToken(PyTokenTypes.COLON)) {
- parseSingleExpression(false, true);
+ parseSingleExpression(false);
}
sliceItemStart.done(PyElementTypes.SLICE_ITEM);
@@ -427,12 +430,12 @@ public class ExpressionParsing extends Parsing {
while (atToken(PyTokenTypes.COMMA)) {
nextToken();
PsiBuilder.Marker sliceItemStart = myBuilder.mark();
- parseTestExpression(false, false, true);
+ parseTestExpression(false, false);
if (matchToken(PyTokenTypes.COLON)) {
inSlice = true;
- parseTestExpression(false, false, true);
+ parseTestExpression(false, false);
if (matchToken(PyTokenTypes.COLON)) {
- parseTestExpression(false, false, true);
+ parseTestExpression(false, false);
}
}
sliceItemStart.done(PyElementTypes.SLICE_ITEM);
@@ -479,7 +482,7 @@ public class ExpressionParsing extends Parsing {
if (myBuilder.getTokenType() == PyTokenTypes.MULT || myBuilder.getTokenType() == PyTokenTypes.EXP) {
final PsiBuilder.Marker starArgMarker = myBuilder.mark();
myBuilder.advanceLexer();
- if (!parseSingleExpression(false, false)) {
+ if (!parseSingleExpression(false)) {
myBuilder.error(message("PARSE.expected.expression"));
}
starArgMarker.done(PyElementTypes.STAR_ARGUMENT_EXPRESSION);
@@ -490,7 +493,7 @@ public class ExpressionParsing extends Parsing {
myBuilder.advanceLexer();
if (myBuilder.getTokenType() == PyTokenTypes.EQ) {
myBuilder.advanceLexer();
- if (!parseSingleExpression(false, false)) {
+ if (!parseSingleExpression(false)) {
myBuilder.error(message("PARSE.expected.expression"));
}
keywordArgMarker.done(PyElementTypes.KEYWORD_ARGUMENT_EXPRESSION);
@@ -498,7 +501,7 @@ public class ExpressionParsing extends Parsing {
}
keywordArgMarker.rollbackTo();
}
- if (!parseSingleExpression(false, false)) {
+ if (!parseSingleExpression(false)) {
myBuilder.error(message("PARSE.expected.expression"));
break;
}
@@ -513,11 +516,11 @@ public class ExpressionParsing extends Parsing {
}
public boolean parseExpressionOptional() {
- return parseTupleExpression(false, false, false, false);
+ return parseTupleExpression(false, false, false);
}
public boolean parseExpressionOptional(boolean isTargetExpression) {
- return parseTupleExpression(false, isTargetExpression, false, false);
+ return parseTupleExpression(false, isTargetExpression, false);
}
public void parseExpression() {
@@ -527,7 +530,7 @@ public class ExpressionParsing extends Parsing {
}
public void parseExpression(boolean stopOnIn, boolean isTargetExpression) {
- if (!parseTupleExpression(stopOnIn, isTargetExpression, false, false)) {
+ if (!parseTupleExpression(stopOnIn, isTargetExpression, false)) {
myBuilder.error(message("PARSE.expected.expression"));
}
}
@@ -538,7 +541,7 @@ public class ExpressionParsing extends Parsing {
myBuilder.advanceLexer();
if (myBuilder.getTokenType() == PyTokenTypes.FROM_KEYWORD) {
myBuilder.advanceLexer();
- final boolean parsed = parseTupleExpression(false, isTargetExpression, false, false);
+ final boolean parsed = parseTupleExpression(false, isTargetExpression, false);
if (!parsed) {
myBuilder.error(message("PARSE.expected.expression"));
}
@@ -546,19 +549,19 @@ public class ExpressionParsing extends Parsing {
return parsed;
}
else {
- parseTupleExpression(false, isTargetExpression, false, false);
+ parseTupleExpression(false, isTargetExpression, false);
yieldExpr.done(PyElementTypes.YIELD_EXPRESSION);
return true;
}
}
else {
- return parseTupleExpression(false, isTargetExpression, false, false);
+ return parseTupleExpression(false, isTargetExpression, false);
}
}
- protected boolean parseTupleExpression(boolean stopOnIn, boolean isTargetExpression, final boolean oldTest, boolean allowEllipsis) {
+ protected boolean parseTupleExpression(boolean stopOnIn, boolean isTargetExpression, final boolean oldTest) {
PsiBuilder.Marker expr = myBuilder.mark();
- boolean exprParseResult = oldTest ? parseOldTestExpression() : parseTestExpression(stopOnIn, isTargetExpression, allowEllipsis);
+ boolean exprParseResult = oldTest ? parseOldTestExpression() : parseTestExpression(stopOnIn, isTargetExpression);
if (!exprParseResult) {
expr.drop();
return false;
@@ -567,7 +570,7 @@ public class ExpressionParsing extends Parsing {
while (myBuilder.getTokenType() == PyTokenTypes.COMMA) {
myBuilder.advanceLexer();
PsiBuilder.Marker expr2 = myBuilder.mark();
- exprParseResult = oldTest ? parseOldTestExpression() : parseTestExpression(stopOnIn, isTargetExpression, allowEllipsis);
+ exprParseResult = oldTest ? parseOldTestExpression() : parseTestExpression(stopOnIn, isTargetExpression);
if (!exprParseResult) {
expr2.rollbackTo();
break;
@@ -582,8 +585,8 @@ public class ExpressionParsing extends Parsing {
return true;
}
- public boolean parseSingleExpression(boolean isTargetExpression, boolean allowEllipsis) {
- return parseTestExpression(false, isTargetExpression, allowEllipsis);
+ public boolean parseSingleExpression(boolean isTargetExpression) {
+ return parseTestExpression(false, isTargetExpression);
}
public boolean parseOldExpression() {
@@ -593,13 +596,10 @@ public class ExpressionParsing extends Parsing {
return parseORTestExpression(false, false);
}
- private boolean parseTestExpression(boolean stopOnIn, boolean isTargetExpression, boolean allowEllipsis) {
+ private boolean parseTestExpression(boolean stopOnIn, boolean isTargetExpression) {
if (myBuilder.getTokenType() == PyTokenTypes.LAMBDA_KEYWORD) {
return parseLambdaExpression(false);
}
- if (allowEllipsis && parseEllipsis()) {
- return true;
- }
PsiBuilder.Marker condExpr = myBuilder.mark();
if (!parseORTestExpression( stopOnIn, isTargetExpression)) {
condExpr.drop();
@@ -616,7 +616,7 @@ public class ExpressionParsing extends Parsing {
}
else {
myBuilder.advanceLexer();
- if (!parseTestExpression(stopOnIn, isTargetExpression, allowEllipsis)) {
+ if (!parseTestExpression(stopOnIn, isTargetExpression)) {
myBuilder.error(message("PARSE.expected.expression"));
}
}
@@ -640,7 +640,7 @@ public class ExpressionParsing extends Parsing {
PsiBuilder.Marker expr = myBuilder.mark();
myBuilder.advanceLexer();
getFunctionParser().parseParameterListContents(PyTokenTypes.COLON, false, true);
- boolean parseExpressionResult = oldTest ? parseOldTestExpression() : parseSingleExpression(false, false);
+ boolean parseExpressionResult = oldTest ? parseOldTestExpression() : parseSingleExpression(false);
if (!parseExpressionResult) {
myBuilder.error(message("PARSE.expected.expression"));
}
diff --git a/python/src/com/jetbrains/python/parsing/FunctionParsing.java b/python/src/com/jetbrains/python/parsing/FunctionParsing.java
index 40ca2371334d..7bb12f969585 100644
--- a/python/src/com/jetbrains/python/parsing/FunctionParsing.java
+++ b/python/src/com/jetbrains/python/parsing/FunctionParsing.java
@@ -65,7 +65,7 @@ public class FunctionParsing extends Parsing {
PsiBuilder.Marker maybeReturnAnnotation = myBuilder.mark();
nextToken();
if (matchToken(PyTokenTypes.GT)) {
- if (!myContext.getExpressionParser().parseSingleExpression(false, false)) {
+ if (!myContext.getExpressionParser().parseSingleExpression(false)) {
myBuilder.error(message("PARSE.expected.expression"));
}
maybeReturnAnnotation.done(PyElementTypes.ANNOTATION);
@@ -195,13 +195,13 @@ public class FunctionParsing extends Parsing {
if (!isLambda && myContext.getLanguageLevel().isPy3K() && atToken(PyTokenTypes.COLON)) {
PsiBuilder.Marker annotationMarker = myBuilder.mark();
nextToken();
- if (!getExpressionParser().parseSingleExpression(false, false)) {
+ if (!getExpressionParser().parseSingleExpression(false)) {
myBuilder.error(message("PARSE.expected.expression"));
}
annotationMarker.done(PyElementTypes.ANNOTATION);
}
if (!isStarParameter && matchToken(PyTokenTypes.EQ)) {
- if (!getExpressionParser().parseSingleExpression(false, false)) {
+ if (!getExpressionParser().parseSingleExpression(false)) {
PsiBuilder.Marker invalidElements = myBuilder.mark();
while(!atAnyOfTokens(endToken, PyTokenTypes.LINE_BREAK, PyTokenTypes.COMMA, null)) {
nextToken();
@@ -251,7 +251,7 @@ public class FunctionParsing extends Parsing {
}
if (myBuilder.getTokenType() == PyTokenTypes.EQ) {
myBuilder.advanceLexer();
- getExpressionParser().parseSingleExpression(false, false);
+ getExpressionParser().parseSingleExpression(false);
}
tuple.done(PyElementTypes.TUPLE_PARAMETER);
}
diff --git a/python/src/com/jetbrains/python/parsing/StatementParsing.java b/python/src/com/jetbrains/python/parsing/StatementParsing.java
index 37751366a56e..9cb92b119ddc 100644
--- a/python/src/com/jetbrains/python/parsing/StatementParsing.java
+++ b/python/src/com/jetbrains/python/parsing/StatementParsing.java
@@ -278,18 +278,18 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
if (builder.getTokenType() == PyTokenTypes.GTGT) {
final PsiBuilder.Marker target = builder.mark();
builder.advanceLexer();
- getExpressionParser().parseSingleExpression(false, false);
+ getExpressionParser().parseSingleExpression(false);
target.done(PyElementTypes.PRINT_TARGET);
}
else {
- getExpressionParser().parseSingleExpression(false, false);
+ getExpressionParser().parseSingleExpression(false);
}
while (builder.getTokenType() == PyTokenTypes.COMMA) {
builder.advanceLexer();
if (getEndOfStatementsTokens().contains(builder.getTokenType())) {
break;
}
- getExpressionParser().parseSingleExpression(false, false);
+ getExpressionParser().parseSingleExpression(false);
}
checkEndOfStatement(scope);
statement.done(PyElementTypes.PRINT_STATEMENT);
@@ -317,13 +317,13 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
assertCurrentToken(PyTokenTypes.DEL_KEYWORD);
final PsiBuilder.Marker delStatement = myBuilder.mark();
myBuilder.advanceLexer();
- if (!getExpressionParser().parseSingleExpression(false, false)) {
+ if (!getExpressionParser().parseSingleExpression(false)) {
myBuilder.error("Expression expected");
}
while (myBuilder.getTokenType() == PyTokenTypes.COMMA) {
myBuilder.advanceLexer();
if (!getEndOfStatementsTokens().contains(myBuilder.getTokenType())) {
- if (!getExpressionParser().parseSingleExpression(false, false)) {
+ if (!getExpressionParser().parseSingleExpression(false)) {
myBuilder.error("Expression expected");
}
}
@@ -338,18 +338,18 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
final PsiBuilder.Marker raiseStatement = myBuilder.mark();
myBuilder.advanceLexer();
if (!getEndOfStatementsTokens().contains(myBuilder.getTokenType())) {
- getExpressionParser().parseSingleExpression(false, false);
+ getExpressionParser().parseSingleExpression(false);
if (myBuilder.getTokenType() == PyTokenTypes.COMMA) {
myBuilder.advanceLexer();
- getExpressionParser().parseSingleExpression(false, false);
+ getExpressionParser().parseSingleExpression(false);
if (myBuilder.getTokenType() == PyTokenTypes.COMMA) {
myBuilder.advanceLexer();
- getExpressionParser().parseSingleExpression(false, false);
+ getExpressionParser().parseSingleExpression(false);
}
}
else if (myBuilder.getTokenType() == PyTokenTypes.FROM_KEYWORD) {
myBuilder.advanceLexer();
- if (!getExpressionParser().parseSingleExpression(false, false)) {
+ if (!getExpressionParser().parseSingleExpression(false)) {
myBuilder.error("Expression expected");
}
}
@@ -362,10 +362,10 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
assertCurrentToken(PyTokenTypes.ASSERT_KEYWORD);
final PsiBuilder.Marker assertStatement = myBuilder.mark();
myBuilder.advanceLexer();
- if (getExpressionParser().parseSingleExpression(false, false)) {
+ if (getExpressionParser().parseSingleExpression(false)) {
if (myBuilder.getTokenType() == PyTokenTypes.COMMA) {
myBuilder.advanceLexer();
- if (!getExpressionParser().parseSingleExpression(false, false)) {
+ if (!getExpressionParser().parseSingleExpression(false)) {
myContext.getBuilder().error(EXPRESSION_EXPECTED);
}
}
@@ -562,10 +562,10 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
getExpressionParser().parseExpression(true, false);
if (myBuilder.getTokenType() == PyTokenTypes.IN_KEYWORD) {
myBuilder.advanceLexer();
- getExpressionParser().parseSingleExpression(false, false);
+ getExpressionParser().parseSingleExpression(false);
if (myBuilder.getTokenType() == PyTokenTypes.COMMA) {
myBuilder.advanceLexer();
- getExpressionParser().parseSingleExpression(false, false);
+ getExpressionParser().parseSingleExpression(false);
}
}
checkEndOfStatement(inSuite);
@@ -646,7 +646,7 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
final PsiBuilder.Marker statement = myBuilder.mark();
final PsiBuilder.Marker whilePart = myBuilder.mark();
myBuilder.advanceLexer();
- if (!getExpressionParser().parseSingleExpression(false, false)) {
+ if (!getExpressionParser().parseSingleExpression(false)) {
myBuilder.error(EXPRESSION_EXPECTED);
}
parseColonAndSuite(scope);
@@ -677,13 +677,13 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
final PsiBuilder.Marker exceptBlock = myBuilder.mark();
myBuilder.advanceLexer();
if (myBuilder.getTokenType() != PyTokenTypes.COLON) {
- if (!getExpressionParser().parseSingleExpression(false, false)) {
+ if (!getExpressionParser().parseSingleExpression(false)) {
myBuilder.error(EXPRESSION_EXPECTED);
}
setExpectAsKeyword(true);
if (myBuilder.getTokenType() == PyTokenTypes.COMMA || myBuilder.getTokenType() == PyTokenTypes.AS_KEYWORD) {
myBuilder.advanceLexer();
- if (!getExpressionParser().parseSingleExpression(true, false)) {
+ if (!getExpressionParser().parseSingleExpression(true)) {
myBuilder.error(EXPRESSION_EXPECTED);
}
}
@@ -738,7 +738,7 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
setExpectAsKeyword(true);
if (myBuilder.getTokenType() == PyTokenTypes.AS_KEYWORD) {
myBuilder.advanceLexer();
- getExpressionParser().parseSingleExpression(true, false); // 'as' is followed by a target
+ getExpressionParser().parseSingleExpression(true); // 'as' is followed by a target
}
withItem.done(PyElementTypes.WITH_ITEM);
if (!matchToken(PyTokenTypes.COMMA)) {
diff --git a/python/src/com/jetbrains/python/psi/impl/PyNoneLiteralExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyNoneLiteralExpressionImpl.java
index 21b7fe494a5a..256a1c86881e 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyNoneLiteralExpressionImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyNoneLiteralExpressionImpl.java
@@ -1,6 +1,7 @@
package com.jetbrains.python.psi.impl;
import com.intellij.lang.ASTNode;
+import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.psi.PyElementVisitor;
import com.jetbrains.python.psi.PyNoneLiteralExpression;
import com.jetbrains.python.psi.types.PyNoneType;
@@ -24,4 +25,9 @@ public class PyNoneLiteralExpressionImpl extends PyElementImpl implements PyNone
protected void acceptPyVisitor(PyElementVisitor pyVisitor) {
pyVisitor.visitPyNoneLiteralExpression(this);
}
+
+ @Override
+ public boolean isEllipsis() {
+ return getNode().findChildByType(PyTokenTypes.DOT) != null;
+ }
}
diff --git a/python/src/com/jetbrains/python/validation/CompatibilityVisitor.java b/python/src/com/jetbrains/python/validation/CompatibilityVisitor.java
index bd1471516bf4..81febf3554f2 100644
--- a/python/src/com/jetbrains/python/validation/CompatibilityVisitor.java
+++ b/python/src/com/jetbrains/python/validation/CompatibilityVisitor.java
@@ -511,6 +511,20 @@ public abstract class CompatibilityVisitor extends PyAnnotator {
}
}
+ @Override
+ public void visitPyNoneLiteralExpression(PyNoneLiteralExpression node) {
+ if (shouldBeCompatibleWithPy2() && node.isEllipsis()) {
+ final PySubscriptionExpression subscription = PsiTreeUtil.getParentOfType(node, PySubscriptionExpression.class);
+ if (subscription != null && PsiTreeUtil.isAncestor(subscription.getIndexExpression(), node, false)) {
+ return;
+ }
+ final PySliceItem sliceItem = PsiTreeUtil.getParentOfType(node, PySliceItem.class);
+ if (sliceItem != null) {
+ return;
+ }
+ registerProblem(node, "Python versions < 3.0 do not support '...' outside of sequence slicings.");
+ }
+ }
private static class YieldVisitor extends PyElementVisitor {
private boolean _haveYield = false;
diff --git a/python/testData/inspections/PyCompatibilityInspection/ellipsisAsStatementPy2.py b/python/testData/inspections/PyCompatibilityInspection/ellipsisAsStatementPy2.py
new file mode 100644
index 000000000000..6e4f90cd7034
--- /dev/null
+++ b/python/testData/inspections/PyCompatibilityInspection/ellipsisAsStatementPy2.py
@@ -0,0 +1,2 @@
+def foo():
+ ...
diff --git a/python/testData/inspections/PyCompatibilityInspection/ellipsisInSubscriptionPy2.py b/python/testData/inspections/PyCompatibilityInspection/ellipsisInSubscriptionPy2.py
new file mode 100644
index 000000000000..e0e70df1ee91
--- /dev/null
+++ b/python/testData/inspections/PyCompatibilityInspection/ellipsisInSubscriptionPy2.py
@@ -0,0 +1,5 @@
+import numpy
+
+x = numpy.zeros((3, 4, 5))
+y = x[..., 0] # pass
+y = x[..., 0, :] # pass
diff --git a/python/testData/psi/EllipsisAsStatement.py b/python/testData/psi/EllipsisAsStatement.py
deleted file mode 100644
index e1efdfe13f1e..000000000000
--- a/python/testData/psi/EllipsisAsStatement.py
+++ /dev/null
@@ -1,5 +0,0 @@
-def a():
- ... # <- highlighted as "Statement seems to have no effect"
- pass
-
-a()
\ No newline at end of file
diff --git a/python/testData/psi/EllipsisAsStatement.txt b/python/testData/psi/EllipsisAsStatement.txt
deleted file mode 100644
index dbe4c271bd31..000000000000
--- a/python/testData/psi/EllipsisAsStatement.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-PyFile:EllipsisAsStatement.py
- PyFunction('a')
- PsiElement(Py:DEF_KEYWORD)('def')
- PsiWhiteSpace(' ')
- PsiElement(Py:IDENTIFIER)('a')
- PyParameterList
- PsiElement(Py:LPAR)('(')
- PsiElement(Py:RPAR)(')')
- PsiElement(Py:COLON)(':')
- PsiWhiteSpace('\n ')
- PyStatementList
- PsiElement(Py:DOT)('.')
- PsiErrorElement:Statement expected, found Py:DOT
-
- PsiElement(Py:DOT)('.')
- PsiErrorElement:Statement expected, found Py:DOT
-
- PsiElement(Py:DOT)('.')
- PsiErrorElement:Statement expected, found Py:DOT
-
- PsiWhiteSpace(' ')
- PsiComment(Py:END_OF_LINE_COMMENT)('# <- highlighted as "Statement seems to have no effect"')
- PsiWhiteSpace('\n ')
- PyPassStatement
- PsiElement(Py:PASS_KEYWORD)('pass')
- PsiWhiteSpace('\n\n')
- PyExpressionStatement
- PyCallExpression: a
- PyReferenceExpression: a
- PsiElement(Py:IDENTIFIER)('a')
- PyArgumentList
- PsiElement(Py:LPAR)('(')
- PsiElement(Py:RPAR)(')')
\ No newline at end of file
diff --git a/python/testData/psi/EllipsisPython3.py b/python/testData/psi/EllipsisPython3.py
new file mode 100644
index 000000000000..e4d7775aa912
--- /dev/null
+++ b/python/testData/psi/EllipsisPython3.py
@@ -0,0 +1,5 @@
+...
+x = ...
+[1, 2, ...]
+def f():
+ ...
diff --git a/python/testData/psi/EllipsisPython3.txt b/python/testData/psi/EllipsisPython3.txt
new file mode 100644
index 000000000000..af6f8ea82aa2
--- /dev/null
+++ b/python/testData/psi/EllipsisPython3.txt
@@ -0,0 +1,50 @@
+PyFile:EllipsisPython3.py
+ PyExpressionStatement
+ PyNoneLiteralExpression
+ PsiElement(Py:DOT)('.')
+ PsiElement(Py:DOT)('.')
+ PsiElement(Py:DOT)('.')
+ PsiWhiteSpace('\n')
+ PyAssignmentStatement
+ PyTargetExpression: x
+ PsiElement(Py:IDENTIFIER)('x')
+ PsiWhiteSpace(' ')
+ PsiElement(Py:EQ)('=')
+ PsiWhiteSpace(' ')
+ PyNoneLiteralExpression
+ PsiElement(Py:DOT)('.')
+ PsiElement(Py:DOT)('.')
+ PsiElement(Py:DOT)('.')
+ PsiWhiteSpace('\n')
+ PyExpressionStatement
+ PyListLiteralExpression
+ PsiElement(Py:LBRACKET)('[')
+ PyNumericLiteralExpression
+ PsiElement(Py:INTEGER_LITERAL)('1')
+ PsiElement(Py:COMMA)(',')
+ PsiWhiteSpace(' ')
+ PyNumericLiteralExpression
+ PsiElement(Py:INTEGER_LITERAL)('2')
+ PsiElement(Py:COMMA)(',')
+ PsiWhiteSpace(' ')
+ PyNoneLiteralExpression
+ PsiElement(Py:DOT)('.')
+ PsiElement(Py:DOT)('.')
+ PsiElement(Py:DOT)('.')
+ PsiElement(Py:RBRACKET)(']')
+ PsiWhiteSpace('\n')
+ PyFunction('f')
+ PsiElement(Py:DEF_KEYWORD)('def')
+ PsiWhiteSpace(' ')
+ PsiElement(Py:IDENTIFIER)('f')
+ PyParameterList
+ PsiElement(Py:LPAR)('(')
+ PsiElement(Py:RPAR)(')')
+ PsiElement(Py:COLON)(':')
+ PsiWhiteSpace('\n ')
+ PyStatementList
+ PyExpressionStatement
+ PyNoneLiteralExpression
+ PsiElement(Py:DOT)('.')
+ PsiElement(Py:DOT)('.')
+ PsiElement(Py:DOT)('.')
\ No newline at end of file
diff --git a/python/testSrc/com/jetbrains/python/PythonParsingTest.java b/python/testSrc/com/jetbrains/python/PythonParsingTest.java
index 4cdd61188e8f..f338c203a2c8 100644
--- a/python/testSrc/com/jetbrains/python/PythonParsingTest.java
+++ b/python/testSrc/com/jetbrains/python/PythonParsingTest.java
@@ -356,10 +356,6 @@ public class PythonParsingTest extends ParsingTestCase {
doTest();
}
- public void testEllipsisAsStatement() { // PY-7763
- doTest();
- }
-
// PY-8606
public void testEllipsisInSliceList() {
doTest();
@@ -374,6 +370,11 @@ public class PythonParsingTest extends ParsingTestCase {
doTest();
}
+ // PY-8752
+ public void testEllipsisPython3() {
+ doTest(LanguageLevel.PYTHON33);
+ }
+
public void doTest(LanguageLevel languageLevel) {
LanguageLevel prev = myLanguageLevel;
myLanguageLevel = languageLevel;
diff --git a/python/testSrc/com/jetbrains/python/inspections/PyCompatibilityInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyCompatibilityInspectionTest.java
index 0bafbd187f90..e4f263bdb89b 100644
--- a/python/testSrc/com/jetbrains/python/inspections/PyCompatibilityInspectionTest.java
+++ b/python/testSrc/com/jetbrains/python/inspections/PyCompatibilityInspectionTest.java
@@ -2,6 +2,7 @@ package com.jetbrains.python.inspections;
import com.jetbrains.python.fixtures.PyTestCase;
import com.jetbrains.python.psi.LanguageLevel;
+import org.jetbrains.annotations.NotNull;
/**
* User : catherine
@@ -119,6 +120,25 @@ public class PyCompatibilityInspectionTest extends PyTestCase {
doTest();
}
+ // PY-7763
+ public void testEllipsisAsStatementPy2() {
+ doTest(LanguageLevel.PYTHON33);
+ }
+
+ // PY-8606
+ public void testEllipsisInSubscriptionPy2() {
+ doTest(LanguageLevel.PYTHON33);
+ }
+
+ private void doTest(@NotNull LanguageLevel level) {
+ runWithLanguageLevel(level, new Runnable() {
+ @Override
+ public void run() {
+ doTest();
+ }
+ });
+ }
+
private void doTest() {
myFixture.configureByFile("inspections/PyCompatibilityInspection/" + getTestName(true) + ".py");
myFixture.enableInspections(PyCompatibilityInspection.class);