mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-77538 Extract PyPositionalVariadicType marker interface
that indicates types compatible with PyTypeVarTupleType: PyTypeVarTupleType and PyUnpackedTupleType. It will allow introducing a counterpart interface for types compatible with PyParamSpecType. GitOrigin-RevId: 0d5c77dd21d2bc7a21b246cfbd951cdd096918e9
This commit is contained in:
committed by
intellij-monorepo-bot
parent
8b87ae9d16
commit
816845add5
+17
@@ -0,0 +1,17 @@
|
||||
// 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.ApiStatus;
|
||||
|
||||
|
||||
/**
|
||||
* Two variants of such types described in <a href="https://peps.python.org/pep-0646/">PEP 646 – Variadic Generics</a> are
|
||||
* TypeVarTuples and unpacked tuple types.
|
||||
*
|
||||
* @see PyTypeVarTupleType
|
||||
* @see PyUnpackedTupleType
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
public interface PyPositionalVariadicType extends PyVariadicType {
|
||||
|
||||
}
|
||||
@@ -23,5 +23,5 @@ package com.jetbrains.python.psi.types;
|
||||
* @see <a href="https://peps.python.org/pep-0646/#type-variable-tuples">PEP 646 – Variadic Generics</a>
|
||||
* @see PyUnpackedTupleType
|
||||
*/
|
||||
public interface PyTypeVarTupleType extends PyTypeParameterType, PyVariadicType {
|
||||
public interface PyTypeVarTupleType extends PyTypeParameterType, PyPositionalVariadicType {
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ import java.util.List;
|
||||
* @see <a href="https://peps.python.org/pep-0646/#unpacking-tuple-types">PEP 646 – Variadic Generics</a>
|
||||
* @see PyTypeVarTupleType
|
||||
*/
|
||||
public interface PyUnpackedTupleType extends PyVariadicType {
|
||||
public interface PyUnpackedTupleType extends PyPositionalVariadicType {
|
||||
/**
|
||||
* Returns types contained inside this unpacked tuple type.
|
||||
* <p>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// 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 com.intellij.psi.PsiElement;
|
||||
@@ -15,13 +15,11 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A marker interface for type forms that can be "unpacked" into a series of types.
|
||||
* A marker interface for type forms that can be "unpacked" into a collection of other types, either a nameless series,
|
||||
* or associated with parameters of a callable type.
|
||||
* Normally, such constructs cannot be used on their own in type hints, and can appear only inside other generic types.
|
||||
* Two variants of such types described in <a href="https://peps.python.org/pep-0646/">PEP 646 – Variadic Generics</a> are
|
||||
* TypeVarTuples and unpacked tuple types.
|
||||
*
|
||||
* @see PyTypeVarTupleType
|
||||
* @see PyUnpackedTupleType
|
||||
* @see PyPositionalVariadicType
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
public interface PyVariadicType extends PyType {
|
||||
|
||||
+1
-1
@@ -1744,7 +1744,7 @@ public final class PyTypingTypeProvider extends PyTypeProviderWithCustomContext<
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PyVariadicType getUnpackedType(@NotNull PsiElement element, @NotNull TypeEvalContext context) {
|
||||
public static PyPositionalVariadicType getUnpackedType(@NotNull PsiElement element, @NotNull TypeEvalContext context) {
|
||||
Ref<@Nullable PyType> typeRef = getTypeFromStarExpression(element, context);
|
||||
if (typeRef == null) {
|
||||
typeRef = getTypeFromUnpackOperator(element, context);
|
||||
|
||||
+2
-2
@@ -386,7 +386,7 @@ 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 PyVariadicType)) continue;
|
||||
if (unmappedContainer.getName() == null || !(containerType instanceof PyPositionalVariadicType)) continue;
|
||||
PyType expandedVararg = PyTypeChecker.substitute(containerType, substitutions, myTypeEvalContext);
|
||||
if (!(expandedVararg instanceof PyUnpackedTupleType unpackedTuple) || unpackedTuple.isUnbound()) continue;
|
||||
unfilledPositionalVarargs.add(
|
||||
@@ -450,7 +450,7 @@ public class PyTypeCheckerInspection extends PyInspection {
|
||||
@NotNull PyTypeChecker.GenericSubstitutions substitutions) {
|
||||
final PyType expected = container.getArgumentType(myTypeEvalContext);
|
||||
|
||||
if (container.isPositionalContainer() && expected instanceof PyVariadicType) {
|
||||
if (container.isPositionalContainer() && expected instanceof PyPositionalVariadicType) {
|
||||
PyUnpackedTupleType argumentTypes = PyUnpackedTupleTypeImpl.create(ContainerUtil.map(arguments, myTypeEvalContext::getType));
|
||||
boolean matched = matchParameterAndArgument(expected, argumentTypes, null, substitutions);
|
||||
return ContainerUtil.map(arguments, argument -> {
|
||||
|
||||
+1
-1
@@ -138,7 +138,7 @@ class PyTypeHintsInspection : PyInspection() {
|
||||
return
|
||||
}
|
||||
|
||||
if (myTypeEvalContext.getType(node) is PyVariadicType) {
|
||||
if (myTypeEvalContext.getType(node) is PyPositionalVariadicType) {
|
||||
checkTypeVarTupleUnpacked(node)
|
||||
}
|
||||
|
||||
|
||||
@@ -132,7 +132,7 @@ public final class PyTypeChecker {
|
||||
return Optional.of(match(typeVarTupleType, expected, context));
|
||||
}
|
||||
|
||||
if (expected instanceof PyVariadicType variadic) {
|
||||
if (expected instanceof PyPositionalVariadicType variadic) {
|
||||
return Optional.of(match(variadic, actual, context));
|
||||
}
|
||||
|
||||
@@ -291,11 +291,11 @@ public final class PyTypeChecker {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean match(@NotNull PyVariadicType expected, @Nullable PyType actual, @NotNull MatchContext context) {
|
||||
private static boolean match(@NotNull PyPositionalVariadicType expected, @Nullable PyType actual, @NotNull MatchContext context) {
|
||||
if (actual == null) {
|
||||
return true;
|
||||
}
|
||||
if (!(actual instanceof PyVariadicType actualVariadic)) {
|
||||
if (!(actual instanceof PyPositionalVariadicType actualVariadic)) {
|
||||
return false;
|
||||
}
|
||||
if (expected instanceof PyUnpackedTupleType expectedUnpackedTupleType) {
|
||||
@@ -326,7 +326,7 @@ public final class PyTypeChecker {
|
||||
}
|
||||
// The expected type is just a TypeVarTuple
|
||||
else {
|
||||
PyVariadicType substitution = context.mySubstitutions.typeVarTuples.get(expected);
|
||||
PyPositionalVariadicType substitution = context.mySubstitutions.typeVarTuples.get(expected);
|
||||
if (substitution != null && !substitution.equals(PyUnpackedTupleTypeImpl.UNSPECIFIED)) {
|
||||
if (expected.equals(actual) || substitution.equals(expected)) {
|
||||
return true;
|
||||
@@ -675,7 +675,7 @@ public final class PyTypeChecker {
|
||||
.filter(cp -> !(cp.getParameter() instanceof PySlashParameter || cp.getParameter() instanceof PySingleStarParameter))
|
||||
.map(cp -> {
|
||||
PyType argType = cp.getArgumentType(context);
|
||||
if (cp.isPositionalContainer() && !(argType instanceof PyVariadicType)) {
|
||||
if (cp.isPositionalContainer() && !(argType instanceof PyPositionalVariadicType)) {
|
||||
return PyUnpackedTupleTypeImpl.createUnbound(argType);
|
||||
}
|
||||
return argType;
|
||||
@@ -1100,7 +1100,7 @@ public final class PyTypeChecker {
|
||||
if (!substitutions.typeVarTuples.containsKey(typeVarTupleType)) {
|
||||
return type;
|
||||
}
|
||||
PyVariadicType substitution = substitutions.typeVarTuples.get(typeVarTupleType);
|
||||
PyPositionalVariadicType substitution = substitutions.typeVarTuples.get(typeVarTupleType);
|
||||
if (!typeVarTupleType.equals(substitution) && hasGenerics(substitution, context)) {
|
||||
return substitute(substitution, substitutions, context, substituting);
|
||||
}
|
||||
@@ -1408,7 +1408,7 @@ public final class PyTypeChecker {
|
||||
return true;
|
||||
}
|
||||
final PyType expectedArgumentType = container.getArgumentType(context);
|
||||
if (container.isPositionalContainer() && expectedArgumentType instanceof PyVariadicType variadicType) {
|
||||
if (container.isPositionalContainer() && expectedArgumentType instanceof PyPositionalVariadicType variadicType) {
|
||||
return match(variadicType, PyUnpackedTupleTypeImpl.create(actualArgumentTypes),
|
||||
new MatchContext(context, substitutions, false));
|
||||
}
|
||||
@@ -1444,7 +1444,7 @@ public final class PyTypeChecker {
|
||||
for (Map.Entry<PyTypeVarType, PyType> typeVarMapping : newSubstitutions.typeVars.entrySet()) {
|
||||
substitutions.typeVars.putIfAbsent(typeVarMapping.getKey(), typeVarMapping.getValue());
|
||||
}
|
||||
for (Map.Entry<PyTypeVarTupleType, PyVariadicType> typeVarMapping : newSubstitutions.typeVarTuples.entrySet()) {
|
||||
for (Map.Entry<PyTypeVarTupleType, PyPositionalVariadicType> typeVarMapping : newSubstitutions.typeVarTuples.entrySet()) {
|
||||
substitutions.typeVarTuples.putIfAbsent(typeVarMapping.getKey(), typeVarMapping.getValue());
|
||||
}
|
||||
for (Map.Entry<PyParamSpecType, PyParamSpecType> paramSpecMapping : newSubstitutions.paramSpecs.entrySet()) {
|
||||
@@ -1708,7 +1708,7 @@ public final class PyTypeChecker {
|
||||
private final Map<PyTypeVarType, PyType> typeVars;
|
||||
|
||||
@NotNull
|
||||
private final Map<PyTypeVarTupleType, PyVariadicType> typeVarTuples;
|
||||
private final Map<PyTypeVarTupleType, PyPositionalVariadicType> typeVarTuples;
|
||||
|
||||
@NotNull
|
||||
private final Map<PyParamSpecType, PyParamSpecType> paramSpecs;
|
||||
@@ -1723,7 +1723,7 @@ public final class PyTypeChecker {
|
||||
.toCustomMap(LinkedHashMap::new),
|
||||
EntryStream.of(typeParameters)
|
||||
.selectKeys(PyTypeVarTupleType.class)
|
||||
.selectValues(PyVariadicType.class)
|
||||
.selectValues(PyPositionalVariadicType.class)
|
||||
.toCustomMap(LinkedHashMap::new),
|
||||
EntryStream.of(typeParameters)
|
||||
.selectKeys(PyParamSpecType.class)
|
||||
@@ -1738,7 +1738,7 @@ public final class PyTypeChecker {
|
||||
}
|
||||
|
||||
private GenericSubstitutions(@NotNull Map<PyTypeVarType, PyType> typeVars,
|
||||
@NotNull Map<PyTypeVarTupleType, PyVariadicType> typeVarTuples,
|
||||
@NotNull Map<PyTypeVarTupleType, PyPositionalVariadicType> typeVarTuples,
|
||||
@NotNull Map<PyParamSpecType, PyParamSpecType> paramSpecs,
|
||||
@Nullable PyType qualifierType) {
|
||||
this.typeVars = typeVars;
|
||||
@@ -1755,7 +1755,7 @@ public final class PyTypeChecker {
|
||||
return Collections.unmodifiableMap(typeVars);
|
||||
}
|
||||
|
||||
public @NotNull Map<PyTypeVarTupleType, PyVariadicType> getTypeVarTuples() {
|
||||
public @NotNull Map<PyTypeVarTupleType, PyPositionalVariadicType> getTypeVarTuples() {
|
||||
return Collections.unmodifiableMap(typeVarTuples);
|
||||
}
|
||||
|
||||
|
||||
+16
-14
@@ -20,10 +20,10 @@ public final class PyTypeParameterMapping {
|
||||
for (Couple<PyType> couple : mapping) {
|
||||
PyType expectedType = couple.getFirst();
|
||||
PyType actualType = couple.getSecond();
|
||||
if (expectedType instanceof PyVariadicType && !(actualType instanceof PyVariadicType || actualType == null)) {
|
||||
if (expectedType instanceof PyPositionalVariadicType && !(actualType instanceof PyPositionalVariadicType || actualType == null)) {
|
||||
throw new IllegalArgumentException("Variadic type " + expectedType + " cannot be mapped to a non-variadic type " + actualType);
|
||||
}
|
||||
if (!(expectedType instanceof PyVariadicType) && actualType instanceof PyVariadicType) {
|
||||
if (!(expectedType instanceof PyPositionalVariadicType) && actualType instanceof PyPositionalVariadicType) {
|
||||
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(PyVariadicType.class))
|
||||
int expectedArity = ContainerUtil.exists(flattenedExpectedParameterTypes, Conditions.instanceOf(PyPositionalVariadicType.class))
|
||||
? -1
|
||||
: flattenedExpectedParameterTypes.size();
|
||||
|
||||
@@ -74,14 +74,14 @@ public final class PyTypeParameterMapping {
|
||||
}
|
||||
|
||||
if (positionalVarargArgumentTypes.size() > 1 ||
|
||||
positionalVarargArgumentTypes.size() == 1 && !(positionalVarargArgumentTypes.get(0) instanceof PyVariadicType)) {
|
||||
positionalVarargArgumentTypes.size() == 1 && !(positionalVarargArgumentTypes.get(0) instanceof PyPositionalVariadicType)) {
|
||||
requiredPositionalArgumentTypes.addAll(optionalPositionalArgumentTypes);
|
||||
optionalPositionalArgumentTypes.clear();
|
||||
requiredPositionalArgumentTypes.addAll(positionalVarargArgumentTypes);
|
||||
positionalVarargArgumentTypes.clear();
|
||||
}
|
||||
|
||||
int actualArity = ContainerUtil.exists(requiredPositionalArgumentTypes, Conditions.instanceOf(PyVariadicType.class)) ?
|
||||
int actualArity = ContainerUtil.exists(requiredPositionalArgumentTypes, Conditions.instanceOf(PyPositionalVariadicType.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 PyVariadicType;
|
||||
assert positionalVarargArgumentTypes.size() == 1 && positionalVarargArgumentTypes.get(0) instanceof PyPositionalVariadicType;
|
||||
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 PyVariadicType) {
|
||||
if (leftmostExpected instanceof PyPositionalVariadicType) {
|
||||
break;
|
||||
}
|
||||
// The leftmost expected type is a regular type
|
||||
PyType leftmostActual = actualTypesDeque.peekFirst();
|
||||
if (leftmostActual instanceof PyVariadicType) {
|
||||
if (leftmostActual instanceof PyPositionalVariadicType) {
|
||||
break;
|
||||
}
|
||||
expectedTypesDeque.removeFirst();
|
||||
@@ -138,12 +138,12 @@ public final class PyTypeParameterMapping {
|
||||
|
||||
while (expectedTypesDeque.size() != 0 && actualTypesDeque.size() != 0) {
|
||||
PyType rightmostExpected = expectedTypesDeque.peekLast();
|
||||
if (rightmostExpected instanceof PyVariadicType) {
|
||||
if (rightmostExpected instanceof PyPositionalVariadicType) {
|
||||
break;
|
||||
}
|
||||
expectedTypesDeque.removeLast();
|
||||
PyType rightmostActual = actualTypesDeque.peekLast();
|
||||
if (rightmostActual instanceof PyVariadicType rightmostActualVariadic) {
|
||||
if (rightmostActual instanceof PyPositionalVariadicType rightmostActualVariadic) {
|
||||
if (rightmostActualVariadic instanceof PyUnpackedTupleType unpackedTupleType && unpackedTupleType.isUnbound()) {
|
||||
PyType repeatedActualType = unpackedTupleType.getElementTypes().get(0);
|
||||
rightMappedTypes.add(Couple.of(rightmostExpected, repeatedActualType));
|
||||
@@ -160,10 +160,10 @@ public final class PyTypeParameterMapping {
|
||||
}
|
||||
|
||||
if (expectedTypesDeque.size() != 0 && actualTypesDeque.size() != 0
|
||||
&& !(expectedTypesDeque.peekFirst() instanceof PyVariadicType)
|
||||
&& (actualTypesDeque.peekFirst() instanceof PyVariadicType variadic)) {
|
||||
&& !(expectedTypesDeque.peekFirst() instanceof PyPositionalVariadicType)
|
||||
&& (actualTypesDeque.peekFirst() instanceof PyPositionalVariadicType variadic)) {
|
||||
if (variadic instanceof PyUnpackedTupleType actualUnpackedTupleType && actualUnpackedTupleType.isUnbound()) {
|
||||
while (expectedTypesDeque.size() != 0 && !(expectedTypesDeque.peekFirst() instanceof PyVariadicType)) {
|
||||
while (expectedTypesDeque.size() != 0 && !(expectedTypesDeque.peekFirst() instanceof PyPositionalVariadicType)) {
|
||||
PyType repeatedActualType = actualUnpackedTupleType.getElementTypes().get(0);
|
||||
leftMappedTypes.add(Couple.of(expectedTypesDeque.peekFirst(), repeatedActualType));
|
||||
expectedTypesDeque.removeFirst();
|
||||
@@ -182,11 +182,13 @@ public final class PyTypeParameterMapping {
|
||||
if (expectedTypesDeque.size() == 0) {
|
||||
boolean allActualTypesMatched = actualTypesDeque.size() == 0;
|
||||
boolean onlySingleActualVariadicLeft = actualTypesDeque.size() == 1 &&
|
||||
actualTypesDeque.peekFirst() instanceof PyVariadicType;
|
||||
actualTypesDeque.peekFirst() instanceof PyPositionalVariadicType;
|
||||
sizeMismatch = !(allActualTypesMatched || onlySingleActualVariadicLeft);
|
||||
}
|
||||
else if (expectedTypesDeque.size() == 1) {
|
||||
PyType onlyLeftExpectedType = expectedTypesDeque.peekFirst();
|
||||
if (onlyLeftExpectedType instanceof PyPositionalVariadicType) {
|
||||
if (actualTypesDeque.size() == 1 && actualTypesDeque.peekFirst() instanceof PyPositionalVariadicType variadicType) {
|
||||
if (onlyLeftExpectedType instanceof PyVariadicType) {
|
||||
// [*Ts] <- [*Ts] or [*Ts] <- [*tuple[T1, ...]]
|
||||
if (actualTypesDeque.size() == 1 && actualTypesDeque.peekFirst() instanceof PyVariadicType variadicType) {
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ public final class PyUnpackedTupleTypeImpl implements PyUnpackedTupleType {
|
||||
if (elementTypes.size() != 1) {
|
||||
throw new IllegalArgumentException("Unbounded unpacked tuple type can have only one type parameter");
|
||||
}
|
||||
if (elementTypes.get(0) instanceof PyVariadicType) {
|
||||
if (elementTypes.get(0) instanceof PyPositionalVariadicType) {
|
||||
throw new IllegalArgumentException("Unbounded unpacked tuple type of a TypeVarTuple or another unpacked tuple type is now allowed");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user