PY-78235 PyAnyType

GitOrigin-RevId: cac1389d7f20e8054223e07a0bf3f86b7b3c5b51
This commit is contained in:
Morgan Bartholomew
2026-02-16 02:48:40 +00:00
committed by intellij-monorepo-bot
parent 5f035ba041
commit c028889a56
20 changed files with 129 additions and 76 deletions
@@ -243,7 +243,8 @@ public final @NonNls class PyNames {
public static final String NOT_IMPLEMENTED_ERROR = "NotImplementedError";
public static final @NlsSafe String UNKNOWN_TYPE = "Any";
public static final @NlsSafe String ANY_TYPE = "Any";
public static final @NlsSafe String UNKNOWN_TYPE = "Unknown";
public static final @NlsSafe String UNNAMED_ELEMENT = "<unnamed>";
@@ -0,0 +1,41 @@
// 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 com.intellij.psi.PsiElement
import com.intellij.util.ProcessingContext
import com.jetbrains.python.PyNames
import com.jetbrains.python.psi.AccessDirection
import com.jetbrains.python.psi.PyExpression
import com.jetbrains.python.psi.resolve.PyResolveContext
import com.jetbrains.python.psi.resolve.RatedResolveResult
import org.jetbrains.annotations.ApiStatus
@ApiStatus.Experimental
class PyAnyType private constructor(override val name: String) : PyType {
override fun resolveMember(
name: String,
location: PyExpression?,
direction: AccessDirection,
resolveContext: PyResolveContext,
): List<RatedResolveResult> {
return emptyList()
}
override fun getCompletionVariants(completionPrefix: String?, location: PsiElement, context: ProcessingContext): Array<Any> {
return emptyArray()
}
override val isBuiltin: Boolean = false
override fun assertValid(message: String?) {
}
override fun <T> acceptTypeVisitor(visitor: PyTypeVisitor<T>): T? =
if (this === Any) visitor.visitAnyType()
else visitor.visitUnknownType()
companion object {
val Any: PyAnyType = PyAnyType(PyNames.ANY_TYPE)
val Unknown: PyAnyType = PyAnyType(PyNames.UNKNOWN_TYPE)
}
}
@@ -80,14 +80,14 @@ public interface PyCallableType extends PyType {
builder.append(name);
builder.append(": ");
}
builder.append(type != null ? type.getName() : PyNames.UNKNOWN_TYPE);
builder.append(type != null ? type.getName() : PyNames.ANY_TYPE);
return builder.toString();
}
return PyNames.UNKNOWN_TYPE;
return PyNames.ANY_TYPE;
},
", ") :
"...",
returnType != null ? returnType.getName() : PyNames.UNKNOWN_TYPE);
returnType != null ? returnType.getName() : PyNames.ANY_TYPE);
}
default @Nullable PyCallable getCallable() {
@@ -64,7 +64,7 @@ interface PyType {
* @param context to share state between nested invocations
* @return completion variants good for [com.intellij.psi.PsiReference.getVariants] return value.
*/
fun getCompletionVariants(completionPrefix: String?, location: PsiElement, context: ProcessingContext): Array<out @JvmWildcard Any>
fun getCompletionVariants(completionPrefix: String?, location: PsiElement, context: ProcessingContext): Array<out Any>
@get:NlsSafe
val name: @NlsSafe String?
@@ -1,85 +1,93 @@
// Copyright 2000-2024 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;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
package com.jetbrains.python.psi.types
import org.jetbrains.annotations.ApiStatus
/**
* Similarly to {@link com.intellij.psi.PsiElementVisitor}, implements double dispatching for the {@link PyType} hierarchy.
* <p>
* Because the "unknown" type is historically represented as {@code null} in the type system, {@code PyTypeVisitor.visitPyType(type, visitor)}
* should be used instead of direct {@code type.acceptTypeVisitor(visitor)} to properly account for possible {@code null} values.
* <p>
* 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 <tt>intellij.python.psi</tt> module.
* Most actual implementations should extend {@link PyTypeVisitorExt}.
* <p>
* There are helper {@link PyRecursiveTypeVisitor} and {@link PyCloningTypeVisitor} for recursive type
* 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(PyTypeVisitor)
* @see #visit(PyType, PyTypeVisitor)
* @see #visitUnknownType()
*
* @see PyType.acceptTypeVisitor
* @see .visit
* @see .visitUnknownType
*/
@ApiStatus.Experimental
public abstract class PyTypeVisitor<T> {
/**
* Use this method instead of {@link PyType#acceptTypeVisitor(PyTypeVisitor)} to take into account
* "unknown" {@code null} types, for which {@link #visitUnknownType()} should be called.
*/
public static <T> T visit(@Nullable PyType type, @NotNull PyTypeVisitor<T> visitor) {
return type == null ? visitor.visitUnknownType() : type.acceptTypeVisitor(visitor);
abstract class PyTypeVisitor<T> {
open fun visitPyType(type: PyType): T? {
return null
}
public T visitPyType(@NotNull PyType type) {
return null;
open fun visitPyClassType(classType: PyClassType): T? {
return visitPyClassLikeType(classType)
}
public T visitPyClassType(@NotNull PyClassType classType) {
return visitPyClassLikeType(classType);
}
public T visitPyClassLikeType(@NotNull PyClassLikeType classLikeType) {
open fun visitPyClassLikeType(classLikeType: PyClassLikeType): T? {
// Don't treat PyClassLikeType as PyCallableType. It's usually not what a visitor's user expects.
return visitPyType(classLikeType);
return visitPyType(classLikeType)
}
public T visitPyFunctionType(@NotNull PyFunctionType functionType) {
return visitPyCallableType(functionType);
open fun visitPyFunctionType(functionType: PyFunctionType): T? {
return visitPyCallableType(functionType)
}
public T visitPyCallableType(@NotNull PyCallableType callableType) {
return visitPyType(callableType);
open fun visitPyCallableType(callableType: PyCallableType): T? {
return visitPyType(callableType)
}
public T visitPyTypeVarType(@NotNull PyTypeVarType typeVarType) {
return visitPyTypeParameterType(typeVarType);
open fun visitPyTypeVarType(typeVarType: PyTypeVarType): T? {
return visitPyTypeParameterType(typeVarType)
}
public T visitPyTypeVarTupleType(@NotNull PyTypeVarTupleType typeVarTupleType) {
return visitPyTypeParameterType(typeVarTupleType);
open fun visitPyTypeVarTupleType(typeVarTupleType: PyTypeVarTupleType): T? {
return visitPyTypeParameterType(typeVarTupleType)
}
public T visitPyTypeParameterType(@NotNull PyTypeParameterType typeParameterType) {
return visitPyType(typeParameterType);
open fun visitPyTypeParameterType(typeParameterType: PyTypeParameterType): T? {
return visitPyType(typeParameterType)
}
public T visitPyUnpackedTupleType(@NotNull PyUnpackedTupleType unpackedTupleType) {
return visitPyType(unpackedTupleType);
open fun visitPyUnpackedTupleType(unpackedTupleType: PyUnpackedTupleType): T? {
return visitPyType(unpackedTupleType)
}
public T visitPyCallableParameterListType(@NotNull PyCallableParameterListType callableParameterListType) {
return visitPyType(callableParameterListType);
open fun visitPyCallableParameterListType(callableParameterListType: PyCallableParameterListType): T? {
return visitPyType(callableParameterListType)
}
public T visitPyNeverType(@NotNull PyNeverType neverType) {
return visitPyType(neverType);
open fun visitPyNeverType(neverType: PyNeverType): T? {
return visitPyType(neverType)
}
public T visitUnknownType() {
return null;
open fun visitAnyType(): T? {
return null
}
open fun visitUnknownType(): T? {
return null
}
companion object {
/**
* Use this method instead of [PyType.acceptTypeVisitor] to take into account
* "unknown" `null` types, for which [.visitUnknownType] should be called.
*/
@JvmStatic
fun <T> visit(type: PyType?, visitor: PyTypeVisitor<T>): T? =
if (type == null) visitor.visitUnknownType() else type.acceptTypeVisitor(visitor)
}
}
@@ -220,7 +220,7 @@ public abstract class PyTypeRenderer extends PyTypeVisitorExt<@NotNull HtmlChunk
}
@Override
public @NotNull HtmlChunk visitPyIntersectionType(com.jetbrains.python.psi.types.@NotNull PyIntersectionType intersectionType) {
public @NotNull HtmlChunk visitPyIntersectionType(@NotNull PyIntersectionType intersectionType) {
// There is no way to represent intersections through the standard type hints at the moment
return visitUnknownType();
}
@@ -465,9 +465,15 @@ public abstract class PyTypeRenderer extends PyTypeVisitorExt<@NotNull HtmlChunk
return result.toFragment();
}
@Override
public HtmlChunk visitAnyType() {
return HtmlChunk.raw(isRenderingFqn() ? PyTypingTypeProvider.ANY : PyNames.ANY_TYPE); //NON-NLS
}
@Override
public HtmlChunk visitUnknownType() {
return HtmlChunk.raw(isRenderingFqn() ? "typing.Any" : "Any"); //NON-NLS
// TODO: show "Unknown" instead of "typing.Any" when we convert to it
return visitAnyType();
}
@Override
@@ -533,10 +539,7 @@ public abstract class PyTypeRenderer extends PyTypeVisitorExt<@NotNull HtmlChunk
case ", " -> {
yield styled(separator, PyHighlighter.PY_COMMA);
}
case " | " -> {
yield styled(separator, PyHighlighter.PY_OPERATION_SIGN);
}
case " & " -> {
case " | ", " & " -> {
yield styled(separator, PyHighlighter.PY_OPERATION_SIGN);
}
default -> {
@@ -115,7 +115,7 @@ public final class PyDocstringTypesInspection extends PyInspection {
return type.getName();
}
else {
return PyNames.UNKNOWN_TYPE;
return PyNames.ANY_TYPE;
}
}
@@ -25,7 +25,7 @@ public final class PyCallableParameterListTypeImpl implements PyCallableParamete
return String.format("[%s]",
StringUtil.join(myParameters, param -> {
PyType type = param.getType(context);
return type != null ? type.getName() : PyNames.UNKNOWN_TYPE;
return type != null ? type.getName() : PyNames.ANY_TYPE;
},
", "));
}
@@ -6,7 +6,7 @@ package com.jetbrains.python.psi.types
class PyConcatenateType(val firstTypes: List<PyType?>, val paramSpec: PyParamSpecType?) : PyCallableParameterVariadicType {
override val name: String = "Concatenate(${firstTypes.joinToString { it?.name ?: "Any" }}, ${paramSpec?.name ?: "..."})"
override fun <T> acceptTypeVisitor(visitor: PyTypeVisitor<T>): T {
override fun <T> acceptTypeVisitor(visitor: PyTypeVisitor<T>): T? {
if (visitor is PyTypeVisitorExt) {
return visitor.visitPyConcatenateType(this)
}
@@ -41,6 +41,6 @@ public final class PyDynamicallyEvaluatedType extends PyUnionType {
@Override
public String getName() {
PyType res = excludeNull();
return res != null ? res.getName() : PyNames.UNKNOWN_TYPE;
return res != null ? res.getName() : PyNames.ANY_TYPE;
}
}
@@ -51,7 +51,7 @@ class PyIntersectionType private constructor(members: Collection<PyType?>) : PyT
}
}
override fun <T> acceptTypeVisitor(visitor: PyTypeVisitor<T>): T {
override fun <T> acceptTypeVisitor(visitor: PyTypeVisitor<T>): T? {
if (visitor is PyTypeVisitorExt<T>) {
return visitor.visitPyIntersectionType(this)
}
@@ -33,7 +33,7 @@ class PyLiteralStringType private constructor(val cls: PyClass) : PyClassTypeImp
return Objects.hash(super.hashCode(), cls)
}
override fun <T> acceptTypeVisitor(visitor: PyTypeVisitor<T>): T {
override fun <T> acceptTypeVisitor(visitor: PyTypeVisitor<T>): T? {
if (visitor is PyTypeVisitorExt) {
return visitor.visitPyLiteralStringType(this)
}
@@ -52,7 +52,7 @@ class PyLiteralType private constructor(cls: PyClass, val expression: PyExpressi
override fun hashCode(): Int = 31 * pyClass.hashCode()
override fun <T> acceptTypeVisitor(visitor: PyTypeVisitor<T>): T {
override fun <T> acceptTypeVisitor(visitor: PyTypeVisitor<T>): T? {
if (visitor is PyTypeVisitorExt) {
return visitor.visitPyLiteralType(this)
}
@@ -88,7 +88,7 @@ class PyNarrowedType private constructor(
}
}
override fun <T> acceptTypeVisitor(visitor: PyTypeVisitor<T>): T {
override fun <T> acceptTypeVisitor(visitor: PyTypeVisitor<T>): T? {
if (visitor is PyTypeVisitorExt) {
return visitor.visitPyNarrowedType(this)
}
@@ -56,7 +56,7 @@ public class PyTupleType extends PyClassTypeImpl implements PyCollectionType {
}
private static @Nullable String getTypeName(@Nullable PyType type) {
return type == null ? PyNames.UNKNOWN_TYPE : type.getName();
return type == null ? PyNames.ANY_TYPE : type.getName();
}
@Override
@@ -1269,12 +1269,12 @@ object PyTypeChecker {
generics: GenericsImpl,
) {
PyRecursiveTypeVisitor.traverse(type, context, object : PyTypeTraverser() {
override fun visitPyTypeVarType(typeVarType: PyTypeVarType): PyRecursiveTypeVisitor.Traversal {
override fun visitPyTypeVarType(typeVarType: PyTypeVarType): PyRecursiveTypeVisitor.Traversal? {
generics.typeVars.add(typeVarType)
return super.visitPyTypeVarType(typeVarType)
}
override fun visitPyTypeVarTupleType(typeVarTupleType: PyTypeVarTupleType): PyRecursiveTypeVisitor.Traversal {
override fun visitPyTypeVarTupleType(typeVarTupleType: PyTypeVarTupleType): PyRecursiveTypeVisitor.Traversal? {
generics.typeVarTuples.add(typeVarTupleType)
return super.visitPyTypeVarTupleType(typeVarTupleType)
}
@@ -546,7 +546,7 @@ public final class PyTypeParser {
final String name = token.getText().toString();
final TextRange range = token.getRange();
if (PyNames.UNKNOWN_TYPE.equals(name)) {
if (PyNames.ANY_TYPE.equals(name)) {
return EMPTY_RESULT;
}
else if (PyNames.NONE.equals(name)) {
@@ -318,7 +318,7 @@ class PyTypedDictType(
val hasErrors: Boolean get() = valueTypeErrors.isNotEmpty() || missingKeys.isNotEmpty() || extraKeys.isNotEmpty()
}
override fun <T> acceptTypeVisitor(visitor: PyTypeVisitor<T>): T {
override fun <T> acceptTypeVisitor(visitor: PyTypeVisitor<T>): T? {
if (visitor is PyTypeVisitorExt) {
return visitor.visitPyTypedDictType(this)
}
@@ -96,7 +96,7 @@ class PyTypingNewType(
return 31 * classType.hashCode() + name.hashCode()
}
override fun <T> acceptTypeVisitor(visitor: PyTypeVisitor<T>): T {
override fun <T> acceptTypeVisitor(visitor: PyTypeVisitor<T>): T? {
if (visitor is PyTypeVisitorExt) {
return visitor.visitPyTypingNewType(this)
}
@@ -91,7 +91,7 @@ class PyUnsafeUnionType private constructor(members: Collection<PyType?>) : PyTy
}
}
override fun <T> acceptTypeVisitor(visitor: PyTypeVisitor<T>): T {
override fun <T> acceptTypeVisitor(visitor: PyTypeVisitor<T>): T? {
if (visitor is PyTypeVisitorExt<T>) {
return visitor.visitPyUnsafeUnionType(this)
}