mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-30 10:20:15 +07:00
PY-53105 PEP 646: Split PyGenericVariadicType into PyUnpackedTupleType and PyTypeVarTupleType
TypeVarTuples, i.e. type parameters, such as *Ts, and unpacked tuples types, i.e. concrete types, such as *tuple[int, ...], are two independent entities in the type system. Keeping them both represented as a single type is confusing and introduces a lot of bookkeeping for accessing their state and filtering out unpacked tuples in every place where a type parameter is expected. For cases where both types are applicable, and we need to distinguish them from regular "non-unpackable" types, PyVariadicType marker interface was introduced. Also, make the API names more consistent with the PEPs terminology: "unbound" unpacked tuple types instead of "homogeneous" unpacked tuple types. GitOrigin-RevId: be77eae46fd78512eaf74d5a9709faacc762e45f
This commit is contained in:
committed by
intellij-monorepo-bot
parent
b0b7d9aacd
commit
15c37a5bad
@@ -0,0 +1,5 @@
|
||||
// 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;
|
||||
|
||||
public interface PyTypeVarTupleType extends PyTypeParameterType, PyVariadicType {
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// 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.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface PyUnpackedTupleType extends PyVariadicType {
|
||||
@NotNull List<PyType> getElementTypes();
|
||||
|
||||
boolean isUnbound();
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
// 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.intellij.psi.PsiElement;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
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;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ApiStatus.Experimental
|
||||
public interface PyVariadicType extends PyType {
|
||||
@Override
|
||||
default boolean isBuiltin() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
default void assertValid(String message) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
default List<? extends RatedResolveResult> resolveMember(@NotNull String name,
|
||||
@Nullable PyExpression location,
|
||||
@NotNull AccessDirection direction,
|
||||
@NotNull PyResolveContext resolveContext) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
default Object[] getCompletionVariants(String completionPrefix, PsiElement location, ProcessingContext context) {
|
||||
return ArrayUtil.EMPTY_OBJECT_ARRAY;
|
||||
}
|
||||
}
|
||||
@@ -965,7 +965,7 @@ public class PyTypingTypeProvider extends PyTypeProviderWithCustomContext<PyTypi
|
||||
if (type instanceof PyParamSpecType paramSpec) {
|
||||
return paramSpec.withScopeOwner(getTypeParameterScope(paramSpec.getName(), typeHint, context)).withTargetExpression(targetExpr);
|
||||
}
|
||||
if (type instanceof PyGenericVariadicType typeVarTuple) {
|
||||
if (type instanceof PyTypeVarTupleTypeImpl typeVarTuple) {
|
||||
return typeVarTuple.withScopeOwner(getTypeParameterScope(typeVarTuple.getName(), typeHint, context)).withTargetExpression(targetExpr);
|
||||
}
|
||||
return type;
|
||||
@@ -1477,7 +1477,7 @@ public class PyTypingTypeProvider extends PyTypeProviderWithCustomContext<PyTypi
|
||||
if (firstArgument instanceof PyStringLiteralExpression) {
|
||||
final String name = ((PyStringLiteralExpression)firstArgument).getStringValue();
|
||||
if (calleeQNames.contains(TYPE_VAR_TUPLE)) {
|
||||
return new PyGenericVariadicType(name);
|
||||
return new PyTypeVarTupleTypeImpl(name);
|
||||
}
|
||||
else {
|
||||
return new PyTypeVarTypeImpl(name, getGenericTypeBound(arguments, context));
|
||||
@@ -1565,7 +1565,7 @@ public class PyTypingTypeProvider extends PyTypeProviderWithCustomContext<PyTypi
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PyType getUnpackedType(@NotNull PsiElement element, @NotNull TypeEvalContext context) {
|
||||
public static PyVariadicType getUnpackedType(@NotNull PsiElement element, @NotNull TypeEvalContext context) {
|
||||
// TODO Add support for Unpacked here
|
||||
if (!(element instanceof PyStarExpression starExpression)) return null;
|
||||
var typeHint = starExpression.getExpression();
|
||||
@@ -1576,10 +1576,10 @@ public class PyTypingTypeProvider extends PyTypeProviderWithCustomContext<PyTypi
|
||||
var expressionType = typeRef.get();
|
||||
|
||||
if (expressionType instanceof PyTupleType tupleType) {
|
||||
return new PyGenericVariadicType("", tupleType.isHomogeneous(), tupleType.getElementTypes());
|
||||
return new PyUnpackedTupleTypeImpl(tupleType.getElementTypes(), tupleType.isHomogeneous());
|
||||
}
|
||||
if (expressionType instanceof PyGenericVariadicType) {
|
||||
return expressionType;
|
||||
if (expressionType instanceof PyTypeVarTupleType typeVarTupleType) {
|
||||
return typeVarTupleType;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -355,9 +355,9 @@ public class PyTypeCheckerInspection extends PyInspection {
|
||||
List<UnfilledPositionalVararg> unfilledPositionalVarargs = new ArrayList<>();
|
||||
for (var unmappedContainer: mapping.getUnmappedContainerParameters()) {
|
||||
PyType containerType = unmappedContainer.getArgumentType(myTypeEvalContext);
|
||||
if (unmappedContainer.getName() == null || !(containerType instanceof PyGenericVariadicType)) continue;
|
||||
if (unmappedContainer.getName() == null || !(containerType instanceof PyVariadicType)) continue;
|
||||
PyType expandedVararg = PyTypeChecker.substitute(containerType, substitutions, myTypeEvalContext);
|
||||
if (!(expandedVararg instanceof PyGenericVariadicType unpackedTuple) || unpackedTuple.isHomogeneous()) continue;
|
||||
if (!(expandedVararg instanceof PyUnpackedTupleType unpackedTuple) || unpackedTuple.isUnbound()) continue;
|
||||
unfilledPositionalVarargs.add(
|
||||
new UnfilledPositionalVararg(unmappedContainer.getName(),
|
||||
PythonDocumentationProvider.getTypeName(expandedVararg, myTypeEvalContext)));
|
||||
@@ -419,9 +419,8 @@ public class PyTypeCheckerInspection extends PyInspection {
|
||||
@NotNull PyTypeChecker.GenericSubstitutions substitutions) {
|
||||
final PyType expected = container.getArgumentType(myTypeEvalContext);
|
||||
|
||||
if (container.isPositionalContainer() && expected instanceof PyGenericVariadicType) {
|
||||
PyGenericVariadicType argumentTypes =
|
||||
PyGenericVariadicType.fromElementTypes(ContainerUtil.map(arguments, myTypeEvalContext::getType));
|
||||
if (container.isPositionalContainer() && expected instanceof PyVariadicType) {
|
||||
PyUnpackedTupleType argumentTypes = PyUnpackedTupleTypeImpl.create(ContainerUtil.map(arguments, myTypeEvalContext::getType));
|
||||
boolean matched = matchParameterAndArgument(expected, argumentTypes, null, substitutions);
|
||||
return ContainerUtil.map(arguments, argument -> {
|
||||
PyType expectedWithSubstitutions = substituteGenerics(expected, substitutions);
|
||||
|
||||
@@ -129,7 +129,7 @@ class PyTypeHintsInspection : PyInspection() {
|
||||
return
|
||||
}
|
||||
|
||||
if (myTypeEvalContext.getType(node) is PyGenericVariadicType) {
|
||||
if (myTypeEvalContext.getType(node) is PyVariadicType) {
|
||||
checkTypeVarTupleUnpacked(node)
|
||||
}
|
||||
|
||||
|
||||
@@ -219,8 +219,8 @@ public final class PyCallableParameterImpl implements PyCallableParameter {
|
||||
// *args: str is equivalent to *args: *tuple[str, ...]
|
||||
// *args: *Ts is equivalent to *args: *tuple[*Ts]
|
||||
// Convert its type to a more general form of an unpacked tuple
|
||||
PyGenericVariadicType unpackedTupleType = tupleType.asUnpackedTupleType();
|
||||
if (unpackedTupleType.isHomogeneous()) {
|
||||
PyUnpackedTupleType unpackedTupleType = tupleType.asUnpackedTupleType();
|
||||
if (unpackedTupleType.isUnbound()) {
|
||||
return unpackedTupleType.getElementTypes().get(0);
|
||||
}
|
||||
return unpackedTupleType;
|
||||
|
||||
@@ -1,185 +0,0 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.jetbrains.python.psi.types;
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
import com.jetbrains.python.psi.AccessDirection;
|
||||
import com.jetbrains.python.psi.PyExpression;
|
||||
import com.jetbrains.python.psi.PyQualifiedNameOwner;
|
||||
import com.jetbrains.python.psi.PyTargetExpression;
|
||||
import com.jetbrains.python.psi.resolve.PyResolveContext;
|
||||
import com.jetbrains.python.psi.resolve.RatedResolveResult;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public final class PyGenericVariadicType implements PyTypeParameterType {
|
||||
private final @NotNull String myName;
|
||||
private final @Nullable PyQualifiedNameOwner myScopeOwner;
|
||||
private final PyTargetExpression myTarget;
|
||||
|
||||
private final @Nullable List<PyType> myElementTypes;
|
||||
private final boolean myIsHomogeneous;
|
||||
|
||||
public PyGenericVariadicType(@NotNull String name) {
|
||||
this(name, false, null);
|
||||
}
|
||||
|
||||
public PyGenericVariadicType(@NotNull String name, boolean isHomogeneous, @Nullable List<PyType> elementTypes) {
|
||||
this(name, null, isHomogeneous, elementTypes, null);
|
||||
}
|
||||
|
||||
private PyGenericVariadicType(@NotNull String name, @Nullable PyTargetExpression target,
|
||||
boolean isHomogeneous, @Nullable List<PyType> elementTypes, @Nullable PyQualifiedNameOwner scopeOwner) {
|
||||
myName = name;
|
||||
myTarget = target;
|
||||
myElementTypes = elementTypes;
|
||||
myIsHomogeneous = isHomogeneous;
|
||||
myScopeOwner = scopeOwner;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PyGenericVariadicType withScopeOwner(@Nullable PyQualifiedNameOwner scopeOwner) {
|
||||
return new PyGenericVariadicType(myName, myTarget, myIsHomogeneous, myElementTypes, scopeOwner);
|
||||
}
|
||||
|
||||
public PyGenericVariadicType withTargetExpression(@Nullable PyTargetExpression targetExpression) {
|
||||
return new PyGenericVariadicType(myName, targetExpression, myIsHomogeneous, myElementTypes, myScopeOwner);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static PyGenericVariadicType fromElementTypes(@NotNull List<PyType> elementTypes) {
|
||||
return new PyGenericVariadicType("", false, elementTypes);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static PyGenericVariadicType homogeneous(@Nullable PyType type) {
|
||||
if (type instanceof PyGenericVariadicType) {
|
||||
throw new IllegalArgumentException("Unpacked tuple of a TypeVarTuple or another unpacked tuple cannot be constructed");
|
||||
}
|
||||
var elementTypes = new ArrayList<PyType>();
|
||||
elementTypes.add(type);
|
||||
return new PyGenericVariadicType("", true, elementTypes);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
if (myElementTypes == null) {
|
||||
return "*" + myName;
|
||||
}
|
||||
else {
|
||||
return "*" + getElementTypesToStr();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable PyQualifiedNameOwner getScopeOwner() {
|
||||
return myScopeOwner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final PyGenericVariadicType type = (PyGenericVariadicType)o;
|
||||
return myName.equals(type.myName) && Objects.equals(getScopeOwner(), type.getScopeOwner()) &&
|
||||
Objects.equals(myElementTypes, type.myElementTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int res = myName.hashCode();
|
||||
if (myElementTypes == null) return res;
|
||||
return res + myElementTypes.hashCode();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getElementTypesToStr() {
|
||||
if (myElementTypes == null) return "";
|
||||
StringBuilder res = new StringBuilder("tuple[");
|
||||
StringUtil.join(myElementTypes, type -> type != null ? type.getName() : "Any", ", ", res);
|
||||
if (isHomogeneous()) {
|
||||
res.append(", ...");
|
||||
}
|
||||
res.append("]");
|
||||
return res.toString();
|
||||
}
|
||||
|
||||
public boolean isHomogeneous() {
|
||||
return isUnpackedTupleType() && myIsHomogeneous;
|
||||
}
|
||||
|
||||
public boolean isUnspecified() {
|
||||
return isHomogeneous() && myElementTypes != null && myElementTypes.size() == 1 && myElementTypes.get(0) == null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PyType getIteratedItemType() {
|
||||
if (myElementTypes == null) return null;
|
||||
return PyUnionType.union(myElementTypes);
|
||||
}
|
||||
|
||||
public @Nullable List<PyType> getElementTypes() {
|
||||
return myElementTypes != null ? Collections.unmodifiableList(myElementTypes) : null;
|
||||
}
|
||||
|
||||
public boolean isUnpackedTupleType() {
|
||||
return myName.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBuiltin() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assertValid(String message) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable List<? extends RatedResolveResult> resolveMember(@NotNull String name,
|
||||
@Nullable PyExpression location,
|
||||
@NotNull AccessDirection direction,
|
||||
@NotNull PyResolveContext resolveContext) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getCompletionVariants(String completionPrefix, PsiElement location, ProcessingContext context) {
|
||||
return ArrayUtil.EMPTY_OBJECT_ARRAY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (myName.isEmpty()) {
|
||||
return "PyGenericVariadicType: " + getElementTypesToStr();
|
||||
}
|
||||
else {
|
||||
String scopeName = myScopeOwner != null ? Objects.requireNonNullElse(myScopeOwner.getQualifiedName(), myScopeOwner.getName()) : null;
|
||||
return "PyGenericVariadicType: " + (scopeName != null ? scopeName + ":" : "") + myName;
|
||||
}
|
||||
}
|
||||
|
||||
public @Nullable PyTupleType asTupleType(@NotNull PsiElement anchor) {
|
||||
if (isUnpackedTupleType()) {
|
||||
if (isHomogeneous()) {
|
||||
return PyTupleType.createHomogeneous(anchor, getElementTypes().get(0));
|
||||
}
|
||||
else {
|
||||
return PyTupleType.create(anchor, getElementTypes());
|
||||
}
|
||||
}
|
||||
else {
|
||||
return PyTupleType.create(anchor, Collections.singletonList(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -124,10 +124,10 @@ public class PyTupleType extends PyClassTypeImpl implements PyCollectionType {
|
||||
return PyUnionType.union(myElementTypes);
|
||||
}
|
||||
|
||||
public @NotNull PyGenericVariadicType asUnpackedTupleType() {
|
||||
public @NotNull PyUnpackedTupleType asUnpackedTupleType() {
|
||||
if (isHomogeneous()) {
|
||||
return PyGenericVariadicType.homogeneous(getElementType(0));
|
||||
return PyUnpackedTupleTypeImpl.createUnbound(getElementType(0));
|
||||
}
|
||||
return PyGenericVariadicType.fromElementTypes(getElementTypes());
|
||||
return PyUnpackedTupleTypeImpl.create(getElementTypes());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,12 +121,12 @@ public final class PyTypeChecker {
|
||||
}
|
||||
}
|
||||
|
||||
if (actual instanceof PyGenericVariadicType genericVariadicType && !genericVariadicType.isUnpackedTupleType() && context.reversedSubstitutions) {
|
||||
return Optional.of(match((PyGenericVariadicType)actual, expected, context));
|
||||
if (actual instanceof PyTypeVarTupleType typeVarTupleType && context.reversedSubstitutions) {
|
||||
return Optional.of(match(typeVarTupleType, expected, context));
|
||||
}
|
||||
|
||||
if (expected instanceof PyGenericVariadicType) {
|
||||
return Optional.of(match((PyGenericVariadicType)expected, actual, context));
|
||||
if (expected instanceof PyVariadicType variadic) {
|
||||
return Optional.of(match(variadic, actual, context));
|
||||
}
|
||||
|
||||
if (actual instanceof PyGenericType && context.reversedSubstitutions) {
|
||||
@@ -270,48 +270,49 @@ public final class PyTypeChecker {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean match(@NotNull PyGenericVariadicType expected, @Nullable PyType actual, @NotNull MatchContext context) {
|
||||
private static boolean match(@NotNull PyVariadicType expected, @Nullable PyType actual, @NotNull MatchContext context) {
|
||||
if (actual == null) {
|
||||
return true;
|
||||
}
|
||||
if (!(actual instanceof PyGenericVariadicType actualVariadic)) {
|
||||
if (!(actual instanceof PyVariadicType actualVariadic)) {
|
||||
return false;
|
||||
}
|
||||
if (expected.isUnpackedTupleType()) {
|
||||
if (expected instanceof PyUnpackedTupleType expectedUnpackedTupleType) {
|
||||
// The actual type is just a TypeVarTuple
|
||||
if (!actualVariadic.isUnpackedTupleType()) {
|
||||
if (!(actualVariadic instanceof PyUnpackedTupleType actualUnpackedTupleType)) {
|
||||
return false;
|
||||
}
|
||||
if (expected.isHomogeneous()) {
|
||||
if (actualVariadic.isHomogeneous()) {
|
||||
return match(expected.getIteratedItemType(), actualVariadic.getIteratedItemType(), context).orElse(false);
|
||||
if (expectedUnpackedTupleType.isUnbound()) {
|
||||
PyType repeatedExpectedType = expectedUnpackedTupleType.getElementTypes().get(0);
|
||||
if (actualUnpackedTupleType.isUnbound()) {
|
||||
return match(repeatedExpectedType, actualUnpackedTupleType.getElementTypes().get(0), context).orElse(false);
|
||||
}
|
||||
else {
|
||||
//noinspection DataFlowIssue
|
||||
return ContainerUtil.all(actualVariadic.getElementTypes(), singleActualType -> match(expected.getIteratedItemType(), singleActualType, context).orElse(false));
|
||||
return ContainerUtil.all(actualUnpackedTupleType.getElementTypes(),
|
||||
singleActualType -> match(repeatedExpectedType, singleActualType, context).orElse(false));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (actualVariadic.isHomogeneous()) {
|
||||
//noinspection DataFlowIssue
|
||||
return ContainerUtil.all(expected.getElementTypes(), singleExpectedType -> match(singleExpectedType, actualVariadic.getIteratedItemType(), context).orElse(false));
|
||||
if (actualUnpackedTupleType.isUnbound()) {
|
||||
PyType repeatedActualType = actualUnpackedTupleType.getElementTypes().get(0);
|
||||
return ContainerUtil.all(expectedUnpackedTupleType.getElementTypes(),
|
||||
singleExpectedType -> match(singleExpectedType, repeatedActualType, context).orElse(false));
|
||||
}
|
||||
else {
|
||||
//noinspection DataFlowIssue
|
||||
return matchTypeParameters(expected.getElementTypes(), actualVariadic.getElementTypes(), context);
|
||||
return matchTypeParameters(expectedUnpackedTupleType.getElementTypes(), actualUnpackedTupleType.getElementTypes(), context);
|
||||
}
|
||||
}
|
||||
}
|
||||
// The expected type is just a TypeVarTuple
|
||||
else {
|
||||
PyGenericVariadicType substitution = context.mySubstitutions.typeVarTuples.get(expected);
|
||||
if (substitution != null && !substitution.isUnspecified()) {
|
||||
PyVariadicType substitution = context.mySubstitutions.typeVarTuples.get(expected);
|
||||
if (substitution != null && !substitution.equals(PyUnpackedTupleTypeImpl.UNSPECIFIED)) {
|
||||
if (expected.equals(actual) || substitution.equals(expected)) {
|
||||
return true;
|
||||
}
|
||||
return context.reversedSubstitutions ? match(actualVariadic, substitution, context) : match(substitution, actualVariadic, context);
|
||||
}
|
||||
context.mySubstitutions.typeVarTuples.put(expected, actualVariadic);
|
||||
context.mySubstitutions.typeVarTuples.put((PyTypeVarTupleType)expected, actualVariadic);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -628,8 +629,8 @@ public final class PyTypeChecker {
|
||||
|
||||
List<PyType> expectedElementTypes = ContainerUtil.map(expectedParameters, cp -> {
|
||||
PyType argType = cp.getArgumentType(context);
|
||||
if (cp.isPositionalContainer() && !(argType instanceof PyGenericVariadicType)) {
|
||||
return PyGenericVariadicType.homogeneous(argType);
|
||||
if (cp.isPositionalContainer() && !(argType instanceof PyVariadicType)) {
|
||||
return PyUnpackedTupleTypeImpl.createUnbound(argType);
|
||||
}
|
||||
return argType;
|
||||
});
|
||||
@@ -745,9 +746,9 @@ public final class PyTypeChecker {
|
||||
if (entry.getKey() instanceof PyGenericType) {
|
||||
result.typeVars.put((PyGenericType)entry.getKey(), entry.getValue());
|
||||
}
|
||||
else if (entry.getKey() instanceof PyGenericVariadicType typeVarTuple) {
|
||||
assert entry.getValue() instanceof PyGenericVariadicType;
|
||||
result.typeVarTuples.put(typeVarTuple, (PyGenericVariadicType)entry.getValue());
|
||||
else if (entry.getKey() instanceof PyTypeVarTupleType typeVarTuple) {
|
||||
assert entry.getValue() instanceof PyVariadicType;
|
||||
result.typeVarTuples.put(typeVarTuple, (PyVariadicType)entry.getValue());
|
||||
}
|
||||
// TODO Handle ParamSpecs here
|
||||
}
|
||||
@@ -758,14 +759,14 @@ public final class PyTypeChecker {
|
||||
List<PyType> definitionTypeParameters = genericDefinitionType.getElementTypes();
|
||||
if (!(classType instanceof PyCollectionType genericType)) {
|
||||
for (PyType typeParameter : definitionTypeParameters) {
|
||||
if (typeParameter instanceof PyGenericVariadicType gvt) {
|
||||
result.typeVarTuples.put(gvt, null);
|
||||
if (typeParameter instanceof PyTypeVarTupleType typeVarTupleType) {
|
||||
result.typeVarTuples.put(typeVarTupleType, null);
|
||||
}
|
||||
else if (typeParameter instanceof PyParamSpecType pst) {
|
||||
result.paramSpecs.put(pst, null);
|
||||
else if (typeParameter instanceof PyParamSpecType paramSpecType) {
|
||||
result.paramSpecs.put(paramSpecType, null);
|
||||
}
|
||||
else if (typeParameter instanceof PyTypeVarType tvt) {
|
||||
result.typeVars.put((PyGenericType)tvt, null);
|
||||
else if (typeParameter instanceof PyTypeVarType typeVarType) {
|
||||
result.typeVars.put((PyGenericType)typeVarType, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -779,9 +780,9 @@ public final class PyTypeChecker {
|
||||
if (typeParameter instanceof PyGenericType) {
|
||||
result.typeVars.put((PyGenericType)typeParameter, typeArgument);
|
||||
}
|
||||
else if (typeParameter instanceof PyGenericVariadicType typeVarTuple) {
|
||||
assert typeArgument instanceof PyGenericVariadicType || typeArgument == null;
|
||||
result.typeVarTuples.put(typeVarTuple, (PyGenericVariadicType)typeArgument);
|
||||
else if (typeParameter instanceof PyTypeVarTupleType typeVarTuple) {
|
||||
assert typeArgument instanceof PyVariadicType || typeArgument == null;
|
||||
result.typeVarTuples.put(typeVarTuple, (PyVariadicType)typeArgument);
|
||||
}
|
||||
else if (typeParameter instanceof PyParamSpecType) {
|
||||
result.getParamSpecs().put((PyParamSpecType)typeParameter, as(typeArgument, PyParamSpecType.class));
|
||||
@@ -945,9 +946,7 @@ public final class PyTypeChecker {
|
||||
@NotNull Generics generics,
|
||||
@NotNull Set<? super PyType> visited) {
|
||||
if (type instanceof PyTypeParameterType typeParameter) {
|
||||
if (!(type instanceof PyGenericVariadicType genericVariadic && genericVariadic.isUnpackedTupleType())) {
|
||||
generics.allTypeParameters.add(typeParameter);
|
||||
}
|
||||
generics.allTypeParameters.add(typeParameter);
|
||||
}
|
||||
if (visited.contains(type)) {
|
||||
return;
|
||||
@@ -956,8 +955,8 @@ public final class PyTypeChecker {
|
||||
if (type instanceof PyGenericType) {
|
||||
generics.typeVars.add((PyGenericType)type);
|
||||
}
|
||||
if (type instanceof PyGenericVariadicType genericVariadic && !genericVariadic.isUnpackedTupleType()) {
|
||||
generics.typeVarTuples.add(genericVariadic);
|
||||
if (type instanceof PyTypeVarTupleType typeVarTupleType) {
|
||||
generics.typeVarTuples.add(typeVarTupleType);
|
||||
}
|
||||
// TODO Filter out PyParamSpecTypes representing actual lists of parameters, not type parameters declared via ParamSpec
|
||||
if (type instanceof PyParamSpecType) {
|
||||
@@ -997,9 +996,8 @@ public final class PyTypeChecker {
|
||||
}
|
||||
collectGenerics(callable.getReturnType(context), context, generics, visited);
|
||||
}
|
||||
else if (type instanceof PyGenericVariadicType genericVariadicType && genericVariadicType.isUnpackedTupleType()) {
|
||||
//noinspection DataFlowIssue
|
||||
for (PyType elementType : genericVariadicType.getElementTypes()) {
|
||||
else if (type instanceof PyUnpackedTupleType unpackedTupleType) {
|
||||
for (PyType elementType : unpackedTupleType.getElementTypes()) {
|
||||
collectGenerics(elementType, context, generics, visited);
|
||||
}
|
||||
}
|
||||
@@ -1010,9 +1008,8 @@ public final class PyTypeChecker {
|
||||
@NotNull TypeEvalContext context,
|
||||
@NotNull Set<PyType> substituting) {
|
||||
PyType substituted = substitute(type, substitutions, context, substituting);
|
||||
if (substituted instanceof PyGenericVariadicType typeVarTuple && typeVarTuple.isUnpackedTupleType() && !typeVarTuple.isHomogeneous()) {
|
||||
//noinspection DataFlowIssue
|
||||
return typeVarTuple.getElementTypes();
|
||||
if (substituted instanceof PyUnpackedTupleType unpackedTupleType && !unpackedTupleType.isUnbound()) {
|
||||
return unpackedTupleType.getElementTypes();
|
||||
}
|
||||
return Collections.singletonList(substituted);
|
||||
}
|
||||
@@ -1033,24 +1030,21 @@ public final class PyTypeChecker {
|
||||
}
|
||||
try {
|
||||
if (hasGenerics(type, context)) {
|
||||
if (type instanceof PyGenericVariadicType genericVariadicType) {
|
||||
if (genericVariadicType.isUnpackedTupleType()) {
|
||||
//noinspection DataFlowIssue
|
||||
return new PyGenericVariadicType("", genericVariadicType.isHomogeneous(),
|
||||
ContainerUtil.flatMap(genericVariadicType.getElementTypes(),
|
||||
t -> substituteExpand(t, substitutions, context, substituting)));
|
||||
if (type instanceof PyUnpackedTupleType unpackedTupleType) {
|
||||
return new PyUnpackedTupleTypeImpl(ContainerUtil.flatMap(unpackedTupleType.getElementTypes(),
|
||||
t -> substituteExpand(t, substitutions, context, substituting)),
|
||||
unpackedTupleType.isUnbound());
|
||||
}
|
||||
if (type instanceof PyTypeVarTupleType typeVarTupleType) {
|
||||
if (!substitutions.typeVarTuples.containsKey(typeVarTupleType)) {
|
||||
return type;
|
||||
}
|
||||
else {
|
||||
if (!substitutions.typeVarTuples.containsKey(genericVariadicType)) {
|
||||
return type;
|
||||
}
|
||||
PyGenericVariadicType substitution = substitutions.typeVarTuples.get(genericVariadicType);
|
||||
if (!genericVariadicType.equals(substitution) && hasGenerics(substitution, context)) {
|
||||
return substitute(substitution, substitutions, context, substituting);
|
||||
}
|
||||
// Replace unknown TypeVarTuples by *tuple[Any, ...] instead of plain Any
|
||||
return substitution == null ? PyGenericVariadicType.homogeneous(null) : substitution;
|
||||
PyVariadicType substitution = substitutions.typeVarTuples.get(typeVarTupleType);
|
||||
if (!typeVarTupleType.equals(substitution) && hasGenerics(substitution, context)) {
|
||||
return substitute(substitution, substitutions, context, substituting);
|
||||
}
|
||||
// Replace unknown TypeVarTuples by *tuple[Any, ...] instead of plain Any
|
||||
return substitution == null ? PyUnpackedTupleTypeImpl.UNSPECIFIED : substitution;
|
||||
}
|
||||
if (type instanceof PyGenericType typeVar) {
|
||||
// Both mappings of kind {T: T2} (and no mapping for T2) and {T: T} mean the substitution process should stop for T.
|
||||
@@ -1250,8 +1244,8 @@ public final class PyTypeChecker {
|
||||
}
|
||||
final List<PyType> actualArgumentTypes = ContainerUtil.map(arguments, context::getType);
|
||||
final PyType expectedArgumentType = container.getArgumentType(context);
|
||||
if (container.isPositionalContainer() && expectedArgumentType instanceof final PyGenericVariadicType genericVariadicType) {
|
||||
return match(genericVariadicType, PyGenericVariadicType.fromElementTypes(actualArgumentTypes),
|
||||
if (container.isPositionalContainer() && expectedArgumentType instanceof PyVariadicType variadicType) {
|
||||
return match(variadicType, PyUnpackedTupleTypeImpl.create(actualArgumentTypes),
|
||||
new MatchContext(context, substitutions, false));
|
||||
}
|
||||
return match(expectedArgumentType, PyUnionType.union(actualArgumentTypes), context, substitutions);
|
||||
@@ -1277,7 +1271,7 @@ public final class PyTypeChecker {
|
||||
for (Map.Entry<PyGenericType, PyType> typeVarMapping : newSubstitutions.typeVars.entrySet()) {
|
||||
substitutions.typeVars.putIfAbsent(typeVarMapping.getKey(), typeVarMapping.getValue());
|
||||
}
|
||||
for (Map.Entry<PyGenericVariadicType, PyGenericVariadicType> typeVarMapping : newSubstitutions.typeVarTuples.entrySet()) {
|
||||
for (Map.Entry<PyTypeVarTupleType, PyVariadicType> typeVarMapping : newSubstitutions.typeVarTuples.entrySet()) {
|
||||
substitutions.typeVarTuples.putIfAbsent(typeVarMapping.getKey(), typeVarMapping.getValue());
|
||||
}
|
||||
for (Map.Entry<PyParamSpecType, PyParamSpecType> paramSpecMapping : newSubstitutions.paramSpecs.entrySet()) {
|
||||
@@ -1466,9 +1460,9 @@ public final class PyTypeChecker {
|
||||
if (pair.getFirst() instanceof PyTypeVarType typeVar) {
|
||||
substitutions.typeVars.put((PyGenericType)typeVar, pair.getSecond());
|
||||
}
|
||||
else if (pair.getFirst() instanceof PyGenericVariadicType typeVarTuple) {
|
||||
assert pair.getSecond() instanceof PyGenericVariadicType;
|
||||
substitutions.typeVarTuples.put(typeVarTuple, (PyGenericVariadicType)pair.getSecond());
|
||||
else if (pair.getFirst() instanceof PyTypeVarTupleType typeVarTuple) {
|
||||
assert pair.getSecond() instanceof PyVariadicType;
|
||||
substitutions.typeVarTuples.put(typeVarTuple, (PyVariadicType)pair.getSecond());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1493,7 +1487,7 @@ public final class PyTypeChecker {
|
||||
private final Set<PyGenericType> typeVars = new LinkedHashSet<>();
|
||||
|
||||
@NotNull
|
||||
private final Set<PyGenericVariadicType> typeVarTuples = new LinkedHashSet<>();
|
||||
private final Set<PyTypeVarTupleType> typeVarTuples = new LinkedHashSet<>();
|
||||
|
||||
@NotNull
|
||||
private final List<PyTypeParameterType> allTypeParameters = new ArrayList<>();
|
||||
@@ -1511,7 +1505,7 @@ public final class PyTypeChecker {
|
||||
return Collections.unmodifiableSet(typeVars);
|
||||
}
|
||||
|
||||
public @NotNull Set<PyGenericVariadicType> getTypeVarTuples() {
|
||||
public @NotNull Set<PyTypeVarTupleType> getTypeVarTuples() {
|
||||
return Collections.unmodifiableSet(typeVarTuples);
|
||||
}
|
||||
|
||||
@@ -1543,7 +1537,7 @@ public final class PyTypeChecker {
|
||||
private final Map<PyGenericType, PyType> typeVars;
|
||||
|
||||
@NotNull
|
||||
private final Map<PyGenericVariadicType, PyGenericVariadicType> typeVarTuples;
|
||||
private final Map<PyTypeVarTupleType, PyVariadicType> typeVarTuples;
|
||||
|
||||
@NotNull
|
||||
private final Map<PyParamSpecType, PyParamSpecType> paramSpecs;
|
||||
@@ -1560,7 +1554,7 @@ public final class PyTypeChecker {
|
||||
}
|
||||
|
||||
GenericSubstitutions(@NotNull Map<PyGenericType, PyType> typeVars,
|
||||
@NotNull Map<PyGenericVariadicType, PyGenericVariadicType> typeVarTuples,
|
||||
@NotNull Map<PyTypeVarTupleType, PyVariadicType> typeVarTuples,
|
||||
@NotNull Map<PyParamSpecType, PyParamSpecType> paramSpecs,
|
||||
@Nullable PyType qualifierType) {
|
||||
this.typeVars = typeVars;
|
||||
@@ -1577,7 +1571,7 @@ public final class PyTypeChecker {
|
||||
return typeVars;
|
||||
}
|
||||
|
||||
public @NotNull Map<PyGenericVariadicType, PyGenericVariadicType> getTypeVarTuples() {
|
||||
public @NotNull Map<PyTypeVarTupleType, PyVariadicType> getTypeVarTuples() {
|
||||
return typeVarTuples;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,10 +20,10 @@ public final class PyTypeParameterMapping {
|
||||
for (Couple<PyType> couple : mapping) {
|
||||
PyType expectedType = couple.getFirst();
|
||||
PyType actualType = couple.getSecond();
|
||||
if (expectedType instanceof PyGenericVariadicType && !(actualType instanceof PyGenericVariadicType || actualType == null)) {
|
||||
if (expectedType instanceof PyVariadicType && !(actualType instanceof PyVariadicType || actualType == null)) {
|
||||
throw new IllegalArgumentException("Variadic type " + expectedType + " cannot be mapped to a non-variadic type " + actualType);
|
||||
}
|
||||
if (!(expectedType instanceof PyGenericVariadicType) && actualType instanceof PyGenericVariadicType) {
|
||||
if (!(expectedType instanceof PyVariadicType) && actualType instanceof PyVariadicType) {
|
||||
throw new IllegalArgumentException("Non-variadic type " + expectedType + " cannot be mapped to a variadic type " + actualType);
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,7 @@ public final class PyTypeParameterMapping {
|
||||
@NotNull List<PyCallableParameter> actualParameters,
|
||||
@NotNull TypeEvalContext context) {
|
||||
List<PyType> flattenedExpectedParameterTypes = flattenUnpackedTupleTypes(expectedParameterTypes);
|
||||
int expectedArity = ContainerUtil.exists(flattenedExpectedParameterTypes, Conditions.instanceOf(PyGenericVariadicType.class))
|
||||
int expectedArity = ContainerUtil.exists(flattenedExpectedParameterTypes, Conditions.instanceOf(PyVariadicType.class))
|
||||
? -1
|
||||
: flattenedExpectedParameterTypes.size();
|
||||
|
||||
@@ -74,14 +74,14 @@ public final class PyTypeParameterMapping {
|
||||
}
|
||||
|
||||
if (positionalVarargArgumentTypes.size() > 1 ||
|
||||
positionalVarargArgumentTypes.size() == 1 && !(positionalVarargArgumentTypes.get(0) instanceof PyGenericVariadicType)) {
|
||||
positionalVarargArgumentTypes.size() == 1 && !(positionalVarargArgumentTypes.get(0) instanceof PyVariadicType)) {
|
||||
requiredPositionalArgumentTypes.addAll(optionalPositionalArgumentTypes);
|
||||
optionalPositionalArgumentTypes.clear();
|
||||
requiredPositionalArgumentTypes.addAll(positionalVarargArgumentTypes);
|
||||
positionalVarargArgumentTypes.clear();
|
||||
}
|
||||
|
||||
int actualArity = ContainerUtil.exists(requiredPositionalArgumentTypes, Conditions.instanceOf(PyGenericVariadicType.class)) ?
|
||||
int actualArity = ContainerUtil.exists(requiredPositionalArgumentTypes, Conditions.instanceOf(PyVariadicType.class)) ?
|
||||
-1 :
|
||||
requiredPositionalArgumentTypes.size();
|
||||
|
||||
@@ -95,7 +95,7 @@ public final class PyTypeParameterMapping {
|
||||
0, Math.min(optionalPositionalArgumentTypes.size(), expectedArity - arityAdjustedActualParameterTypes.size())
|
||||
));
|
||||
if (!positionalVarargArgumentTypes.isEmpty() && expectedArity - arityAdjustedActualParameterTypes.size() > 0) {
|
||||
assert positionalVarargArgumentTypes.size() == 1 && positionalVarargArgumentTypes.get(0) instanceof PyGenericVariadicType;
|
||||
assert positionalVarargArgumentTypes.size() == 1 && positionalVarargArgumentTypes.get(0) instanceof PyVariadicType;
|
||||
arityAdjustedActualParameterTypes.add(positionalVarargArgumentTypes.get(0));
|
||||
}
|
||||
return mapByShape(flattenedExpectedParameterTypes, arityAdjustedActualParameterTypes);
|
||||
@@ -123,12 +123,12 @@ public final class PyTypeParameterMapping {
|
||||
while (expectedTypesDeque.size() != 0 && actualTypesDeque.size() != 0) {
|
||||
PyType leftmostExpected = expectedTypesDeque.peekFirst();
|
||||
// Either a variadic type parameter *Ts or an unbounded unpacked tuple *tuple[int, ...]
|
||||
if (leftmostExpected instanceof PyGenericVariadicType) {
|
||||
if (leftmostExpected instanceof PyVariadicType) {
|
||||
break;
|
||||
}
|
||||
// The leftmost expected type is a regular type
|
||||
PyType leftmostActual = actualTypesDeque.peekFirst();
|
||||
if (leftmostActual instanceof PyGenericVariadicType) {
|
||||
if (leftmostActual instanceof PyVariadicType) {
|
||||
break;
|
||||
}
|
||||
expectedTypesDeque.removeFirst();
|
||||
@@ -138,15 +138,14 @@ public final class PyTypeParameterMapping {
|
||||
|
||||
while (expectedTypesDeque.size() != 0 && actualTypesDeque.size() != 0) {
|
||||
PyType rightmostExpected = expectedTypesDeque.peekLast();
|
||||
if (rightmostExpected instanceof PyGenericVariadicType) {
|
||||
if (rightmostExpected instanceof PyVariadicType) {
|
||||
break;
|
||||
}
|
||||
expectedTypesDeque.removeLast();
|
||||
PyType rightmostActual = actualTypesDeque.peekLast();
|
||||
if (rightmostActual instanceof PyGenericVariadicType rightmostActualVariadic) {
|
||||
if (isUnboundedUnpackedTupleType(rightmostActualVariadic)) {
|
||||
//noinspection DataFlowIssue
|
||||
PyType repeatedActualType = rightmostActualVariadic.getElementTypes().get(0);
|
||||
if (rightmostActual instanceof PyVariadicType rightmostActualVariadic) {
|
||||
if (rightmostActualVariadic instanceof PyUnpackedTupleType unpackedTupleType && unpackedTupleType.isUnbound()) {
|
||||
PyType repeatedActualType = unpackedTupleType.getElementTypes().get(0);
|
||||
rightMappedTypes.add(Couple.of(rightmostExpected, repeatedActualType));
|
||||
}
|
||||
else {
|
||||
@@ -161,12 +160,11 @@ public final class PyTypeParameterMapping {
|
||||
}
|
||||
|
||||
if (expectedTypesDeque.size() != 0 && actualTypesDeque.size() != 0
|
||||
&& !(expectedTypesDeque.peekFirst() instanceof PyGenericVariadicType)
|
||||
&& (actualTypesDeque.peekFirst() instanceof PyGenericVariadicType variadic)) {
|
||||
if (isUnboundedUnpackedTupleType(variadic)) {
|
||||
while (expectedTypesDeque.size() != 0 && !(expectedTypesDeque.peekFirst() instanceof PyGenericVariadicType)) {
|
||||
//noinspection DataFlowIssue
|
||||
PyType repeatedActualType = variadic.getElementTypes().get(0);
|
||||
&& !(expectedTypesDeque.peekFirst() instanceof PyVariadicType)
|
||||
&& (actualTypesDeque.peekFirst() instanceof PyVariadicType variadic)) {
|
||||
if (variadic instanceof PyUnpackedTupleType actualUnpackedTupleType && actualUnpackedTupleType.isUnbound()) {
|
||||
while (expectedTypesDeque.size() != 0 && !(expectedTypesDeque.peekFirst() instanceof PyVariadicType)) {
|
||||
PyType repeatedActualType = actualUnpackedTupleType.getElementTypes().get(0);
|
||||
leftMappedTypes.add(Couple.of(expectedTypesDeque.peekFirst(), repeatedActualType));
|
||||
expectedTypesDeque.removeFirst();
|
||||
}
|
||||
@@ -184,18 +182,18 @@ public final class PyTypeParameterMapping {
|
||||
if (expectedTypesDeque.size() == 0) {
|
||||
boolean allActualTypesMatched = actualTypesDeque.size() == 0;
|
||||
boolean onlySingleActualVariadicLeft = actualTypesDeque.size() == 1 &&
|
||||
actualTypesDeque.peekFirst() instanceof PyGenericVariadicType;
|
||||
actualTypesDeque.peekFirst() instanceof PyVariadicType;
|
||||
sizeMismatch = !(allActualTypesMatched || onlySingleActualVariadicLeft);
|
||||
}
|
||||
else if (expectedTypesDeque.size() == 1) {
|
||||
PyType onlyLeftExpectedType = expectedTypesDeque.peekFirst();
|
||||
if (onlyLeftExpectedType instanceof PyGenericVariadicType) {
|
||||
if (actualTypesDeque.size() == 1 && actualTypesDeque.peekFirst() instanceof PyGenericVariadicType variadicType) {
|
||||
if (onlyLeftExpectedType instanceof PyVariadicType) {
|
||||
if (actualTypesDeque.size() == 1 && actualTypesDeque.peekFirst() instanceof PyVariadicType variadicType) {
|
||||
centerMappedTypes.add(Couple.of(onlyLeftExpectedType, variadicType));
|
||||
}
|
||||
else {
|
||||
List<PyType> unmatchedActualTypes = actualTypesDeque.toList();
|
||||
centerMappedTypes.add(Couple.of(onlyLeftExpectedType, PyGenericVariadicType.fromElementTypes(unmatchedActualTypes)));
|
||||
centerMappedTypes.add(Couple.of(onlyLeftExpectedType, PyUnpackedTupleTypeImpl.create(unmatchedActualTypes)));
|
||||
}
|
||||
sizeMismatch = false;
|
||||
}
|
||||
@@ -228,21 +226,13 @@ public final class PyTypeParameterMapping {
|
||||
|
||||
private static @NotNull List<PyType> flattenUnpackedTupleTypes(List<? extends PyType> types) {
|
||||
return ContainerUtil.flatMap(types, type -> {
|
||||
if (type instanceof PyGenericVariadicType typeVarTuple && isBoundedUnpackedTupleType(typeVarTuple)) {
|
||||
return flattenUnpackedTupleTypes(typeVarTuple.getElementTypes());
|
||||
if (type instanceof PyUnpackedTupleType unpackedTupleType && !unpackedTupleType.isUnbound()) {
|
||||
return flattenUnpackedTupleTypes(unpackedTupleType.getElementTypes());
|
||||
}
|
||||
return Collections.singletonList(type);
|
||||
});
|
||||
}
|
||||
|
||||
private static boolean isBoundedUnpackedTupleType(@NotNull PyGenericVariadicType typeVarTupleType) {
|
||||
return typeVarTupleType.isUnpackedTupleType() && !typeVarTupleType.isHomogeneous();
|
||||
}
|
||||
|
||||
private static boolean isUnboundedUnpackedTupleType(@NotNull PyGenericVariadicType typeVarTupleType) {
|
||||
return typeVarTupleType.isUnpackedTupleType() && typeVarTupleType.isHomogeneous();
|
||||
}
|
||||
|
||||
public @NotNull List<Couple<PyType>> getMappedTypes() {
|
||||
return Collections.unmodifiableList(myMappedTypes);
|
||||
}
|
||||
|
||||
@@ -90,8 +90,11 @@ public final class PyTypeUtil {
|
||||
|
||||
@Nullable
|
||||
public static PyTupleType toPositionalContainerType(@NotNull PsiElement anchor, @Nullable PyType elementType) {
|
||||
if (elementType instanceof PyGenericVariadicType genericVariadicType) {
|
||||
return genericVariadicType.asTupleType(anchor);
|
||||
if (elementType instanceof PyUnpackedTupleTypeImpl unpackedTupleType) {
|
||||
return unpackedTupleType.asTupleType(anchor);
|
||||
}
|
||||
else if (elementType instanceof PyTypeVarTupleType) {
|
||||
return PyTupleType.create(anchor, Collections.singletonList(elementType));
|
||||
}
|
||||
return PyTupleType.createHomogeneous(anchor, elementType);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
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;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public final class PyTypeVarTupleTypeImpl implements PyTypeVarTupleType {
|
||||
private final @NotNull String myName;
|
||||
private final @Nullable PyQualifiedNameOwner myScopeOwner;
|
||||
private final @Nullable PyTargetExpression myTarget;
|
||||
|
||||
public PyTypeVarTupleTypeImpl(@NotNull String name) {
|
||||
this(name, null, null);
|
||||
}
|
||||
|
||||
private PyTypeVarTupleTypeImpl(@NotNull String name, @Nullable PyTargetExpression target, @Nullable PyQualifiedNameOwner scopeOwner) {
|
||||
myName = name;
|
||||
myTarget = target;
|
||||
myScopeOwner = scopeOwner;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PyTypeVarTupleTypeImpl withScopeOwner(@Nullable PyQualifiedNameOwner scopeOwner) {
|
||||
return new PyTypeVarTupleTypeImpl(myName, myTarget, scopeOwner);
|
||||
}
|
||||
|
||||
public PyTypeVarTupleTypeImpl withTargetExpression(@Nullable PyTargetExpression targetExpression) {
|
||||
return new PyTypeVarTupleTypeImpl(myName, targetExpression, myScopeOwner);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return "*" + myName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable PyQualifiedNameOwner getScopeOwner() {
|
||||
return myScopeOwner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final PyTypeVarTupleTypeImpl type = (PyTypeVarTupleTypeImpl)o;
|
||||
return myName.equals(type.myName) && Objects.equals(getScopeOwner(), type.getScopeOwner());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(myName, myScopeOwner);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String scopeName = myScopeOwner != null ? Objects.requireNonNullElse(myScopeOwner.getQualifiedName(), myScopeOwner.getName()) : null;
|
||||
return "PyGenericVariadicType: " + (scopeName != null ? scopeName + ":" : "") + myName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package com.jetbrains.python.psi.types;
|
||||
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public final class PyUnpackedTupleTypeImpl implements PyUnpackedTupleType {
|
||||
public static final PyUnpackedTupleType UNSPECIFIED = new PyUnpackedTupleTypeImpl(Collections.singletonList(null), true);
|
||||
|
||||
private final List<PyType> myElementTypes;
|
||||
private final boolean myIsHomogeneous;
|
||||
|
||||
public PyUnpackedTupleTypeImpl(@NotNull List<PyType> elementTypes, boolean isUnbound) {
|
||||
if (isUnbound) {
|
||||
if (elementTypes.size() != 1) {
|
||||
throw new IllegalArgumentException("Unbounded unpacked tuple type can have only one type parameter");
|
||||
}
|
||||
if (elementTypes.get(0) instanceof PyVariadicType) {
|
||||
throw new IllegalArgumentException("Unbounded unpacked tuple type of a TypeVarTuple or another unpacked tuple type is now allowed");
|
||||
}
|
||||
}
|
||||
myElementTypes = new ArrayList<>(elementTypes);
|
||||
myIsHomogeneous = isUnbound;
|
||||
}
|
||||
|
||||
public static @NotNull PyUnpackedTupleType create(@NotNull List<PyType> elementTypes) {
|
||||
return new PyUnpackedTupleTypeImpl(elementTypes, false);
|
||||
}
|
||||
|
||||
public static @NotNull PyUnpackedTupleType createUnbound(@Nullable PyType type) {
|
||||
return new PyUnpackedTupleTypeImpl(Collections.singletonList(type), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getName() {
|
||||
StringBuilder res = new StringBuilder("*tuple[");
|
||||
StringUtil.join(myElementTypes, type -> type != null ? type.getName() : "Any", ", ", res);
|
||||
if (isUnbound()) {
|
||||
res.append(", ...");
|
||||
}
|
||||
res.append("]");
|
||||
return res.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull List<PyType> getElementTypes() {
|
||||
return Collections.unmodifiableList(myElementTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnbound() {
|
||||
return myIsHomogeneous;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
PyUnpackedTupleTypeImpl type = (PyUnpackedTupleTypeImpl)o;
|
||||
return myIsHomogeneous == type.myIsHomogeneous && Objects.equals(myElementTypes, type.myElementTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(myElementTypes, myIsHomogeneous);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PyUnpackedTupleType: " + getName();
|
||||
}
|
||||
|
||||
public @Nullable PyTupleType asTupleType(@NotNull PsiElement anchor) {
|
||||
if (isUnbound()) {
|
||||
return PyTupleType.createHomogeneous(anchor, getElementTypes().get(0));
|
||||
}
|
||||
else {
|
||||
return PyTupleType.create(anchor, getElementTypes());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user