Remove PyStringLiteralType.fromLiteral

It's sufficient to promote the type of string literals to Literal['content']
when a type containing a literal type (either Literal or LiteralString) is
expected, since Literal['content'] is always compatible with LiteralString.

(cherry picked from commit 3c9c0b1c451a17b7f56f3376d9e6cd493a770a73)

IJ-MR-112631

GitOrigin-RevId: 92e3ad2da4874e33af22c56d9dd38fd9c8ff871e
This commit is contained in:
Mikhail Golubev
2023-11-07 14:33:45 +02:00
committed by intellij-monorepo-bot
parent be82cf6646
commit 75aaa14404
2 changed files with 13 additions and 59 deletions

View File

@@ -50,51 +50,5 @@ class PyLiteralStringType private constructor(val cls: PyClass) : PyClassTypeImp
fun match(expected: PyLiteralStringType, actual: PyClassType): Boolean {
return actual is PyLiteralStringType || actual is PyLiteralType && expected.pyClass == actual.pyClass
}
fun fromLiteral(expression: PyExpression, context: TypeEvalContext): PyType? {
val value = when (expression) {
is PyKeywordArgument -> expression.valueExpression
is PyParenthesizedExpression -> PyPsiUtils.flattenParens(expression)
else -> expression
}
if (value is PyStringLiteralExpression) {
val firstNode = value.stringNodes.firstOrNull()
if (firstNode != null) {
if (firstNode.elementType === PyElementTypes.FSTRING_NODE) {
val allLiteralStringFragments: Boolean = value.stringElements.filterIsInstance<PyFormattedStringElement>().flatMap { it.fragments }.mapNotNull {
if (it.expression != null) context.getType(it.expression!!) else null
}.all { it is PyLiteralStringType }
return if (allLiteralStringFragments) create(expression) else PyBuiltinCache.getInstance(expression).strType
}
return create(value)
}
}
else if (value is PySequenceExpression) {
val classes = if (value is PyDictLiteralExpression) {
val keyTypes = value.elements.map { fromLiteral(it.key, context) }
val valueTypes = value.elements.map { type -> type.value?.let { fromLiteral(it, context) } }
listOf(PyUnionType.union(keyTypes), PyUnionType.union(valueTypes))
}
else value.elements.map { fromLiteral(it, context) }
if (value is PyTupleExpression) {
return PyTupleType.create(value, classes)
}
else {
val name = when (value) {
is PyListLiteralExpression -> "list"
is PySetLiteralExpression -> "set"
is PyDictLiteralExpression -> "dict"
else -> null
}
return name?.let { PyCollectionTypeImpl.createTypeByQName(value, name, false, classes) }
}
}
else if (value is PyConditionalExpression) {
return PyUnionType.union(fromLiteral(value.truePart, context),
value.falsePart?.let { fromLiteral(it, context) })
}
return context.getType(value ?: return null)
}
}
}

View File

@@ -97,12 +97,6 @@ class PyLiteralType private constructor(cls: PyClass, val expression: PyExpressi
}
val substitution = if (substitutions != null) PyTypeChecker.substitute(expected, substitutions, context) else expected
val substitutionOrBound = if (substitution is PyTypeVarType) substitution.bound else substitution
if (containsLiteralString(substitutionOrBound)) {
val literalStringType = PyLiteralStringType.fromLiteral(expression, context)
if (literalStringType != null) {
return literalStringType
}
}
if (containsLiteral(substitutionOrBound)) {
return fromLiteralValue(expression, context)
}
@@ -110,17 +104,11 @@ class PyLiteralType private constructor(cls: PyClass, val expression: PyExpressi
}
private fun containsLiteral(type: PyType?): Boolean {
return type is PyLiteralType ||
return type is PyLiteralType || type is PyLiteralStringType ||
type is PyUnionType && type.members.any { containsLiteral(it) } ||
type is PyCollectionType && type.elementTypes.any { containsLiteral(it) }
}
private fun containsLiteralString(type: PyType?): Boolean {
return type is PyLiteralStringType ||
type is PyUnionType && type.members.any { containsLiteralString(it) } ||
type is PyCollectionType && type.elementTypes.any { containsLiteralString(it) }
}
private fun toLiteralType(expression: PyExpression, context: TypeEvalContext, index: Boolean): PyType? {
if (expression is PyNoneLiteralExpression && !expression.isEllipsis ||
expression is PyReferenceExpression &&
@@ -151,6 +139,18 @@ class PyLiteralType private constructor(cls: PyClass, val expression: PyExpressi
})
}
if (expression is PyStringLiteralExpression && expression.isInterpolated) {
val allLiteralStringFragments = expression.stringElements
.filterIsInstance<PyFormattedStringElement>()
.flatMap { it.fragments }
.mapNotNull { it.expression }
.map { context.getType(it) }
.all { it is PyLiteralStringType }
if (allLiteralStringFragments) {
return PyLiteralStringType.create(expression)
}
}
return classOfAcceptableLiteral(expression, context, index)?.let { PyLiteralType(it, expression) }
}