diff --git a/python/src/com/jetbrains/python/parsing/FunctionParsing.java b/python/src/com/jetbrains/python/parsing/FunctionParsing.java index 70c2bb67bbab..62f4d9508937 100644 --- a/python/src/com/jetbrains/python/parsing/FunctionParsing.java +++ b/python/src/com/jetbrains/python/parsing/FunctionParsing.java @@ -150,7 +150,11 @@ public class FunctionParsing extends Parsing { } if (!isStarParameter && matchToken(PyTokenTypes.EQ)) { if (!getExpressionParser().parseSingleExpression(false)) { - myBuilder.error(message("PARSE.expected.expression")); + PsiBuilder.Marker invalidElements = myBuilder.mark(); + while(!atAnyOfTokens(endToken, PyTokenTypes.LINE_BREAK, PyTokenTypes.COMMA, null)) { + nextToken(); + } + invalidElements.error(message("PARSE.expected.expression")); } } parameter.done(PyElementTypes.NAMED_PARAMETER); diff --git a/python/src/com/jetbrains/python/parsing/Parsing.java b/python/src/com/jetbrains/python/parsing/Parsing.java index 77bcc849b0e2..1975fc2c0ec2 100644 --- a/python/src/com/jetbrains/python/parsing/Parsing.java +++ b/python/src/com/jetbrains/python/parsing/Parsing.java @@ -62,6 +62,14 @@ public class Parsing { return myBuilder.getTokenType() == tokenType; } + protected boolean atAnyOfTokens(final IElementType... tokenTypes) { + IElementType currentTokenType = myBuilder.getTokenType(); + for (IElementType tokenType : tokenTypes) { + if (currentTokenType == tokenType) return true; + } + return false; + } + protected boolean matchToken(final IElementType tokenType) { if (myBuilder.getTokenType() == tokenType) { myBuilder.advanceLexer(); diff --git a/python/testData/psi/KeywordAsDefaultParameterValue.py b/python/testData/psi/KeywordAsDefaultParameterValue.py new file mode 100644 index 000000000000..46762951dbcc --- /dev/null +++ b/python/testData/psi/KeywordAsDefaultParameterValue.py @@ -0,0 +1,2 @@ +def select2(self, fields=from): + pass diff --git a/python/testData/psi/KeywordAsDefaultParameterValue.txt b/python/testData/psi/KeywordAsDefaultParameterValue.txt new file mode 100644 index 000000000000..2c0c3bb02689 --- /dev/null +++ b/python/testData/psi/KeywordAsDefaultParameterValue.txt @@ -0,0 +1,22 @@ +PyFile:KeywordAsDefaultParameterValue.py + PyFunction('select2') + PsiElement(Py:DEF_KEYWORD)('def') + PsiWhiteSpace(' ') + PsiElement(Py:IDENTIFIER)('select2') + PyParameterList + PsiElement(Py:LPAR)('(') + PyNamedParameter('self') + PsiElement(Py:IDENTIFIER)('self') + PsiElement(Py:COMMA)(',') + PsiWhiteSpace(' ') + PyNamedParameter('fields') + PsiElement(Py:IDENTIFIER)('fields') + PsiElement(Py:EQ)('=') + PsiErrorElement:expression expected + PsiElement(Py:FROM_KEYWORD)('from') + PsiElement(Py:RPAR)(')') + PsiElement(Py:COLON)(':') + PsiWhiteSpace('\n ') + PyStatementList + PyPassStatement + PsiElement(Py:PASS_KEYWORD)('pass') \ 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 75115b2d16a0..7ef573f17db7 100644 --- a/python/testSrc/com/jetbrains/python/PythonParsingTest.java +++ b/python/testSrc/com/jetbrains/python/PythonParsingTest.java @@ -271,6 +271,10 @@ public class PythonParsingTest extends ParsingTestCase { doTest(); } + public void testKeywordAsDefaultParameterValue() { // PY-3713 + doTest(); + } + public void testTrailingCommaInArgList() { // PY-4016 doTest(); }