PY-19036 Fixed: Using await in a non-asynchronous nested function not marked as a syntax error

Don't inherit async flag in ParsingScope, pass async flag to function parsing
This commit is contained in:
Semyon Proshev
2016-04-18 14:07:04 +03:00
parent c55dd274ea
commit 673bc32291
6 changed files with 97 additions and 20 deletions
@@ -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);
@@ -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;
}
}
@@ -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);
@@ -0,0 +1,8 @@
import asyncio
async def connect():
def callback():
return await asyncio.sleep(5)
return await asyncio.sleep(5)
@@ -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
<empty list>
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)(')')
@@ -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);
}