PY-76877 Conformance test failure: overloads_basic.py

PySliceExpression is replaced by PySubscriptionExpression in AST.
PySliceItem is returned by PySubscriptionExpression.getIndexExpression(). For that purpose PySliceItem is now a PyExpression of type `builtins.slice`.

GitOrigin-RevId: 9aa8de13ef7c51741e248317c5264b3a06ffb9bf
This commit is contained in:
Petr
2025-05-12 18:15:13 +00:00
committed by intellij-monorepo-bot
parent 6eb1b97d67
commit c8fb196d52
31 changed files with 132 additions and 101 deletions
@@ -74,8 +74,7 @@ public interface PyAstAssignmentStatement extends PyAstStatement, PyAstNamedElem
if (raw ||
expr instanceof PyAstTargetExpression ||
expr instanceof PyAstReferenceExpression ||
expr instanceof PyAstSubscriptionExpression ||
expr instanceof PyAstSliceExpression) {
expr instanceof PyAstSubscriptionExpression) {
targets.add(expr);
}
}
@@ -8,6 +8,8 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@SuppressWarnings("MissingDeprecatedAnnotation")
@Deprecated(forRemoval = true)
@ApiStatus.Experimental
public interface PyAstSliceExpression extends PyAstExpression {
default @NotNull PyAstExpression getOperand() {
@@ -7,7 +7,7 @@ import org.jetbrains.annotations.Nullable;
@ApiStatus.Experimental
public interface PyAstSliceItem extends PyAstElement {
public interface PyAstSliceItem extends PyAstExpression {
default @Nullable PyAstExpression getLowerBound() {
return childToPsi(PythonDialectsTokenSetProvider.getInstance().getExpressionTokens(), 0);
}
@@ -73,7 +73,6 @@ public interface PyElementTypes {
PyElementType BOOL_LITERAL_EXPRESSION = new PyElementType("BOOL_LITERAL_EXPRESSION", Companion.getINSTANCE().getBoolLiteralExpressionConstructor());
PyElementType PARENTHESIZED_EXPRESSION = new PyElementType("PARENTHESIZED_EXPRESSION", Companion.getINSTANCE().getParenthesizedExpressionConstructor());
PyElementType SUBSCRIPTION_EXPRESSION = new PyElementType("SUBSCRIPTION_EXPRESSION", Companion.getINSTANCE().getSubscriptionExpressionConstructor());
PyElementType SLICE_EXPRESSION = new PyElementType("SLICE_EXPRESSION", Companion.getINSTANCE().getSliceExpressionConstructor());
PyElementType SLICE_ITEM = new PyElementType("SLICE_ITEM", Companion.getINSTANCE().getSliceItemConstructor());
PyElementType BINARY_EXPRESSION = new PyElementType("BINARY_EXPRESSION", Companion.getINSTANCE().getBinaryExpressionConstructor());
PyElementType PREFIX_EXPRESSION = new PyElementType("PREFIX_EXPRESSION", Companion.getINSTANCE().getPrefixExpressionConstructor());
@@ -71,7 +71,6 @@ abstract class PyElementTypesFacade {
abstract val parenthesizedExpressionConstructor: Function<in ASTNode, out PsiElement>
abstract val subscriptionExpressionConstructor: Function<in ASTNode, out PsiElement>
abstract val sliceExpressionConstructor: Function<in ASTNode, out PsiElement>
abstract val sliceItemConstructor: Function<in ASTNode, out PsiElement>
abstract val binaryExpressionConstructor: Function<in ASTNode, out PsiElement>
abstract val prefixExpressionConstructor: Function<in ASTNode, out PsiElement>
@@ -36,7 +36,7 @@ public final class PythonTokenSetContributor extends PythonDialectsTokenSetContr
public @NotNull TokenSet getExpressionTokens() {
return TokenSet.create(EMPTY_EXPRESSION, REFERENCE_EXPRESSION, INTEGER_LITERAL_EXPRESSION, FLOAT_LITERAL_EXPRESSION,
IMAGINARY_LITERAL_EXPRESSION, STRING_LITERAL_EXPRESSION, PARENTHESIZED_EXPRESSION,
SUBSCRIPTION_EXPRESSION, SLICE_EXPRESSION, BINARY_EXPRESSION, PREFIX_EXPRESSION, CALL_EXPRESSION,
SUBSCRIPTION_EXPRESSION, SLICE_ITEM, BINARY_EXPRESSION, PREFIX_EXPRESSION, CALL_EXPRESSION,
LIST_LITERAL_EXPRESSION, TUPLE_EXPRESSION, KEYWORD_ARGUMENT_EXPRESSION, STAR_ARGUMENT_EXPRESSION,
LAMBDA_EXPRESSION, LIST_COMP_EXPRESSION, DICT_LITERAL_EXPRESSION, KEY_VALUE_EXPRESSION,
REPR_EXPRESSION, GENERATOR_EXPRESSION, CONDITIONAL_EXPRESSION, YIELD_EXPRESSION,
@@ -601,7 +601,7 @@ public class ExpressionParsing extends Parsing {
sliceMarker.done(PyElementTypes.EMPTY_EXPRESSION);
sliceItemStart.done(PyElementTypes.SLICE_ITEM);
nextToken();
exprStart.done(PyElementTypes.SLICE_EXPRESSION);
exprStart.done(PyElementTypes.SUBSCRIPTION_EXPRESSION);
return;
}
else {
@@ -653,7 +653,7 @@ public class ExpressionParsing extends Parsing {
if (sliceOrTupleStart != null) {
sliceOrTupleStart.drop();
}
exprStart.done(PyElementTypes.SLICE_EXPRESSION);
exprStart.done(PyElementTypes.SUBSCRIPTION_EXPRESSION);
}
return inSlice;
}
@@ -6,6 +6,8 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@SuppressWarnings("MissingDeprecatedAnnotation")
@Deprecated(forRemoval = true)
public interface PySliceExpression extends PyAstSliceExpression, PyExpression {
@Override
default @NotNull PyExpression getOperand() {
@@ -5,7 +5,7 @@ import com.jetbrains.python.ast.PyAstSliceItem;
import org.jetbrains.annotations.Nullable;
public interface PySliceItem extends PyAstSliceItem, PyElement {
public interface PySliceItem extends PyAstSliceItem, PyExpression {
@Override
default @Nullable PyExpression getLowerBound() {
return (PyExpression)PyAstSliceItem.super.getLowerBound();
@@ -124,8 +124,6 @@ class PyElementTypesFacadeImpl : PyElementTypesFacade() {
get() = F { node -> PyParenthesizedExpressionImpl(node) }
override val subscriptionExpressionConstructor: F
get() = F { node -> PySubscriptionExpressionImpl(node) }
override val sliceExpressionConstructor: F
get() = F { node -> PySliceExpressionImpl(node) }
override val sliceItemConstructor: F
get() = F { node -> PySliceItemImpl(node) }
override val binaryExpressionConstructor: F
@@ -86,7 +86,46 @@ public final class PyStringFormatInspection extends PyInspection {
final PyResolveContext resolveContext = PyResolveContext.defaultContext(myTypeEvalContext);
final String s = myFormatSpec.get("1");
if (PsiTreeUtil.instanceOf(rightExpression, SIMPLE_RHS_EXPRESSIONS)) {
if (rightExpression instanceof PySubscriptionExpression subscription &&
subscription.getIndexExpression() instanceof PySliceItem sliceItem &&
s != null) {
final PyType type = myTypeEvalContext.getType(subscription.getOperand());
final PyType stringType = PyBuiltinCache.getInstance(rightExpression).getStringType(LanguageLevel.forElement(rightExpression));
final PyType listType = PyBuiltinCache.getInstance(rightExpression).getListType();
if (type == null) return -1;
if (PyTypeChecker.match(listType, type, myTypeEvalContext)
|| PyTypeChecker.match(stringType, type, myTypeEvalContext)) {
checkTypeCompatible(problemTarget, builtinCache.getStrType(),
PyTypeParser.getTypeByName(problemTarget, s, myTypeEvalContext));
return 1;
}
PyExpression lower = sliceItem.getLowerBound();
PyExpression upper = sliceItem.getUpperBound();
PyExpression stride = sliceItem.getStride();
if (upper instanceof PyNumericLiteralExpression) {
BigInteger lowerVal;
if (lower instanceof PyNumericLiteralExpression) {
lowerVal = ((PyNumericLiteralExpression)lower).getBigIntegerValue();
}
else {
lowerVal = BigInteger.ZERO;
}
int count = (((PyNumericLiteralExpression)upper).getBigIntegerValue().subtract(lowerVal)).intValue();
int strideVal;
if (stride instanceof PyNumericLiteralExpression) {
strideVal = ((PyNumericLiteralExpression)stride).getBigIntegerValue().intValue();
}
else {
strideVal = 1;
}
int res = count / strideVal;
int residue = count % strideVal == 0 ? 0 : 1;
return res + residue;
}
return -1;
}
else if (PsiTreeUtil.instanceOf(rightExpression, SIMPLE_RHS_EXPRESSIONS)) {
if (s != null) {
final PyType rightType = myTypeEvalContext.getType(rightExpression);
if (rightType instanceof PyTupleType tupleType) {
@@ -160,46 +199,6 @@ public final class PyStringFormatInspection extends PyInspection {
return 1;
}
}
else if (rightExpression instanceof PySliceExpression && s != null) {
final PyType type = myTypeEvalContext.getType(((PySliceExpression)rightExpression).getOperand());
final PyType stringType = PyBuiltinCache.getInstance(rightExpression).getStringType(LanguageLevel.forElement(rightExpression));
final PyType listType = PyBuiltinCache.getInstance(rightExpression).getListType();
if (type == null) return -1;
if (PyTypeChecker.match(listType, type, myTypeEvalContext)
|| PyTypeChecker.match(stringType, type, myTypeEvalContext)) {
checkTypeCompatible(problemTarget, builtinCache.getStrType(),
PyTypeParser.getTypeByName(problemTarget, s, myTypeEvalContext));
return 1;
}
PySliceItem sliceItem = ((PySliceExpression)rightExpression).getSliceItem();
if (sliceItem != null) {
PyExpression lower = sliceItem.getLowerBound();
PyExpression upper = sliceItem.getUpperBound();
PyExpression stride = sliceItem.getStride();
if (upper instanceof PyNumericLiteralExpression) {
BigInteger lowerVal;
if (lower instanceof PyNumericLiteralExpression) {
lowerVal = ((PyNumericLiteralExpression)lower).getBigIntegerValue();
}
else {
lowerVal = BigInteger.ZERO;
}
int count = (((PyNumericLiteralExpression)upper).getBigIntegerValue().subtract(lowerVal)).intValue();
int strideVal;
if (stride instanceof PyNumericLiteralExpression) {
strideVal = ((PyNumericLiteralExpression)stride).getBigIntegerValue().intValue();
}
else {
strideVal = 1;
}
int res = count / strideVal;
int residue = count % strideVal == 0 ? 0 : 1;
return res + residue;
}
}
return -1;
}
return -1;
}
@@ -73,8 +73,6 @@ public class PyTypeCheckerInspection extends PyInspection {
@Override
public void visitPySubscriptionExpression(@NotNull PySubscriptionExpression node) {
// TODO: Support slice PySliceExpressions
PyType operandType = myTypeEvalContext.getType(node.getOperand());
if (operandType instanceof PyTupleType tupleType && !tupleType.isHomogeneous()) {
PyExpression indexExpression = node.getIndexExpression();
@@ -45,7 +45,7 @@ import org.jetbrains.annotations.NonNls
class PyBuiltinCache(
val builtinsFile: PyFile? = null,
private val myTypeshedFile: PyFile? = null,
private val myExceptionsFile: PyFile? = null
private val myExceptionsFile: PyFile? = null,
) {
/**
* Stores the most often used types, returned by nNNType.
@@ -199,6 +199,8 @@ class PyBuiltinCache(
val typeType: PyClassType?
get() = getObjectType("type")
val sliceType: PyClassType?
get() = getObjectType("slice")
val noneType: PyClassType?
get() {
@@ -24,6 +24,8 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@SuppressWarnings("ALL")
@Deprecated(forRemoval = true)
public class PySliceExpressionImpl extends PyElementImpl implements PySliceExpression {
public PySliceExpressionImpl(ASTNode astNode) {
super(astNode);
@@ -3,10 +3,19 @@ package com.jetbrains.python.psi.impl;
import com.intellij.lang.ASTNode;
import com.jetbrains.python.psi.PySliceItem;
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 PySliceItemImpl extends PyElementImpl implements PySliceItem {
public PySliceItemImpl(ASTNode astNode) {
super(astNode);
}
@Override
public @Nullable PyType getType(@NotNull TypeEvalContext context, TypeEvalContext.@NotNull Key key) {
return PyBuiltinCache.getInstance(this).getSliceType();
}
}
@@ -23,6 +23,7 @@ import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.python.codeInsight.typing.PyTypingTypeProvider;
import com.jetbrains.python.psi.PyElementVisitor;
import com.jetbrains.python.psi.PyExpression;
import com.jetbrains.python.psi.PySliceItem;
import com.jetbrains.python.psi.PySubscriptionExpression;
import com.jetbrains.python.psi.impl.references.PyOperatorReference;
import com.jetbrains.python.psi.resolve.PyResolveContext;
@@ -48,25 +49,34 @@ public class PySubscriptionExpressionImpl extends PyElementImpl implements PySub
@Override
public @Nullable PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) {
final PyExpression indexExpression = getIndexExpression();
final PyType type = indexExpression != null ? context.getType(getOperand()) : null;
if (type instanceof PyTupleType tupleType) {
List<Integer> indexPossibleValues = getIndexExpressionPossibleValues(indexExpression, context, Integer.class);
List<@Nullable PyType> possibleTypes = ContainerUtil.map(indexPossibleValues, index -> {
if (!tupleType.isHomogeneous() && index < 0) {
index += tupleType.getElementCount();
if (indexExpression != null) {
final PyType operandType = context.getType(getOperand());
if (indexExpression instanceof PySliceItem) {
if (operandType instanceof PyTupleType) {
return ((PyTupleType)operandType).isHomogeneous() ? operandType : PyBuiltinCache.getInstance(this).getTupleType();
}
}
else {
if (operandType instanceof PyTupleType tupleType) {
List<Integer> indexPossibleValues = getIndexExpressionPossibleValues(indexExpression, context, Integer.class);
List<@Nullable PyType> possibleTypes = ContainerUtil.map(indexPossibleValues, index -> {
if (!tupleType.isHomogeneous() && index < 0) {
index += tupleType.getElementCount();
}
return tupleType.getElementType(index);
});
return PyUnionType.union(possibleTypes);
}
if (operandType instanceof PyTypedDictType typedDictType) {
List<String> indexPossibleValues = getIndexExpressionPossibleValues(indexExpression, context, String.class);
return PyUnionType.union(ContainerUtil.map(indexPossibleValues, typedDictType::getElementType));
}
if (operandType instanceof PyClassType) {
PyType parameterizedType = Ref.deref(PyTypingTypeProvider.getType(this, context));
if (parameterizedType instanceof PyCollectionType collectionType) {
return collectionType.toClass();
}
}
return tupleType.getElementType(index);
});
return PyUnionType.union(possibleTypes);
}
if (type instanceof PyTypedDictType typedDictType) {
List<String> indexPossibleValues = getIndexExpressionPossibleValues(indexExpression, context, String.class);
return PyUnionType.union(ContainerUtil.map(indexPossibleValues, typedDictType::getElementType));
}
if (type instanceof PyClassType) {
PyType parameterizedType = Ref.deref(PyTypingTypeProvider.getType(this, context));
if (parameterizedType instanceof PyCollectionType collectionType) {
return collectionType.toClass();
}
}
return PyCallExpressionHelper.getCallType(this, context, key);
@@ -425,7 +425,7 @@ public final class PyReplaceExpressionUtil implements PyElementTypes {
private static boolean isNotAssociative(final @NotNull PyBinaryExpression binaryExpression) {
final IElementType opType = getOperationType(binaryExpression);
return COMPARISON_OPERATIONS.contains(opType) || binaryExpression instanceof PySliceExpression ||
return COMPARISON_OPERATIONS.contains(opType) ||
opType == DIV || opType == FLOORDIV || opType == PERC || opType == EXP || opType == MINUS;
}
@@ -433,7 +433,6 @@ public final class PyReplaceExpressionUtil implements PyElementTypes {
int priority = 0;
if (expr instanceof PyReferenceExpression ||
expr instanceof PySubscriptionExpression ||
expr instanceof PySliceExpression ||
expr instanceof PyCallExpression) priority = 1;
else if (expr instanceof PyPrefixExpression) {
final IElementType opType = getOperationType(expr);
@@ -35,7 +35,6 @@ public final class PyEditorHandlerConfig {
PyAstArgumentList.class,
PyAstParameterList.class,
PyAstDecoratorList.class,
PyAstSliceExpression.class,
PyAstSubscriptionExpression.class,
PyAstGeneratorExpression.class,
PyAstGroupPattern.class,
@@ -45,7 +45,6 @@ public class PyBlock implements ASTBlock {
PyElementTypes.PARAMETER_LIST,
PyElementTypes.TUPLE_EXPRESSION,
PyElementTypes.PARENTHESIZED_EXPRESSION,
PyElementTypes.SLICE_EXPRESSION,
PyElementTypes.SUBSCRIPTION_EXPRESSION,
PyElementTypes.GENERATOR_EXPRESSION,
PyElementTypes.SEQUENCE_PATTERN,
@@ -758,8 +757,9 @@ public class PyBlock implements ASTBlock {
}
private boolean isSliceOperand(@NotNull ASTNode child) {
if (myNode.getPsi() instanceof PyAstSliceExpression sliceExpression) {
final PyAstExpression operand = sliceExpression.getOperand();
if (myNode.getPsi() instanceof PyAstSubscriptionExpression subscription &&
subscription.getIndexExpression() instanceof PyAstSliceItem) {
final PyAstExpression operand = subscription.getOperand();
return operand.getNode() == child;
}
return false;
@@ -247,8 +247,7 @@ private fun getCallInnerReferenceExpression(parameters: CompletionParameters): P
}
private fun getSliceSubscriptionReferenceExpression(parameters: CompletionParameters): PyExpression? {
val expression = PsiTreeUtil.getParentOfType(parameters.position, PySubscriptionExpression::class.java) ?: PsiTreeUtil.getParentOfType(
parameters.position, PySliceExpression::class.java)
val expression = PsiTreeUtil.getParentOfType(parameters.position, PySubscriptionExpression::class.java)
val result = PsiTreeUtil.getChildOfType(expression, PyReferenceExpression::class.java)
if (result != null) {
return PyPsiUtils.getFirstQualifier(result)
@@ -38,7 +38,6 @@ public class PyMissingBracesFixer extends PyFixer<PyElement> {
}
}
else if (psiElement instanceof PyListLiteralExpression ||
psiElement instanceof PySliceExpression ||
psiElement instanceof PySubscriptionExpression) {
final PsiElement lastChild = PyPsiUtils.getPrevNonCommentSibling(psiElement.getLastChild(), false);
if (lastChild != null && !"]".equals(lastChild.getText())) {
@@ -60,7 +60,6 @@ public final class PyDebugSupportUtils {
private static boolean isSimpleEnough(final PsiElement element) {
return element instanceof PyLiteralExpression ||
element instanceof PyQualifiedExpression ||
element instanceof PySliceExpression ||
element instanceof PyNamedParameter ||
element instanceof PyCallExpression;
}
@@ -5,5 +5,6 @@
4(5) element: PySubscriptionExpression
5(6) READ ACCESS: foo
6(7) element: PyDelStatement
7(8) READ ACCESS: foo
8() element: null
7(8) element: PySubscriptionExpression
8(9) READ ACCESS: foo
9() element: null
@@ -1,4 +1,4 @@
def rc(s):
return s.translate(
'*****************************************************************TVGHEFCDIJMLKNOPQYSAUBWXRZ[\]^_`tvghefcdijmlknopqysaubwxrz*************************************************************************************************************************************')[
::-1]
::-1]
@@ -53,7 +53,7 @@ PyFile:AssignmentExpressionsInIndexes.py
PsiComment(Py:END_OF_LINE_COMMENT)('# valid')
PsiWhiteSpace('\n\n')
PyExpressionStatement
PySliceExpression
PySubscriptionExpression
PyReferenceExpression: s
PsiElement(Py:IDENTIFIER)('s')
PsiElement(Py:LBRACKET)('[')
+6 -6
View File
@@ -1,6 +1,6 @@
PyFile:ExtendedSlices.py
PyExpressionStatement
PySliceExpression
PySubscriptionExpression
PyReferenceExpression: d
PsiElement(Py:IDENTIFIER)('d')
PsiElement(Py:LBRACKET)('[')
@@ -14,7 +14,7 @@ PyFile:ExtendedSlices.py
PsiElement(Py:RBRACKET)(']')
PsiWhiteSpace('\n')
PyExpressionStatement
PySliceExpression
PySubscriptionExpression
PyReferenceExpression: d
PsiElement(Py:IDENTIFIER)('d')
PsiElement(Py:LBRACKET)('[')
@@ -30,7 +30,7 @@ PyFile:ExtendedSlices.py
PsiElement(Py:RBRACKET)(']')
PsiWhiteSpace('\n')
PyExpressionStatement
PySliceExpression
PySubscriptionExpression
PyReferenceExpression: d
PsiElement(Py:IDENTIFIER)('d')
PsiElement(Py:LBRACKET)('[')
@@ -44,7 +44,7 @@ PyFile:ExtendedSlices.py
PsiElement(Py:RBRACKET)(']')
PsiWhiteSpace('\n')
PyExpressionStatement
PySliceExpression
PySubscriptionExpression
PyReferenceExpression: d
PsiElement(Py:IDENTIFIER)('d')
PsiElement(Py:LBRACKET)('[')
@@ -57,7 +57,7 @@ PyFile:ExtendedSlices.py
PsiElement(Py:RBRACKET)(']')
PsiWhiteSpace('\n')
PyAssignmentStatement
PySliceExpression
PySubscriptionExpression
PyReferenceExpression: d
PsiElement(Py:IDENTIFIER)('d')
PsiElement(Py:LBRACKET)('[')
@@ -89,7 +89,7 @@ PyFile:ExtendedSlices.py
PsiElement(Py:INTEGER_LITERAL)('1')
PsiWhiteSpace('\n')
PyExpressionStatement
PySliceExpression
PySubscriptionExpression
PyReferenceExpression: d
PsiElement(Py:IDENTIFIER)('d')
PsiElement(Py:LBRACKET)('[')
+1 -1
View File
@@ -10,7 +10,7 @@ PyFile:RangeAsLHS.py
PsiElement(Py:RBRACKET)(']')
PsiWhiteSpace('\n')
PyAssignmentStatement
PySliceExpression
PySubscriptionExpression
PyReferenceExpression: foo
PsiElement(Py:IDENTIFIER)('foo')
PsiElement(Py:LBRACKET)('[')
+1 -1
View File
@@ -1,6 +1,6 @@
PyFile:SliceList.py
PyExpressionStatement
PySliceExpression
PySubscriptionExpression
PyReferenceExpression: a
PsiElement(Py:IDENTIFIER)('a')
PsiElement(Py:LBRACKET)('[')
@@ -50,7 +50,6 @@ namedtuples_define_class.py
namedtuples_type_compat.py
namedtuples_usage.py
narrowing_typeis.py
overloads_basic.py
overloads_consistency.py
overloads_definitions.py
overloads_definitions_stub.pyi
@@ -135,13 +135,13 @@ public class Py3TypeTest extends PyTestCase {
// doTest("int | Any",
// """
// from typing import Any, TypeGuard
//
//
// def is_positive_integer(value: Any) -> TypeGuard[int]:
// return isinstance(value, int) and value > 0
//
// def bar() -> object:
// return 321
//
//
// def foo():
// for i in range(1, 100):
// if i > 1:
@@ -168,12 +168,12 @@ public class Py3TypeTest extends PyTestCase {
// class D:
// def bar() -> A:
// return A()
//
//
// def foo(b):
// x = A()
// while b:
// x = x.bar()
//
//
// expr = x""");
//}
@@ -3696,6 +3696,23 @@ public class Py3TypeTest extends PyTestCase {
});
}
public void testSliceExpression() {
doTest("int", """
from typing import overload
class A[T]:
@overload
def __getitem__(self, s: str) -> str: ...
@overload
def __getitem__(self, s: slice) -> T: ...
def __getitem__(self, s: str | slice) -> str | T: ...
expr = A[int]()[0:2]
""");
}
private void doTest(final String expectedType, final String text) {
myFixture.configureByText(PythonFileType.INSTANCE, text);
final PyExpression expr = myFixture.findElementByText("expr", PyExpression.class);
@@ -3122,7 +3122,7 @@ public class PyTypeTest extends PyTestCase {
public void testSliceOnUnion() {
runWithLanguageLevel(
LanguageLevel.PYTHON36,
() -> doTest("Union[str, Any]",
() -> doTest("str",
"""
from typing import Union
myvar: Union[str, int]