[FIR] KT-54220: Don't crash on unsigned integers when no stdlib present

^KT-54220 Fixed
This commit is contained in:
Nikolay Lunyak
2022-11-04 09:57:09 +02:00
parent b03e14f565
commit 267ce1d892
23 changed files with 128 additions and 7 deletions
@@ -203,6 +203,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.UNSIGNED_LITERAL_WITHOUT_DECLARATIONS_ON_CLASSPATH) { firDiagnostic ->
UnsignedLiteralWithoutDeclarationsOnClasspathImpl(
firDiagnostic as KtPsiDiagnostic,
token,
)
}
add(FirErrors.DIVISION_BY_ZERO) { firDiagnostic ->
DivisionByZeroImpl(
firDiagnostic as KtPsiDiagnostic,
@@ -179,6 +179,10 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = WrongLongSuffix::class
}
abstract class UnsignedLiteralWithoutDeclarationsOnClasspath : KtFirDiagnostic<KtElement>() {
override val diagnosticClass get() = UnsignedLiteralWithoutDeclarationsOnClasspath::class
}
abstract class DivisionByZero : KtFirDiagnostic<KtExpression>() {
override val diagnosticClass get() = DivisionByZero::class
}
@@ -201,6 +201,11 @@ internal class WrongLongSuffixImpl(
override val token: KtLifetimeToken,
) : KtFirDiagnostic.WrongLongSuffix(), KtAbstractFirDiagnostic<KtElement>
internal class UnsignedLiteralWithoutDeclarationsOnClasspathImpl(
override val firDiagnostic: KtPsiDiagnostic,
override val token: KtLifetimeToken,
) : KtFirDiagnostic.UnsignedLiteralWithoutDeclarationsOnClasspath(), KtAbstractFirDiagnostic<KtElement>
internal class DivisionByZeroImpl(
override val firDiagnostic: KtPsiDiagnostic,
override val token: KtLifetimeToken,
@@ -368,6 +368,7 @@ internal object FirCompileTimeConstantEvaluator {
ConstantValueKind.UnsignedShort -> value.toLong().toUShort()
ConstantValueKind.UnsignedInt -> value.toLong().toUInt()
ConstantValueKind.UnsignedLong -> value.toLong().toULong()
ConstantValueKind.UnsignedIntegerLiteral -> value.toLong().toULong()
else -> null
}
}
@@ -362,6 +362,12 @@ public class DiagnosisCompilerFirTestdataTestGenerated extends AbstractDiagnosis
runTest("compiler/fir/analysis-tests/testData/resolve/kt41990.kt");
}
@Test
@TestMetadata("kt54220.kt")
public void testKt54220() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/kt54220.kt");
}
@Test
@TestMetadata("labelAndReceiverForInfix.kt")
public void testLabelAndReceiverForInfix() throws Exception {
@@ -4664,6 +4670,12 @@ public class DiagnosisCompilerFirTestdataTestGenerated extends AbstractDiagnosis
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/kotlinComparatorAlias.kt");
}
@Test
@TestMetadata("kt54220.kt")
public void testKt54220() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/kt54220.kt");
}
@Test
@TestMetadata("listPlusAssign.kt")
public void testListPlusAssign() throws Exception {
@@ -309,6 +309,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract
runTest("compiler/fir/analysis-tests/testData/resolve/kt41990.kt");
}
@TestMetadata("kt54220.kt")
public void testKt54220() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/kt54220.kt");
}
@TestMetadata("labelAndReceiverForInfix.kt")
public void testLabelAndReceiverForInfix() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/labelAndReceiverForInfix.kt");
@@ -0,0 +1,14 @@
FILE: kt54220.kt
public final const val c: R|kotlin/String| = ERROR_EXPR(Unsigned integers need stdlib).R|kotlin/plus|(ERROR_EXPR(Unsigned integers need stdlib))
public get(): R|kotlin/String|
public final fun box(): R|kotlin/String| {
^box when () {
!=(R|/c|, ERROR_EXPR(Unsigned integers need stdlib)) -> {
String(fail)
}
else -> {
String(OK)
}
}
}
@@ -0,0 +1,6 @@
const val c = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!><!UNSIGNED_LITERAL_WITHOUT_DECLARATIONS_ON_CLASSPATH!>1u<!> + <!UNSIGNED_LITERAL_WITHOUT_DECLARATIONS_ON_CLASSPATH!>2u<!><!>
fun box() = when {
c != <!UNSIGNED_LITERAL_WITHOUT_DECLARATIONS_ON_CLASSPATH!>3u<!> -> "fail"
else -> "OK"
}
@@ -0,0 +1,14 @@
FILE: kt54220.kt
public final const val c: R|kotlin/UInt| = UInt(1).R|kotlin/UInt.plus|(UInt(2))
public get(): R|kotlin/UInt|
public final fun box(): R|kotlin/String| {
^box when () {
!=(R|/c|, UInt(3)) -> {
String(fail)
}
else -> {
String(OK)
}
}
}
@@ -0,0 +1,6 @@
const val c = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>1u + 2u<!>
fun box() = when {
c != 3u -> "fail"
else -> "OK"
}
@@ -362,6 +362,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest {
runTest("compiler/fir/analysis-tests/testData/resolve/kt41990.kt");
}
@Test
@TestMetadata("kt54220.kt")
public void testKt54220() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/kt54220.kt");
}
@Test
@TestMetadata("labelAndReceiverForInfix.kt")
public void testLabelAndReceiverForInfix() throws Exception {
@@ -4664,6 +4670,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest {
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/kotlinComparatorAlias.kt");
}
@Test
@TestMetadata("kt54220.kt")
public void testKt54220() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/kt54220.kt");
}
@Test
@TestMetadata("listPlusAssign.kt")
public void testListPlusAssign() throws Exception {
@@ -362,6 +362,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
runTest("compiler/fir/analysis-tests/testData/resolve/kt41990.kt");
}
@Test
@TestMetadata("kt54220.kt")
public void testKt54220() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/kt54220.kt");
}
@Test
@TestMetadata("labelAndReceiverForInfix.kt")
public void testLabelAndReceiverForInfix() throws Exception {
@@ -4664,6 +4670,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/kotlinComparatorAlias.kt");
}
@Test
@TestMetadata("kt54220.kt")
public void testKt54220() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/kt54220.kt");
}
@Test
@TestMetadata("listPlusAssign.kt")
public void testListPlusAssign() throws Exception {
@@ -76,6 +76,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val INT_LITERAL_OUT_OF_RANGE by error<PsiElement>()
val FLOAT_LITERAL_OUT_OF_RANGE by error<PsiElement>()
val WRONG_LONG_SUFFIX by error<KtElement>(PositioningStrategy.LONG_LITERAL_SUFFIX)
val UNSIGNED_LITERAL_WITHOUT_DECLARATIONS_ON_CLASSPATH by error<KtElement>()
val DIVISION_BY_ZERO by warning<KtExpression>()
val VAL_OR_VAR_ON_LOOP_PARAMETER by error<KtParameter>(PositioningStrategy.VAL_OR_VAR_NODE) {
parameter<KtKeywordToken>("valOrVar")
@@ -133,6 +133,7 @@ object FirErrors {
val INT_LITERAL_OUT_OF_RANGE by error0<PsiElement>()
val FLOAT_LITERAL_OUT_OF_RANGE by error0<PsiElement>()
val WRONG_LONG_SUFFIX by error0<KtElement>(SourceElementPositioningStrategies.LONG_LITERAL_SUFFIX)
val UNSIGNED_LITERAL_WITHOUT_DECLARATIONS_ON_CLASSPATH by error0<KtElement>()
val DIVISION_BY_ZERO by warning0<KtExpression>()
val VAL_OR_VAR_ON_LOOP_PARAMETER by error1<KtParameter, KtKeywordToken>(SourceElementPositioningStrategies.VAL_OR_VAR_NODE)
val VAL_OR_VAR_ON_FUN_PARAMETER by error1<KtParameter, KtKeywordToken>(SourceElementPositioningStrategies.VAL_OR_VAR_NODE)
@@ -532,6 +532,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSAFE_CALL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSAFE_IMPLICIT_INVOKE_CALL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSAFE_INFIX_CALL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSAFE_OPERATOR_CALL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSIGNED_LITERAL_WITHOUT_DECLARATIONS_ON_CLASSPATH
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSUPPORTED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSUPPORTED_CONTEXTUAL_DECLARATION_CALL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSUPPORTED_FEATURE
@@ -633,6 +634,10 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
map.put(WRONG_LONG_SUFFIX, "Use 'L' instead of 'l'")
map.put(EMPTY_CHARACTER_LITERAL, "Empty character literal")
map.put(FLOAT_LITERAL_OUT_OF_RANGE, "The value is out of range")
map.put(
UNSIGNED_LITERAL_WITHOUT_DECLARATIONS_ON_CLASSPATH,
"Type of the constant expression cannot be resolved. Please make sure you have the required dependencies for unsigned types in the classpath"
)
map.put(INCORRECT_CHARACTER_LITERAL, "Incorrect character literal")
map.put(TOO_MANY_CHARACTERS_IN_CHARACTER_LITERAL, "Too many characters in a character literal")
map.put(ILLEGAL_ESCAPE, "Illegal escape")
@@ -499,6 +499,7 @@ private fun ConeSimpleDiagnostic.getFactory(source: KtSourceElement): KtDiagnost
DiagnosticKind.IntLiteralOutOfRange -> FirErrors.INT_LITERAL_OUT_OF_RANGE
DiagnosticKind.FloatLiteralOutOfRange -> FirErrors.FLOAT_LITERAL_OUT_OF_RANGE
DiagnosticKind.WrongLongSuffix -> FirErrors.WRONG_LONG_SUFFIX
DiagnosticKind.UnsignedNumbersAreNotPresent -> FirErrors.UNSIGNED_LITERAL_WITHOUT_DECLARATIONS_ON_CLASSPATH
DiagnosticKind.IncorrectCharacterLiteral -> FirErrors.INCORRECT_CHARACTER_LITERAL
DiagnosticKind.EmptyCharacterLiteral -> FirErrors.EMPTY_CHARACTER_LITERAL
DiagnosticKind.TooManyCharactersInCharacterLiteral -> FirErrors.TOO_MANY_CHARACTERS_IN_CHARACTER_LITERAL
@@ -1010,11 +1010,15 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT
ConstantValueKind.IntegerLiteral, ConstantValueKind.UnsignedIntegerLiteral -> {
val expressionType = ConeIntegerLiteralConstantTypeImpl.create(
constExpression.value as Long,
isTypePresent = { it.lookupTag.toSymbol(session) != null },
isUnsigned = kind == ConstantValueKind.UnsignedIntegerLiteral
)
val expectedTypeRef = data.expectedType
@Suppress("UNCHECKED_CAST")
when {
expressionType is ConeErrorType -> {
expressionType
}
expressionType is ConeClassLikeType -> {
constExpression.replaceKind(expressionType.toConstKind() as ConstantValueKind<T>)
expressionType
@@ -1040,7 +1044,16 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT
dataFlowAnalyzer.exitConstExpression(constExpression as FirConstExpression<*>)
constExpression.resultType = constExpression.resultType.resolvedTypeFromPrototype(type)
return constExpression
return when (val resolvedType = constExpression.resultType.coneType) {
is ConeErrorType -> buildErrorExpression {
expression = constExpression
diagnostic = resolvedType.diagnostic
source = constExpression.source
}
else -> constExpression
}
}
override fun transformAnnotation(annotation: FirAnnotation, data: ResolutionMode): FirStatement {
@@ -87,6 +87,7 @@ enum class DiagnosticKind {
IntLiteralOutOfRange,
FloatLiteralOutOfRange,
WrongLongSuffix,
UnsignedNumbersAreNotPresent,
IsEnumEntry,
EnumEntryAsType,
@@ -5,6 +5,8 @@
package org.jetbrains.kotlin.fir.types
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
import org.jetbrains.kotlin.fir.isLong
import org.jetbrains.kotlin.fir.isULong
import org.jetbrains.kotlin.name.StandardClassIds
@@ -38,6 +40,7 @@ class ConeIntegerLiteralConstantTypeImpl(
fun create(
value: Long,
isUnsigned: Boolean,
isTypePresent: (ConeClassLikeType) -> Boolean,
nullability: ConeNullability = ConeNullability.NOT_NULL
): ConeSimpleKotlinType {
val possibleTypes = mutableListOf<ConeClassLikeType>()
@@ -64,6 +67,9 @@ class ConeIntegerLiteralConstantTypeImpl(
if (isUnsigned) {
addUnsignedPossibleType()
if (possibleTypes.any { !isTypePresent(it) }) {
return ConeErrorType(ConeSimpleDiagnostic("Unsigned integers need stdlib", DiagnosticKind.UnsignedNumbersAreNotPresent))
}
} else {
addSignedPossibleTypes()
}
@@ -1,3 +0,0 @@
val u1 = 1u
val u2 = 0xFu
val u3 = 0b1u
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
val u1 = <!UNSIGNED_LITERAL_WITHOUT_DECLARATIONS_ON_CLASSPATH!>1u<!>
val u2 = <!UNSIGNED_LITERAL_WITHOUT_DECLARATIONS_ON_CLASSPATH!>0xFu<!>
val u3 = <!UNSIGNED_LITERAL_WITHOUT_DECLARATIONS_ON_CLASSPATH!>0b1u<!>
@@ -1,3 +0,0 @@
val u1 = 1u
val u2 = 0xFu
val u3 = 0b1u
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
val u1 = <!UNSIGNED_LITERAL_WITHOUT_DECLARATIONS_ON_CLASSPATH!>1u<!>
val u2 = <!UNSIGNED_LITERAL_WITHOUT_DECLARATIONS_ON_CLASSPATH!>0xFu<!>
val u3 = <!UNSIGNED_LITERAL_WITHOUT_DECLARATIONS_ON_CLASSPATH!>0b1u<!>