diff --git a/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java b/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java index 00793c8ffd0e..0e58f56d5ff3 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java +++ b/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java @@ -161,15 +161,33 @@ public class PyBuiltinCache { } @Nullable - static PyType createLiteralCollectionType(final PySequenceExpression sequence, final String name) { - final PyBuiltinCache builtinCache = getInstance(sequence); - final PyClass setClass = builtinCache.getClass(name); - if (setClass != null) { - return new PyLiteralCollectionType(setClass, false, sequence); + public PyType createLiteralCollectionType(final PySequenceExpression sequence, final String name, @NotNull TypeEvalContext context) { + final PyClass cls = getClass(name); + if (cls != null) { + return new PyCollectionTypeImpl(cls, false, getSequenceElementType(sequence, context)); } return null; } + @Nullable + private static PyType getSequenceElementType(@NotNull PySequenceExpression sequence, @NotNull TypeEvalContext context) { + final PyExpression[] elements = sequence.getElements(); + if (elements.length == 0 || elements.length > 10 /* performance */) { + return null; + } + final PyType result = context.getType(elements[0]); + if (result == null) { + return null; + } + for (int i = 1; i < elements.length; i++) { + final PyType elementType = context.getType(elements[i]); + if (elementType == null || !elementType.equals(result)) { + return null; + } + } + return result; + } + @Nullable public PyFile getBuiltinsFile() { return myBuiltinsFile; diff --git a/python/src/com/jetbrains/python/psi/impl/PyDictLiteralExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyDictLiteralExpressionImpl.java index b7b73bd91ad9..e6010154cf7c 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyDictLiteralExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyDictLiteralExpressionImpl.java @@ -38,7 +38,7 @@ public class PyDictLiteralExpressionImpl extends PyElementImpl implements PyDict } public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) { - return PyBuiltinCache.createLiteralCollectionType(this, "dict"); + return PyBuiltinCache.getInstance(this).createLiteralCollectionType(this, "dict", context); } @Override diff --git a/python/src/com/jetbrains/python/psi/impl/PyListLiteralExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyListLiteralExpressionImpl.java index 63f4b29c435a..a71519266e48 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyListLiteralExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyListLiteralExpressionImpl.java @@ -86,6 +86,6 @@ public class PyListLiteralExpressionImpl extends PyElementImpl implements PyList } public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) { - return PyBuiltinCache.createLiteralCollectionType(this, "list"); + return PyBuiltinCache.getInstance(this).createLiteralCollectionType(this, "list", context); } } diff --git a/python/src/com/jetbrains/python/psi/impl/PySetLiteralExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PySetLiteralExpressionImpl.java index 9d60b576aea2..89c87692748a 100644 --- a/python/src/com/jetbrains/python/psi/impl/PySetLiteralExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PySetLiteralExpressionImpl.java @@ -31,7 +31,7 @@ public class PySetLiteralExpressionImpl extends PyElementImpl implements PySetLi } public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) { - return PyBuiltinCache.createLiteralCollectionType(this, "set"); + return PyBuiltinCache.getInstance(this).createLiteralCollectionType(this, "set", context); } @Override diff --git a/python/src/com/jetbrains/python/psi/types/PyLiteralCollectionType.java b/python/src/com/jetbrains/python/psi/types/PyLiteralCollectionType.java deleted file mode 100644 index 896c9d57d929..000000000000 --- a/python/src/com/jetbrains/python/psi/types/PyLiteralCollectionType.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2000-2014 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.jetbrains.python.psi.types; - -import com.jetbrains.python.psi.PyClass; -import com.jetbrains.python.psi.PyExpression; -import com.jetbrains.python.psi.PySequenceExpression; -import org.jetbrains.annotations.NotNull; - -/** - * @author yole - */ -public class PyLiteralCollectionType extends PyClassTypeImpl implements PyCollectionType { - private final PySequenceExpression mySequence; - - public PyLiteralCollectionType(@NotNull PyClass source, boolean isDefinition, PySequenceExpression sequence) { - super(source, isDefinition); - mySequence = sequence; - } - - @Override - public PyType getElementType(@NotNull TypeEvalContext context) { - final PyExpression[] elements = mySequence.getElements(); - if (elements.length == 0 || elements.length > 10 /* performance */) { - return null; - } - PyType result = context.getType(elements [0]); - if (result == null) { - return null; - } - for (int i = 1; i < elements.length; i++) { - PyType elementType = context.getType(elements[i]); - if (elementType == null || !elementType.equals(result)) { - return null; - } - } - return result; - } -} diff --git a/python/testData/inspections/PyTypeCheckerInspection/RecursiveDictAttribute.py b/python/testData/inspections/PyTypeCheckerInspection/RecursiveDictAttribute.py new file mode 100644 index 000000000000..72f10ac35f4c --- /dev/null +++ b/python/testData/inspections/PyTypeCheckerInspection/RecursiveDictAttribute.py @@ -0,0 +1,5 @@ +class C: + def f(self, x): + self.foo = x + self.foo = {'foo': self.foo} + return self.foo['foo'] + 10 diff --git a/python/testSrc/com/jetbrains/python/PyTypeTest.java b/python/testSrc/com/jetbrains/python/PyTypeTest.java index d4f6acda8fd3..5ff68c4f8f62 100644 --- a/python/testSrc/com/jetbrains/python/PyTypeTest.java +++ b/python/testSrc/com/jetbrains/python/PyTypeTest.java @@ -505,7 +505,7 @@ public class PyTypeTest extends PyTestCase { // EA-40207 public void testRecursion() { - doTest("list[list]", + doTest("list", "def f():\n" + " return [f()]\n" + "expr = f()\n"); diff --git a/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java index 0b15d89dfddf..65ea0ed75497 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java @@ -237,4 +237,9 @@ public class PyTypeCheckerInspectionTest extends PyTestCase { public void testDefaultTupleParameter() { doTest(); } + + // PY-14222 + public void testRecursiveDictAttribute() { + doTest(); + } }