mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 13:02:30 +07:00
PY-61853 PEP 695 Type Parameter Syntax: Parsing
GitOrigin-RevId: 286b53bb4e69cf1deb58dc75f41652e6a12a3af3
This commit is contained in:
committed by
intellij-monorepo-bot
parent
3ed8555cf1
commit
8b217ed53a
@@ -44,6 +44,7 @@ public final class PyTokenTypes {
|
||||
public static final PyElementType IS_KEYWORD = new PyElementType("IS_KEYWORD");
|
||||
public static final PyElementType LAMBDA_KEYWORD = new PyElementType("LAMBDA_KEYWORD");
|
||||
public static final PyElementType MATCH_KEYWORD = new PyElementType("MATCH_KEYWORD");
|
||||
public static final PyElementType TYPE_KEYWORD = new PyElementType("TYPE_KEYWORD");
|
||||
public static final PyElementType NOT_KEYWORD = new PyElementType("NOT_KEYWORD");
|
||||
public static final PyElementType OR_KEYWORD = new PyElementType("OR_KEYWORD");
|
||||
public static final PyElementType PASS_KEYWORD = new PyElementType("PASS_KEYWORD");
|
||||
|
||||
@@ -39,7 +39,8 @@ import java.util.Map;
|
||||
* Represents a class declaration in source.
|
||||
*/
|
||||
public interface PyClass extends PsiNameIdentifierOwner, PyCompoundStatement, PyDocStringOwner, StubBasedPsiElement<PyClassStub>,
|
||||
ScopeOwner, PyDecoratable, PyTypedElement, PyQualifiedNameOwner, PyStatementListContainer, PyWithAncestors {
|
||||
ScopeOwner, PyDecoratable, PyTypedElement, PyQualifiedNameOwner, PyStatementListContainer, PyWithAncestors,
|
||||
PyTypeParameterListOwner {
|
||||
PyClass[] EMPTY_ARRAY = new PyClass[0];
|
||||
ArrayFactory<PyClass> ARRAY_FACTORY = count -> count == 0 ? EMPTY_ARRAY : new PyClass[count];
|
||||
|
||||
@@ -74,7 +75,7 @@ public interface PyClass extends PsiNameIdentifierOwner, PyCompoundStatement, Py
|
||||
* @see #getSuperClassTypes(TypeEvalContext) for the full list of super classes.
|
||||
* @see #getAncestorTypes(TypeEvalContext) for the full list of ancestors.
|
||||
*/
|
||||
PyClass @NotNull [] getSuperClasses(@Nullable TypeEvalContext context);
|
||||
PyClass @NotNull [] getSuperClasses(@Nullable TypeEvalContext context);
|
||||
|
||||
/**
|
||||
* Returns a PSI element for the super classes list.
|
||||
@@ -160,8 +161,8 @@ public interface PyClass extends PsiNameIdentifierOwner, PyCompoundStatement, Py
|
||||
/**
|
||||
* Finds a property with the specified name in the class or one of its ancestors.
|
||||
*
|
||||
* @param name of the property
|
||||
* @param context type eval (null to use loose context, but you better provide one)
|
||||
* @param name of the property
|
||||
* @param context type eval (null to use loose context, but you better provide one)
|
||||
* @return descriptor of property accessors, or null if such property does not exist.
|
||||
*/
|
||||
@Nullable
|
||||
@@ -203,7 +204,7 @@ public interface PyClass extends PsiNameIdentifierOwner, PyCompoundStatement, Py
|
||||
*
|
||||
* @param context context to use for this process
|
||||
* @return list of attrs.
|
||||
*
|
||||
* <p>
|
||||
* TODO: Replace it and {@link #getClassAttributes()} with a single getClassAttributes(@NotNull TypeEvalContext context, boolean inherited)
|
||||
*/
|
||||
@NotNull
|
||||
@@ -256,7 +257,7 @@ public interface PyClass extends PsiNameIdentifierOwner, PyCompoundStatement, Py
|
||||
/**
|
||||
* @return True iff this and parent are the same or parent is one of our superclasses.
|
||||
*/
|
||||
boolean isSubclass(PyClass parent, @Nullable TypeEvalContext context);
|
||||
boolean isSubclass(PyClass parent, @Nullable TypeEvalContext context);
|
||||
|
||||
boolean isSubclass(@NotNull String superClassQName, @Nullable TypeEvalContext context);
|
||||
|
||||
|
||||
@@ -385,4 +385,16 @@ public class PyElementVisitor extends PsiElementVisitor {
|
||||
public void visitPyCaseClause(@NotNull PyCaseClause node) {
|
||||
visitPyElement(node);
|
||||
}
|
||||
|
||||
public void visitPyTypeAliasStatement(@NotNull PyTypeAliasStatement node) {
|
||||
visitPyStatement(node);
|
||||
}
|
||||
|
||||
public void visitPyTypeParameter(@NotNull PyTypeParameter node) {
|
||||
visitPyElement(node);
|
||||
}
|
||||
|
||||
public void visitPyTypeParameterList(@NotNull PyTypeParameterList node) {
|
||||
visitPyElement(node);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.jetbrains.python.psi;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiNameIdentifierOwner;
|
||||
import com.intellij.psi.PsiNamedElement;
|
||||
import com.intellij.psi.StubBasedPsiElement;
|
||||
import com.intellij.util.ArrayFactory;
|
||||
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
|
||||
@@ -20,7 +19,7 @@ import java.util.List;
|
||||
*/
|
||||
public interface PyFunction extends StubBasedPsiElement<PyFunctionStub>, PsiNameIdentifierOwner, PyCompoundStatement,
|
||||
PyDecoratable, PyCallable, PyStatementListContainer, PyPossibleClassMember,
|
||||
ScopeOwner, PyDocStringOwner, PyTypeCommentOwner, PyAnnotationOwner {
|
||||
ScopeOwner, PyDocStringOwner, PyTypeCommentOwner, PyAnnotationOwner, PyTypeParameterListOwner {
|
||||
|
||||
PyFunction[] EMPTY_ARRAY = new PyFunction[0];
|
||||
ArrayFactory<PyFunction> ARRAY_FACTORY = count -> count == 0 ? EMPTY_ARRAY : new PyFunction[count];
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.jetbrains.python.psi;
|
||||
|
||||
import com.intellij.psi.PsiNameIdentifierOwner;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Represents Type Alias Statement added in <a href="https://peps.python.org/pep-0695/">PEP 695</a>
|
||||
*/
|
||||
public interface PyTypeAliasStatement extends PyStatement, PsiNameIdentifierOwner, PyTypeParameterListOwner, PyTypedElement {
|
||||
|
||||
@Nullable
|
||||
PyExpression getTypeExpression();
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.jetbrains.python.psi;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiNameIdentifierOwner;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Represents a Type Parameter that can be a part of {@link PyTypeParameterList}<br>
|
||||
* For more information see <a href="https://peps.python.org/pep-0695/">PEP 695</a>
|
||||
*/
|
||||
public interface PyTypeParameter extends PyElement, PsiNameIdentifierOwner, PyTypedElement {
|
||||
|
||||
@Nullable
|
||||
PyExpression getBoundExpression();
|
||||
|
||||
@Nullable
|
||||
ASTNode getNameNode();
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.jetbrains.python.psi;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a list of generic Type Parameters.<br>
|
||||
* e.g. {@code def foo[T, U](x: T | U): ...}<br>
|
||||
* where {@code [T, U]} is the list of generic Type Parameters.<br>
|
||||
* For more information see <a href="https://peps.python.org/pep-0695/">PEP 695</a>
|
||||
*/
|
||||
public interface PyTypeParameterList extends PyElement {
|
||||
|
||||
@NotNull
|
||||
List<PyTypeParameter> getTypeParameters();
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.jetbrains.python.psi;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* PSI element that can contain {@link PyTypeParameterList}
|
||||
* which was added in <a href="https://peps.python.org/pep-0695/">PEP 695</a>
|
||||
*/
|
||||
public interface PyTypeParameterListOwner extends PsiElement {
|
||||
|
||||
@Nullable
|
||||
default PyTypeParameterList getTypeParameterList() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -210,6 +210,7 @@ PARSE.expected.number=Number expected
|
||||
PARSE.expected.case.clause=Case clause expected
|
||||
PARSE.expected.pattern=Pattern expected
|
||||
PARSE.expected.name.or.wildcard=Name or '_' expected
|
||||
PARSE.expected.type.parameter=Type parameter expected
|
||||
|
||||
statement.expected.found.0=Statement expected, found {0}
|
||||
unexpected.indent=Unexpected indent
|
||||
|
||||
@@ -55,6 +55,8 @@ public interface PyElementTypes {
|
||||
|
||||
PyElementType PRINT_TARGET = new PyElementType("PRINT_TARGET", node -> new PyPrintTargetImpl(node));
|
||||
PyElementType DECORATOR = new PyElementType("DECORATOR", node -> new PyDecoratorImpl(node));
|
||||
PyElementType TYPE_PARAMETER = new PyElementType("TYPE_PARAMETER", node -> new PyTypeParameterImpl(node));
|
||||
PyElementType TYPE_PARAMETER_LIST = new PyElementType("TYPE_PARAMETER_LIST", node -> new PyTypeParameterListImpl(node));
|
||||
|
||||
// Statements
|
||||
PyElementType EXPRESSION_STATEMENT = new PyElementType("EXPRESSION_STATEMENT", node -> new PyExpressionStatementImpl(node));
|
||||
@@ -171,4 +173,5 @@ public interface PyElementTypes {
|
||||
PyElementType KEYWORD_PATTERN = new PyElementType("KEYWORD_PATTERN", node -> new PyKeywordPatternImpl(node));
|
||||
PyElementType OR_PATTERN = new PyElementType("OR_PATTERN", node -> new PyOrPatternImpl(node));
|
||||
PyElementType AS_PATTERN = new PyElementType("AS_PATTERN", node -> new PyAsPatternImpl(node));
|
||||
PyElementType TYPE_ALIAS_STATEMENT = new PyElementType("TYPE_ALIAS_STATEMENT", node -> new PyTypeAliasStatementImpl(node));
|
||||
}
|
||||
|
||||
@@ -29,7 +29,8 @@ public class PythonTokenSetContributor extends PythonDialectsTokenSetContributor
|
||||
ASSERT_STATEMENT, BREAK_STATEMENT, CONTINUE_STATEMENT, DEL_STATEMENT, EXEC_STATEMENT, FOR_STATEMENT,
|
||||
FROM_IMPORT_STATEMENT, GLOBAL_STATEMENT, IMPORT_STATEMENT, IF_STATEMENT, PASS_STATEMENT,
|
||||
PRINT_STATEMENT, RAISE_STATEMENT, RETURN_STATEMENT, TRY_EXCEPT_STATEMENT, WITH_STATEMENT,
|
||||
WHILE_STATEMENT, NONLOCAL_STATEMENT, CLASS_DECLARATION, FUNCTION_DECLARATION, MATCH_STATEMENT, CASE_CLAUSE);
|
||||
WHILE_STATEMENT, NONLOCAL_STATEMENT, CLASS_DECLARATION, FUNCTION_DECLARATION, MATCH_STATEMENT, CASE_CLAUSE,
|
||||
TYPE_ALIAS_STATEMENT);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -59,7 +60,7 @@ public class PythonTokenSetContributor extends PythonDialectsTokenSetContributor
|
||||
RAISE_KEYWORD, RETURN_KEYWORD, TRY_KEYWORD, WITH_KEYWORD, WHILE_KEYWORD,
|
||||
YIELD_KEYWORD,
|
||||
MATCH_KEYWORD, CASE_KEYWORD,
|
||||
NONE_KEYWORD, TRUE_KEYWORD, FALSE_KEYWORD, NONLOCAL_KEYWORD, DEBUG_KEYWORD, ASYNC_KEYWORD, AWAIT_KEYWORD);
|
||||
NONE_KEYWORD, TRUE_KEYWORD, FALSE_KEYWORD, NONLOCAL_KEYWORD, DEBUG_KEYWORD, ASYNC_KEYWORD, AWAIT_KEYWORD, TYPE_KEYWORD);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -44,7 +44,8 @@ public class FunctionParsing extends Parsing {
|
||||
|
||||
protected void parseFunctionInnards(@NotNull SyntaxTreeBuilder.Marker functionMarker, boolean async) {
|
||||
myBuilder.advanceLexer();
|
||||
parseIdentifierOrSkip(PyTokenTypes.LPAR);
|
||||
parseIdentifierOrSkip(PyTokenTypes.LPAR, PyTokenTypes.LBRACKET);
|
||||
myContext.getStatementParser().parseTypeParameterList();
|
||||
parseParameterList();
|
||||
parseReturnTypeAnnotation();
|
||||
checkMatches(PyTokenTypes.COLON, message("PARSE.expected.colon"));
|
||||
|
||||
@@ -127,6 +127,11 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
|
||||
parseAsyncStatement(false);
|
||||
return;
|
||||
}
|
||||
if (atToken(PyTokenTypes.IDENTIFIER, TOK_TYPE)) {
|
||||
if (parseTypeAliasStatement()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (atToken(PyTokenTypes.IDENTIFIER, TOK_ASYNC)) {
|
||||
if (parseAsyncStatement(true)) {
|
||||
@@ -142,6 +147,24 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
|
||||
parseSimpleStatement();
|
||||
}
|
||||
|
||||
private boolean parseTypeAliasStatement() {
|
||||
assert atToken(PyTokenTypes.IDENTIFIER, TOK_TYPE);
|
||||
SyntaxTreeBuilder.Marker mark = myBuilder.mark();
|
||||
myBuilder.remapCurrentToken(PyTokenTypes.TYPE_KEYWORD);
|
||||
nextToken();
|
||||
if (!atToken(PyTokenTypes.IDENTIFIER)) {
|
||||
mark.rollbackTo();
|
||||
myBuilder.remapCurrentToken(PyTokenTypes.IDENTIFIER);
|
||||
return false;
|
||||
}
|
||||
parseIdentifierOrSkip(PyTokenTypes.LBRACKET, PyTokenTypes.EQ);
|
||||
parseTypeParameterList();
|
||||
checkMatches(PyTokenTypes.EQ, PyPsiBundle.message("PARSE.eq.expected"));
|
||||
myContext.getExpressionParser().parseExpression();
|
||||
mark.done(PyElementTypes.TYPE_ALIAS_STATEMENT);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean parseMatchStatement() {
|
||||
assert atToken(PyTokenTypes.IDENTIFIER, TOK_MATCH);
|
||||
SyntaxTreeBuilder.Marker mark = myBuilder.mark();
|
||||
@@ -913,7 +936,8 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
|
||||
public void parseClassDeclaration(SyntaxTreeBuilder.Marker classMarker) {
|
||||
assertCurrentToken(PyTokenTypes.CLASS_KEYWORD);
|
||||
myBuilder.advanceLexer();
|
||||
parseIdentifierOrSkip(PyTokenTypes.LPAR, PyTokenTypes.COLON);
|
||||
parseIdentifierOrSkip(PyTokenTypes.LPAR, PyTokenTypes.LBRACKET, PyTokenTypes.COLON);
|
||||
parseTypeParameterList();
|
||||
if (myBuilder.getTokenType() == PyTokenTypes.LPAR) {
|
||||
getExpressionParser().parseArgumentList();
|
||||
}
|
||||
@@ -1017,6 +1041,52 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper {
|
||||
}
|
||||
}
|
||||
|
||||
public void parseTypeParameterList() {
|
||||
if (atToken(PyTokenTypes.LBRACKET)) {
|
||||
final SyntaxTreeBuilder.Marker typeParamList = myBuilder.mark();
|
||||
nextToken();
|
||||
do {
|
||||
if (!parseTypeParameter()) {
|
||||
myBuilder.error(PyPsiBundle.message("PARSE.expected.type.parameter"));
|
||||
}
|
||||
|
||||
if (atToken(PyTokenTypes.COMMA)) {
|
||||
nextToken();
|
||||
}
|
||||
else if (!atToken(PyTokenTypes.RBRACKET)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (!atToken(PyTokenTypes.RBRACKET));
|
||||
checkMatches(PyTokenTypes.RBRACKET, PyPsiBundle.message("PARSE.expected.symbols", ",", "]"));
|
||||
typeParamList.done(PyElementTypes.TYPE_PARAMETER_LIST);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean parseTypeParameter() {
|
||||
if (isIdentifier(myBuilder) || atToken(PyTokenTypes.MULT) || atToken(PyTokenTypes.EXP)) {
|
||||
SyntaxTreeBuilder.Marker typeParamMarker = myBuilder.mark();
|
||||
|
||||
if (atAnyOfTokens(PyTokenTypes.MULT, PyTokenTypes.EXP)) {
|
||||
nextToken();
|
||||
}
|
||||
|
||||
if (!parseIdentifierOrSkip(PyTokenTypes.RBRACKET, PyTokenTypes.COMMA, PyTokenTypes.COLON)) {
|
||||
typeParamMarker.drop();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (matchToken(PyTokenTypes.COLON)) {
|
||||
if (!myContext.getExpressionParser().parseSingleExpression(false)) {
|
||||
myBuilder.error(PyPsiBundle.message("PARSE.expected.expression"));
|
||||
}
|
||||
}
|
||||
typeParamMarker.done(PyElementTypes.TYPE_PARAMETER);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IElementType filter(final IElementType source, final int start, final int end, final CharSequence text) {
|
||||
return filter(source, start, end, text, true);
|
||||
|
||||
@@ -143,6 +143,12 @@ public class PyClassImpl extends PyBaseElementImpl<PyClassStub> implements PyCla
|
||||
return statementList;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public PyTypeParameterList getTypeParameterList() {
|
||||
return childToPsi(PyElementTypes.TYPE_PARAMETER_LIST);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PyArgumentList getSuperClassExpressionList() {
|
||||
final PyArgumentList argList = PsiTreeUtil.getChildOfType(this, PyArgumentList.class);
|
||||
|
||||
@@ -64,6 +64,12 @@ public class PyFunctionImpl extends PyBaseElementImpl<PyFunctionStub> implements
|
||||
super(stub, nodeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public PyTypeParameterList getTypeParameterList() {
|
||||
return childToPsi(PyElementTypes.TYPE_PARAMETER_LIST);
|
||||
}
|
||||
|
||||
private class CachedStructuredDocStringProvider implements CachedValueProvider<StructuredDocString> {
|
||||
@Override
|
||||
public @Nullable Result<StructuredDocString> compute() {
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.jetbrains.python.psi.impl;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiErrorElement;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.jetbrains.python.PyElementTypes;
|
||||
import com.jetbrains.python.PyTokenTypes;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.types.PyType;
|
||||
import com.jetbrains.python.psi.types.TypeEvalContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class PyTypeAliasStatementImpl extends PyElementImpl implements PyTypeAliasStatement {
|
||||
public PyTypeAliasStatementImpl(ASTNode astNode) {
|
||||
super(astNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void acceptPyVisitor(PyElementVisitor pyVisitor) {
|
||||
pyVisitor.visitPyTypeAliasStatement(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public PyExpression getTypeExpression() {
|
||||
PsiElement child = getLastChild();
|
||||
while (child != null && !(child instanceof PyExpression)) {
|
||||
if (child instanceof PsiErrorElement) return null;
|
||||
child = child.getPrevSibling();
|
||||
}
|
||||
return (PyExpression)child;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public PyTypeParameterList getTypeParameterList() {
|
||||
return childToPsi(PyElementTypes.TYPE_PARAMETER_LIST);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public PsiElement getNameIdentifier() {
|
||||
ASTNode nameNode = getNode().findChildByType(PyTokenTypes.IDENTIFIER);
|
||||
return nameNode != null ? nameNode.getPsi() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
PsiElement identifier = getNameIdentifier();
|
||||
return identifier != null ? identifier.getText() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement setName(@NotNull String name) throws IncorrectOperationException {
|
||||
PsiElement identifier = getNameIdentifier();
|
||||
if (identifier != null) {
|
||||
ASTNode newName = PyUtil.createNewName(this, name);
|
||||
ASTNode nameNode = identifier.getNode();
|
||||
|
||||
getNode().replaceChild(nameNode, newName);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public PyType getType(@NotNull TypeEvalContext context, TypeEvalContext.@NotNull Key key) {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.jetbrains.python.psi.impl;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.jetbrains.python.PyTokenTypes;
|
||||
import com.jetbrains.python.psi.PyElementVisitor;
|
||||
import com.jetbrains.python.psi.PyExpression;
|
||||
import com.jetbrains.python.psi.PyTypeParameter;
|
||||
import com.jetbrains.python.psi.PyUtil;
|
||||
import com.jetbrains.python.psi.types.PyType;
|
||||
import com.jetbrains.python.psi.types.TypeEvalContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class PyTypeParameterImpl extends PyElementImpl implements PyTypeParameter {
|
||||
|
||||
public PyTypeParameterImpl(ASTNode astNode) {
|
||||
super(astNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void acceptPyVisitor(PyElementVisitor pyVisitor) {
|
||||
pyVisitor.visitPyTypeParameter(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String getName() {
|
||||
ASTNode nameNode = getNameNode();
|
||||
return nameNode != null ? nameNode.getText() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public PyExpression getBoundExpression() {
|
||||
return PsiTreeUtil.getChildOfType(this, PyExpression.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public ASTNode getNameNode() {
|
||||
return getNode().findChildByType(PyTokenTypes.IDENTIFIER);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public PsiElement getNameIdentifier() {
|
||||
ASTNode nameNode = getNameNode();
|
||||
return nameNode != null ? nameNode.getPsi() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement setName(@NotNull String name) throws IncorrectOperationException {
|
||||
ASTNode oldNameElement = getNameNode();
|
||||
if (oldNameElement != null) {
|
||||
ASTNode nameElement = PyUtil.createNewName(this, name);
|
||||
getNode().replaceChild(oldNameElement, nameElement);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public PyType getType(@NotNull TypeEvalContext context, TypeEvalContext.@NotNull Key key) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.jetbrains.python.psi.impl;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.jetbrains.python.PyElementTypes;
|
||||
import com.jetbrains.python.psi.PyElementVisitor;
|
||||
import com.jetbrains.python.psi.PyTypeParameter;
|
||||
import com.jetbrains.python.psi.PyTypeParameterList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PyTypeParameterListImpl extends PyElementImpl implements PyTypeParameterList {
|
||||
public PyTypeParameterListImpl(ASTNode astNode) {
|
||||
super(astNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void acceptPyVisitor(PyElementVisitor pyVisitor) {
|
||||
pyVisitor.visitPyTypeParameterList(this);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<PyTypeParameter> getTypeParameters() {
|
||||
return findChildrenByType(PyElementTypes.TYPE_PARAMETER);
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,7 @@ public class StarAnnotator extends PyAnnotator {
|
||||
if (!node.isAssignmentTarget() &&
|
||||
!allowedUnpacking(node) &&
|
||||
!(parent instanceof PyParameterTypeList) &&
|
||||
!(parent instanceof PyTypeParameter) &&
|
||||
!(parent instanceof PyAnnotation && isVariadicArg(parent.getParent()))) {
|
||||
getHolder().newAnnotation(HighlightSeverity.ERROR, PyPsiBundle.message("ANN.can.t.use.starred.expression.here")).create();
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
type MyType[] = int | str
|
||||
@@ -0,0 +1,21 @@
|
||||
PyFile:TypeAliasStatementRecoveryWithEmptyTypeParameterList.py
|
||||
PyTypeAliasStatement
|
||||
PsiElement(Py:TYPE_KEYWORD)('type')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:IDENTIFIER)('MyType')
|
||||
PyTypeParameterList
|
||||
PsiElement(Py:LBRACKET)('[')
|
||||
PsiErrorElement:Type parameter expected
|
||||
<empty list>
|
||||
PsiElement(Py:RBRACKET)(']')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PyBinaryExpression
|
||||
PyReferenceExpression: int
|
||||
PsiElement(Py:IDENTIFIER)('int')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:OR)('|')
|
||||
PsiWhiteSpace(' ')
|
||||
PyReferenceExpression: str
|
||||
PsiElement(Py:IDENTIFIER)('str')
|
||||
@@ -0,0 +1 @@
|
||||
type MyType =
|
||||
@@ -0,0 +1,9 @@
|
||||
PyFile:TypeAliasStatementRecoveryWithEqSignButNoAssignedType.py
|
||||
PyTypeAliasStatement
|
||||
PsiElement(Py:TYPE_KEYWORD)('type')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:IDENTIFIER)('MyType')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiErrorElement:Expression expected
|
||||
<empty list>
|
||||
@@ -0,0 +1 @@
|
||||
type MyType
|
||||
@@ -0,0 +1,7 @@
|
||||
PyFile:TypeAliasStatementRecoveryWithNoAssignedType.py
|
||||
PyTypeAliasStatement
|
||||
PsiElement(Py:TYPE_KEYWORD)('type')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:IDENTIFIER)('MyType')
|
||||
PsiErrorElement:'=' expected
|
||||
<empty list>
|
||||
@@ -0,0 +1 @@
|
||||
type MyType[T: str] = List[T]
|
||||
@@ -0,0 +1,24 @@
|
||||
PyFile:TypeAliasStatementWithBoundedTypeParameter.py
|
||||
PyTypeAliasStatement
|
||||
PsiElement(Py:TYPE_KEYWORD)('type')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:IDENTIFIER)('MyType')
|
||||
PyTypeParameterList
|
||||
PsiElement(Py:LBRACKET)('[')
|
||||
PyTypeParameter
|
||||
PsiElement(Py:IDENTIFIER)('T')
|
||||
PsiElement(Py:COLON)(':')
|
||||
PsiWhiteSpace(' ')
|
||||
PyReferenceExpression: str
|
||||
PsiElement(Py:IDENTIFIER)('str')
|
||||
PsiElement(Py:RBRACKET)(']')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PySubscriptionExpression
|
||||
PyReferenceExpression: List
|
||||
PsiElement(Py:IDENTIFIER)('List')
|
||||
PsiElement(Py:LBRACKET)('[')
|
||||
PyReferenceExpression: T
|
||||
PsiElement(Py:IDENTIFIER)('T')
|
||||
PsiElement(Py:RBRACKET)(']')
|
||||
@@ -0,0 +1 @@
|
||||
type MyType[T: str, ] = list[T]
|
||||
@@ -0,0 +1,26 @@
|
||||
PyFile:TypeAliasStatementWithBoundedTypeParameterAndDanglingComma.py
|
||||
PyTypeAliasStatement
|
||||
PsiElement(Py:TYPE_KEYWORD)('type')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:IDENTIFIER)('MyType')
|
||||
PyTypeParameterList
|
||||
PsiElement(Py:LBRACKET)('[')
|
||||
PyTypeParameter
|
||||
PsiElement(Py:IDENTIFIER)('T')
|
||||
PsiElement(Py:COLON)(':')
|
||||
PsiWhiteSpace(' ')
|
||||
PyReferenceExpression: str
|
||||
PsiElement(Py:IDENTIFIER)('str')
|
||||
PsiElement(Py:COMMA)(',')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:RBRACKET)(']')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PySubscriptionExpression
|
||||
PyReferenceExpression: list
|
||||
PsiElement(Py:IDENTIFIER)('list')
|
||||
PsiElement(Py:LBRACKET)('[')
|
||||
PyReferenceExpression: T
|
||||
PsiElement(Py:IDENTIFIER)('T')
|
||||
PsiElement(Py:RBRACKET)(']')
|
||||
1
python/testData/psi/TypeAliasStatementWithParamSpec.py
Normal file
1
python/testData/psi/TypeAliasStatementWithParamSpec.py
Normal file
@@ -0,0 +1 @@
|
||||
type MyTypeWithParamSpec[**P] = Callable[P, int]
|
||||
26
python/testData/psi/TypeAliasStatementWithParamSpec.txt
Normal file
26
python/testData/psi/TypeAliasStatementWithParamSpec.txt
Normal file
@@ -0,0 +1,26 @@
|
||||
PyFile:TypeAliasStatementWithParamSpec.py
|
||||
PyTypeAliasStatement
|
||||
PsiElement(Py:TYPE_KEYWORD)('type')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:IDENTIFIER)('MyTypeWithParamSpec')
|
||||
PyTypeParameterList
|
||||
PsiElement(Py:LBRACKET)('[')
|
||||
PyTypeParameter
|
||||
PsiElement(Py:EXP)('**')
|
||||
PsiElement(Py:IDENTIFIER)('P')
|
||||
PsiElement(Py:RBRACKET)(']')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PySubscriptionExpression
|
||||
PyReferenceExpression: Callable
|
||||
PsiElement(Py:IDENTIFIER)('Callable')
|
||||
PsiElement(Py:LBRACKET)('[')
|
||||
PyTupleExpression
|
||||
PyReferenceExpression: P
|
||||
PsiElement(Py:IDENTIFIER)('P')
|
||||
PsiElement(Py:COMMA)(',')
|
||||
PsiWhiteSpace(' ')
|
||||
PyReferenceExpression: int
|
||||
PsiElement(Py:IDENTIFIER)('int')
|
||||
PsiElement(Py:RBRACKET)(']')
|
||||
@@ -0,0 +1 @@
|
||||
type MyType[T, ] = list[T]
|
||||
@@ -0,0 +1,22 @@
|
||||
PyFile:TypeAliasStatementWithTypeParameterAndDanglingComma.py
|
||||
PyTypeAliasStatement
|
||||
PsiElement(Py:TYPE_KEYWORD)('type')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:IDENTIFIER)('MyType')
|
||||
PyTypeParameterList
|
||||
PsiElement(Py:LBRACKET)('[')
|
||||
PyTypeParameter
|
||||
PsiElement(Py:IDENTIFIER)('T')
|
||||
PsiElement(Py:COMMA)(',')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:RBRACKET)(']')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PySubscriptionExpression
|
||||
PyReferenceExpression: list
|
||||
PsiElement(Py:IDENTIFIER)('list')
|
||||
PsiElement(Py:LBRACKET)('[')
|
||||
PyReferenceExpression: T
|
||||
PsiElement(Py:IDENTIFIER)('T')
|
||||
PsiElement(Py:RBRACKET)(']')
|
||||
@@ -0,0 +1 @@
|
||||
type MyType[T: (int | str)] = list[T]
|
||||
@@ -0,0 +1,33 @@
|
||||
PyFile:TypeAliasStatementWithTypeParameterBoundedWithExpression.py
|
||||
PyTypeAliasStatement
|
||||
PsiElement(Py:TYPE_KEYWORD)('type')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:IDENTIFIER)('MyType')
|
||||
PyTypeParameterList
|
||||
PsiElement(Py:LBRACKET)('[')
|
||||
PyTypeParameter
|
||||
PsiElement(Py:IDENTIFIER)('T')
|
||||
PsiElement(Py:COLON)(':')
|
||||
PsiWhiteSpace(' ')
|
||||
PyParenthesizedExpression
|
||||
PsiElement(Py:LPAR)('(')
|
||||
PyBinaryExpression
|
||||
PyReferenceExpression: int
|
||||
PsiElement(Py:IDENTIFIER)('int')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:OR)('|')
|
||||
PsiWhiteSpace(' ')
|
||||
PyReferenceExpression: str
|
||||
PsiElement(Py:IDENTIFIER)('str')
|
||||
PsiElement(Py:RPAR)(')')
|
||||
PsiElement(Py:RBRACKET)(']')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PySubscriptionExpression
|
||||
PyReferenceExpression: list
|
||||
PsiElement(Py:IDENTIFIER)('list')
|
||||
PsiElement(Py:LBRACKET)('[')
|
||||
PyReferenceExpression: T
|
||||
PsiElement(Py:IDENTIFIER)('T')
|
||||
PsiElement(Py:RBRACKET)(']')
|
||||
@@ -0,0 +1 @@
|
||||
type MyType[T, U] = Union[T, U]
|
||||
@@ -0,0 +1,29 @@
|
||||
PyFile:TypeAliasStatementWithTypeParameterList.py
|
||||
PyTypeAliasStatement
|
||||
PsiElement(Py:TYPE_KEYWORD)('type')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:IDENTIFIER)('MyType')
|
||||
PyTypeParameterList
|
||||
PsiElement(Py:LBRACKET)('[')
|
||||
PyTypeParameter
|
||||
PsiElement(Py:IDENTIFIER)('T')
|
||||
PsiElement(Py:COMMA)(',')
|
||||
PsiWhiteSpace(' ')
|
||||
PyTypeParameter
|
||||
PsiElement(Py:IDENTIFIER)('U')
|
||||
PsiElement(Py:RBRACKET)(']')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PySubscriptionExpression
|
||||
PyReferenceExpression: Union
|
||||
PsiElement(Py:IDENTIFIER)('Union')
|
||||
PsiElement(Py:LBRACKET)('[')
|
||||
PyTupleExpression
|
||||
PyReferenceExpression: T
|
||||
PsiElement(Py:IDENTIFIER)('T')
|
||||
PsiElement(Py:COMMA)(',')
|
||||
PsiWhiteSpace(' ')
|
||||
PyReferenceExpression: U
|
||||
PsiElement(Py:IDENTIFIER)('U')
|
||||
PsiElement(Py:RBRACKET)(']')
|
||||
@@ -0,0 +1 @@
|
||||
type MyTypeWithTypeVarTuple[*Ts] = Tuple[*Ts]
|
||||
23
python/testData/psi/TypeAliasStatementWithTypeVarTuple.txt
Normal file
23
python/testData/psi/TypeAliasStatementWithTypeVarTuple.txt
Normal file
@@ -0,0 +1,23 @@
|
||||
PyFile:TypeAliasStatementWithTypeVarTuple.py
|
||||
PyTypeAliasStatement
|
||||
PsiElement(Py:TYPE_KEYWORD)('type')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:IDENTIFIER)('MyTypeWithTypeVarTuple')
|
||||
PyTypeParameterList
|
||||
PsiElement(Py:LBRACKET)('[')
|
||||
PyTypeParameter
|
||||
PsiElement(Py:MULT)('*')
|
||||
PsiElement(Py:IDENTIFIER)('Ts')
|
||||
PsiElement(Py:RBRACKET)(']')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PySubscriptionExpression
|
||||
PyReferenceExpression: Tuple
|
||||
PsiElement(Py:IDENTIFIER)('Tuple')
|
||||
PsiElement(Py:LBRACKET)('[')
|
||||
PyStarExpression
|
||||
PsiElement(Py:MULT)('*')
|
||||
PyReferenceExpression: Ts
|
||||
PsiElement(Py:IDENTIFIER)('Ts')
|
||||
PsiElement(Py:RBRACKET)(']')
|
||||
@@ -0,0 +1 @@
|
||||
type MyType = str
|
||||
@@ -0,0 +1,10 @@
|
||||
PyFile:TypeAliasStatementWithoutTypeParameterList.py
|
||||
PyTypeAliasStatement
|
||||
PsiElement(Py:TYPE_KEYWORD)('type')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:IDENTIFIER)('MyType')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PyReferenceExpression: str
|
||||
PsiElement(Py:IDENTIFIER)('str')
|
||||
1
python/testData/psi/TypeKeywordAsIdentifier.py
Normal file
1
python/testData/psi/TypeKeywordAsIdentifier.py
Normal file
@@ -0,0 +1 @@
|
||||
type = 3
|
||||
9
python/testData/psi/TypeKeywordAsIdentifier.txt
Normal file
9
python/testData/psi/TypeKeywordAsIdentifier.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
PyFile:TypeKeywordAsIdentifier.py
|
||||
PyAssignmentStatement
|
||||
PyTargetExpression: type
|
||||
PsiElement(Py:IDENTIFIER)('type')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PyNumericLiteralExpression
|
||||
PsiElement(Py:INTEGER_LITERAL)('3')
|
||||
@@ -0,0 +1 @@
|
||||
type MyType[T: ] = list[T]
|
||||
@@ -0,0 +1,24 @@
|
||||
PyFile:TypeParameterInTypeAliasStatementRecoveryIncompleteBound.py
|
||||
PyTypeAliasStatement
|
||||
PsiElement(Py:TYPE_KEYWORD)('type')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:IDENTIFIER)('MyType')
|
||||
PyTypeParameterList
|
||||
PsiElement(Py:LBRACKET)('[')
|
||||
PyTypeParameter
|
||||
PsiElement(Py:IDENTIFIER)('T')
|
||||
PsiElement(Py:COLON)(':')
|
||||
PsiErrorElement:Expression expected
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:RBRACKET)(']')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PySubscriptionExpression
|
||||
PyReferenceExpression: list
|
||||
PsiElement(Py:IDENTIFIER)('list')
|
||||
PsiElement(Py:LBRACKET)('[')
|
||||
PyReferenceExpression: T
|
||||
PsiElement(Py:IDENTIFIER)('T')
|
||||
PsiElement(Py:RBRACKET)(']')
|
||||
@@ -0,0 +1 @@
|
||||
class Clazz[T]: pass
|
||||
17
python/testData/psi/TypeParameterListInClassDeclaration.txt
Normal file
17
python/testData/psi/TypeParameterListInClassDeclaration.txt
Normal file
@@ -0,0 +1,17 @@
|
||||
PyFile:TypeParameterListInClassDeclaration.py
|
||||
PyClass: Clazz
|
||||
PsiElement(Py:CLASS_KEYWORD)('class')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:IDENTIFIER)('Clazz')
|
||||
PyTypeParameterList
|
||||
PsiElement(Py:LBRACKET)('[')
|
||||
PyTypeParameter
|
||||
PsiElement(Py:IDENTIFIER)('T')
|
||||
PsiElement(Py:RBRACKET)(']')
|
||||
PyArgumentList
|
||||
<empty list>
|
||||
PsiElement(Py:COLON)(':')
|
||||
PsiWhiteSpace(' ')
|
||||
PyStatementList
|
||||
PyPassStatement
|
||||
PsiElement(Py:PASS_KEYWORD)('pass')
|
||||
@@ -0,0 +1 @@
|
||||
def foo[T](a): pass
|
||||
@@ -0,0 +1,20 @@
|
||||
PyFile:TypeParameterListInFunctionDeclaration.py
|
||||
PyFunction('foo')
|
||||
PsiElement(Py:DEF_KEYWORD)('def')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:IDENTIFIER)('foo')
|
||||
PyTypeParameterList
|
||||
PsiElement(Py:LBRACKET)('[')
|
||||
PyTypeParameter
|
||||
PsiElement(Py:IDENTIFIER)('T')
|
||||
PsiElement(Py:RBRACKET)(']')
|
||||
PyParameterList
|
||||
PsiElement(Py:LPAR)('(')
|
||||
PyNamedParameter('a')
|
||||
PsiElement(Py:IDENTIFIER)('a')
|
||||
PsiElement(Py:RPAR)(')')
|
||||
PsiElement(Py:COLON)(':')
|
||||
PsiWhiteSpace(' ')
|
||||
PyStatementList
|
||||
PyPassStatement
|
||||
PsiElement(Py:PASS_KEYWORD)('pass')
|
||||
@@ -0,0 +1 @@
|
||||
def foo[T(a): ...
|
||||
@@ -0,0 +1,24 @@
|
||||
PyFile:TypeParameterListInFunctionDeclarationRecoveryNotClosedRightBracket.py
|
||||
PyFunction('foo')
|
||||
PsiElement(Py:DEF_KEYWORD)('def')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:IDENTIFIER)('foo')
|
||||
PyTypeParameterList
|
||||
PsiElement(Py:LBRACKET)('[')
|
||||
PyTypeParameter
|
||||
PsiElement(Py:IDENTIFIER)('T')
|
||||
PsiErrorElement:',' or ']' expected
|
||||
<empty list>
|
||||
PyParameterList
|
||||
PsiElement(Py:LPAR)('(')
|
||||
PyNamedParameter('a')
|
||||
PsiElement(Py:IDENTIFIER)('a')
|
||||
PsiElement(Py:RPAR)(')')
|
||||
PsiElement(Py:COLON)(':')
|
||||
PsiWhiteSpace(' ')
|
||||
PyStatementList
|
||||
PyExpressionStatement
|
||||
PyNoneLiteralExpression
|
||||
PsiElement(Py:DOT)('.')
|
||||
PsiElement(Py:DOT)('.')
|
||||
PsiElement(Py:DOT)('.')
|
||||
@@ -0,0 +1 @@
|
||||
type MyType[T = list[T]
|
||||
@@ -0,0 +1,21 @@
|
||||
PyFile:TypeParameterListInTypeAliasStatementRecoveryNotClosedRightBracket.py
|
||||
PyTypeAliasStatement
|
||||
PsiElement(Py:TYPE_KEYWORD)('type')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:IDENTIFIER)('MyType')
|
||||
PyTypeParameterList
|
||||
PsiElement(Py:LBRACKET)('[')
|
||||
PyTypeParameter
|
||||
PsiElement(Py:IDENTIFIER)('T')
|
||||
PsiErrorElement:',' or ']' expected
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PySubscriptionExpression
|
||||
PyReferenceExpression: list
|
||||
PsiElement(Py:IDENTIFIER)('list')
|
||||
PsiElement(Py:LBRACKET)('[')
|
||||
PyReferenceExpression: T
|
||||
PsiElement(Py:IDENTIFIER)('T')
|
||||
PsiElement(Py:RBRACKET)(']')
|
||||
@@ -0,0 +1 @@
|
||||
type MyType[T,,] = list[T]
|
||||
@@ -0,0 +1,24 @@
|
||||
PyFile:TypeParameterListInTypeAliasStatementRecoveryUnexpectedSymbolAfterComma.py
|
||||
PyTypeAliasStatement
|
||||
PsiElement(Py:TYPE_KEYWORD)('type')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:IDENTIFIER)('MyType')
|
||||
PyTypeParameterList
|
||||
PsiElement(Py:LBRACKET)('[')
|
||||
PyTypeParameter
|
||||
PsiElement(Py:IDENTIFIER)('T')
|
||||
PsiElement(Py:COMMA)(',')
|
||||
PsiErrorElement:Type parameter expected
|
||||
<empty list>
|
||||
PsiElement(Py:COMMA)(',')
|
||||
PsiElement(Py:RBRACKET)(']')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PySubscriptionExpression
|
||||
PyReferenceExpression: list
|
||||
PsiElement(Py:IDENTIFIER)('list')
|
||||
PsiElement(Py:LBRACKET)('[')
|
||||
PyReferenceExpression: T
|
||||
PsiElement(Py:IDENTIFIER)('T')
|
||||
PsiElement(Py:RBRACKET)(']')
|
||||
@@ -1230,6 +1230,80 @@ public class PythonParsingTest extends ParsingTestCase {
|
||||
doTest(LanguageLevel.getLatest());
|
||||
}
|
||||
|
||||
public void testTypeAliasStatementWithoutTypeParameterList() {
|
||||
doTest(LanguageLevel.PYTHON312);
|
||||
}
|
||||
|
||||
public void testTypeAliasStatementWithTypeParameterList() {
|
||||
doTest(LanguageLevel.PYTHON312);
|
||||
}
|
||||
|
||||
public void testTypeAliasStatementWithTypeVarTuple() {
|
||||
doTest(LanguageLevel.PYTHON312);
|
||||
}
|
||||
|
||||
public void testTypeAliasStatementWithParamSpec() {
|
||||
doTest(LanguageLevel.PYTHON312);
|
||||
}
|
||||
|
||||
public void testTypeAliasStatementWithBoundedTypeParameter() {
|
||||
doTest(LanguageLevel.PYTHON312);
|
||||
}
|
||||
|
||||
public void testTypeAliasStatementWithTypeParameterBoundedWithExpression() {
|
||||
doTest(LanguageLevel.PYTHON312);
|
||||
}
|
||||
|
||||
public void testTypeAliasStatementWithTypeParameterAndDanglingComma() {
|
||||
// Valid case
|
||||
doTest(LanguageLevel.PYTHON312);
|
||||
}
|
||||
|
||||
public void testTypeAliasStatementWithBoundedTypeParameterAndDanglingComma() {
|
||||
// Valid case
|
||||
doTest(LanguageLevel.PYTHON312);
|
||||
}
|
||||
|
||||
public void testTypeAliasStatementRecoveryWithEmptyTypeParameterList() {
|
||||
doTest(LanguageLevel.PYTHON312);
|
||||
}
|
||||
|
||||
public void testTypeAliasStatementRecoveryWithNoAssignedType() {
|
||||
doTest(LanguageLevel.PYTHON312);
|
||||
}
|
||||
|
||||
public void testTypeAliasStatementRecoveryWithEqSignButNoAssignedType() {
|
||||
doTest(LanguageLevel.PYTHON312);
|
||||
}
|
||||
|
||||
public void testTypeParameterInTypeAliasStatementRecoveryIncompleteBound() {
|
||||
doTest(LanguageLevel.PYTHON312);
|
||||
}
|
||||
|
||||
public void testTypeParameterListInTypeAliasStatementRecoveryNotClosedRightBracket() {
|
||||
doTest(LanguageLevel.PYTHON312);
|
||||
}
|
||||
|
||||
public void testTypeParameterListInTypeAliasStatementRecoveryUnexpectedSymbolAfterComma() {
|
||||
doTest(LanguageLevel.PYTHON312);
|
||||
}
|
||||
|
||||
public void testTypeParameterListInFunctionDeclaration() {
|
||||
doTest(LanguageLevel.PYTHON312);
|
||||
}
|
||||
|
||||
public void testTypeParameterListInFunctionDeclarationRecoveryNotClosedRightBracket() {
|
||||
doTest(LanguageLevel.PYTHON312);
|
||||
}
|
||||
|
||||
public void testTypeParameterListInClassDeclaration() {
|
||||
doTest(LanguageLevel.PYTHON312);
|
||||
}
|
||||
|
||||
public void testTypeKeywordAsIdentifier() {
|
||||
doTest(LanguageLevel.PYTHON312);
|
||||
}
|
||||
|
||||
public void doTest() {
|
||||
doTest(LanguageLevel.PYTHON26);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user