PY-59241 Extract PyTypeVarType and PyTypeParameter interfaces, deprecate PyGenericType

Existing usages haven't been updated yet not to hinder the upcoming integration
of TypeVarTuple (PY-53105) and LiteralString (PY-58857) support.

GitOrigin-RevId: 16aafd07edfdc98dee0240dce7cd3383b5eb0b00
This commit is contained in:
Mikhail Golubev
2023-03-06 23:31:58 +00:00
committed by intellij-monorepo-bot
parent f8d597af33
commit fb5a3a200a
4 changed files with 138 additions and 5 deletions
@@ -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:
* <pre>{@code
*
* from typing import TypeVar
*
* T = TypeVar('T')
*
* def identity(x: T) -> T:
* return x
*
* }</pre>
* <p>
* making the type of "identity" parameterized by "T".
* Other examples of type parameters are {@code ParamSpec} and {@code TypeVarTuple}.
* <p>
* 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.
* <p>
* For instance, here
* <pre>{@code
* from typing import TypeVar
*
* T = TypeVar('T')
*
* def min(xs: list[T]) -> T | None:
* ...
* }</pre>
* <p>
* "T" is bound to the "min" function definition, and here
* <pre>{@code
* from typing import Generic, TypeVar
*
* T = TypeVar('T')
*
* class ListOps(Generic[T]):
* def min(self, xs: list[T]) -> T | None:
* ...
* }</pre>
* <p>
* it is bound to the enclosing class "ListOps".
* <p>
* In the following, type parameters "T" of "f" and "g" are unrelated to each other, despite sharing the same name:
* <pre>{@code
* from typing import TypeVar
*
* T = TypeVar('T')
*
* def f(x: T) -> T:
* return g(x)
*
* def g(x: T) -> T:
* return f(x)
* }</pre>
* <p>
* See the section <a href="https://peps.python.org/pep-0484/#scoping-rules-for-type-variables">Scoping rules for type variables</a>
* in PEP 484.
* <p>
* Results of {@code getScopeOwner()} and {@link #getName()} constitute unique "coordinates" of a given type parameter.
*/
@Nullable PyQualifiedNameOwner getScopeOwner();
}
@@ -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
* <pre>{@code
* from typing import TypeVar
*
* T = TypeVar('T')
* }</pre>
* but can also come from other sources, such as docstrings.
*/
public interface PyTypeVarType extends PyTypeParameterType, PyInstantiableType<PyTypeVarType> {
/**
* Returns the upper bound for this type parameter if it was specified.
* <p>
* For instance, for the following declaration
* <pre>{@code
* from typing import TypeVar
*
* T = TypeVar('T', bound=list[int])
* }</pre>
* this method should return the type corresponding to the type hint {@code list[int]}.
* <p>
* See the section <a href="https://peps.python.org/pep-0484/#type-variables-with-an-upper-bound">Type variables with an upper bound</a>
* in PEP 484.
*/
@Nullable PyType getBound();
}
@@ -17,7 +17,12 @@ import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Objects;
public class PyGenericType implements PyType, PyInstantiableType<PyGenericType> {
/**
* @deprecated Use {@link PyTypeVarType} and {@link PyTypeVarTypeImpl} instead.
* See <a href="https://youtrack.jetbrains.com/issue/PY-59241">PY-59241</a> for the reasoning and transition plan.
*/
@Deprecated
public class PyGenericType implements PyTypeVarType {
@NotNull private final String myName;
@Nullable private final PyType myBound;
private final boolean myIsDefinition;
@@ -126,8 +131,8 @@ public class PyGenericType implements PyType, PyInstantiableType<PyGenericType>
return "PyGenericType: " + (scopeName != null ? scopeName + ":" : "") + getName();
}
@Nullable
public PyType getBound() {
@Override
public @Nullable PyType getBound() {
return myBound;
}
@@ -136,8 +141,8 @@ public class PyGenericType implements PyType, PyInstantiableType<PyGenericType>
return myIsDefinition;
}
@Nullable
public PyQualifiedNameOwner getScopeOwner() {
@Override
public @Nullable PyQualifiedNameOwner getScopeOwner() {
return myScopeOwner;
}
@@ -0,0 +1,14 @@
package com.jetbrains.python.psi.types;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public final class PyTypeVarTypeImpl extends PyGenericType {
public PyTypeVarTypeImpl(@NotNull String name, @Nullable PyType bound) {
super(name, bound);
}
public PyTypeVarTypeImpl(@NotNull String name, @Nullable PyType bound, boolean isDefinition) {
super(name, bound, isDefinition);
}
}