FE 1.0: report TYPE_VARIANCE_CONFLICT also on qualifier type arguments

#KT-51439 Fixed
This commit is contained in:
Mikhail Glukhikh
2022-02-22 13:15:59 +03:00
committed by Space
parent fdb01d96f0
commit 7781413a93
15 changed files with 224 additions and 17 deletions
@@ -17448,6 +17448,18 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
runTest("compiler/testData/diagnostics/tests/inner/traits.kt");
}
@Test
@TestMetadata("typeVarianceConflict.kt")
public void testTypeVarianceConflict() throws Exception {
runTest("compiler/testData/diagnostics/tests/inner/typeVarianceConflict.kt");
}
@Test
@TestMetadata("typeVarianceConflictFeatureOn.kt")
public void testTypeVarianceConflictFeatureOn() throws Exception {
runTest("compiler/testData/diagnostics/tests/inner/typeVarianceConflictFeatureOn.kt");
}
@Test
@TestMetadata("visibility.kt")
public void testVisibility() throws Exception {
@@ -17448,6 +17448,18 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/inner/traits.kt");
}
@Test
@TestMetadata("typeVarianceConflict.kt")
public void testTypeVarianceConflict() throws Exception {
runTest("compiler/testData/diagnostics/tests/inner/typeVarianceConflict.kt");
}
@Test
@TestMetadata("typeVarianceConflictFeatureOn.kt")
public void testTypeVarianceConflictFeatureOn() throws Exception {
runTest("compiler/testData/diagnostics/tests/inner/typeVarianceConflictFeatureOn.kt");
}
@Test
@TestMetadata("visibility.kt")
public void testVisibility() throws Exception {
@@ -17448,6 +17448,18 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/inner/traits.kt");
}
@Test
@TestMetadata("typeVarianceConflict.kt")
public void testTypeVarianceConflict() throws Exception {
runTest("compiler/testData/diagnostics/tests/inner/typeVarianceConflict.kt");
}
@Test
@TestMetadata("typeVarianceConflictFeatureOn.kt")
public void testTypeVarianceConflictFeatureOn() throws Exception {
runTest("compiler/testData/diagnostics/tests/inner/typeVarianceConflictFeatureOn.kt");
}
@Test
@TestMetadata("visibility.kt")
public void testVisibility() throws Exception {
@@ -199,6 +199,8 @@ public interface Errors {
DiagnosticFactory1.create(WARNING, VARIANCE_IN_PROJECTION);
DiagnosticFactory1<PsiElement, VarianceConflictDiagnosticData> TYPE_VARIANCE_CONFLICT =
DiagnosticFactory1.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
DiagnosticFactory1<PsiElement, VarianceConflictDiagnosticData> TYPE_VARIANCE_CONFLICT_WARNING =
DiagnosticFactory1.create(WARNING, DECLARATION_SIGNATURE_OR_DEFAULT);
DiagnosticFactory1<PsiElement, VarianceConflictDiagnosticData> TYPE_VARIANCE_CONFLICT_IN_EXPANDED_TYPE =
DiagnosticFactory1.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
DiagnosticFactory0<PsiElement> FINITE_BOUNDS_VIOLATION = DiagnosticFactory0.create(ERROR);
@@ -807,6 +807,9 @@ public class DefaultErrorMessages {
};
MAP.put(TYPE_VARIANCE_CONFLICT, "Type parameter {0} is declared as ''{1}'' but occurs in ''{2}'' position in type {3}",
varianceConflictDataRenderer);
MAP.put(TYPE_VARIANCE_CONFLICT_WARNING, "Type parameter {0} is declared as ''{1}'' but occurs in ''{2}'' position in type {3}. " +
"This diagnostic will become an error soon. See https://youtrack.jetbrains.com/issue/KT-50947",
varianceConflictDataRenderer);
MAP.put(TYPE_VARIANCE_CONFLICT_IN_EXPANDED_TYPE, "Type parameter {0} is declared as ''{1}'' but occurs in ''{2}'' position in abbreviated type {3}",
varianceConflictDataRenderer);
@@ -218,7 +218,7 @@ class LazyTopDownAnalyzer(
overrideResolver.check(c)
varianceChecker.check(c)
varianceChecker.check(c, languageVersionSettings)
declarationResolver.resolveAnnotationsOnFiles(c, fileScopeProvider)
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.psi.KtCallableDeclaration
import org.jetbrains.kotlin.psi.KtTypeElement
import org.jetbrains.kotlin.psi.KtTypeReference
import org.jetbrains.kotlin.psi.KtUserType
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.types.*
@@ -30,6 +31,7 @@ interface TypeBinding<out P : PsiElement> {
val type: KotlinType
val isInAbbreviation: Boolean
val arguments: List<TypeArgumentBinding<P>?>
val isArgumentFromQualifier: Boolean get() = false
}
interface TypeArgumentBinding<out P : PsiElement> {
@@ -44,15 +46,20 @@ fun KtTypeReference.createTypeBinding(trace: BindingContext): TypeBinding<KtType
return if (type == null || psiElement == null)
null
else
createTypeBindingFromPsi(trace, psiElement, type)
createTypeBindingFromPsi(trace, psiElement, type, isArgumentFromQualifier = false)
}
private fun createTypeBindingFromPsi(trace: BindingContext, psiElement: KtTypeElement, type: KotlinType): TypeBinding<KtTypeElement> {
private fun createTypeBindingFromPsi(
trace: BindingContext,
psiElement: KtTypeElement,
type: KotlinType,
isArgumentFromQualifier: Boolean
): TypeBinding<KtTypeElement> {
val abbreviatedType = type.getAbbreviatedType()
return if (abbreviatedType != null)
AbbreviatedTypeBinding(type, psiElement)
AbbreviatedTypeBinding(type, psiElement, isArgumentFromQualifier)
else
ExplicitTypeBinding(trace, psiElement, type)
ExplicitTypeBinding(trace, psiElement, type, isArgumentFromQualifier)
}
fun KtCallableDeclaration.createTypeBindingForReturnType(trace: BindingContext): TypeBinding<PsiElement>? {
@@ -74,13 +81,20 @@ private class TypeArgumentBindingImpl<out P : PsiElement>(
private class ExplicitTypeBinding(
private val trace: BindingContext,
override val psiElement: KtTypeElement,
override val type: KotlinType
override val type: KotlinType,
override val isArgumentFromQualifier: Boolean
) : TypeBinding<KtTypeElement> {
override val isInAbbreviation: Boolean get() = false
override val arguments: List<TypeArgumentBinding<KtTypeElement>?>
get() {
val psiTypeArguments = psiElement.typeArgumentsAsTypes
val psiTypeArguments = psiElement.typeArgumentsAsTypes.toMutableList()
val qualifierArgumentStartIndex = psiTypeArguments.size
var current = psiElement
while (current is KtUserType) {
current = current.qualifier ?: break
psiTypeArguments += current.typeArgumentsAsTypes
}
assert(type.getAbbreviatedType() == null) { "Non-abbreviated type expected: $type" }
val isErrorBinding = run {
val sizeIsEqual = psiTypeArguments.size == type.arguments.size
@@ -90,16 +104,17 @@ private class ExplicitTypeBinding(
return psiTypeArguments.indices.map { index: Int ->
// todo fix for List<*>
val jetTypeReference = psiTypeArguments[index]
val jetTypeElement = jetTypeReference?.typeElement ?: return@map null
val typeReference = psiTypeArguments[index]
val typeElement = typeReference?.typeElement ?: return@map null
val isArgumentFromQualifier = index >= qualifierArgumentStartIndex
if (isErrorBinding) {
val nextJetType = trace[BindingContext.TYPE, jetTypeReference] ?: return@map null
val nextType = trace[BindingContext.TYPE, typeReference] ?: return@map null
return@map TypeArgumentBindingImpl(
TypeProjectionImpl(nextJetType),
TypeProjectionImpl(nextType),
null,
createTypeBindingFromPsi(trace, jetTypeElement, nextJetType)
createTypeBindingFromPsi(trace, typeElement, nextType, isArgumentFromQualifier)
)
}
@@ -107,7 +122,7 @@ private class ExplicitTypeBinding(
return@map TypeArgumentBindingImpl(
typeProjection,
type.constructor.parameters[index],
createTypeBindingFromPsi(trace, jetTypeElement, typeProjection.type)
createTypeBindingFromPsi(trace, typeElement, typeProjection.type, isArgumentFromQualifier)
)
}
}
@@ -115,13 +130,14 @@ private class ExplicitTypeBinding(
private class AbbreviatedTypeBinding(
override val type: KotlinType,
override val psiElement: KtTypeElement
override val psiElement: KtTypeElement,
override val isArgumentFromQualifier: Boolean
) : TypeBinding<KtTypeElement> {
override val isInAbbreviation: Boolean get() = true
override val arguments: List<TypeArgumentBinding<KtTypeElement>?>
get() = createTypeArgumentBindingsWithSinglePsiElement(type) { argumentType ->
AbbreviatedTypeBinding(argumentType, psiElement)
AbbreviatedTypeBinding(argumentType, psiElement, isArgumentFromQualifier)
}
}
@@ -18,6 +18,9 @@ package org.jetbrains.kotlin.resolve
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageFeature.ReportTypeVarianceConflictOnQualifierArguments
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.PropertyAccessorDescriptorImpl
@@ -43,7 +46,8 @@ class ManualVariance(val descriptor: TypeParameterDescriptor, val variance: Vari
class VarianceChecker(trace: BindingTrace) {
private val core = VarianceCheckerCore(trace.bindingContext, trace)
fun check(c: TopDownAnalysisContext) {
fun check(c: TopDownAnalysisContext, languageVersionSettings: LanguageVersionSettings) {
core.languageVersionSettings = languageVersionSettings
core.check(c)
}
}
@@ -59,6 +63,7 @@ class VarianceCheckerCore(
private val diagnosticSink: DiagnosticSink,
private val manualVariance: ManualVariance? = null
) {
internal var languageVersionSettings: LanguageVersionSettings? = null
fun check(c: TopDownAnalysisContext) {
checkClasses(c)
@@ -153,7 +158,17 @@ class VarianceCheckerCore(
) {
val varianceConflictDiagnosticData = VarianceConflictDiagnosticData(containingType, classifierDescriptor, position)
val diagnostic =
if (isInAbbreviation) Errors.TYPE_VARIANCE_CONFLICT_IN_EXPANDED_TYPE else Errors.TYPE_VARIANCE_CONFLICT
when {
isArgumentFromQualifier -> {
if (languageVersionSettings?.supportsFeature(ReportTypeVarianceConflictOnQualifierArguments) == true) {
Errors.TYPE_VARIANCE_CONFLICT
} else {
Errors.TYPE_VARIANCE_CONFLICT_WARNING
}
}
isInAbbreviation -> Errors.TYPE_VARIANCE_CONFLICT_IN_EXPANDED_TYPE
else -> Errors.TYPE_VARIANCE_CONFLICT
}
diagnosticSink.report(diagnostic.on(psiElement, varianceConflictDiagnosticData))
}
return declarationVariance.allowsPosition(position)
@@ -0,0 +1,23 @@
// !LANGUAGE: -ReportTypeVarianceConflictOnQualifierArguments
class Bar<K> {
inner class Inner {
inner class SuperInner
}
}
abstract class Foo<in T> {
abstract fun yuckyEventHandler(
fn: Bar<<!TYPE_VARIANCE_CONFLICT!>T<!>>.Inner.() -> Unit
): () -> Unit
abstract fun second(fn: Bar<<!TYPE_VARIANCE_CONFLICT!>T<!>>.Inner)
abstract fun third(fn: Bar<<!TYPE_VARIANCE_CONFLICT!>T<!>>.Inner.SuperInner)
}
abstract class Baz<out T> {
abstract fun yuckyEventHandler(
fn: Bar<<!TYPE_VARIANCE_CONFLICT!>T<!>>.Inner.() -> Unit
): () -> Unit
}
@@ -0,0 +1,23 @@
// !LANGUAGE: -ReportTypeVarianceConflictOnQualifierArguments
class Bar<K> {
inner class Inner {
inner class SuperInner
}
}
abstract class Foo<in T> {
abstract fun yuckyEventHandler(
fn: Bar<<!TYPE_VARIANCE_CONFLICT_WARNING!>T<!>>.Inner.() -> Unit
): () -> Unit
abstract fun second(fn: Bar<<!TYPE_VARIANCE_CONFLICT_WARNING!>T<!>>.Inner)
abstract fun third(fn: Bar<<!TYPE_VARIANCE_CONFLICT_WARNING!>T<!>>.Inner.SuperInner)
}
abstract class Baz<out T> {
abstract fun yuckyEventHandler(
fn: Bar<<!TYPE_VARIANCE_CONFLICT_WARNING!>T<!>>.Inner.() -> Unit
): () -> Unit
}
@@ -0,0 +1,41 @@
package
public final class Bar</*0*/ K> {
public constructor Bar</*0*/ K>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
public final inner class Inner /*captured type parameters: /*0*/ K*/ {
public constructor Inner()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
public final inner class SuperInner /*captured type parameters: /*0*/ K*/ {
public constructor SuperInner()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
}
}
public abstract class Baz</*0*/ out T> {
public constructor Baz</*0*/ out T>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
public abstract fun yuckyEventHandler(/*0*/ fn: Bar<T>.Inner.() -> kotlin.Unit): () -> kotlin.Unit
}
public abstract class Foo</*0*/ in T> {
public constructor Foo</*0*/ in T>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public abstract fun second(/*0*/ fn: Bar<T>.Inner): kotlin.Unit
public abstract fun third(/*0*/ fn: Bar<T>.Inner.SuperInner): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
public abstract fun yuckyEventHandler(/*0*/ fn: Bar<T>.Inner.() -> kotlin.Unit): () -> kotlin.Unit
}
@@ -0,0 +1,12 @@
// FIR_IDENTICAL
// !LANGUAGE: +ReportTypeVarianceConflictOnQualifierArguments
class Bar<K> {
inner class Inner
}
abstract class Foo<in T> {
abstract fun yuckyEventHandler(
fn: Bar<<!TYPE_VARIANCE_CONFLICT!>T<!>>.Inner.() -> Unit
): () -> Unit
}
@@ -0,0 +1,23 @@
package
public final class Bar</*0*/ K> {
public constructor Bar</*0*/ K>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
public final inner class Inner /*captured type parameters: /*0*/ K*/ {
public constructor Inner()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
}
public abstract class Foo</*0*/ in T> {
public constructor Foo</*0*/ in T>()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
public abstract fun yuckyEventHandler(/*0*/ fn: Bar<T>.Inner.() -> kotlin.Unit): () -> kotlin.Unit
}
@@ -17454,6 +17454,18 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/inner/traits.kt");
}
@Test
@TestMetadata("typeVarianceConflict.kt")
public void testTypeVarianceConflict() throws Exception {
runTest("compiler/testData/diagnostics/tests/inner/typeVarianceConflict.kt");
}
@Test
@TestMetadata("typeVarianceConflictFeatureOn.kt")
public void testTypeVarianceConflictFeatureOn() throws Exception {
runTest("compiler/testData/diagnostics/tests/inner/typeVarianceConflictFeatureOn.kt");
}
@Test
@TestMetadata("visibility.kt")
public void testVisibility() throws Exception {
@@ -269,6 +269,7 @@ enum class LanguageFeature(
ForbidExtensionFunctionTypeOnNonFunctionTypes(KOTLIN_1_9), // related to KT-43527
ProhibitEnumDeclaringClass(KOTLIN_1_9, kind = BUG_FIX), // KT-49653
StopPropagatingDeprecationThroughOverrides(KOTLIN_1_9, kind = BUG_FIX), // KT-47902
ReportTypeVarianceConflictOnQualifierArguments(KOTLIN_1_9, kind = BUG_FIX), // KT-50947
// Disabled for indefinite time. See KT-48535 and related discussion
ApproximateIntegerLiteralTypesInReceiverPosition(sinceVersion = null),