diff --git a/python/src/com/jetbrains/python/codeInsight/typing/PyTypingTypeProvider.java b/python/src/com/jetbrains/python/codeInsight/typing/PyTypingTypeProvider.java index 289a6a1bf362..a4c2c95a070c 100644 --- a/python/src/com/jetbrains/python/codeInsight/typing/PyTypingTypeProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/typing/PyTypingTypeProvider.java @@ -828,6 +828,15 @@ public class PyTypingTypeProvider extends PyTypeProviderBase { 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 Ref classType = getClassType(resolved, context.getTypeContext()); if (classType != null) { return classType; @@ -841,6 +850,14 @@ public class PyTypingTypeProvider extends PyTypeProviderBase { } } + @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 addTypeVarAlias(@Nullable PyType type, @Nullable PyTargetExpression alias) { final PyGenericType typeVar = as(type, PyGenericType.class); diff --git a/python/testData/types/TrivialRecursiveTypeAliasInAnotherFile/other.py b/python/testData/types/TrivialRecursiveTypeAliasInAnotherFile/other.py new file mode 100644 index 000000000000..5d0bc14c50a2 --- /dev/null +++ b/python/testData/types/TrivialRecursiveTypeAliasInAnotherFile/other.py @@ -0,0 +1,2 @@ +alias2 = 'alias' +alias = alias2 diff --git a/python/testData/types/TrivialTypeAliasInAnotherFile/other.py b/python/testData/types/TrivialTypeAliasInAnotherFile/other.py new file mode 100644 index 000000000000..7a78a617f711 --- /dev/null +++ b/python/testData/types/TrivialTypeAliasInAnotherFile/other.py @@ -0,0 +1 @@ +alias = str diff --git a/python/testData/types/TrivialUnresolvedTypeAliasInAnotherFile/other.py b/python/testData/types/TrivialUnresolvedTypeAliasInAnotherFile/other.py new file mode 100644 index 000000000000..540c9c85afa6 --- /dev/null +++ b/python/testData/types/TrivialUnresolvedTypeAliasInAnotherFile/other.py @@ -0,0 +1 @@ +alias = unresolved diff --git a/python/testSrc/com/jetbrains/python/PyTypingTest.java b/python/testSrc/com/jetbrains/python/PyTypingTest.java index 8dfa17593c77..ade4aa62ed39 100644 --- a/python/testSrc/com/jetbrains/python/PyTypingTest.java +++ b/python/testSrc/com/jetbrains/python/PyTypingTest.java @@ -1424,6 +1424,30 @@ public class PyTypingTest extends PyTestCase { "\n"); } + // PY-34478 + public void testTrivialTypeAliasInAnotherFile() { + doMultiFileStubAwareTest("str", + "from other import alias\n" + + "\n" + + "expr: alias"); + } + + // PY-34478 + public void testTrivialUnresolvedTypeAliasInAnotherFile() { + doMultiFileStubAwareTest("Any", + "from other import alias\n" + + "\n" + + "expr: alias"); + } + + // PY-34478 + public void testTrivialRecursiveTypeAliasInAnotherFile() { + doMultiFileStubAwareTest("Any", + "from other import alias\n" + + "\n" + + "expr: alias"); + } + private void doTestNoInjectedText(@NotNull String text) { myFixture.configureByText(PythonFileType.INSTANCE, text); final InjectedLanguageManager languageManager = InjectedLanguageManager.getInstance(myFixture.getProject());