diff --git a/python/src/com/jetbrains/python/parsing/ExpressionParsing.java b/python/src/com/jetbrains/python/parsing/ExpressionParsing.java index dc41d743c04f..e5bdc0eb259c 100644 --- a/python/src/com/jetbrains/python/parsing/ExpressionParsing.java +++ b/python/src/com/jetbrains/python/parsing/ExpressionParsing.java @@ -210,6 +210,7 @@ public class ExpressionParsing extends Parsing { public boolean parseMemberExpression(PsiBuilder builder, boolean isTargetExpression) { // in sequence a.b.... .c all members but last are always references, and the last may be target. boolean recast_first_identifier = false; + boolean recast_qualifier = false; do { boolean first_identifier_is_target = isTargetExpression && ! recast_first_identifier; PsiBuilder.Marker expr = builder.mark(); @@ -229,7 +230,7 @@ public class ExpressionParsing extends Parsing { else recast_first_identifier = false; builder.advanceLexer(); checkMatches(PyTokenTypes.IDENTIFIER, message("PARSE.expected.name")); - if (isTargetExpression && builder.getTokenType() != PyTokenTypes.DOT) { + if (isTargetExpression && ! recast_qualifier && builder.getTokenType() != PyTokenTypes.DOT) { expr.done(PyElementTypes.TARGET_EXPRESSION); } else { @@ -257,8 +258,9 @@ public class ExpressionParsing extends Parsing { else { checkMatches(PyTokenTypes.RBRACKET, message("PARSE.expected.rbracket")); expr.done(PyElementTypes.SUBSCRIPTION_EXPRESSION); - if (first_identifier_is_target) { + if (isTargetExpression && ! recast_qualifier) { recast_first_identifier = true; // subscription is always a reference + recast_qualifier = true; // recast non-first qualifiers too expr.rollbackTo(); break; } @@ -271,6 +273,7 @@ public class ExpressionParsing extends Parsing { break; } recast_first_identifier = false; // it is true only after a break; normal flow always unsets it. + // recast_qualifier is untouched, it remembers whether qualifiers were already recast } } while (recast_first_identifier); diff --git a/python/testData/psi/SubscribedAssignmentLHS.py b/python/testData/psi/SubscribedAssignmentLHS.py index 9d9d6c15e721..a0b0841b7da1 100644 --- a/python/testData/psi/SubscribedAssignmentLHS.py +++ b/python/testData/psi/SubscribedAssignmentLHS.py @@ -1 +1,2 @@ -a[1] = 2 +a[1] = 1 +a.b[1] = 2 diff --git a/python/testData/psi/SubscribedAssignmentLHS.txt b/python/testData/psi/SubscribedAssignmentLHS.txt index cb659f951426..5077ded8453a 100644 --- a/python/testData/psi/SubscribedAssignmentLHS.txt +++ b/python/testData/psi/SubscribedAssignmentLHS.txt @@ -1,14 +1,31 @@ -PyFile:SubscribedAssignmentLHS.py(0,8) - PyAssignmentStatement(0,8) - PySubscriptionExpression(0,4) - PyReferenceExpression: a(0,1) - PsiElement(Py:IDENTIFIER)('a')(0,1) - PsiElement(Py:LBRACKET)('[')(1,2) - PyNumericLiteralExpression(2,3) - PsiElement(Py:INTEGER_LITERAL)('1')(2,3) - PsiElement(Py:RBRACKET)(']')(3,4) - PsiWhiteSpace(' ')(4,5) - PsiElement(Py:EQ)('=')(5,6) - PsiWhiteSpace(' ')(6,7) - PyNumericLiteralExpression(7,8) - PsiElement(Py:INTEGER_LITERAL)('2')(7,8) +PyFile:SubscribedAssignmentLHS.py + PyAssignmentStatement + PySubscriptionExpression + PyReferenceExpression: a + PsiElement(Py:IDENTIFIER)('a') + PsiElement(Py:LBRACKET)('[') + PyNumericLiteralExpression + PsiElement(Py:INTEGER_LITERAL)('1') + PsiElement(Py:RBRACKET)(']') + PsiWhiteSpace(' ') + PsiElement(Py:EQ)('=') + PsiWhiteSpace(' ') + PyNumericLiteralExpression + PsiElement(Py:INTEGER_LITERAL)('1') + PsiWhiteSpace('\n') + PyAssignmentStatement + PySubscriptionExpression + PyReferenceExpression: b + PyReferenceExpression: a + PsiElement(Py:IDENTIFIER)('a') + PsiElement(Py:DOT)('.') + PsiElement(Py:IDENTIFIER)('b') + PsiElement(Py:LBRACKET)('[') + PyNumericLiteralExpression + PsiElement(Py:INTEGER_LITERAL)('1') + PsiElement(Py:RBRACKET)(']') + PsiWhiteSpace(' ') + PsiElement(Py:EQ)('=') + PsiWhiteSpace(' ') + PyNumericLiteralExpression + PsiElement(Py:INTEGER_LITERAL)('2')