diff --git a/python/python-psi-api/src/com/jetbrains/python/psi/types/PyTypeVisitor.kt b/python/python-psi-api/src/com/jetbrains/python/psi/types/PyTypeVisitor.kt
index c69256c673af..5aa323992e4b 100644
--- a/python/python-psi-api/src/com/jetbrains/python/psi/types/PyTypeVisitor.kt
+++ b/python/python-psi-api/src/com/jetbrains/python/psi/types/PyTypeVisitor.kt
@@ -1,27 +1,27 @@
-// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.psi.types
import org.jetbrains.annotations.ApiStatus
/**
* Similarly to [com.intellij.psi.PsiElementVisitor], implements double dispatching for the [PyType] hierarchy.
- *
- *
+ *
+ *
* Because the "unknown" type is historically represented as `null` in the type system, `PyTypeVisitor.visitPyType(type, visitor)`
* should be used instead of direct `type.acceptTypeVisitor(visitor)` to properly account for possible `null` values.
- *
- *
+ *
+ *
* This class gives access only to the types declared in the intellij.python.psi module.
* Most actual implementations should extend [PyTypeVisitorExt].
- *
- *
+ *
+ *
* There are helper [PyRecursiveTypeVisitor] and [PyCloningTypeVisitor] for recursive type
* traversal and deep cloning of a type respectively.
- *
+ *
* @see PyRecursiveTypeVisitor
- *
+ *
* @see PyCloningTypeVisitor
- *
+ *
* @see PyType.acceptTypeVisitor
* @see .visit
* @see .visitUnknownType
@@ -74,11 +74,11 @@ abstract class PyTypeVisitor {
}
open fun visitAnyType(): T? {
- return null
+ return if (PyAnyType.isEnabled) visitPyType(PyAnyType.Any) else null
}
open fun visitUnknownType(): T? {
- return null
+ return if (PyAnyType.isEnabled) visitPyType(PyAnyType.Unknown) else null
}
companion object {
diff --git a/python/python-psi-impl/src/com/jetbrains/python/codeInsight/controlflow/ReadWriteInstruction.java b/python/python-psi-impl/src/com/jetbrains/python/codeInsight/controlflow/ReadWriteInstruction.java
index d237bd020bbb..6a4b7519d477 100644
--- a/python/python-psi-impl/src/com/jetbrains/python/codeInsight/controlflow/ReadWriteInstruction.java
+++ b/python/python-psi-impl/src/com/jetbrains/python/codeInsight/controlflow/ReadWriteInstruction.java
@@ -21,6 +21,7 @@ import com.intellij.openapi.util.Ref;
import com.intellij.psi.PsiElement;
import com.jetbrains.python.psi.PyElement;
import com.jetbrains.python.psi.PyExpression;
+import com.jetbrains.python.psi.types.PyAnyType;
import com.jetbrains.python.psi.types.PyType;
import com.jetbrains.python.psi.types.TypeEvalContext;
import org.jetbrains.annotations.NonNls;
@@ -31,7 +32,7 @@ public final class ReadWriteInstruction extends InstructionImpl {
private static InstructionTypeCallback instructionTypeCallback(@Nullable PsiElement element) {
return element instanceof PyExpression expression
? context -> Ref.create(context.getType(expression))
- : context -> Ref.create(null);
+ : context -> Ref.create(PyAnyType.getUnknown());
}
public enum ACCESS {
diff --git a/python/python-psi-impl/src/com/jetbrains/python/codeInsight/typeRepresentation/psi/PyFunctionTypeRepresentation.kt b/python/python-psi-impl/src/com/jetbrains/python/codeInsight/typeRepresentation/psi/PyFunctionTypeRepresentation.kt
index 5881d2340dfb..0ad3d5a1e1f0 100644
--- a/python/python-psi-impl/src/com/jetbrains/python/codeInsight/typeRepresentation/psi/PyFunctionTypeRepresentation.kt
+++ b/python/python-psi-impl/src/com/jetbrains/python/codeInsight/typeRepresentation/psi/PyFunctionTypeRepresentation.kt
@@ -36,6 +36,7 @@ import com.jetbrains.python.psi.types.PyCallableTypeImpl
import com.jetbrains.python.psi.types.PyCollectionTypeImpl
import com.jetbrains.python.psi.types.PyFunctionTypeImpl
import com.jetbrains.python.psi.types.PyType
+import com.jetbrains.python.psi.types.PyTypeUtil.derefOrUnknown
import com.jetbrains.python.psi.types.PyTypeVarType
import com.jetbrains.python.psi.types.PyTypeVarTypeImpl
import com.jetbrains.python.psi.types.TypeEvalContext
@@ -209,7 +210,7 @@ class PyFunctionTypeRepresentation(astNode: ASTNode) : PyElementImpl(astNode), P
// Otherwise, resolve normally
return when (expr) {
is PyDoubleStarExpression -> PyTypingTypeProvider.getType(expr.expression!!, context)?.get()
- else -> PyTypingTypeProvider.getType(expr, context)?.get()
+ else -> PyTypingTypeProvider.getType(expr, context).derefOrUnknown()
}
}
}
diff --git a/python/python-psi-impl/src/com/jetbrains/python/codeInsight/typing/PyTypingTypeProvider.kt b/python/python-psi-impl/src/com/jetbrains/python/codeInsight/typing/PyTypingTypeProvider.kt
index 9e390161a89b..23fbbc35cb66 100644
--- a/python/python-psi-impl/src/com/jetbrains/python/codeInsight/typing/PyTypingTypeProvider.kt
+++ b/python/python-psi-impl/src/com/jetbrains/python/codeInsight/typing/PyTypingTypeProvider.kt
@@ -122,6 +122,7 @@ import com.jetbrains.python.psi.types.PyTypeParameterType
import com.jetbrains.python.psi.types.PyTypeParser
import com.jetbrains.python.psi.types.PyTypeUtil
import com.jetbrains.python.psi.types.PyTypeUtil.convertToType
+import com.jetbrains.python.psi.types.PyTypeUtil.derefOrUnknown
import com.jetbrains.python.psi.types.PyTypeUtil.toKeywordContainerType
import com.jetbrains.python.psi.types.PyTypeUtil.toPositionalContainerType
import com.jetbrains.python.psi.types.PyTypeVarTupleType
@@ -179,7 +180,7 @@ class PyTypingTypeProvider : PyTypeProviderWithCustomContext() {
if (annotation != null) {
val funcTypeCommentParamHint: PyExpression? = findParamTypeHintInFunctionTypeComment(annotation, param, func)
if (funcTypeCommentParamHint == null) {
- return Ref()
+ return Ref(PyAnyType.unknown)
}
typeHint = funcTypeCommentParamHint
}
@@ -199,7 +200,7 @@ class PyTypingTypeProvider : PyTypeProviderWithCustomContext() {
) {
typeHint = typeHint.qualifier!!
}
- val type = Ref.deref(getType(typeHint, context))
+ val type = getType(typeHint, context).derefOrUnknown()
if (param.isPositionalContainer && type !is PyParamSpecType) {
return Ref(param.toPositionalContainerType(type))
}
@@ -225,7 +226,7 @@ class PyTypingTypeProvider : PyTypeProviderWithCustomContext() {
return typeRef
}
// Don't rely on other type providers if a type hint is present but cannot be resolved.
- return Ref()
+ return Ref(PyAnyType.unknown)
}
}
return null
@@ -316,7 +317,7 @@ class PyTypingTypeProvider : PyTypeProviderWithCustomContext() {
}
}
- val annotatedType: Ref? = getTypeFromTypeHint(referenceTarget, context)
+ val annotatedType = getTypeFromTypeHint(referenceTarget, context)
if (annotatedType != null) {
return annotatedType
}
@@ -991,8 +992,7 @@ class PyTypingTypeProvider : PyTypeProviderWithCustomContext() {
.collect(PyTypeUtil.toUnionFromRef())
}
- private fun
- getTypeFromTypeHint(element: T, context: Context): Ref? where T : PyAnnotationOwner?, T : PyTypeCommentOwner? {
+ private fun getTypeFromTypeHint(element: T, context: Context): Ref? where T : PyAnnotationOwner?, T : PyTypeCommentOwner? {
val annotation: PyExpression? = getAnnotationValue(element!!, context.typeContext)
if (annotation != null) {
return getType(annotation, context)
@@ -1034,7 +1034,7 @@ class PyTypingTypeProvider : PyTypeProviderWithCustomContext() {
private fun evaluateSuperClassesAsTypeHints(pyClass: PyClass, context: TypeEvalContext): MutableList {
val results: MutableList = ArrayList()
for (superClassExpression in getSuperClassExpressions(pyClass)) {
- val type = Ref.deref(getType(superClassExpression, context))
+ val type = getType(superClassExpression, context).derefOrUnknown()
if (type is PyClassType) {
results.add(type)
}
@@ -1394,7 +1394,7 @@ class PyTypingTypeProvider : PyTypeProviderWithCustomContext() {
if (typeEngineType != null) {
return typeEngineType
}
- return PyAnyType.unknown?.let { Ref(it) }
+ return null
}
finally {
if (resolved is PyClass) {
@@ -1409,7 +1409,7 @@ class PyTypingTypeProvider : PyTypeProviderWithCustomContext() {
private fun getTypeEngineType(typeHint: PyExpression, context: Context): Ref? {
if (!context.typeRepresentationMode) return null
if (typeHint.text == "Unknown") {
- return Ref()
+ return Ref(PyAnyType.unknown)
}
if (typeHint is PyFunctionTypeRepresentation) {
val result = context.typeContext.getType(typeHint)
@@ -1554,7 +1554,7 @@ class PyTypingTypeProvider : PyTypeProviderWithCustomContext() {
if (resolved is PyQualifiedNameOwner) {
val qualifiedName = resolved.qualifiedName
if (TYPE_ALIAS == qualifiedName || TYPE_ALIAS_EXT == qualifiedName) {
- return Ref()
+ return Ref(PyAnyType.unknown)
}
}
return null
@@ -1592,7 +1592,7 @@ class PyTypingTypeProvider : PyTypeProviderWithCustomContext() {
return getAsClassObjectType(indexExpr, context)
}
// Map Type[Something] with unsupported type parameter to Any, instead of a generic type for the class "type"
- return Ref()
+ return Ref(PyAnyType.unknown)
}
}
else if (TYPE == getQualifiedName(resolved)) {
@@ -1621,7 +1621,7 @@ class PyTypingTypeProvider : PyTypeProviderWithCustomContext() {
) {
return Ref(type.map { (it as PyClassType).toClass() })
}
- return Ref()
+ return Ref(PyAnyType.unknown)
}
private fun getAnyType(element: PsiElement, context: Context): Ref? {
@@ -1695,7 +1695,7 @@ class PyTypingTypeProvider : PyTypeProviderWithCustomContext() {
return Ref(PyUnionType.union(typeRef.get(), getInstance(element).noneType))
}
}
- return Ref()
+ return Ref(PyAnyType.unknown)
}
}
return null
@@ -2121,7 +2121,7 @@ class PyTypingTypeProvider : PyTypeProviderWithCustomContext() {
if (arguments.size < 2) return null
val prefixTypeExprs = arguments.subList(0, arguments.size - 1)
- val prefixTypes = prefixTypeExprs.map { Ref.deref(getType(it!!, context.typeContext)) }
+ val prefixTypes = prefixTypeExprs.map { getType(it, context.typeContext).derefOrUnknown() }
val lastTypeExpr = arguments[arguments.size - 1]
val paramSpecType = if (lastTypeExpr is PyEllipsisLiteralExpression) {
@@ -2161,7 +2161,7 @@ class PyTypingTypeProvider : PyTypeProviderWithCustomContext() {
.takeWhile { it !is PyKeywordArgument }
.map { Ref.deref(getType(it, context)) }
val boundExpression = element.getKeywordArgument("bound")
- val bound = if (boundExpression == null) null else Ref.deref(getType(boundExpression, context))
+ val bound = if (boundExpression == null) PyAnyType.unknown else Ref.deref(getType(boundExpression, context))
val variance: PyTypeVarType.Variance = getTypeVarVarianceFromDeclaration(element)
val assignStmt = element.getParent() as? PyAssignmentStatement
val mappingPair = assignStmt?.targetsToValuesMapping?.firstOrNull { pair -> pair.second == element }
@@ -2253,7 +2253,7 @@ class PyTypingTypeProvider : PyTypeProviderWithCustomContext() {
defaultType = if (defaultExprWithoutParens != null)
getTypePreventingRecursion(defaultExprWithoutParens, context)
else
- Ref()
+ Ref(PyAnyType.unknown)
}
val declarationElement = element as? PyQualifiedNameOwner
diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyBinaryExpressionImpl.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyBinaryExpressionImpl.java
index 64cec3a88be8..f0cdcb0abe9a 100644
--- a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyBinaryExpressionImpl.java
+++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyBinaryExpressionImpl.java
@@ -12,6 +12,7 @@ import com.jetbrains.python.psi.PyElementVisitor;
import com.jetbrains.python.psi.PyExpression;
import com.jetbrains.python.psi.impl.references.PyOperatorReference;
import com.jetbrains.python.psi.resolve.PyResolveContext;
+import com.jetbrains.python.psi.types.PyAnyType;
import com.jetbrains.python.psi.types.PyStructuralType;
import com.jetbrains.python.psi.types.PyType;
import com.jetbrains.python.psi.types.PyTypeChecker;
@@ -21,6 +22,8 @@ import com.jetbrains.python.psi.types.TypeEvalContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import static com.jetbrains.python.psi.types.PyTypeUtilKt.isUnknown;
+
public class PyBinaryExpressionImpl extends PyElementImpl implements PyBinaryExpression {
@@ -66,7 +69,7 @@ public class PyBinaryExpressionImpl extends PyElementImpl implements PyBinaryExp
final PyExpression right = getRightExpression();
final PyType rightType = right != null ? context.getType(right) : null;
if (leftType == null && rightType == null) {
- return null;
+ return PyAnyType.getUnknown();
}
if (isOperator(PyNames.OR)) {
// TODO: also exclude Literal[False, 0, ""]
@@ -80,13 +83,13 @@ public class PyBinaryExpressionImpl extends PyElementImpl implements PyBinaryExp
return PyBuiltinCache.getInstance(this).getBoolType();
}
PyType callResultType = PyCallExpressionHelper.getCallType(this, context, key);
- if (callResultType == null) {
+ if (callResultType instanceof PyAnyType.Any) return callResultType;
+ if (isUnknown(callResultType)) {
if (referencedName != null && PyNames.COMPARISON_OPERATORS.contains(referencedName)) {
- // we don't know if it was explicit or not, so we form an unsafe union of Any and bool
- // TODO: when { explicit Any -> Any, Unknown -> UnsafeUnion[bool | Any] }
- return PyUnsafeUnionType.unsafeUnion(null, PyBuiltinCache.getInstance(this).getBoolType());
+ // it was not an explicit `Any`, so we form an unsafe union of `Unknown` and `bool`
+ return PyUnsafeUnionType.unsafeUnion(callResultType, PyBuiltinCache.getInstance(this).getBoolType());
}
- return null;
+ return callResultType;
}
boolean bothOperandsAreKnown = operandIsKnown(getLeftExpression(), context) && operandIsKnown(getRightExpression(), context);
// TODO requires weak union. See PyTypeCheckerInspectionTest#testBinaryExpressionWithUnknownOperand
diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.kt b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.kt
index f71376782dae..c4ccda35c852 100644
--- a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.kt
+++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.kt
@@ -52,6 +52,7 @@ import com.jetbrains.python.psi.resolve.PyResolveUtil
import com.jetbrains.python.psi.resolve.QualifiedRatedResolveResult
import com.jetbrains.python.psi.resolve.QualifiedResolveResult
import com.jetbrains.python.psi.resolve.RatedResolveResult
+import com.jetbrains.python.psi.types.PyAnyType
import com.jetbrains.python.psi.types.PyCallableParameter
import com.jetbrains.python.psi.types.PyCallableParameterImpl
import com.jetbrains.python.psi.types.PyCallableType
@@ -78,6 +79,7 @@ import com.jetbrains.python.psi.types.PyUnionType
import com.jetbrains.python.psi.types.PyUnsafeUnionType
import com.jetbrains.python.psi.types.TypeEvalContext
import com.jetbrains.python.psi.types.isNoneType
+import com.jetbrains.python.psi.types.isUnknown
import com.jetbrains.python.pyi.PyiUtil
import com.jetbrains.python.toolbox.Maybe
import org.jetbrains.annotations.ApiStatus
@@ -231,7 +233,7 @@ private fun PyCallExpression.getExplicitResolveResults(resolveContext: PyResolve
for (type in calleeType.toStream()) {
// When invoking cls(), turn type[Self] into Self.
// Otherwise, we will delegate to __init__() of its scope class and return a concrete type class
- // as a call result, losing Self.
+ // as a call result, losing Self.
// See e.g. Py3TypeCheckerInspectionTest.testSelfInClassMethods
if (type is PySelfType) {
result.add(type)
@@ -365,9 +367,9 @@ private fun PyCallSiteExpression.toCallableType(
clarifiedResolved.getImplicitArgumentCount(resolvedModifier, isConstructorCall, isByInstance, isByClass)
val clarifiedConstructorCallType =
- if (PyUtil.isInitOrNewMethod(clarifiedResolved)) resolveResult.clarifyConstructorCallType(this, context) else null
+ if (PyUtil.isInitOrNewMethod(clarifiedResolved)) resolveResult.clarifyConstructorCallType(this, context) else PyAnyType.unknown
- if (callableType.modifier == resolvedModifier && callableType.implicitOffset == resolvedImplicitOffset && clarifiedConstructorCallType == null) {
+ if (callableType.modifier == resolvedModifier && callableType.implicitOffset == resolvedImplicitOffset && clarifiedConstructorCallType.isUnknown) {
return callableType
}
@@ -601,14 +603,14 @@ private fun List.resolveOverloadsCallType(callSite: PyCallSiteEx
return matchingOverloads[0].getCallType(context, callSite)
}
val someArgumentsHaveUnknownType = arguments.any {
- context.getType(it) == null
+ context.getType(it).isUnknown
}
if (someArgumentsHaveUnknownType) {
return matchingOverloads
.map { it.getCallType(context, callSite) }
.let { PyUnionType.union(it) }
}
- return matchingOverloads.firstOrNull()?.getCallType(context, callSite)
+ return matchingOverloads.firstOrNull()?.getCallType(context, callSite) ?: PyAnyType.unknown
}
private fun ClarifiedResolveResult.clarifyConstructorCallType(callSite: PyCallSiteExpression, context: TypeEvalContext): PyType? {
@@ -634,12 +636,12 @@ private fun ClarifiedResolveResult.clarifyConstructorCallType(callSite: PyCallSi
if (initOrNewCallType is PyCollectionType) {
return initOrNewCallType
}
- if (initOrNewCallType == null) {
+ if (initOrNewCallType.isUnknown) {
// TODO requires weak union. See PyUnresolvedReferencesInspectionTest.testCustomNewReturnInAnotherModule
return PyUnionType.createWeakType(PyClassTypeImpl(receiverClass, false))
}
- return null
+ return PyAnyType.unknown
}
private fun PyCallExpression.getSuperCallType(context: TypeEvalContext): Maybe {
diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyClassImpl.java
index 894ef579d507..2231e4386eea 100644
--- a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyClassImpl.java
+++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyClassImpl.java
@@ -91,6 +91,7 @@ import com.jetbrains.python.psi.stubs.PropertyStubStorage;
import com.jetbrains.python.psi.stubs.PyClassStub;
import com.jetbrains.python.psi.stubs.PyFunctionStub;
import com.jetbrains.python.psi.stubs.PyTargetExpressionStub;
+import com.jetbrains.python.psi.types.PyAnyType;
import com.jetbrains.python.psi.types.PyCallableParameter;
import com.jetbrains.python.psi.types.PyClassLikeType;
import com.jetbrains.python.psi.types.PyClassType;
@@ -148,7 +149,7 @@ public class PyClassImpl extends PyBaseElementImpl implements PyCla
@Override
public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) {
if (PyTypingTypeProvider.ANY.equals(getQualifiedName())) {
- return null;
+ return PyAnyType.getAny();
}
return new PyClassTypeImpl(this, true);
}
diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java
index 05dab8409e8e..e5185a04649a 100644
--- a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java
+++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java
@@ -72,6 +72,7 @@ import com.jetbrains.python.psi.stubs.PyAnnotationOwnerStub;
import com.jetbrains.python.psi.stubs.PyClassStub;
import com.jetbrains.python.psi.stubs.PyFunctionStub;
import com.jetbrains.python.psi.stubs.PyTargetExpressionStub;
+import com.jetbrains.python.psi.types.PyAnyType;
import com.jetbrains.python.psi.types.PyCallableParameter;
import com.jetbrains.python.psi.types.PyCallableParameterImpl;
import com.jetbrains.python.psi.types.PyCallableType;
@@ -110,6 +111,7 @@ import static com.jetbrains.python.ast.PyAstFunction.Modifier.STATICMETHOD;
import static com.jetbrains.python.psi.PyUtil.as;
import static com.jetbrains.python.psi.impl.PyCallExpressionHelper.interpretAsModifierWrappingCall;
import static com.jetbrains.python.psi.impl.PyDeprecationUtilKt.extractDeprecationMessageFromDecorator;
+import static com.jetbrains.python.psi.types.PyTypeUtilKt.isUnknown;
public class PyFunctionImpl extends PyBaseElementImpl implements PyFunction {
@@ -221,7 +223,7 @@ public class PyFunctionImpl extends PyBaseElementImpl implements
@Override
public @Nullable PyType getInferredReturnType(@NotNull TypeEvalContext context) {
- PyType inferredType = null;
+ PyType inferredType = PyAnyType.getUnknown();
if (context.allowReturnTypes(this)) {
final PyType returnType = getReturnStatementType(context);
final Pair yieldSendTypePair = getYieldExpressionType(context);
@@ -307,14 +309,14 @@ public class PyFunctionImpl extends PyBaseElementImpl implements
type = PyTypeChecker.substitute(type, substitutionsWithUnresolvedReturnGenerics, context);
}
else {
- type = null;
+ type = PyAnyType.getUnknown();
}
}
// TODO Is it still needed if we infer Self as a return type?
else if (receiver != null) {
type = replaceSelf(type, receiver, context);
}
- if (type != null && isDynamicallyEvaluated(parameters.values(), context)) {
+ if (!isUnknown(type) && isDynamicallyEvaluated(parameters.values(), context)) {
type = PyUnionType.createWeakType(type);
}
return PyNarrowedType.Companion.bindIfNeeded(type, callSiteExpression);
diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java
index 7ef1915b2673..e71e90dbbd9c 100644
--- a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java
+++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java
@@ -11,6 +11,7 @@ import com.jetbrains.python.psi.PyExpression;
import com.jetbrains.python.psi.PyLambdaExpression;
import com.jetbrains.python.psi.PyNamedParameter;
import com.jetbrains.python.psi.PySlashParameter;
+import com.jetbrains.python.psi.types.PyAnyType;
import com.jetbrains.python.psi.types.PyCallableParameter;
import com.jetbrains.python.psi.types.PyCallableParameterImpl;
import com.jetbrains.python.psi.types.PyCallableType;
@@ -104,7 +105,7 @@ public class PyLambdaExpressionImpl extends PyElementImpl implements PyLambdaExp
@Override
public @Nullable PyType getReturnType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) {
final PyExpression body = getBody();
- if (body == null) return null;
+ if (body == null) return PyAnyType.getUnknown();
final PyFunctionImpl.YieldCollector visitor = new PyFunctionImpl.YieldCollector();
body.accept(visitor);
diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java
index 99bc8b4695ea..07ab7bab531c 100644
--- a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java
+++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java
@@ -49,6 +49,7 @@ import com.jetbrains.python.psi.PyUtil;
import com.jetbrains.python.psi.resolve.PyResolveContext;
import com.jetbrains.python.psi.stubs.PyAnnotationOwnerStub;
import com.jetbrains.python.psi.stubs.PyNamedParameterStub;
+import com.jetbrains.python.psi.types.PyAnyType;
import com.jetbrains.python.psi.types.PyCallableParameter;
import com.jetbrains.python.psi.types.PyCallableParameterImpl;
import com.jetbrains.python.psi.types.PyClassTypeImpl;
@@ -299,7 +300,7 @@ public class PyNamedParameterImpl extends PyBaseElementImpl typeFromTargetsRef = getTypeFromTargets(context);
- final PyType typeFromTargets = Ref.deref(typeFromTargetsRef);
+ final PyType typeFromTargets = PyTypeUtil.derefOrUnknown(typeFromTargetsRef);
if (qualified && isNoneType(typeFromTargets)) {
- return null;
+ return PyAnyType.getUnknown();
}
final Ref descriptorType = PyDescriptorTypeUtil.getDunderGetReturnType(this, typeFromTargets, context);
@@ -264,7 +266,7 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere
return getTypeFromDunderGetAttr(context);
}
- return Ref.deref(typeFromTargetsRef);
+ return typeFromTargets;
}
private @Nullable PyType getCallableType(@NotNull TypeEvalContext context) {
@@ -422,7 +424,7 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere
LOG.info(PluginException.createByClass("Failed to get expression type via " + provider.getClass(), e, provider.getClass()));
}
}
- return null;
+ return PyAnyType.getUnknown();
}
private static @Nullable Ref getTypeFromTarget(@NotNull PsiElement target,
@@ -485,7 +487,7 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere
if (!ScopeUtil.getElementsOfAccessType(name, scopeOwner, ReadWriteInstruction.ACCESS.ASSERTTYPE).isEmpty() ||
(target instanceof PyTargetExpression || target instanceof PyNamedParameter) && ScopeUtil.getScopeOwner(target) == scopeOwner) {
final PyType type = getTypeByControlFlow(name, context, anchor, scopeOwner);
- if (type != null) {
+ if (!isUnknown(type)) {
return Ref.create(type);
}
}
@@ -572,7 +574,7 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere
if (narrowedType.getTypeIs()) {
return PyTypeAssertionEvaluator.createAssertionType(initial, type, positive, false, context);
}
- return Ref.create((positive) ? type : initial);
+ return Ref.create(positive ? type : initial);
}
}
}
@@ -581,7 +583,7 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere
})
.nonNull()
.collect(PyTypeUtil.toUnionFromRef());
- return Ref.deref(combinedType);
+ return PyTypeUtil.derefOrUnknown(combinedType);
}
public static @Nullable Ref getReferenceTypeFromProviders(@NotNull PsiElement target,
diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java
index 8b077149af49..062d6c478857 100644
--- a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java
+++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java
@@ -73,6 +73,7 @@ import com.jetbrains.python.psi.stubs.PyFunctionStub;
import com.jetbrains.python.psi.stubs.PyLiteralKind;
import com.jetbrains.python.psi.stubs.PyTargetExpressionStub;
import com.jetbrains.python.psi.types.PyABCUtil;
+import com.jetbrains.python.psi.types.PyAnyType;
import com.jetbrains.python.psi.types.PyCallableParameter;
import com.jetbrains.python.psi.types.PyClassLikeType;
import com.jetbrains.python.psi.types.PyClassType;
@@ -97,6 +98,8 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
+import static com.jetbrains.python.psi.types.PyTypeUtilKt.isUnknown;
+
public class PyTargetExpressionImpl extends PyBaseElementImpl implements PyTargetExpression {
private volatile @Nullable QualifiedName myQualifiedName;
@@ -147,14 +150,14 @@ public class PyTargetExpressionImpl extends PyBaseElementImpl pyType = PyReferenceExpressionImpl.getReferenceTypeFromProviders(this, context, null);
if (pyType != null) {
return pyType.get();
}
PyType type = getTypeFromDocString();
- if (type != null) {
+ if (!isUnknown(type)) {
return type;
}
if (!context.maySwitchToAST(this)) {
@@ -188,7 +191,7 @@ public class PyTargetExpressionImpl extends PyBaseElementImpl getIterationType(member, source, anchor, isAsync, context));
}
if (!isAsync) {
- if (iterableType != null && PyABCUtil.isSubtype(iterableType, PyNames.ITERABLE, context)) {
+ if (!isUnknown(iterableType) && PyABCUtil.isSubtype(iterableType, PyNames.ITERABLE, context)) {
final PyFunction iterateMethod = findMethodByName(iterableType, PyNames.ITER, context);
if (iterateMethod != null) {
final PyType iterateReturnType = getContextSensitiveType(iterateMethod, context, source);
@@ -472,7 +475,7 @@ public class PyTargetExpressionImpl extends PyBaseElementImpl getNextMethodCallType(@Nullable PyType type,
@@ -572,7 +575,7 @@ public class PyTargetExpressionImpl extends PyBaseElementImpl {
promoteDictLiteral(expectedType, value)
@@ -121,7 +121,7 @@ class PyLiteralType private constructor(cls: PyClass, val expression: PyExpressi
}
else -> {
val type = if (inferLiteralTypes) getLiteralOrLiteralStringType(value, context) else null
- return type ?: context.getType(value)
+ type ?: context.getType(value)
}
}
}
@@ -202,7 +202,7 @@ class PyLiteralType private constructor(cls: PyClass, val expression: PyExpressi
): PyType? {
val substitution = if (substitutions != null) PyTypeChecker.substitute(expected, substitutions, context) else expected
val substitutionOrBound = if (substitution is PyTypeVarType) substitution.getEffectiveBound() else substitution
- if (substitutionOrBound == null) return null
+ if (substitutionOrBound == null) return PyAnyType.unknown
return TypePromoter(context, containsLiteral(substitutionOrBound)).promoteToType(substitutionOrBound, expression)
}
diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/types/PySyntheticCallHelper.java b/python/python-psi-impl/src/com/jetbrains/python/psi/types/PySyntheticCallHelper.java
index 485d71d6fd1b..df53ae7419a6 100644
--- a/python/python-psi-impl/src/com/jetbrains/python/psi/types/PySyntheticCallHelper.java
+++ b/python/python-psi-impl/src/com/jetbrains/python/psi/types/PySyntheticCallHelper.java
@@ -60,7 +60,7 @@ public final class PySyntheticCallHelper {
@NotNull List argumentTypes,
@NotNull TypeEvalContext context) {
List functions = resolveFunctionsByArgumentTypes(functionName, argumentTypes, receiverType, context);
- if (functions.isEmpty()) return null;
+ if (functions.isEmpty()) return PyAnyType.getUnknown();
return StreamEx.of(functions)
.nonNull()
.map(function -> getCallTypeOnTypesOnly(function, receiverType, argumentTypes, context))
diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyTypeChecker.kt b/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyTypeChecker.kt
index 7fc92e65f745..2bd4ea2735a5 100644
--- a/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyTypeChecker.kt
+++ b/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyTypeChecker.kt
@@ -45,6 +45,7 @@ import com.jetbrains.python.psi.types.PyLiteralStringType.Companion.match
import com.jetbrains.python.psi.types.PyLiteralType.Companion.match
import com.jetbrains.python.psi.types.PyRecursiveTypeVisitor.PyTypeTraverser
import com.jetbrains.python.psi.types.PyTypeChecker.match
+import com.jetbrains.python.psi.types.PyTypeUtil.derefOrUnknown
import com.jetbrains.python.psi.types.PyTypeUtil.getEffectiveBound
import com.jetbrains.python.psi.types.PyTypeUtil.toStream
import com.jetbrains.python.pyi.PyiFile
@@ -177,7 +178,7 @@ object PyTypeChecker {
return Optional.of(match(expected, actual, context))
}
- if (expected == null || actual == null || isUnknown(actual, context.context)) {
+ if (expected.isAnyOrUnknown || actual.isAnyOrUnknown || isUnknown(actual, context.context)) {
return Optional.of(true)
}
@@ -358,13 +359,13 @@ object PyTypeChecker {
}
}
- if (safeActual != null) {
+ if (!safeActual.isUnknown) {
val type = if (constraints.isEmpty()) safeActual else constraints[matchedConstraintIndex]
context.mySubstitutions.putTypeVar(expected, Ref(type), KeyImpl)
}
else {
val effectiveBound = expected.getEffectiveBound()
- if (effectiveBound != null) {
+ if (!effectiveBound.isUnknown) {
context.mySubstitutions.putTypeVar(expected, Ref(PyUnionType.createWeakType(effectiveBound)), KeyImpl)
}
}
@@ -1392,7 +1393,7 @@ object PyTypeChecker {
return typeVarType
}
val substitutionRef = substitutions.typeVars[typeVarType]
- var substitution = Ref.deref(substitutionRef)
+ var substitution = substitutionRef.derefOrUnknown()
if (substitutionRef == null) {
val invertedTypeVar: PyInstantiableType<*> = typeVarType.invert()
val invertedSubstitution = Ref.deref(substitutions.typeVars[invertedTypeVar]) as? PyInstantiableType<*>
@@ -1762,7 +1763,7 @@ object PyTypeChecker {
}
receiverType.toStream()
.select(PyClassType::class.java)
- .map { type: PyClassType? -> collectTypeSubstitutions(type!!, context) }
+ .map { collectTypeSubstitutions(it, context) }
.forEach { newSubstitutions ->
for (typeVarMapping in newSubstitutions.typeVars.entries) {
substitutions.putTypeVar(typeVarMapping.key, typeVarMapping.value, KeyImpl, true)
diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyTypeInferenceCspFactory.kt b/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyTypeInferenceCspFactory.kt
index e8ab47ad0271..d903b7664dc7 100644
--- a/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyTypeInferenceCspFactory.kt
+++ b/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyTypeInferenceCspFactory.kt
@@ -75,10 +75,10 @@ object PyTypeInferenceCspFactory {
val builder = CspBuilder(context)
- for (typeVarEntry in substitutions.typeVars.entries) {
- ensureInferenceVariables(builder, receiverType, typeVarEntry.key, context)
- if (typeVarEntry.value != null) {
- builder.addConstraint(typeVarEntry.key, typeVarEntry.value!!.get(), Variance.INVARIANT, ConstraintPriority.HIGH)
+ for ((key, value) in substitutions.typeVars) {
+ ensureInferenceVariables(builder, receiverType, key, context)
+ if (value != null) {
+ builder.addConstraint(key, value.get(), Variance.INVARIANT, ConstraintPriority.HIGH)
}
}
@@ -89,9 +89,7 @@ object PyTypeInferenceCspFactory {
}
// arguments
- for (entry in mappedParameters) {
- val argument = entry.key
- val parameter: PyCallableParameter = entry.value
+ for ((argument, parameter) in mappedParameters) {
if (parameter.isPositionalContainer() || parameter.isKeywordContainer()) {
throw NotSupportedException()
}
@@ -99,7 +97,7 @@ object PyTypeInferenceCspFactory {
val expectedParameterType = parameter.getArgumentType(context)
val passedArgumentType = getArgumentType(parameter, argument, expectedParameterType, substitutions, context)
- if (expectedParameterType != null
+ if (!expectedParameterType.isUnknown
&& (expectedParameterType.hasGenerics(context) || passedArgumentType.hasGenerics(context))
) {
ensureInferenceVariables(builder, receiverType, expectedParameterType, context)
@@ -113,7 +111,7 @@ object PyTypeInferenceCspFactory {
if (declaredReturn.hasGenerics(context)) {
ensureInferenceVariables(builder, receiverType, declaredReturn, context)
val expectedReturnType = getExpectedType(callSite, context)
- if (expectedReturnType != null) {
+ if (!expectedReturnType.isUnknown) {
val declaredReturn_selfBounded = substituteSelfTypes(declaredReturn, receiverType, context)
// semantics: RT <: ExpectedReturnType
builder.addConstraint(declaredReturn_selfBounded, expectedReturnType, Variance.COVARIANT, ConstraintPriority.LOW)
diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyTypeInferenceCspSolver.kt b/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyTypeInferenceCspSolver.kt
index 1b72ccbcd202..1c83d21915fb 100644
--- a/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyTypeInferenceCspSolver.kt
+++ b/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyTypeInferenceCspSolver.kt
@@ -24,6 +24,7 @@ import com.jetbrains.python.psi.resolve.PyResolveContext
import com.jetbrains.python.psi.resolve.RatedResolveResult
import com.jetbrains.python.psi.types.ConstraintReducer.reduce
import com.jetbrains.python.psi.types.PyRecursiveTypeVisitor.PyTypeTraverser
+import com.jetbrains.python.psi.types.PyTypeUtil.derefOrUnknown
import com.jetbrains.python.psi.types.PyTypeUtil.getEffectiveBound
import com.jetbrains.python.psi.types.PyTypeVarType.Variance
import com.jetbrains.python.psi.types.SubtypeJudgement.isRawSubtype
@@ -156,15 +157,15 @@ class CspBuilder(val context: TypeEvalContext) {
val originalTypeVar = instantiatedType.typeVariable
return when {
keepUnconstrained -> originalTypeVar
- originalTypeVar.defaultType != null -> originalTypeVar.defaultType?.get()
+ originalTypeVar.defaultType != null -> originalTypeVar.defaultType.derefOrUnknown()
originalTypeVar.bound != null -> originalTypeVar.bound
- else -> null
+ else -> PyAnyType.unknown
}
}
is PyTypeVarType -> {
// if the solution is another PyTypeVarType, check the declared default types
if (inferenceVariable.typeVariable.defaultType != null) {
- return inferenceVariable.typeVariable.defaultType?.get()
+ return inferenceVariable.typeVariable.defaultType.derefOrUnknown()
}
else {
return instantiatedType
@@ -1435,7 +1436,7 @@ private object TypeBoundResolver {
*/
private fun collectLowerBounds(cp: ConstraintProblem, infVar: InferenceVariable, context: TypeEvalContext): Array {
return collectBounds(cp, infVar, context) { b: TypeBound ->
- (b.variance === Variance.INVARIANT) || (b.variance === Variance.CONTRAVARIANT && b.right != null)
+ (b.variance === Variance.INVARIANT) || (b.variance === Variance.CONTRAVARIANT && !b.right.isUnknown)
}
}
@@ -1564,8 +1565,8 @@ private object SubtypeJudgement {
/** True iff left is a subtype of right */
fun isSubtype(left: PyType?, right: PyType?, context: TypeEvalContext): Boolean {
- val leftProper = if (left is PyUnconstrainedTypeVariable) left.typeVariable.defaultType?.get() else left
- val rightProper = if (right is PyUnconstrainedTypeVariable) right.typeVariable.defaultType?.get() else right
+ val leftProper = if (left is PyUnconstrainedTypeVariable) left.typeVariable.defaultType.derefOrUnknown() else left
+ val rightProper = if (right is PyUnconstrainedTypeVariable) right.typeVariable.defaultType.derefOrUnknown() else right
return PyTypeChecker.match(rightProper, leftProper, context)
}
@@ -1676,7 +1677,7 @@ private fun substituteByInferenceVars(
}
private fun substitutePyTypeVarTypes(original: PyType?, inferenceVars: InferenceVariablePool, context: TypeEvalContext): PyType? {
- if (original == null) {
+ if (original.isUnknown) {
return original
}
return PyCloningTypeVisitor.clone(original, object : PyCloningTypeVisitor(context) {
@@ -1707,7 +1708,7 @@ private fun PyType?.isTopType(context: TypeEvalContext): Boolean {
}
private fun PyType?.isBottomType(): Boolean {
- return this == null || this is PyNeverType // Any or Never
+ return this.isAnyOrUnknown || this is PyNeverType // Any or Never
}
private fun PyType?.isOptional(): Boolean {
diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyUnionType.java b/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyUnionType.java
index fa4aca640fc8..f9afe832fc60 100644
--- a/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyUnionType.java
+++ b/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyUnionType.java
@@ -27,6 +27,8 @@ import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
+import static com.jetbrains.python.psi.types.PyTypeUtilKt.isUnknown;
+
public class PyUnionType implements PyUnionLikeType {
@@ -113,7 +115,7 @@ public class PyUnionType implements PyUnionLikeType {
* @return a PyType representing the union, or null if no valid members
*/
public static @Nullable PyType union(@NotNull Collection<@Nullable PyType> members) {
- return unionOrDefault(members, null);
+ return unionOrDefault(members, PyAnyType.getUnknown());
}
/**
@@ -155,8 +157,8 @@ public class PyUnionType implements PyUnionLikeType {
* @see PyUnsafeUnionType
*/
public static @Nullable PyType createWeakType(@Nullable PyType type) {
- if (type == null) {
- return null;
+ if (isUnknown(type)) {
+ return type;
}
else if (type instanceof PyUnionType unionType) {
if (unionType.isWeak()) {
@@ -164,9 +166,9 @@ public class PyUnionType implements PyUnionLikeType {
}
}
if (isStrictSemanticsEnabled()) {
- return PyUnsafeUnionType.unsafeUnion(type, null);
+ return PyUnsafeUnionType.unsafeUnion(type, PyAnyType.getUnknown());
}
- return union(type, null);
+ return union(type, PyAnyType.getUnknown());
}
/**
@@ -196,7 +198,7 @@ public class PyUnionType implements PyUnionLikeType {
*/
@Deprecated
public boolean isWeak() {
- return !isStrictSemanticsEnabled() && myMembers.contains(null);
+ return !isStrictSemanticsEnabled() && myMembers.contains(PyAnyType.getUnknown());
}
/**
@@ -220,7 +222,7 @@ public class PyUnionType implements PyUnionLikeType {
* @return union with excluded types
*/
public @Nullable PyType exclude(@Nullable PyType type, @NotNull TypeEvalContext context) {
- if (type == null) return excludeNull();
+ if (isUnknown(type)) return excludeNull();
final List members = new ArrayList<>();
for (PyType m : getMembers()) {
diff --git a/python/testSrc/com/jetbrains/python/Py3TypeTest.java b/python/testSrc/com/jetbrains/python/Py3TypeTest.java
index 161a3648e8dc..831cc6d673ba 100644
--- a/python/testSrc/com/jetbrains/python/Py3TypeTest.java
+++ b/python/testSrc/com/jetbrains/python/Py3TypeTest.java
@@ -4618,6 +4618,21 @@ public class Py3TypeTest extends PyTestCase {
""");
}
+ @TestFor(issues = "PY-81651")
+ public void testEqWithNewAny() {
+ withNewAnyTypeEnabled(() -> {
+ doTest("Any", """
+ from typing import Any
+
+ class A:
+ def __eq__(self, other) -> Any:
+ return "hello :)"
+
+ expr = A() == 1
+ """);
+ });
+ }
+
@TestFor(issues = "PY-84524")
public void testBuiltinsCallable() {
doTest("(...) -> object", """
diff --git a/python/testSrc/com/jetbrains/python/PyTypingTest.java b/python/testSrc/com/jetbrains/python/PyTypingTest.java
index b9b6981e495a..2ad166bc4ff6 100644
--- a/python/testSrc/com/jetbrains/python/PyTypingTest.java
+++ b/python/testSrc/com/jetbrains/python/PyTypingTest.java
@@ -5,7 +5,6 @@ import com.intellij.idea.TestFor;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
-import com.intellij.openapi.util.registry.Registry;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiLanguageInjectionHost;
import com.intellij.psi.util.PsiTreeUtil;
@@ -6944,6 +6943,64 @@ public class PyTypingTest extends PyTestCase {
});
}
+ public void testTypeVarDefaultAny() {
+ withNewAnyTypeEnabled(() -> {
+ doTest("Any", """
+ from typing import Any
+
+ def f[T=Any]() -> T: ...
+
+ expr = f()
+ """);
+ });
+ }
+
+ public void testUnsolvedTypeVar() {
+ withNewAnyTypeEnabled(() -> {
+ doTest("Unknown", """
+ def f[T]() -> T: ...
+
+ expr = f()
+ """);
+ });
+ }
+
+ public void testPsiStubbedAny() {
+ withNewAnyTypeEnabled(() -> {
+ runWithAdditionalFileInLibDir("other.py", """
+ from typing import Any
+
+ x: Any
+ """, x -> {
+ myFixture.configureByText(PythonFileType.INSTANCE, """
+ from other import x
+
+ expr = x
+ """);
+ final PyExpression expr = myFixture.findElementByText("expr", PyExpression.class);
+ final TypeEvalContext codeAnalysis = TypeEvalContext.codeAnalysis(expr.getProject(), expr.getContainingFile());
+ assertType("Failed in code analysis context", "Any", expr, codeAnalysis);
+ });
+ });
+ }
+
+ public void testPsiStubbedUnknown() {
+ withNewAnyTypeEnabled(() -> {
+ runWithAdditionalFileInLibDir("other.py", """
+ x = asdf
+ """, x -> {
+ myFixture.configureByText(PythonFileType.INSTANCE, """
+ from other import x
+
+ expr = x
+ """);
+ final PyExpression expr = myFixture.findElementByText("expr", PyExpression.class);
+ final TypeEvalContext codeAnalysis = TypeEvalContext.codeAnalysis(expr.getProject(), expr.getContainingFile());
+ assertType("Failed in code analysis context", "Unknown", expr, codeAnalysis);
+ });
+ });
+ }
+
@TestFor(issues = "PY-84430")
public void testQuotedAny() {
fixme("quoted Any", AssertionError.class, "Failed in code analysis context expected:<[Any]> but was:<[Literal[0]]>", () ->
@@ -7007,16 +7064,4 @@ public class PyTypingTest extends PyTestCase {
final TypeEvalContext userInitiated = TypeEvalContext.userInitiated(expr.getProject(), expr.getContainingFile()).withTracing();
assertType("Failed in user initiated context", expectedType, expr, userInitiated);
}
-
- private static void withNewAnyTypeEnabled(@NotNull Runnable test) {
- var key = Registry.get("python.type.any");
- var previousValue = key.asBoolean();
- try {
- key.setValue(true);
- test.run();
- }
- finally {
- key.setValue(previousValue);
- }
- }
}
diff --git a/python/testSrc/com/jetbrains/python/fixtures/PyTestCase.java b/python/testSrc/com/jetbrains/python/fixtures/PyTestCase.java
index c1953ef3a7a5..b6a5f5853ccb 100644
--- a/python/testSrc/com/jetbrains/python/fixtures/PyTestCase.java
+++ b/python/testSrc/com/jetbrains/python/fixtures/PyTestCase.java
@@ -25,6 +25,7 @@ import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.impl.FilePropertyPusher;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.TextRange;
+import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.StandardFileSystems;
import com.intellij.openapi.vfs.VfsUtil;
@@ -677,5 +678,17 @@ public abstract class PyTestCase extends UsefulTestCase {
// the fix-me test passed -> the bug/feature was fixed!
fail("Test " + comment + " was previously failing and was suppressed, but now it passes");
}
+
+ protected static void withNewAnyTypeEnabled(@NotNull Runnable test) {
+ var key = Registry.get("python.type.any");
+ var previousValue = key.asBoolean();
+ try {
+ key.setValue(true);
+ test.run();
+ }
+ finally {
+ key.setValue(previousValue);
+ }
+ }
}