Merge remote-tracking branch 'origin/master'

This commit is contained in:
Ekaterina Tuzova
2011-11-23 19:01:07 +01:00
4 changed files with 40 additions and 44 deletions
@@ -305,27 +305,4 @@ public class PyImportReferenceImpl extends PyReferenceImpl {
editor.getCaretModel().moveToOffset(tailOffset + IMPORT_KWD.length());
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
PyImportReferenceImpl that = (PyImportReferenceImpl)o;
if (!myElement.equals(that.myElement)) return false;
if (!myContext.equals(that.myContext)) return false;
return true;
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + myElement.hashCode();
result = 31 * result + myContext.hashCode();
return result;
}
}
@@ -20,19 +20,19 @@ public class PyABCUtil {
}
public static boolean isSubclass(@NotNull PyClass subClass, @NotNull String superClassName) {
final String subClassName = subClass.getName();
if (PyNames.CALLABLE.equals(superClassName)) {
return hasMethod(subClass, PyNames.CALL);
}
if (PyNames.HASHABLE.equals(superClassName)) {
return hasMethod(subClass, PyNames.HASH);
}
final boolean isIterable = hasMethod(subClass, PyNames.ITER);
final boolean hasIter = hasMethod(subClass, PyNames.ITER);
final boolean hasGetItem = hasMethod(subClass, PyNames.GETITEM);
if (PyNames.ITERABLE.equals(superClassName)) {
return isIterable || isStringClass(subClassName);
return hasIter || hasGetItem;
}
if (PyNames.ITERATOR.equals(superClassName)) {
return (isIterable && hasMethod(subClass, PyNames.NEXT)) || isStringClass(subClassName);
return (hasIter && hasMethod(subClass, PyNames.NEXT)) || hasGetItem;
}
final boolean isSized = hasMethod(subClass, PyNames.LEN);
if (PyNames.SIZED.equals(superClassName)) {
@@ -42,12 +42,11 @@ public class PyABCUtil {
if (PyNames.CONTAINER.equals(superClassName)) {
return isContainer;
}
final boolean hasGetItem = hasMethod(subClass, PyNames.GETITEM);
if (PyNames.SEQUENCE.equals(superClassName)) {
return isSized && isIterable && isContainer && hasGetItem;
return isSized && hasIter && isContainer && hasGetItem;
}
if (PyNames.MAPPING.equals(superClassName)) {
return isSized && isIterable && isContainer && hasGetItem && hasMethod(subClass, PyNames.KEYS);
return isSized && hasIter && isContainer && hasGetItem && hasMethod(subClass, PyNames.KEYS);
}
return false;
}
@@ -74,8 +73,4 @@ public class PyABCUtil {
private static boolean hasMethod(PyClass cls, String name) {
return cls.findMethodByName(name, true) != null;
}
private static boolean isStringClass(String className) {
return "bytes".equals(className) || "str".equals(className) || "unicode".equals(className);
}
}
@@ -21,7 +21,12 @@ public class TypeEvalContext {
private final PsiFile myOrigin;
private final Map<PyTypedElement, PyType> myEvaluated = new HashMap<PyTypedElement, PyType>();
private final Set<PyTypedElement> myEvaluating = new HashSet<PyTypedElement>();
private final ThreadLocal<Set<PyTypedElement>> myEvaluating = new ThreadLocal<Set<PyTypedElement>>() {
@Override
protected Set<PyTypedElement> initialValue() {
return new HashSet<PyTypedElement>();
}
};
private TypeEvalContext(boolean allowDataFlow, boolean allowStubToAST, PsiFile origin) {
myAllowDataFlow = allowDataFlow;
@@ -111,17 +116,22 @@ public class TypeEvalContext {
if (myEvaluated.containsKey(element)) {
return myEvaluated.get(element);
}
if (myEvaluating.contains(element)) {
return null;
}
final Set<PyTypedElement> evaluating = myEvaluating.get();
if (evaluating.contains(element)) {
return null;
}
evaluating.add(element);
try {
PyType result = element.getType(this);
synchronized (myEvaluated) {
myEvaluated.put(element, result);
}
myEvaluating.add(element);
return result;
}
PyType result = element.getType(this);
synchronized (myEvaluated) {
myEvaluating.remove(element);
myEvaluated.put(element, result);
finally {
evaluating.remove(element);
}
return result;
}
public boolean maySwitchToAST(StubBasedPsiElement element) {
@@ -8,4 +8,18 @@ def test_union_type():
def foo(*args):
pass
bar = (1,) if True else (1, 2)
foo(*bar) #pass
foo(*bar) #pass
# PY-4890
def test_old_style_iterable():
class C:
def __getitem__(self, key):
if 0 <= key < 10:
return key
else:
raise IndexError('index out of range')
def foo(*args):
pass
xs = C()
foo(*xs) #pass
foo(*'bar') #pass