diff --git a/python/python-common-tests/com/jetbrains/python/PyCommonResolveTest.java b/python/python-common-tests/com/jetbrains/python/PyCommonResolveTest.java index 143c223a9861..2b9e7af91279 100644 --- a/python/python-common-tests/com/jetbrains/python/PyCommonResolveTest.java +++ b/python/python-common-tests/com/jetbrains/python/PyCommonResolveTest.java @@ -2133,6 +2133,18 @@ public abstract class PyCommonResolveTest extends PyCommonResolveTestCase { assertResolvedElement(LanguageLevel.PYTHON34, starImport, TestCase::assertNull); } + // PY-77168 + public void testResolveFromUnderUnmatchedVersionCheck() { + assertResolvesTo(""" + import sys + + Alias = int + if sys.version_info < (3, 12): + name: Alias + # + """, PyTargetExpression.class, "Alias"); + } + private void assertResolvedElement(@NotNull LanguageLevel languageLevel, @NotNull String text, @NotNull Consumer assertion) { runWithLanguageLevel(languageLevel, () -> { myFixture.configureByText(PythonFileType.INSTANCE, text); diff --git a/python/python-psi-impl/src/com/jetbrains/python/refactoring/PyDefUseUtil.java b/python/python-psi-impl/src/com/jetbrains/python/refactoring/PyDefUseUtil.java index c9e9836b639e..816b73ea287d 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/refactoring/PyDefUseUtil.java +++ b/python/python-psi-impl/src/com/jetbrains/python/refactoring/PyDefUseUtil.java @@ -86,9 +86,6 @@ public final class PyDefUseUtil { final HashMap pendingTypeGuard = new HashMap<>(); ControlFlowUtil.iteratePrev(startNum, instructions, instruction -> { - if (unreachableDueToVersionGuard(instruction)) { - return ControlFlowUtil.Operation.CONTINUE; - } if (acceptTypeAssertions && instruction instanceof CallInstruction callInstruction) { var typeGuardInstruction = pendingTypeGuard.get(instruction.getElement()); if (typeGuardInstruction != null) { @@ -123,14 +120,18 @@ public final class PyDefUseUtil { if (access.isWriteAccess() || acceptTypeAssertions && access.isAssertTypeAccess()) { final String name = elementName(element); if (Comparing.strEqual(name, varName)) { - result.add(rwInstruction); + if (isReachableWithVersionChecks(rwInstruction)) { + result.add(rwInstruction); + } return ControlFlowUtil.Operation.CONTINUE; } } } else if (acceptImplicitImports && element instanceof PyImplicitImportNameDefiner implicit) { if (!implicit.multiResolveName(varName).isEmpty()) { - result.add(instruction); + if (isReachableWithVersionChecks(instruction)) { + result.add(instruction); + } return ControlFlowUtil.Operation.CONTINUE; } } @@ -139,12 +140,12 @@ public final class PyDefUseUtil { return result; } - private static boolean unreachableDueToVersionGuard(@NotNull Instruction instruction) { + private static boolean isReachableWithVersionChecks(@NotNull Instruction instruction) { PsiElement element = instruction.getElement(); - if (element == null) return false; + if (element == null) return true; LanguageLevel languageLevel = PythonLanguageLevelPusher.getLanguageLevelForFile(element.getContainingFile()); Version version = new Version(languageLevel.getMajorVersion(), languageLevel.getMinorVersion(), 0); - return !evaluateVersionsForElement(element).contains(version); + return evaluateVersionsForElement(element).contains(version); } @Nullable diff --git a/python/testSrc/com/jetbrains/python/PyTypingTest.java b/python/testSrc/com/jetbrains/python/PyTypingTest.java index 8cbaf4a4a241..6fc30e68ffc6 100644 --- a/python/testSrc/com/jetbrains/python/PyTypingTest.java +++ b/python/testSrc/com/jetbrains/python/PyTypingTest.java @@ -5959,6 +5959,28 @@ public class PyTypingTest extends PyTestCase { """); } + // PY-77168 + public void testReferencingImportedTypeFromUnmatchedVersionGuard() { + doTest("Literal[42]", """ + from typing import Literal + import sys + + if sys.version_info < (3, 0): + expr: Literal[42] + """); + } + + // PY-77168 + public void testReferencingTopLevelTypeFromUnmatchedVersionGuard() { + doTest("int", """ + import sys + + type Alias = int + if sys.version_info < (3, 0): + expr: Alias + """); + } + // PY-76243 public void testGenericClassDeclaredInStubPackage() { runWithAdditionalClassEntryInSdkRoots("types/" + getTestName(false) + "/site-packages", () -> { diff --git a/python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java index fa78a5f4e9a6..a9047e540ca1 100644 --- a/python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java @@ -341,4 +341,18 @@ public class Py3UnresolvedReferencesInspectionTest extends PyInspectionTestCase pass """); } + + // PY-77168 + public void testReferenceFromUnderUnmatchedVersionCheck() { + doTestByText(""" + import sys + from typing import overload + + Alias = int + if sys.version_info < (3, 12): + @overload + def f() -> Alias: + ... + """); + } }