Provide fields' types for typing.NamedTuple(...) inheritors (PY-32240)

This commit is contained in:
Semyon Proshev
2018-11-12 13:58:14 +03:00
parent b27fd517a9
commit abae2f744d
2 changed files with 30 additions and 0 deletions
@@ -34,6 +34,11 @@ class PyNamedTupleTypeProvider : PyTypeProviderBase() {
return fieldTypeForNamedTuple
}
val fieldTypeForTypingNTFunctionInheritor = getFieldTypeForTypingNTFunctionInheritor(referenceExpression, context)
if (fieldTypeForTypingNTFunctionInheritor != null) {
return fieldTypeForTypingNTFunctionInheritor
}
val namedTupleTypeForCallee = getNamedTupleTypeForCallee(referenceExpression, context)
if (namedTupleTypeForCallee != null) {
return namedTupleTypeForCallee
@@ -90,6 +95,20 @@ class PyNamedTupleTypeProvider : PyTypeProviderBase() {
return qualifierNTType.fields[referenceExpression.name]?.type
}
private fun getFieldTypeForTypingNTFunctionInheritor(referenceExpression: PyReferenceExpression, context: TypeEvalContext): PyType? {
val qualifierType = referenceExpression.qualifier?.let { context.getType(it) } as? PyWithAncestors
if (qualifierType == null || qualifierType is PyNamedTupleType) return null
return PyUnionType.union(
qualifierType
.getAncestorTypes(context)
.filterIsInstance<PyNamedTupleType>()
.mapNotNull { it.fields[referenceExpression.name] }
.map { it.type }
.toList()
)
}
private fun getNamedTupleTypeForCallee(referenceExpression: PyReferenceExpression, context: TypeEvalContext): PyNamedTupleType? {
if (PyCallExpressionNavigator.getPyCallExpressionByCallee(referenceExpression) == null) return null
@@ -2588,6 +2588,17 @@ public class PyTypeTest extends PyTestCase {
);
}
// PY-32240
public void testTypingNTFunctionInheritorField() {
doTest("str",
"from typing import NamedTuple\n" +
"\n" +
"class A(NamedTuple(\"NT\", [(\"user\", str)])):\n" +
" pass\n" +
" \n" +
"expr = A(undefined).user");
}
// PY-4351
public void testCollectionsNTInheritorField() {
// Seems that this case won't be supported because