[FIR] Add CAST_NEVER_SUCCEEDS

This commit is contained in:
Ivan Kochurkin
2021-09-16 20:58:52 +03:00
committed by TeamCityServer
parent 4ca757446a
commit 2b5524b18f
42 changed files with 206 additions and 273 deletions
@@ -3104,6 +3104,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.CAST_NEVER_SUCCEEDS) { firDiagnostic ->
CastNeverSucceedsImpl(
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirErrors.USELESS_CAST) { firDiagnostic ->
UselessCastImpl(
firDiagnostic as KtPsiDiagnostic,
@@ -2173,6 +2173,10 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
abstract val type: KtType
}
abstract class CastNeverSucceeds : KtFirDiagnostic<KtBinaryExpressionWithTypeRHS>() {
override val diagnosticClass get() = CastNeverSucceeds::class
}
abstract class UselessCast : KtFirDiagnostic<KtBinaryExpressionWithTypeRHS>() {
override val diagnosticClass get() = UselessCast::class
}
@@ -2618,6 +2618,13 @@ internal class CannotCheckForErasedImpl(
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class CastNeverSucceedsImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.CastNeverSucceeds(), KtAbstractFirDiagnostic<KtBinaryExpressionWithTypeRHS> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class UselessCastImpl(
override val firDiagnostic: KtPsiDiagnostic,
override val token: ValidityToken,
@@ -9,7 +9,7 @@ fun test_1(b: B<String, Number>) {
}
fun test_2(s: String) {
val func = { s.length } as B<Int, Int>
val func = { s.length } <!CAST_NEVER_SUCCEEDS!>as<!> B<Int, Int>
}
class B<out K, V>(val k: K, val v: V)
@@ -1105,6 +1105,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val CANNOT_CHECK_FOR_ERASED by error<PsiElement> {
parameter<ConeKotlinType>("type")
}
val CAST_NEVER_SUCCEEDS by warning<KtBinaryExpressionWithTypeRHS>(PositioningStrategy.OPERATOR)
val USELESS_CAST by warning<KtBinaryExpressionWithTypeRHS>(PositioningStrategy.AS_TYPE)
val USELESS_IS_CHECK by warning<KtElement> {
parameter<Boolean>("compileTimeCheckResult")
@@ -591,6 +591,7 @@ object FirErrors {
// Casts and is-checks
val CANNOT_CHECK_FOR_ERASED by error1<PsiElement, ConeKotlinType>()
val CAST_NEVER_SUCCEEDS by warning0<KtBinaryExpressionWithTypeRHS>(SourceElementPositioningStrategies.OPERATOR)
val USELESS_CAST by warning0<KtBinaryExpressionWithTypeRHS>(SourceElementPositioningStrategies.AS_TYPE)
val USELESS_IS_CHECK by warning1<KtElement, Boolean>()
val IS_ENUM_ENTRY by error0<KtTypeReference>()
@@ -132,7 +132,7 @@ object CommonExpressionCheckers : ExpressionCheckers() {
override val typeOperatorCallCheckers: Set<FirTypeOperatorCallChecker>
get() = setOf(
FirUselessTypeOperationCallChecker,
FirCannotCheckForErasedChecker
FirCastOperatorsChecker
)
override val resolvedQualifierCheckers: Set<FirResolvedQualifierChecker>
@@ -5,19 +5,104 @@
package org.jetbrains.kotlin.fir.analysis.checkers
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.declarations.utils.isInterface
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.resolve.defaultType
import org.jetbrains.kotlin.fir.resolve.platformClassMapper
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap
import org.jetbrains.kotlin.fir.scopes.platformClassMapper
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.typeContext
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.types.AbstractTypeChecker
import org.jetbrains.kotlin.types.AbstractTypeChecker.findCorrespondingSupertypes
import org.jetbrains.kotlin.types.model.typeConstructor
fun isCastPossible(
lhsType: ConeKotlinType,
rhsType: ConeKotlinType,
isSafeCase: Boolean,
context: CheckerContext
): Boolean {
val lhsLowerType = lhsType.lowerBoundIfFlexible()
val rhsLowerType = rhsType.lowerBoundIfFlexible()
val session = context.session
if (lhsLowerType is ConeIntersectionType) {
var result = false
for (intersectedType in lhsLowerType.intersectedTypes) {
val isIntersectedCastPossible = isCastPossible(intersectedType, rhsLowerType, isSafeCase, context)
val intersectedTypeSymbol = intersectedType.toRegularClassSymbol(context.session)
if (intersectedTypeSymbol?.isInterface == false && !isIntersectedCastPossible) {
return false // Any class type in intersection type should be subtype of RHS
}
result = result or isIntersectedCastPossible
}
return result
}
val lhsNullable = lhsLowerType.canBeNull
val rhsNullable = rhsLowerType.canBeNull
if (lhsLowerType.isNothing) return true
if (lhsLowerType.isNullableNothing && !rhsNullable) {
return isSafeCase
}
if (rhsLowerType.isNothing) return false
if (rhsLowerType.isNullableNothing) return lhsNullable
if (lhsNullable && rhsNullable) return true
val lhsClassSymbol = lhsLowerType.toRegularClassSymbol(context.session)
val rhsClassSymbol = rhsLowerType.toRegularClassSymbol(context.session)
if (isRelated(lhsLowerType, rhsLowerType, lhsClassSymbol, rhsClassSymbol, context)) return true
// This is an oversimplification (which does not render the method incomplete):
// we consider any type parameter capable of taking any value, which may be made more precise if we considered bounds
if (lhsLowerType is ConeTypeParameterType || rhsLowerType is ConeTypeParameterType) return true
if (isFinal(lhsLowerType, session) || isFinal(rhsLowerType, session)) return false
if (lhsClassSymbol?.isInterface == true || rhsClassSymbol?.isInterface == true) return true
return false
}
/**
* Two types are related, roughly, when one of them is a subtype of the other constructing class
*
* Note that some types have platform-specific counterparts, i.e. kotlin.String is mapped to java.lang.String,
* such types (and all their sub- and supertypes) are related too.
*
* Due to limitations in PlatformToKotlinClassMap, we only consider mapping of platform classes to Kotlin classed
* (i.e. java.lang.String -> kotlin.String) and ignore mappings that go the other way.
*/
private fun isRelated(
aType: ConeKotlinType,
bType: ConeKotlinType,
aClassSymbol: FirRegularClassSymbol?,
bClassSymbol: FirRegularClassSymbol?,
context: CheckerContext
): Boolean {
val typeContext = context.session.typeContext
if (AbstractTypeChecker.isSubtypeOf(typeContext, aType, bType) ||
AbstractTypeChecker.isSubtypeOf(typeContext, bType, aType)
) {
return true
}
fun getCorrespondingKotlinClass(type: ConeKotlinType): ConeKotlinType {
return context.session.platformClassMapper.getCorrespondingKotlinClass(type.classId)?.defaultType(listOf()) ?: type
}
val aNormalizedType = getCorrespondingKotlinClass(aClassSymbol?.defaultType() ?: aType)
val bNormalizedType = getCorrespondingKotlinClass(bClassSymbol?.defaultType() ?: bType)
return AbstractTypeChecker.isSubtypeOf(typeContext, aNormalizedType, bNormalizedType) ||
AbstractTypeChecker.isSubtypeOf(typeContext, bNormalizedType, aNormalizedType)
}
private fun isFinal(type: ConeKotlinType, session: FirSession): Boolean {
return !type.canHaveSubtypes(session)
}
fun isCastErased(supertype: ConeKotlinType, subtype: ConeKotlinType, context: CheckerContext): Boolean {
val typeContext = context.session.typeContext
@@ -1,31 +0,0 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.isCastErased
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.expressions.FirOperation
import org.jetbrains.kotlin.fir.expressions.FirTypeOperatorCall
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.types.coneType
object FirCannotCheckForErasedChecker : FirTypeOperatorCallChecker() {
override fun check(expression: FirTypeOperatorCall, context: CheckerContext, reporter: DiagnosticReporter) {
if (expression.operation != FirOperation.IS) return
val session = context.session
val subjectType = expression.argumentList.arguments[0].typeRef.coneType.fullyExpandedType(session)
val conversionTypeRef = expression.conversionTypeRef
val targetType = conversionTypeRef.coneType.fullyExpandedType(session)
if (isCastErased(subjectType, targetType, context)) {
reporter.reportOn(conversionTypeRef.source, FirErrors.CANNOT_CHECK_FOR_ERASED, targetType, context)
}
}
}
@@ -5,13 +5,13 @@
package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.analysis.checkers.CastingType
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.isCastErased
import org.jetbrains.kotlin.fir.analysis.checkers.checkCasting
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.expressions.FirExpressionWithSmartcast
import org.jetbrains.kotlin.fir.expressions.FirOperation
import org.jetbrains.kotlin.fir.expressions.FirTypeOperatorCall
@@ -725,6 +725,7 @@ object PositioningStrategies {
override fun mark(element: KtExpression): List<TextRange> {
return when (element) {
is KtBinaryExpression -> mark(element.operationReference)
is KtBinaryExpressionWithTypeRHS -> mark(element.operationReference)
is KtUnaryExpression -> mark(element.operationReference)
else -> super.mark(element)
}
+3 -3
View File
@@ -32,11 +32,11 @@ fun test() {
checkSubtype<Double>(<!ARGUMENT_TYPE_MISMATCH!>1<!>)
checkSubtype<Float>(<!ARGUMENT_TYPE_MISMATCH!>1<!>)
1 as Byte
1 <!CAST_NEVER_SUCCEEDS!>as<!> Byte
1 <!USELESS_CAST!>as Int<!>
0xff as Long
0xff <!CAST_NEVER_SUCCEEDS!>as<!> Long
1.1 as Int
1.1 <!CAST_NEVER_SUCCEEDS!>as<!> Int
checkSubtype<Int>(<!ARGUMENT_TYPE_MISMATCH!>1.1<!>)
varargByte(0x77, 1, 3, <!ARGUMENT_TYPE_MISMATCH!>200<!>, 0b111)
@@ -33,4 +33,4 @@ fun bar(a: Ann = <!ANNOTATION_CLASS_CONSTRUCTOR_CALL!>Ann()<!>) {
operator fun String.invoke() {}
// from stdlib
fun <T> javaClass() : Class<T> = null as Class<T>
fun <T> javaClass() : Class<T> = null <!CAST_NEVER_SUCCEEDS!>as<!> Class<T>
@@ -1,14 +0,0 @@
// Nothing can be cast to Nothing
fun foo(x: String) {
x as Nothing
}
fun gav(y: String?) {
y as Nothing
}
// Only nullable can be cast to Nothing?
fun bar(x: String, y: String?) {
x as Nothing?
y as Nothing?
}
+1
View File
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// Nothing can be cast to Nothing
fun foo(x: String) {
x <!CAST_NEVER_SUCCEEDS!>as<!> Nothing
@@ -1,18 +0,0 @@
typealias MyString = String
val x: MyString = ""
val y = x as Any
interface Base
class Derived : Base
interface Other : Base
typealias IBase = Base
typealias IOther = Other
val ib: IBase = Derived()
val d = ib as Derived
val o = ib as Other
val io = ib as IOther
val s = d as String
val ms = d as MyString
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
typealias MyString = String
val x: MyString = ""
+36 -36
View File
@@ -1,51 +1,51 @@
fun asCall() {
1 <!USELESS_CAST!>as Int<!>
1 as Byte
1 as Short
1 as Long
1 as Char
1 as Double
1 as Float
1 <!CAST_NEVER_SUCCEEDS!>as<!> Byte
1 <!CAST_NEVER_SUCCEEDS!>as<!> Short
1 <!CAST_NEVER_SUCCEEDS!>as<!> Long
1 <!CAST_NEVER_SUCCEEDS!>as<!> Char
1 <!CAST_NEVER_SUCCEEDS!>as<!> Double
1 <!CAST_NEVER_SUCCEEDS!>as<!> Float
1.0 as Int
1.0 as Byte
1.0 as Short
1.0 as Long
1.0 as Char
1.0 <!CAST_NEVER_SUCCEEDS!>as<!> Int
1.0 <!CAST_NEVER_SUCCEEDS!>as<!> Byte
1.0 <!CAST_NEVER_SUCCEEDS!>as<!> Short
1.0 <!CAST_NEVER_SUCCEEDS!>as<!> Long
1.0 <!CAST_NEVER_SUCCEEDS!>as<!> Char
1.0 <!USELESS_CAST!>as Double<!>
1.0 as Float
1.0 <!CAST_NEVER_SUCCEEDS!>as<!> Float
1f as Int
1f as Byte
1f as Short
1f as Long
1f as Char
1f as Double
1f <!CAST_NEVER_SUCCEEDS!>as<!> Int
1f <!CAST_NEVER_SUCCEEDS!>as<!> Byte
1f <!CAST_NEVER_SUCCEEDS!>as<!> Short
1f <!CAST_NEVER_SUCCEEDS!>as<!> Long
1f <!CAST_NEVER_SUCCEEDS!>as<!> Char
1f <!CAST_NEVER_SUCCEEDS!>as<!> Double
1f <!USELESS_CAST!>as Float<!>
}
fun asSafe() {
1 as? Int
1 as? Byte
1 as? Short
1 as? Long
1 as? Char
1 as? Double
1 as? Float
1 <!CAST_NEVER_SUCCEEDS!>as?<!> Byte
1 <!CAST_NEVER_SUCCEEDS!>as?<!> Short
1 <!CAST_NEVER_SUCCEEDS!>as?<!> Long
1 <!CAST_NEVER_SUCCEEDS!>as?<!> Char
1 <!CAST_NEVER_SUCCEEDS!>as?<!> Double
1 <!CAST_NEVER_SUCCEEDS!>as?<!> Float
1.0 as? Int
1.0 as? Byte
1.0 as? Short
1.0 as? Long
1.0 as? Char
1.0 <!CAST_NEVER_SUCCEEDS!>as?<!> Int
1.0 <!CAST_NEVER_SUCCEEDS!>as?<!> Byte
1.0 <!CAST_NEVER_SUCCEEDS!>as?<!> Short
1.0 <!CAST_NEVER_SUCCEEDS!>as?<!> Long
1.0 <!CAST_NEVER_SUCCEEDS!>as?<!> Char
1.0 as? Double
1.0 as? Float
1.0 <!CAST_NEVER_SUCCEEDS!>as?<!> Float
1f as? Int
1f as? Byte
1f as? Short
1f as? Long
1f as? Char
1f as? Double
1f <!CAST_NEVER_SUCCEEDS!>as?<!> Int
1f <!CAST_NEVER_SUCCEEDS!>as?<!> Byte
1f <!CAST_NEVER_SUCCEEDS!>as?<!> Short
1f <!CAST_NEVER_SUCCEEDS!>as?<!> Long
1f <!CAST_NEVER_SUCCEEDS!>as?<!> Char
1f <!CAST_NEVER_SUCCEEDS!>as?<!> Double
1f as? Float
}
@@ -1,33 +0,0 @@
// !DIAGNOSTICS: -PLATFORM_CLASS_MAPPED_TO_KOTLIN -USELESS_CAST
import java.lang.String as JString
import java.lang.CharSequence as JCS
fun test(
s: String,
js: JString,
cs: CharSequence,
jcs: JCS
) {
s as JString
s as JCS
s as CharSequence
s as String
js as JString
js as JCS
js as CharSequence
js as String
cs as JString
cs as JCS
cs as CharSequence
cs as String
jcs as JString
jcs as JCS
jcs as CharSequence
jcs as String
jcs as Int
s as java.lang.Integer
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -PLATFORM_CLASS_MAPPED_TO_KOTLIN -USELESS_CAST
import java.lang.String as JString
import java.lang.CharSequence as JCS
@@ -1,21 +0,0 @@
// !DIAGNOSTICS: -PLATFORM_CLASS_MAPPED_TO_KOTLIN -UNUSED_PARAMETER -ABSTRACT_MEMBER_NOT_IMPLEMENTED -USELESS_CAST
import java.lang.CharSequence as JCS
class JSub: JCS
class Sub: CharSequence
fun test(
s: Sub,
js: JSub,
cs: CharSequence,
jcs: JCS
) {
// js as CharSequence // - this case is not supported due to limitation in PlatformToKotlinClassMap
js as JCS
s as CharSequence
s as JCS
js as Sub
s as JSub
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -PLATFORM_CLASS_MAPPED_TO_KOTLIN -UNUSED_PARAMETER -ABSTRACT_MEMBER_NOT_IMPLEMENTED -USELESS_CAST
import java.lang.CharSequence as JCS
@@ -1,34 +0,0 @@
// !DIAGNOSTICS: -UNCHECKED_CAST
interface Trait1
interface Trait2
open class OClass1
open class OClass2
class FClass1
class FClass2
fun <TP1: OClass1, TP2: OClass2> test(
t1: Trait1,
oc1: OClass1,
fc1: FClass1,
tp1: TP1
) {
t1 as Trait2
t1 as OClass2
t1 as FClass2
t1 as TP2
oc1 as Trait2
oc1 as OClass2
oc1 as FClass2
oc1 as TP2
fc1 as Trait2
fc1 as OClass2
fc1 as FClass2
fc1 as TP2
tp1 as Trait2
tp1 as OClass2
tp1 as FClass2
tp1 as TP2
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -UNCHECKED_CAST
interface Trait1
interface Trait2
@@ -19,35 +19,35 @@ class Inv<T>() {
fun testInOut() {
In<String>().f("1");
(null as In<in String>).f("1")
(null as In<*>).<!NONE_APPLICABLE!>f<!>("1") // Wrong Arg
(null <!CAST_NEVER_SUCCEEDS!>as<!> In<in String>).f("1")
(null <!CAST_NEVER_SUCCEEDS!>as<!> In<*>).<!NONE_APPLICABLE!>f<!>("1") // Wrong Arg
In<String>().f(1);
(null as In<in String>).f(1)
(null as In<*>).f(1);
(null <!CAST_NEVER_SUCCEEDS!>as<!> In<in String>).f(1)
(null <!CAST_NEVER_SUCCEEDS!>as<!> In<*>).f(1);
Out<Int>().f(1)
(null as Out<out Int>).f(1)
(null as Out<*>).f(1)
(null <!CAST_NEVER_SUCCEEDS!>as<!> Out<out Int>).f(1)
(null <!CAST_NEVER_SUCCEEDS!>as<!> Out<*>).f(1)
Out<Int>().f()
(null as Out<out Int>).f()
(null as Out<*>).f()
(null <!CAST_NEVER_SUCCEEDS!>as<!> Out<out Int>).f()
(null <!CAST_NEVER_SUCCEEDS!>as<!> Out<*>).f()
Inv<Int>().f(1)
(null as Inv<in Int>).f(1)
(null as Inv<out Int>).f(<!ARGUMENT_TYPE_MISMATCH!>1<!>) // !!
(null as Inv<*>).f(<!ARGUMENT_TYPE_MISMATCH!>1<!>) // !!
(null <!CAST_NEVER_SUCCEEDS!>as<!> Inv<in Int>).f(1)
(null <!CAST_NEVER_SUCCEEDS!>as<!> Inv<out Int>).f(<!ARGUMENT_TYPE_MISMATCH!>1<!>) // !!
(null <!CAST_NEVER_SUCCEEDS!>as<!> Inv<*>).f(<!ARGUMENT_TYPE_MISMATCH!>1<!>) // !!
Inv<Int>().inf(1)
(null as Inv<in Int>).inf(1)
(null as Inv<out Int>).inf(<!ARGUMENT_TYPE_MISMATCH!>1<!>) // !!
(null as Inv<*>).inf(<!ARGUMENT_TYPE_MISMATCH!>1<!>) // !!
(null <!CAST_NEVER_SUCCEEDS!>as<!> Inv<in Int>).inf(1)
(null <!CAST_NEVER_SUCCEEDS!>as<!> Inv<out Int>).inf(<!ARGUMENT_TYPE_MISMATCH!>1<!>) // !!
(null <!CAST_NEVER_SUCCEEDS!>as<!> Inv<*>).inf(<!ARGUMENT_TYPE_MISMATCH!>1<!>) // !!
Inv<Int>().outf()
checkSubtype<Int>(<!ARGUMENT_TYPE_MISMATCH!>(null as Inv<in Int>).outf()<!>) // Type mismatch
(null as Inv<out Int>).outf()
(null as Inv<*>).outf()
checkSubtype<Int>(<!ARGUMENT_TYPE_MISMATCH!>(null <!CAST_NEVER_SUCCEEDS!>as<!> Inv<in Int>).outf()<!>) // Type mismatch
(null <!CAST_NEVER_SUCCEEDS!>as<!> Inv<out Int>).outf()
(null <!CAST_NEVER_SUCCEEDS!>as<!> Inv<*>).outf()
Inv<Int>().outf(<!TOO_MANY_ARGUMENTS!>1<!>) // Wrong Arg
}
@@ -9,4 +9,4 @@ fun <T> foo2(): T = TODO()
val test = <!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>foo2<!>().plus("") <!USELESS_CAST!>as String<!>
fun <T> T.bar() = this
val barTest = "".bar() as Number
val barTest = "".bar() <!CAST_NEVER_SUCCEEDS!>as<!> Number
@@ -1,11 +0,0 @@
fun <R> runCatching(block: () -> R) = null as Result<R>
class Result<out T> {
fun getOrNull(): T? = null
}
fun main() {
runCatching {
null
}.getOrNull() // don't report IMPLICIT_NOTHING_TYPE_ARGUMENT_IN_RETURN_POSITION
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
fun <R> runCatching(block: () -> R) = null <!CAST_NEVER_SUCCEEDS!>as<!> Result<R>
class Result<out T> {
@@ -52,7 +52,7 @@ fun test() {
if (<!USELESS_IS_CHECK!>x11 is Foo<<!UNRESOLVED_REFERENCE!>_<!>><!>) { }
x10 as <!UNRESOLVED_REFERENCE!>_<!>
x10 as Foo<<!UNRESOLVED_REFERENCE!>_<!>>
x10 <!CAST_NEVER_SUCCEEDS!>as<!> Foo<<!UNRESOLVED_REFERENCE!>_<!>>
val x12: Foo<@<!UNDERSCORE_USAGE_WITHOUT_BACKTICKS, UNRESOLVED_REFERENCE!>_<!> Int>? = null
val x13: Foo<@<!UNDERSCORE_USAGE_WITHOUT_BACKTICKS, UNRESOLVED_REFERENCE!>_<!>() Int>? = null
@@ -1,17 +0,0 @@
// KT-702 Type inference failed
fun <T> getJavaClass() : java.lang.Class<T> { return "" as Class<T> }
public class Throwables() {
companion object {
public fun <X : Throwable?> propagateIfInstanceOf(throwable : Throwable?, declaredType : Class<X?>?) {
if (((throwable != null) && declaredType?.isInstance(throwable)!!))
{
throw <!SAFE_CALL_WILL_CHANGE_NULLABILITY!>declaredType<!UNNECESSARY_SAFE_CALL!>?.<!>cast(throwable)<!>!!
}
}
public fun propagateIfPossible(throwable : Throwable?) {
propagateIfInstanceOf(throwable, getJavaClass<Error?>()) //; Type inference failed: Mismatch while expanding constraints
propagateIfInstanceOf(throwable, getJavaClass<RuntimeException?>()) // Type inference failed: Mismatch while expanding constraints
}
}
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// KT-702 Type inference failed
fun <T> getJavaClass() : java.lang.Class<T> { return "" <!CAST_NEVER_SUCCEEDS!>as<!> Class<T> }
@@ -2,7 +2,7 @@
class TypeInfo<T>
fun <T> typeinfo() : TypeInfo<T> = null as TypeInfo<T>
fun <T> typeinfo() : TypeInfo<T> = null <!CAST_NEVER_SUCCEEDS!>as<!> TypeInfo<T>
fun <T> TypeInfo<T>.getJavaClass() : java.lang.Class<T> {
val t : java.lang.Object = this as java.lang.Object
@@ -13,4 +13,4 @@ fun <T> getJavaClass() = typeinfo<T>().getJavaClass()
fun main() {
System.out.println(getJavaClass<String>())
}
}
@@ -43,7 +43,7 @@ fun f(a: SomeClass?) {
aa<!UNSAFE_CALL!>.<!>hashCode()
aa.<!UNRESOLVED_REFERENCE!>foo<!>
(aa as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
(aa as SomeSubClass).foo
(aa <!CAST_NEVER_SUCCEEDS!>as<!> SomeSubClass).foo
}
val b = (aa as? SomeSubClass)?.foo
aa = null
@@ -52,7 +52,7 @@ fun f(a: SomeClass?) {
aa<!UNSAFE_CALL!>.<!>hashCode()
aa.<!UNRESOLVED_REFERENCE!>foo<!>
(aa as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
(aa as SomeSubClass).foo
(aa <!CAST_NEVER_SUCCEEDS!>as<!> SomeSubClass).foo
}
aa = a
val c = aa as? SomeSubClass
@@ -4,7 +4,7 @@ fun <T : CharSequence> foo(x: Array<Any>, y: IntArray, block: (T, Int) -> Int) {
@Suppress("UNCHECKED_CAST")
// comment
/* comment */
r = block(x[0] as T, "" as Int)
r = block(x[0] as T, "" <!CAST_NEVER_SUCCEEDS!>as<!> Int)
// to prevent unused assignment diagnostic for the above statement
r.hashCode()
@@ -13,42 +13,42 @@ fun <T : CharSequence> foo(x: Array<Any>, y: IntArray, block: (T, Int) -> Int) {
if (i != 1) {
@Suppress("UNCHECKED_CAST")
i += block(x[0] as T, "" as Int).toInt()
i += block(x[0] as T, "" <!CAST_NEVER_SUCCEEDS!>as<!> Int).toInt()
}
if (i != 1)
@Suppress("UNCHECKED_CAST")
i += block(x[0] as T, "" as Int).toInt()
i += block(x[0] as T, "" <!CAST_NEVER_SUCCEEDS!>as<!> Int).toInt()
if (i != 2)
@Suppress("UNCHECKED_CAST")
i += block(x[0] as T, "" as Int).toInt()
i += block(x[0] as T, "" <!CAST_NEVER_SUCCEEDS!>as<!> Int).toInt()
else
@Suppress("UNCHECKED_CAST")
i += block(x[1] as T, "" as Int).toInt()
i += block(x[1] as T, "" <!CAST_NEVER_SUCCEEDS!>as<!> Int).toInt()
while (i != 1)
@Suppress("UNCHECKED_CAST")
i += block(x[0] as T, "" as Int).toInt()
i += block(x[0] as T, "" <!CAST_NEVER_SUCCEEDS!>as<!> Int).toInt()
do
@Suppress("UNCHECKED_CAST")
i += block(x[0] as T, "" as Int).toInt()
i += block(x[0] as T, "" <!CAST_NEVER_SUCCEEDS!>as<!> Int).toInt()
while (i != 1)
for (j in 1..100)
@Suppress("UNCHECKED_CAST")
i += block(x[0] as T, "" as Int).toInt()
i += block(x[0] as T, "" <!CAST_NEVER_SUCCEEDS!>as<!> Int).toInt()
when (i) {
1 ->
@Suppress("UNCHECKED_CAST")
i += block(x[0] as T, "" as Int).toInt()
i += block(x[0] as T, "" <!CAST_NEVER_SUCCEEDS!>as<!> Int).toInt()
}
val l: () -> Unit = {
@Suppress("UNCHECKED_CAST")
i += block(x[0] as T, "" as Int).toInt()
i += block(x[0] as T, "" <!CAST_NEVER_SUCCEEDS!>as<!> Int).toInt()
}
l()
@@ -56,5 +56,5 @@ fun <T : CharSequence> foo(x: Array<Any>, y: IntArray, block: (T, Int) -> Int) {
@Suppress("UNCHECKED_CAST")
y[i] += block(x[0] as T, "" as Int).toInt()
y[i] += block(x[0] as T, "" <!CAST_NEVER_SUCCEEDS!>as<!> Int).toInt()
}
@@ -1,7 +1,7 @@
fun <T : CharSequence> foo(x: Array<Any>, block: (T, Int) -> Int) {
var r: Any?
@Suppress("UNCHECKED_CAST") r = block(x[0] as T, "" as Int)
@Suppress("UNCHECKED_CAST") r = block(x[0] as T, "" <!CAST_NEVER_SUCCEEDS!>as<!> Int)
// to prevent unused assignment diagnostic for the above statement
r.hashCode()
@@ -9,11 +9,11 @@ fun <T : CharSequence> foo(x: Array<Any>, block: (T, Int) -> Int) {
var i = 1
if (i != 1) {
@Suppress("UNCHECKED_CAST") i += block(x[0] as T, "" as Int).toInt()
@Suppress("UNCHECKED_CAST") i += block(x[0] as T, "" <!CAST_NEVER_SUCCEEDS!>as<!> Int).toInt()
}
if (i != 1) @Suppress("UNCHECKED_CAST")
i += block(x[0] as T, "" as Int).toInt()
i += block(x[0] as T, "" <!CAST_NEVER_SUCCEEDS!>as<!> Int).toInt()
if (i != 1) @Suppress("UNCHECKED_CAST") i += block(x[0] as T, "" as Int).toInt()
if (i != 1) @Suppress("UNCHECKED_CAST") i += block(x[0] as T, "" <!CAST_NEVER_SUCCEEDS!>as<!> Int).toInt()
}
@@ -8,5 +8,5 @@ fun interface ReadOnlyProperty<in T, out V> {
class Problem {
val variable: Int by <!DELEGATE_SPECIAL_FUNCTION_RETURN_TYPE_MISMATCH, NEW_INFERENCE_ERROR, NEW_INFERENCE_ERROR!>delegate()<!> // delegate returns `ReadOnlyProperty<Problem, {CharSequence & Int}>`
fun <T : CharSequence> delegate() = null as ReadOnlyProperty<Problem, T>
fun <T : CharSequence> delegate() = null <!CAST_NEVER_SUCCEEDS!>as<!> ReadOnlyProperty<Problem, T>
}
@@ -13,7 +13,7 @@ fun test1(s: SubInt, sWrong: SubIntWrong) {
val a = "foo"
foo(<!ARGUMENT_TYPE_MISMATCH!>a<!>)
a as (Int, String) -> String
a <!CAST_NEVER_SUCCEEDS!>as<!> (Int, String) -> String
foo(<!ARGUMENT_TYPE_MISMATCH!>a<!>)
}
@@ -37,6 +37,6 @@ fun test() {
// TODO: should we allow somehow to call with passing continuation explicitly?
severalParams("", 89, <!TOO_MANY_ARGUMENTS!>6.9<!>) checkType { <!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>_<!><Unit>() }
severalParams("", 89, <!TOO_MANY_ARGUMENTS!>this as Continuation<Double><!>) checkType { <!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>_<!><Unit>() }
severalParams("", 89, <!TOO_MANY_ARGUMENTS!>this <!CAST_NEVER_SUCCEEDS!>as<!> Continuation<Double><!>) checkType { <!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>_<!><Unit>() }
}
}
@@ -9,8 +9,8 @@ fun box() {
val b = Array<<!REIFIED_TYPE_FORBIDDEN_SUBSTITUTION!>Nothing?<!>>(5) { null!! }
val c = <!REIFIED_TYPE_FORBIDDEN_SUBSTITUTION!>foo<!>() { null!! }
val d = foo<Any> { null!! }
val e = <!REIFIED_TYPE_FORBIDDEN_SUBSTITUTION!>foo<!> { "1" as Nothing }
val e1 = <!REIFIED_TYPE_FORBIDDEN_SUBSTITUTION!>foo<!> { "1" as Nothing? }
val e = <!REIFIED_TYPE_FORBIDDEN_SUBSTITUTION!>foo<!> { "1" <!CAST_NEVER_SUCCEEDS!>as<!> Nothing }
val e1 = <!REIFIED_TYPE_FORBIDDEN_SUBSTITUTION!>foo<!> { "1" <!CAST_NEVER_SUCCEEDS!>as<!> Nothing? }
val f = javaClass<<!REIFIED_TYPE_FORBIDDEN_SUBSTITUTION!>Nothing<!>>()
}
@@ -47,7 +47,7 @@ fun case_5(value_1: Int?) {
println("!")
contract {
returns(true) implies (value_1 != null)
} as ContractBuilder
} <!CAST_NEVER_SUCCEEDS!>as<!> ContractBuilder
}
/*
@@ -93,6 +93,6 @@ fun case_9(number: Int?): Boolean {
val value_1 = number != null
contract {
returns(false) implies (value_1)
} as ContractBuilder
} <!CAST_NEVER_SUCCEEDS!>as<!> ContractBuilder
return number == null
}
@@ -8,7 +8,7 @@ fun case_1(value_1: Int?) {
println("!")
contract {
returns(true) implies (value_1 != null)
} as ContractBuilder
} <!CAST_NEVER_SUCCEEDS!>as<!> ContractBuilder
}
// TESTCASE NUMBER: 2
@@ -42,6 +42,6 @@ fun case_5(number: Int?): Boolean {
val value_1 = number != null
contract {
returns(false) implies (value_1)
} as ContractBuilder
} <!CAST_NEVER_SUCCEEDS!>as<!> ContractBuilder
return number == null
}
@@ -6,7 +6,7 @@
fun case_1(x: Interface1) = x
fun case_1(x: Interface2) = x
fun case_1() {
val x: Interface1 = null as Interface1
val x: Interface1 = null <!CAST_NEVER_SUCCEEDS!>as<!> Interface1
x as Interface2
<!OVERLOAD_RESOLUTION_AMBIGUITY!>case_1<!>(<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & Interface2 & Interface1")!>x<!>)
}