PY-16066 Fixed: basestring not treated as a type by PyTypeChecker inspection

Remove replacing basestring with union of str and unicode from PyTypeChecker.
Force this replacement while inferring type.
Update PyTypeAssertionEvaluator to correctly transform union types.
This commit is contained in:
Semyon Proshev
2017-08-18 14:48:48 +03:00
parent 069c549bfb
commit 5def6b554f
7 changed files with 42 additions and 9 deletions
@@ -17,6 +17,7 @@ package com.jetbrains.python.codeInsight.controlflow;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.PsiElement;
import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.psi.*;
@@ -26,6 +27,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Stack;
import java.util.function.Function;
@@ -184,6 +186,10 @@ public class PyTypeAssertionEvaluator extends PyRecursiveElementVisitor {
}
return PyUnionType.union(members);
}
else if (type instanceof PyUnionType) {
final Collection<PyType> members = ((PyUnionType)type).getMembers();
return PyUnionType.union(ContainerUtil.map(members, member -> transformTypeFromAssertion(member, transformToDefinition)));
}
else if (type instanceof PyInstantiableType) {
final PyInstantiableType instantiableType = (PyInstantiableType)type;
return transformToDefinition ? instantiableType.toClass() : instantiableType.toInstance();
@@ -118,7 +118,7 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase {
final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(referenceTarget);
if (referenceTarget instanceof PyElement && builtinCache.isBuiltin(referenceTarget) &&
PyNames.BASESTRING.equals(((PyElement)referenceTarget).getName())) {
return builtinCache.getStrOrUnicodeType();
return builtinCache.getStrOrUnicodeType(true);
}
return null;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -393,7 +393,23 @@ public class PyBuiltinCache {
@Nullable
public PyType getStrOrUnicodeType() {
return PyUnionType.union(getObjectType("str"), getObjectType("unicode"));
return getStrOrUnicodeType(false);
}
@Nullable
public PyType getStrOrUnicodeType(boolean definition) {
PyClassLikeType str = getObjectType("str");
PyClassLikeType unicode = getObjectType("unicode");
if (str != null && str.isDefinition() ^ definition) {
str = definition ? str.toClass() : str.toInstance();
}
if (unicode != null && unicode.isDefinition() ^ definition) {
unicode = definition ? unicode.toClass() : unicode.toInstance();
}
return PyUnionType.union(str, unicode);
}
@Nullable
@@ -90,12 +90,6 @@ public class PyTypeChecker {
}
return false;
}
if (actualClassType != null && PyNames.BASESTRING.equals(actualClassType.getName())) {
final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(actualClassType.getPyClass());
if (actualClassType.equals(builtinCache.getObjectType(PyNames.BASESTRING))) {
return match(expected, builtinCache.getStrOrUnicodeType(), context, substitutions, recursive);
}
}
if (expected instanceof PyGenericType && substitutions != null) {
final PyGenericType generic = (PyGenericType)expected;
final PyType subst = substitutions.get(generic);
@@ -528,6 +528,10 @@ public class PyTypeParser {
final PyClassType type = builtinCache.getDictType();
return type != null ? new ParseResult(type, range) : EMPTY_RESULT;
}
else if (PyNames.BASESTRING.equals(name)) {
final PyType type = builtinCache.getStrOrUnicodeType();
return type != null ? new ParseResult(type, range) : EMPTY_RESULT;
}
final PyType builtinType = builtinCache.getObjectType(name);
if (builtinType != null) {
@@ -0,0 +1,8 @@
class Filter(object):
def __init__(self, allowed_types):
"""
:type allowed_types: type
"""
pass
Filter(basestring)
@@ -442,6 +442,11 @@ public class PyTypeCheckerInspectionTest extends PyTestCase {
doTest();
}
// PY-16066
public void testBasestringMatchesType() {
doTest();
}
// PY-23864
public void testClassObjectAndMetaclassCompatibility() {
doTest();