From d64d621fbef17a0009a2e84d45c8a2863417851f Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Mon, 14 Oct 2024 12:35:55 +0300 Subject: [PATCH] [python] Remove now redundant PyTypingTypeProvider.getAliasedType() The more general getParameterizedTypeFromTypeAlias() does its job. GitOrigin-RevId: b8e49799e8313b29dcb86bf754ede8a5855898f8 --- .../typing/PyTypingTypeProvider.java | 77 +++++++++---------- .../com/jetbrains/python/PyTypingTest.java | 18 +++++ 2 files changed, 54 insertions(+), 41 deletions(-) diff --git a/python/python-psi-impl/src/com/jetbrains/python/codeInsight/typing/PyTypingTypeProvider.java b/python/python-psi-impl/src/com/jetbrains/python/codeInsight/typing/PyTypingTypeProvider.java index ac5bfde0c108..6444a7e2a74f 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/codeInsight/typing/PyTypingTypeProvider.java +++ b/python/python-psi-impl/src/com/jetbrains/python/codeInsight/typing/PyTypingTypeProvider.java @@ -853,9 +853,14 @@ public final class PyTypingTypeProvider extends PyTypeProviderWithCustomContext< if (typeFromParenthesizedExpression != null) { return typeFromParenthesizedExpression; } - final PyType parameterizedTypeFromTypeAlias = getParameterizedTypeFromTypeAlias(alias, typeHint, resolved, context); - if (parameterizedTypeFromTypeAlias != null) { - return Ref.create(parameterizedTypeFromTypeAlias); + // We perform chained resolve only for actual aliases as tryResolvingWithAliases() returns the passed-in + // expression both when it's not a reference expression and when it's failed to resolve it, hence we might + // hit SOE for mere unresolved references in the latter case. + if (alias != null) { + Ref typeFromTypeAlias = getTypeFromTypeAlias(alias, typeHint, resolved, context); + if (typeFromTypeAlias != null) { + return typeFromTypeAlias; + } } final PyType unionType = getUnionType(resolved, context); if (unionType != null) { @@ -937,15 +942,6 @@ public final class PyTypingTypeProvider extends PyTypeProviderWithCustomContext< if (anyType != null) { return anyType; } - // We perform chained resolve only for actual aliases as tryResolvingWithAliases() returns the passed-in - // expression both when it's not a reference expression and when it's failed to resolve it, hence we might - // hit SOE for mere unresolved references in the latter case. - if (alias != null) { - final Ref aliasedType = getAliasedType(resolved, context); - if (aliasedType != null) { - return aliasedType; - } - } final PyType typedDictType = PyTypedDictTypeProvider.Companion.getTypedDictTypeForResolvedElement(resolved, context.getTypeContext()); if (typedDictType != null) { return Ref.create(typedDictType); @@ -1033,14 +1029,6 @@ public final class PyTypingTypeProvider extends PyTypeProviderWithCustomContext< return null; } - @Nullable - private static Ref getAliasedType(@NotNull PsiElement resolved, @NotNull Context context) { - if (resolved instanceof PyReferenceExpression && ((PyReferenceExpression)resolved).asQualifiedName() != null) { - return getType((PyExpression)resolved, context); - } - return null; - } - @Nullable private static PyType anchorTypeParameter(@NotNull PyExpression typeHint, @Nullable PyType type, @NotNull Context context) { PyQualifiedNameOwner typeParamDefinitionFromStack = context.getTypeAliasStack().isEmpty() ? null : context.getTypeAliasStack().peek(); @@ -1901,31 +1889,33 @@ public final class PyTypingTypeProvider extends PyTypeProviderWithCustomContext< return null; } - @Nullable - private static PyType getParameterizedTypeFromTypeAlias(@Nullable PyQualifiedNameOwner alias, - @NotNull PsiElement typeHint, - @NotNull PsiElement element, - @NotNull Context context) { - if (element instanceof PyExpression assignedExpression && alias != null) { - + private static @Nullable Ref getTypeFromTypeAlias(@NotNull PyQualifiedNameOwner alias, + @NotNull PsiElement typeHint, + @NotNull PsiElement element, + @NotNull Context context) { + if (element instanceof PyExpression assignedExpression) { if (alias instanceof PyTypeAliasStatement typeAliasStatement) { - return getParameterizedTypeFromTypeAliasStatement(typeAliasStatement, typeHint, assignedExpression, context); + return getTypeFromTypeAliasStatement(typeAliasStatement, typeHint, assignedExpression, context); } - PyType assignedType = Ref.deref(getType(assignedExpression, context)); - if (assignedType != null) { + @Nullable Ref assignedTypeRef = getType(assignedExpression, context); + if (assignedTypeRef != null) { + @Nullable PyType assignedType = assignedTypeRef.get(); + if (assignedType == null) { + return assignedTypeRef; + } if (typeHint instanceof PySubscriptionExpression subscriptionExpr) { List indexTypes = getIndexTypes(subscriptionExpr, context); - return PyTypeChecker.parameterizeType(assignedType, indexTypes, context.myContext); + return Ref.create(PyTypeChecker.parameterizeType(assignedType, indexTypes, context.myContext)); } if (typeHint instanceof PyReferenceExpression) { if (!(assignedType instanceof PyTypeParameterType)) { List typeAliasTypeParams = PyTypeChecker.collectGenerics(assignedType, context.getTypeContext()).getAllTypeParameters(); if (!typeAliasTypeParams.isEmpty()) { - return PyTypeChecker.parameterizeType(assignedType, List.of(), context.myContext); + return Ref.create(PyTypeChecker.parameterizeType(assignedType, List.of(), context.myContext)); } - return assignedType; + return Ref.create(assignedType); } } } @@ -1934,12 +1924,16 @@ public final class PyTypingTypeProvider extends PyTypeProviderWithCustomContext< } @Nullable - private static PyType getParameterizedTypeFromTypeAliasStatement(@NotNull PyTypeAliasStatement typeAliasStatement, - @NotNull PsiElement typeHint, - @NotNull PyExpression assignedExpression, - @NotNull Context context) { - PyType assignedType = Ref.deref(getType(assignedExpression, context)); - if (assignedType != null) { + private static Ref getTypeFromTypeAliasStatement(@NotNull PyTypeAliasStatement typeAliasStatement, + @NotNull PsiElement typeHint, + @NotNull PyExpression assignedExpression, + @NotNull Context context) { + @Nullable Ref assignedTypeRef = getType(assignedExpression, context); + if (assignedTypeRef != null) { + PyType assignedType = assignedTypeRef.get(); + if (assignedType == null) { + return assignedTypeRef; + } List indexTypes = typeHint instanceof PySubscriptionExpression subscriptionExpr ? getIndexTypes(subscriptionExpr, context) : Collections.emptyList(); @@ -1952,9 +1946,9 @@ public final class PyTypingTypeProvider extends PyTypeProviderWithCustomContext< Option.USE_DEFAULTS, Option.MAP_UNMATCHED_EXPECTED_TYPES_TO_ANY); - return substitutions != null ? PyTypeChecker.substitute(assignedType, substitutions, context.myContext) : null; + return substitutions != null ? Ref.create(PyTypeChecker.substitute(assignedType, substitutions, context.myContext)) : null; } - return assignedType; + return assignedTypeRef; } return null; } @@ -2071,6 +2065,7 @@ public final class PyTypingTypeProvider extends PyTypeProviderWithCustomContext< PyExpression operandExpression = subscriptionExpr.getOperand(); List> results = tryResolvingWithAliases(operandExpression, context); for (Pair pair : results) { + // If the parameterized type is a type alias if (pair.getFirst() != null && pair.getSecond() != null) { elements.add(Pair.create(pair.getFirst(), pair.getSecond())); } diff --git a/python/testSrc/com/jetbrains/python/PyTypingTest.java b/python/testSrc/com/jetbrains/python/PyTypingTest.java index 12d843502c0e..0cd7b0d5bd41 100644 --- a/python/testSrc/com/jetbrains/python/PyTypingTest.java +++ b/python/testSrc/com/jetbrains/python/PyTypingTest.java @@ -6062,6 +6062,24 @@ public class PyTypingTest extends PyTestCase { """); } + public void testTypeAliasToAny() { + doTest("int | Any", """ + from typing import Any, TypeAlias + + Plug: TypeAlias = Any + expr: int | Plug + """); + } + + public void testNewStyleTypeAliasToAny() { + doTest("int | Any", """ + from typing import Any + + type Plug = Any + expr: int | Plug + """); + } + private void doTestNoInjectedText(@NotNull String text) { myFixture.configureByText(PythonFileType.INSTANCE, text); final InjectedLanguageManager languageManager = InjectedLanguageManager.getInstance(myFixture.getProject());