From 94164f5f9715d41d286f3b75b9fdcb835db12157 Mon Sep 17 00:00:00 2001 From: Semyon Proshev Date: Mon, 24 Jul 2017 21:11:20 +0300 Subject: [PATCH] PY-25157 Fixed: Inferred type shows incorrect return type with namedtuple Implement equals and hashCode in PyNamedTupleType so different types are not the same. --- .../codeInsight/stdlib/PyNamedTupleType.java | 17 +++++++++++++++++ .../com/jetbrains/python/PyTypeTest.java | 14 ++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java b/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java index c4791958b6d0..63c1f27b741c 100644 --- a/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java +++ b/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java @@ -135,6 +135,23 @@ public class PyNamedTupleType extends PyClassTypeImpl implements PyCallableType return "PyNamedTupleType: " + myName; } + @Override + public boolean equals(Object o) { + if (o == this) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + + final PyNamedTupleType type = (PyNamedTupleType)o; + return Objects.equals(myName, type.myName) && + Objects.equals(myFields.keySet(), type.myFields.keySet()) && + myDefinitionLevel == type.myDefinitionLevel; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), myName, myFields.keySet(), myDefinitionLevel); + } + @NotNull @Override public Set getMemberNames(boolean inherited, @NotNull TypeEvalContext context) { diff --git a/python/testSrc/com/jetbrains/python/PyTypeTest.java b/python/testSrc/com/jetbrains/python/PyTypeTest.java index 32ddabc43fec..64e74f1a73f9 100644 --- a/python/testSrc/com/jetbrains/python/PyTypeTest.java +++ b/python/testSrc/com/jetbrains/python/PyTypeTest.java @@ -2055,6 +2055,20 @@ public class PyTypeTest extends PyTestCase { " expr = x"); } + // PY-25157 + public void testFunctionWithDifferentNamedTuplesAsParameterAndReturnTypes() { + runWithLanguageLevel( + LanguageLevel.PYTHON35, + () -> doTest("(a: MyType1) -> MyType2", + "from collections import namedtuple\n" + + "MyType1 = namedtuple('MyType1', 'x y')\n" + + "MyType2 = namedtuple('MyType2', 'x y')\n" + + "def foo(a: MyType1) -> MyType2:\n" + + " pass\n" + + "expr = foo") + ); + } + private static List getTypeEvalContexts(@NotNull PyExpression element) { return ImmutableList.of(TypeEvalContext.codeAnalysis(element.getProject(), element.getContainingFile()).withTracing(), TypeEvalContext.userInitiated(element.getProject(), element.getContainingFile()).withTracing());