diff --git a/python/python-psi-api/src/com/jetbrains/python/psi/types/PyTypeParameterType.java b/python/python-psi-api/src/com/jetbrains/python/psi/types/PyTypeParameterType.java new file mode 100644 index 000000000000..9bde566a1aa5 --- /dev/null +++ b/python/python-psi-api/src/com/jetbrains/python/psi/types/PyTypeParameterType.java @@ -0,0 +1,82 @@ +// 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.types; + +import com.jetbrains.python.psi.PyQualifiedNameOwner; +import com.jetbrains.python.psi.PyTargetExpression; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Represents an entity in the type system that can be used to parameterize other types making them "generic". + * A typical example of a type parameter is PEP 484 {@code TypeVar} like "T" in the following: + *
{@code
+ *
+ * from typing import TypeVar
+ *
+ * T = TypeVar('T')
+ *
+ * def identity(x: T) -> T:
+ * return x
+ *
+ * }
+ * + * making the type of "identity" parameterized by "T". + * Other examples of type parameters are {@code ParamSpec} and {@code TypeVarTuple}. + *
+ * Declarations using "magical" factories from typing, such as {@code T = TypeVar("T")}, are the most common source of type parameters. + * The corresponding {@link PyTargetExpression} can be retrieved with {@link #getDeclarationElement()}. + * However, they can also come from docstrings or be created dynamically by type providers and, hence, not have a physical declaration. + */ +public interface PyTypeParameterType extends PyType { + /** + * Returns the name of this type parameter, such as "T" for the {@link PyTypeVarType} instance introduced by {@code T = TypeVar("T")}. + */ + @Override + @NotNull String getName(); + + /** + * Normally, a type parameter must be bound to a specific declaration to avoid collisions with other parameters with the same name. + *
+ * For instance, here + *
{@code
+ * from typing import TypeVar
+ *
+ * T = TypeVar('T')
+ *
+ * def min(xs: list[T]) -> T | None:
+ * ...
+ * }
+ * + * "T" is bound to the "min" function definition, and here + *
{@code
+ * from typing import Generic, TypeVar
+ *
+ * T = TypeVar('T')
+ *
+ * class ListOps(Generic[T]):
+ * def min(self, xs: list[T]) -> T | None:
+ * ...
+ * }
+ * + * it is bound to the enclosing class "ListOps". + *
+ * In the following, type parameters "T" of "f" and "g" are unrelated to each other, despite sharing the same name: + *
{@code
+ * from typing import TypeVar
+ *
+ * T = TypeVar('T')
+ *
+ * def f(x: T) -> T:
+ * return g(x)
+ *
+ * def g(x: T) -> T:
+ * return f(x)
+ * }
+ * + * See the section Scoping rules for type variables + * in PEP 484. + *
+ * Results of {@code getScopeOwner()} and {@link #getName()} constitute unique "coordinates" of a given type parameter. + */ + @Nullable PyQualifiedNameOwner getScopeOwner(); +} diff --git a/python/python-psi-api/src/com/jetbrains/python/psi/types/PyTypeVarType.java b/python/python-psi-api/src/com/jetbrains/python/psi/types/PyTypeVarType.java new file mode 100644 index 000000000000..b7d90375e5b6 --- /dev/null +++ b/python/python-psi-api/src/com/jetbrains/python/psi/types/PyTypeVarType.java @@ -0,0 +1,32 @@ +// 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.types; + +import org.jetbrains.annotations.Nullable; + +/** + * Represents a type parameter that should be substituted with a single type during the unification process. + * Normally, it's declared using {@code TypeVar} function from the "typing" module, as in + *
{@code
+ * from typing import TypeVar
+ *
+ * T = TypeVar('T')
+ * }
+ * but can also come from other sources, such as docstrings.
+ */
+public interface PyTypeVarType extends PyTypeParameterType, PyInstantiableType+ * For instance, for the following declaration + *
{@code
+ * from typing import TypeVar
+ *
+ * T = TypeVar('T', bound=list[int])
+ * }
+ * this method should return the type corresponding to the type hint {@code list[int]}.
+ *
+ * See the section Type variables with an upper bound
+ * in PEP 484.
+ */
+ @Nullable PyType getBound();
+}
diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyGenericType.java b/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyGenericType.java
index 676e5d8fefeb..00e0828648ca 100644
--- a/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyGenericType.java
+++ b/python/python-psi-impl/src/com/jetbrains/python/psi/types/PyGenericType.java
@@ -17,7 +17,12 @@ import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Objects;
-public class PyGenericType implements PyType, PyInstantiableType