diff --git a/python/src/com/jetbrains/python/parsing/FunctionParsing.java b/python/src/com/jetbrains/python/parsing/FunctionParsing.java index 323b1c957dec..4045b6e19582 100644 --- a/python/src/com/jetbrains/python/parsing/FunctionParsing.java +++ b/python/src/com/jetbrains/python/parsing/FunctionParsing.java @@ -34,23 +34,25 @@ public class FunctionParsing extends Parsing { super(context); } - public void parseFunctionDeclaration(@NotNull PsiBuilder.Marker endMarker) { + public void parseFunctionDeclaration(@NotNull PsiBuilder.Marker endMarker, boolean async) { assertCurrentToken(PyTokenTypes.DEF_KEYWORD); - parseFunctionInnards(endMarker); + parseFunctionInnards(endMarker, async); } protected IElementType getFunctionType() { return FUNCTION_TYPE; } - protected void parseFunctionInnards(@NotNull PsiBuilder.Marker functionMarker) { + protected void parseFunctionInnards(@NotNull PsiBuilder.Marker functionMarker, boolean async) { myBuilder.advanceLexer(); parseIdentifierOrSkip(PyTokenTypes.LPAR); parseParameterList(); parseReturnTypeAnnotation(); checkMatches(PyTokenTypes.COLON, message("PARSE.expected.colon")); final ParsingContext context = getParsingContext(); - context.pushScope(context.getScope().withFunction(true)); + ParsingScope newScope = context.getScope().withFunction(true); + if (async) newScope = newScope.withAsync(); + context.pushScope(newScope); getStatementParser().parseSuite(functionMarker, getFunctionType()); context.popScope(); } @@ -98,21 +100,19 @@ public class FunctionParsing extends Parsing { parseDeclarationAfterDecorator(decoratorStartMarker); } - protected void parseDeclarationAfterDecorator(PsiBuilder.Marker endMarker) { + private void parseDeclarationAfterDecorator(PsiBuilder.Marker endMarker) { if (myBuilder.getTokenType() == PyTokenTypes.ASYNC_KEYWORD) { myBuilder.advanceLexer(); - myContext.pushScope(myContext.getScope().withAsync()); - parseSyncDeclarationAfterDecorator(endMarker); - myContext.popScope(); + parseDeclarationAfterDecorator(endMarker, true); } else { - parseSyncDeclarationAfterDecorator(endMarker); + parseDeclarationAfterDecorator(endMarker, false); } } - private void parseSyncDeclarationAfterDecorator(PsiBuilder.Marker endMarker) { + protected void parseDeclarationAfterDecorator(PsiBuilder.Marker endMarker, boolean async) { if (myBuilder.getTokenType() == PyTokenTypes.DEF_KEYWORD) { - parseFunctionInnards(endMarker); + parseFunctionInnards(endMarker, async); } else if (myBuilder.getTokenType() == PyTokenTypes.CLASS_KEYWORD) { getStatementParser().parseClassDeclaration(endMarker); diff --git a/python/src/com/jetbrains/python/parsing/ParsingScope.java b/python/src/com/jetbrains/python/parsing/ParsingScope.java index d73721d52751..d720fbaa9068 100644 --- a/python/src/com/jetbrains/python/parsing/ParsingScope.java +++ b/python/src/com/jetbrains/python/parsing/ParsingScope.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -84,7 +84,6 @@ public class ParsingScope { result.myFunction = myFunction; result.myClass = myClass; result.mySuite = mySuite; - result.myAsync = myAsync; return result; } } diff --git a/python/src/com/jetbrains/python/parsing/StatementParsing.java b/python/src/com/jetbrains/python/parsing/StatementParsing.java index e5c7124c7a5d..a14ba4cbfef8 100644 --- a/python/src/com/jetbrains/python/parsing/StatementParsing.java +++ b/python/src/com/jetbrains/python/parsing/StatementParsing.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -117,7 +117,7 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper { return; } if (firstToken == PyTokenTypes.DEF_KEYWORD) { - getFunctionParser().parseFunctionDeclaration(myBuilder.mark()); + getFunctionParser().parseFunctionDeclaration(myBuilder.mark(), false); return; } if (firstToken == PyTokenTypes.AT) { @@ -819,10 +819,7 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper { myBuilder.advanceLexer(); final IElementType token = myBuilder.getTokenType(); if (token == PyTokenTypes.DEF_KEYWORD) { - final ParsingContext context = getParsingContext(); - context.pushScope(context.getScope().withAsync()); - getFunctionParser().parseFunctionDeclaration(marker); - context.popScope(); + getFunctionParser().parseFunctionDeclaration(marker, true); } else if (token == PyTokenTypes.WITH_KEYWORD) { parseWithStatement(marker); diff --git a/python/testData/psi/AwaitInNonAsyncNestedFunction.py b/python/testData/psi/AwaitInNonAsyncNestedFunction.py new file mode 100644 index 000000000000..4dea0e0144a9 --- /dev/null +++ b/python/testData/psi/AwaitInNonAsyncNestedFunction.py @@ -0,0 +1,8 @@ +import asyncio + + +async def connect(): + def callback(): + return await asyncio.sleep(5) + + return await asyncio.sleep(5) diff --git a/python/testData/psi/AwaitInNonAsyncNestedFunction.txt b/python/testData/psi/AwaitInNonAsyncNestedFunction.txt new file mode 100644 index 000000000000..173605e1d554 --- /dev/null +++ b/python/testData/psi/AwaitInNonAsyncNestedFunction.txt @@ -0,0 +1,68 @@ +PyFile:AwaitInNonAsyncNestedFunction.py + PyImportStatement + PsiElement(Py:IMPORT_KEYWORD)('import') + PsiWhiteSpace(' ') + PyImportElement:asyncio + PyReferenceExpression: asyncio + PsiElement(Py:IDENTIFIER)('asyncio') + PsiWhiteSpace('\n\n\n') + PyFunction('connect') + PsiElement(Py:ASYNC_KEYWORD)('async') + PsiWhiteSpace(' ') + PsiElement(Py:DEF_KEYWORD)('def') + PsiWhiteSpace(' ') + PsiElement(Py:IDENTIFIER)('connect') + PyParameterList + PsiElement(Py:LPAR)('(') + PsiElement(Py:RPAR)(')') + PsiElement(Py:COLON)(':') + PsiWhiteSpace('\n ') + PyStatementList + PyFunction('callback') + PsiElement(Py:DEF_KEYWORD)('def') + PsiWhiteSpace(' ') + PsiElement(Py:IDENTIFIER)('callback') + PyParameterList + PsiElement(Py:LPAR)('(') + PsiElement(Py:RPAR)(')') + PsiElement(Py:COLON)(':') + PsiWhiteSpace('\n ') + PyStatementList + PyReturnStatement + PsiElement(Py:RETURN_KEYWORD)('return') + PsiWhiteSpace(' ') + PyReferenceExpression: await + PsiElement(Py:IDENTIFIER)('await') + PsiErrorElement:End of statement expected + + PsiWhiteSpace(' ') + PyExpressionStatement + PyCallExpression: asyncio.sleep + PyReferenceExpression: sleep + PyReferenceExpression: asyncio + PsiElement(Py:IDENTIFIER)('asyncio') + PsiElement(Py:DOT)('.') + PsiElement(Py:IDENTIFIER)('sleep') + PyArgumentList + PsiElement(Py:LPAR)('(') + PyNumericLiteralExpression + PsiElement(Py:INTEGER_LITERAL)('5') + PsiElement(Py:RPAR)(')') + PsiWhiteSpace('\n\n ') + PyReturnStatement + PsiElement(Py:RETURN_KEYWORD)('return') + PsiWhiteSpace(' ') + PyPrefixExpression + PsiElement(Py:AWAIT_KEYWORD)('await') + PsiWhiteSpace(' ') + PyCallExpression: asyncio.sleep + PyReferenceExpression: sleep + PyReferenceExpression: asyncio + PsiElement(Py:IDENTIFIER)('asyncio') + PsiElement(Py:DOT)('.') + PsiElement(Py:IDENTIFIER)('sleep') + PyArgumentList + PsiElement(Py:LPAR)('(') + PyNumericLiteralExpression + PsiElement(Py:INTEGER_LITERAL)('5') + PsiElement(Py:RPAR)(')') \ 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 a6ded4fdffd3..169c0141848b 100644 --- a/python/testSrc/com/jetbrains/python/PythonParsingTest.java +++ b/python/testSrc/com/jetbrains/python/PythonParsingTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -506,6 +506,11 @@ public class PythonParsingTest extends ParsingTestCase { doTest(LanguageLevel.PYTHON35); } + // PY-19036 + public void testAwaitInNonAsyncNestedFunction() { + doTest(LanguageLevel.PYTHON35); + } + public void testUnpackingExpressions() { doTest(LanguageLevel.PYTHON35); }