[FIR] Improve TYPE_PARAMETER_AS_REIFIED detecting, implement TYPE_PARAMETER_AS_REIFIED_ARRAY, TYPE_PARAMETER_AS_REIFIED_ARRAY_WARNING
This commit is contained in:
committed by
teamcityserver
parent
2333b1bcf6
commit
bade6cb611
+8
@@ -483,6 +483,14 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
parameter<FirTypeParameterSymbol>("typeParameter")
|
||||
}
|
||||
|
||||
val TYPE_PARAMETER_AS_REIFIED_ARRAY by error<PsiElement> {
|
||||
parameter<FirTypeParameterSymbol>("typeParameter")
|
||||
}
|
||||
|
||||
val TYPE_PARAMETER_AS_REIFIED_ARRAY_WARNING by warning<PsiElement> {
|
||||
parameter<FirTypeParameterSymbol>("typeParameter")
|
||||
}
|
||||
|
||||
val FINAL_UPPER_BOUND by warning<KtTypeReference> {
|
||||
parameter<ConeKotlinType>("type")
|
||||
}
|
||||
|
||||
@@ -319,6 +319,8 @@ object FirErrors {
|
||||
val INNER_CLASS_OF_GENERIC_THROWABLE_SUBCLASS by error0<KtClassOrObject>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
val KCLASS_WITH_NULLABLE_TYPE_PARAMETER_IN_SIGNATURE by error1<KtNamedDeclaration, FirTypeParameterSymbol>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
val TYPE_PARAMETER_AS_REIFIED by error1<PsiElement, FirTypeParameterSymbol>()
|
||||
val TYPE_PARAMETER_AS_REIFIED_ARRAY by error1<PsiElement, FirTypeParameterSymbol>()
|
||||
val TYPE_PARAMETER_AS_REIFIED_ARRAY_WARNING by warning1<PsiElement, FirTypeParameterSymbol>()
|
||||
val FINAL_UPPER_BOUND by warning1<KtTypeReference, ConeKotlinType>()
|
||||
val UPPER_BOUND_IS_EXTENSION_FUNCTION_TYPE by error0<KtTypeReference>()
|
||||
val BOUNDS_NOT_ALLOWED_IF_BOUNDED_BY_TYPE_PARAMETER by error0<KtElement>()
|
||||
|
||||
+2
-1
@@ -42,7 +42,8 @@ object CommonExpressionCheckers : ExpressionCheckers() {
|
||||
FirTypeParameterInQualifiedAccessChecker,
|
||||
FirSealedClassConstructorCallChecker,
|
||||
FirUninitializedEnumChecker,
|
||||
FirFunInterfaceConstructorReferenceChecker
|
||||
FirFunInterfaceConstructorReferenceChecker,
|
||||
FirTypeParameterAsReifiedChecker
|
||||
)
|
||||
|
||||
override val functionCallCheckers: Set<FirFunctionCallChecker>
|
||||
|
||||
@@ -601,24 +601,20 @@ fun extractArgumentTypeRefAndSource(typeRef: FirTypeRef?, index: Int): FirTypeRe
|
||||
if (typeRef is FirResolvedTypeRef) {
|
||||
val delegatedTypeRef = typeRef.delegatedTypeRef
|
||||
if (delegatedTypeRef is FirUserTypeRef) {
|
||||
var currentTypeArguments: List<FirTypeProjection>? = null
|
||||
var currentIndex = index
|
||||
val qualifier = delegatedTypeRef.qualifier
|
||||
|
||||
for (i in qualifier.size - 1 downTo 0) {
|
||||
val typeArguments = qualifier[i].typeArgumentList.typeArguments
|
||||
if (currentIndex < typeArguments.size) {
|
||||
currentTypeArguments = typeArguments
|
||||
break
|
||||
val typeArgument = typeArguments.elementAtOrNull(currentIndex)
|
||||
return if (typeArgument is FirTypeProjection)
|
||||
FirTypeRefSource((typeArgument as? FirTypeProjectionWithVariance)?.typeRef, typeArgument.source)
|
||||
else null
|
||||
} else {
|
||||
currentIndex -= typeArguments.size
|
||||
}
|
||||
}
|
||||
|
||||
val typeArgument = currentTypeArguments?.elementAtOrNull(currentIndex)
|
||||
if (typeArgument is FirTypeProjection) {
|
||||
return FirTypeRefSource((typeArgument as? FirTypeProjectionWithVariance)?.typeRef, typeArgument.source)
|
||||
}
|
||||
} else if (delegatedTypeRef is FirFunctionTypeRef) {
|
||||
val valueParameters = delegatedTypeRef.valueParameters
|
||||
if (index < valueParameters.size) {
|
||||
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.fir.FirSourceElement
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticFactory1
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.toResolvedCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
|
||||
object FirTypeParameterAsReifiedChecker : FirQualifiedAccessExpressionChecker() {
|
||||
override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val calleReference = expression.calleeReference
|
||||
val typeArguments = expression.typeArguments
|
||||
val typeParameters = calleReference.toResolvedCallableSymbol()?.typeParameterSymbols ?: return
|
||||
|
||||
val count = minOf(typeArguments.size, typeParameters.size)
|
||||
for (index in 0 until count) {
|
||||
val typeArgumentProjection = typeArguments.elementAt(index)
|
||||
val source = typeArgumentProjection.source ?: calleReference.source
|
||||
val typeArgument = typeArgumentProjection.toConeTypeProjection().type
|
||||
val typeParameter = typeParameters[index]
|
||||
|
||||
if (source != null && (typeParameter.isTypeParameterOfKotlinArray())) {
|
||||
checkArgumentAndReport(typeArgument, source, false, context, reporter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirTypeParameterSymbol.isTypeParameterOfKotlinArray(): Boolean {
|
||||
val containingDeclaration = containingDeclarationSymbol
|
||||
return isReified ||
|
||||
containingDeclaration is FirRegularClassSymbol && containingDeclaration.classId == StandardClassIds.Array
|
||||
}
|
||||
|
||||
private fun checkArgumentAndReport(
|
||||
typeArgument: ConeKotlinType?,
|
||||
source: FirSourceElement,
|
||||
isArray: Boolean,
|
||||
context: CheckerContext,
|
||||
reporter: DiagnosticReporter
|
||||
) {
|
||||
if (typeArgument?.classId == StandardClassIds.Array) {
|
||||
checkArgumentAndReport(typeArgument.typeArguments[0].type, source, true, context, reporter)
|
||||
return
|
||||
}
|
||||
|
||||
var factory: FirDiagnosticFactory1<FirTypeParameterSymbol>? = null
|
||||
|
||||
lateinit var symbol: FirTypeParameterSymbol
|
||||
if (typeArgument is ConeTypeParameterType) {
|
||||
factory = if (isArray) {
|
||||
if (context.session.languageVersionSettings.supportsFeature(LanguageFeature.ProhibitNonReifiedArraysAsReifiedTypeArguments))
|
||||
FirErrors.TYPE_PARAMETER_AS_REIFIED_ARRAY else
|
||||
FirErrors.TYPE_PARAMETER_AS_REIFIED_ARRAY_WARNING
|
||||
} else {
|
||||
FirErrors.TYPE_PARAMETER_AS_REIFIED
|
||||
}
|
||||
symbol = typeArgument.toSymbol(context.session) as FirTypeParameterSymbol
|
||||
}
|
||||
|
||||
if (factory != null && !symbol.isReified) {
|
||||
reporter.reportOn(source, factory, symbol, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
@@ -41,6 +41,10 @@ class ExpressionCheckersDiagnosticComponent(
|
||||
checkers.allFunctionCallCheckers.check(functionCall, data, reporter)
|
||||
}
|
||||
|
||||
override fun visitImplicitInvokeCall(implicitInvokeCall: FirImplicitInvokeCall, data: CheckerContext) {
|
||||
checkers.allFunctionCallCheckers.check(implicitInvokeCall, data, reporter)
|
||||
}
|
||||
|
||||
override fun visitCallableReferenceAccess(callableReferenceAccess: FirCallableReferenceAccess, data: CheckerContext) {
|
||||
checkers.allCallableReferenceAccessCheckers.check(callableReferenceAccess, data, reporter)
|
||||
}
|
||||
|
||||
+12
@@ -365,6 +365,8 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETERS_I
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETERS_IN_OBJECT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETERS_NOT_ALLOWED
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_AS_REIFIED
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_AS_REIFIED_ARRAY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_AS_REIFIED_ARRAY_WARNING
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_IN_CATCH_CLAUSE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_IS_NOT_AN_EXPRESSION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER
|
||||
@@ -782,6 +784,16 @@ class FirDefaultErrorMessages {
|
||||
)
|
||||
|
||||
map.put(TYPE_PARAMETER_AS_REIFIED, "Cannot use ''{0}'' as reified type parameter. Use a class instead", SYMBOL)
|
||||
map.put(
|
||||
TYPE_PARAMETER_AS_REIFIED_ARRAY,
|
||||
"Cannot use ''{0}'' as reified type parameter, since the array type parameter is not reified.",
|
||||
SYMBOL
|
||||
)
|
||||
map.put(
|
||||
TYPE_PARAMETER_AS_REIFIED_ARRAY_WARNING,
|
||||
"Cannot use ''{0}'' as reified type parameter, since the array type parameter is not reified.",
|
||||
SYMBOL
|
||||
)
|
||||
map.put(
|
||||
FINAL_UPPER_BOUND,
|
||||
"''{0}'' is a final type, and thus a value of the type parameter is predetermined",
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
inline operator fun <reified T> T.plus(p: T): T = this
|
||||
|
||||
inline operator fun <reified T> T.invoke(): T = this
|
||||
|
||||
fun <A> main(tp: A, any: Any) {
|
||||
tp + tp
|
||||
any + any
|
||||
|
||||
tp()
|
||||
any()
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
inline operator fun <reified T> T.plus(p: T): T = this
|
||||
|
||||
Vendored
-19
@@ -1,19 +0,0 @@
|
||||
// !LANGUAGE: +ProhibitNonReifiedArraysAsReifiedTypeArguments
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
inline fun <reified T> foo() {}
|
||||
|
||||
fun <T> bar() {
|
||||
foo<T>()
|
||||
foo<Array<T>>()
|
||||
foo<Array<Array<T>>>()
|
||||
foo<Array<Int>>()
|
||||
foo<Array<Array<Int>>>()
|
||||
foo<IntArray>()
|
||||
foo<List<T>>()
|
||||
foo<List<Array<T>>>()
|
||||
}
|
||||
|
||||
fun test(x: Array<String>, y: Array<*>) {
|
||||
bar<Int>()
|
||||
}
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !LANGUAGE: +ProhibitNonReifiedArraysAsReifiedTypeArguments
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
|
||||
compiler/testData/diagnostics/tests/generics/tpAsReified/GenericArrayAsReifiedArgumentWarning.fir.kt
Vendored
-19
@@ -1,19 +0,0 @@
|
||||
// !LANGUAGE: -ProhibitNonReifiedArraysAsReifiedTypeArguments
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
inline fun <reified T> foo() {}
|
||||
|
||||
fun <T> bar() {
|
||||
foo<T>()
|
||||
foo<Array<T>>()
|
||||
foo<Array<Array<T>>>()
|
||||
foo<Array<Int>>()
|
||||
foo<Array<Array<Int>>>()
|
||||
foo<IntArray>()
|
||||
foo<List<T>>()
|
||||
foo<List<Array<T>>>()
|
||||
}
|
||||
|
||||
fun test(x: Array<String>, y: Array<*>) {
|
||||
bar<Int>()
|
||||
}
|
||||
Vendored
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !LANGUAGE: -ProhibitNonReifiedArraysAsReifiedTypeArguments
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
class C<<!REIFIED_TYPE_PARAMETER_NO_INLINE!>reified<!> T>
|
||||
|
||||
fun <T> id(p: T): T = p
|
||||
|
||||
fun <A> main() {
|
||||
<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>C<!>()
|
||||
|
||||
val a: C<A> = C()
|
||||
C<A>()
|
||||
|
||||
val b: C<Int> = C()
|
||||
C<Int>()
|
||||
|
||||
// TODO svtk, uncomment when extensions are called for nested calls!
|
||||
//val < !UNUSED_VARIABLE!>с< !>: C<A> = id(< !TYPE_PARAMETER_AS_REIFIED!>C< !>())
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
class C<<!REIFIED_TYPE_PARAMETER_NO_INLINE!>reified<!> T>
|
||||
|
||||
fun <T> id(p: T): T = p
|
||||
|
||||
@@ -11,11 +11,11 @@ fun <T> id(p: T): T = p
|
||||
fun <A> main() {
|
||||
<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>f<!>()
|
||||
|
||||
val a: A = f()
|
||||
f<A>()
|
||||
val a: A = <!TYPE_PARAMETER_AS_REIFIED!>f<!>()
|
||||
f<<!TYPE_PARAMETER_AS_REIFIED!>A<!>>()
|
||||
|
||||
val b: Int = f()
|
||||
f<Int>()
|
||||
|
||||
val с: A = id(f())
|
||||
val с: A = id(<!TYPE_PARAMETER_AS_REIFIED!>f<!>())
|
||||
}
|
||||
|
||||
@@ -50,6 +50,6 @@ fun test6() = foo<Nothing>()
|
||||
|
||||
class B<T>(val array: Array<T>)
|
||||
|
||||
fun <T> bar() = B<Array<T>>(arrayOf())
|
||||
fun <T> bar() = B<Array<T>>(<!TYPE_PARAMETER_AS_REIFIED_ARRAY!>arrayOf<!>())
|
||||
|
||||
fun test7() = bar<Nothing>()
|
||||
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
|
||||
fun <T> fail1(): Array<T> = Array(1) { null!! }
|
||||
fun <T> ok1(block: () -> Array<T>): Array<T> = block()
|
||||
inline fun <reified T> ok2(): Array<T> = Array(1) { null!! }
|
||||
|
||||
|
||||
fun <T> fail2(): Array<T> = ok1 { Array<T>(1) { null!! } }
|
||||
fun <T> ok3(block: () -> Array<T>): Array<T> = ok1 { block() }
|
||||
inline fun <reified T> ok4(): Array<T> = ok1 { Array<T>(1) { null!! } }
|
||||
|
||||
fun <T> fail3(block: () -> T): Pair<Array<T>, Array<T>> = Pair(arrayOf(
|
||||
block()), arrayOf()
|
||||
)
|
||||
inline fun <reified T> ok5(block: () -> T): Pair<Array<T>, Array<T>> = Pair(
|
||||
arrayOf(block()), arrayOf()
|
||||
)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
|
||||
fun <T> fail1(): Array<T> = <!TYPE_PARAMETER_AS_REIFIED!>Array<!>(1) { null!! }
|
||||
fun <T> ok1(block: () -> Array<T>): Array<T> = block()
|
||||
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE
|
||||
|
||||
fun <T> foo() {
|
||||
val x = arrayOfNulls<T>(5)
|
||||
}
|
||||
|
||||
inline fun <reified T> bar() {
|
||||
val x = arrayOfNulls<T>(5)
|
||||
}
|
||||
|
||||
fun baz() {
|
||||
bar<Int>()
|
||||
val x: Array<Int?> = arrayOfNulls(5)
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE
|
||||
|
||||
fun <T> foo() {
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
class Inv<T>
|
||||
|
||||
inline operator fun <reified T> Inv<T>.invoke() {}
|
||||
|
||||
operator fun <K> Inv<K>.get(i: Int): Inv<K> = this
|
||||
|
||||
fun <K> test(a: Inv<K>) {
|
||||
a[1]()
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
class Inv<T>
|
||||
|
||||
inline operator fun <reified T> Inv<T>.invoke() {}
|
||||
|
||||
+14
@@ -1440,6 +1440,20 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.TYPE_PARAMETER_AS_REIFIED_ARRAY) { firDiagnostic ->
|
||||
TypeParameterAsReifiedArrayImpl(
|
||||
firSymbolBuilder.classifierBuilder.buildTypeParameterSymbol(firDiagnostic.a.fir),
|
||||
firDiagnostic as FirPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.TYPE_PARAMETER_AS_REIFIED_ARRAY_WARNING) { firDiagnostic ->
|
||||
TypeParameterAsReifiedArrayWarningImpl(
|
||||
firSymbolBuilder.classifierBuilder.buildTypeParameterSymbol(firDiagnostic.a.fir),
|
||||
firDiagnostic as FirPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.FINAL_UPPER_BOUND) { firDiagnostic ->
|
||||
FinalUpperBoundImpl(
|
||||
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
|
||||
|
||||
+10
@@ -1024,6 +1024,16 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
abstract val typeParameter: KtTypeParameterSymbol
|
||||
}
|
||||
|
||||
abstract class TypeParameterAsReifiedArray : KtFirDiagnostic<PsiElement>() {
|
||||
override val diagnosticClass get() = TypeParameterAsReifiedArray::class
|
||||
abstract val typeParameter: KtTypeParameterSymbol
|
||||
}
|
||||
|
||||
abstract class TypeParameterAsReifiedArrayWarning : KtFirDiagnostic<PsiElement>() {
|
||||
override val diagnosticClass get() = TypeParameterAsReifiedArrayWarning::class
|
||||
abstract val typeParameter: KtTypeParameterSymbol
|
||||
}
|
||||
|
||||
abstract class FinalUpperBound : KtFirDiagnostic<KtTypeReference>() {
|
||||
override val diagnosticClass get() = FinalUpperBound::class
|
||||
abstract val type: KtType
|
||||
|
||||
+16
@@ -1643,6 +1643,22 @@ internal class TypeParameterAsReifiedImpl(
|
||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class TypeParameterAsReifiedArrayImpl(
|
||||
override val typeParameter: KtTypeParameterSymbol,
|
||||
firDiagnostic: FirPsiDiagnostic,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.TypeParameterAsReifiedArray(), KtAbstractFirDiagnostic<PsiElement> {
|
||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class TypeParameterAsReifiedArrayWarningImpl(
|
||||
override val typeParameter: KtTypeParameterSymbol,
|
||||
firDiagnostic: FirPsiDiagnostic,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.TypeParameterAsReifiedArrayWarning(), KtAbstractFirDiagnostic<PsiElement> {
|
||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class FinalUpperBoundImpl(
|
||||
override val type: KtType,
|
||||
firDiagnostic: FirPsiDiagnostic,
|
||||
|
||||
Reference in New Issue
Block a user