[FIR] Add diagnostic CONFLICTING_PROJECTION
This commit is contained in:
+95
@@ -0,0 +1,95 @@
|
||||
class None<T>
|
||||
class In<in T>
|
||||
class Out<out T>
|
||||
|
||||
fun a1(value: None<Int>) {}
|
||||
fun a2(value: None<in Int>) {}
|
||||
fun a3(value: None<out Int>) {}
|
||||
|
||||
fun a4(value: In<Int>) {}
|
||||
fun a5(value: In<in Int>) {}
|
||||
fun a6(value: <!CONFLICTING_PROJECTION!>In<out Int><!>) {}
|
||||
|
||||
fun a7(value: Out<Int>) {}
|
||||
fun a8(value: <!CONFLICTING_PROJECTION!>Out<in Int><!>) {}
|
||||
fun a9(value: Out<out Int>) {}
|
||||
|
||||
typealias A1<K> = None<K>
|
||||
typealias A2<K> = None<in K>
|
||||
typealias A3<K> = None<out K>
|
||||
|
||||
typealias A4<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>in K<!>> = None<K>
|
||||
typealias A5<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>in K<!>> = None<in K>
|
||||
typealias A6<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>in K<!>> = None<out K>
|
||||
|
||||
typealias A7<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>out K<!>> = None<K>
|
||||
typealias A8<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>out K<!>> = None<in K>
|
||||
typealias A9<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>out K<!>> = None<out K>
|
||||
|
||||
typealias A10<K> = In<K>
|
||||
typealias A11<K> = In<in K>
|
||||
typealias A12<K> = <!CONFLICTING_PROJECTION!>In<out K><!>
|
||||
|
||||
typealias A13<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>in K<!>> = In<K>
|
||||
typealias A14<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>in K<!>> = In<in K>
|
||||
typealias A15<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>in K<!>> = <!CONFLICTING_PROJECTION!>In<out K><!>
|
||||
|
||||
typealias A16<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>out K<!>> = In<K>
|
||||
typealias A17<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>out K<!>> = In<in K>
|
||||
typealias A18<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>out K<!>> = <!CONFLICTING_PROJECTION!>In<out K><!>
|
||||
|
||||
typealias A19<K> = Out<K>
|
||||
typealias A20<K> = <!CONFLICTING_PROJECTION!>Out<in K><!>
|
||||
typealias A21<K> = Out<out K>
|
||||
|
||||
typealias A22<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>in K<!>> = Out<K>
|
||||
typealias A23<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>in K<!>> = <!CONFLICTING_PROJECTION!>Out<in K><!>
|
||||
typealias A24<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>in K<!>> = Out<out K>
|
||||
|
||||
typealias A25<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>out K<!>> = Out<K>
|
||||
typealias A26<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>out K<!>> = <!CONFLICTING_PROJECTION!>Out<in K><!>
|
||||
typealias A27<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>out K<!>> = Out<out K>
|
||||
|
||||
class Outer<T> {
|
||||
inner class Intermediate<K> {
|
||||
inner class Inner<G> {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun test1(): Outer<Int>.Intermediate<String>.Inner<Char> = Outer<Int>().Intermediate<String>().Inner()
|
||||
|
||||
fun test2(): Outer<in Int>.Intermediate<String>.Inner<Char> = Outer<Int>().Intermediate<String>().Inner()
|
||||
fun test3(): Outer<out Int>.Intermediate<String>.Inner<Char> = Outer<Int>().Intermediate<String>().Inner()
|
||||
|
||||
fun test4(): Outer<Int>.Intermediate<in String>.Inner<Char> = Outer<Int>().Intermediate<String>().Inner()
|
||||
fun test5(): Outer<Int>.Intermediate<out String>.Inner<Char> = Outer<Int>().Intermediate<String>().Inner()
|
||||
|
||||
fun test6(): Outer<Int>.Intermediate<String>.Inner<in Char> = Outer<Int>().Intermediate<String>().Inner()
|
||||
fun test7(): Outer<Int>.Intermediate<String>.Inner<out Char> = Outer<Int>().Intermediate<String>().Inner()
|
||||
|
||||
fun test8(): Outer<in Int>.Intermediate<out String>.Inner<Char> = Outer<Int>().Intermediate<String>().Inner()
|
||||
fun test9(): Outer<Int>.Intermediate<in String>.Inner<out Char> = Outer<Int>().Intermediate<String>().Inner()
|
||||
|
||||
class InOuter<in T> {
|
||||
inner class OutIntermediate<out K> {
|
||||
inner class InInner<in G> {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun test10(): InOuter<Int>.OutIntermediate<String>.InInner<Char> = InOuter<Int>().OutIntermediate<String>().InInner()
|
||||
|
||||
fun test11(): InOuter<in Int>.OutIntermediate<String>.InInner<Char> = InOuter<Int>().OutIntermediate<String>().InInner()
|
||||
fun test12(): <!CONFLICTING_PROJECTION!>InOuter<out Int>.OutIntermediate<String>.InInner<Char><!> = InOuter<Int>().OutIntermediate<String>().InInner()
|
||||
|
||||
fun test13(): <!CONFLICTING_PROJECTION!>InOuter<Int>.OutIntermediate<in String>.InInner<Char><!> = InOuter<Int>().OutIntermediate<String>().InInner()
|
||||
fun test14(): InOuter<Int>.OutIntermediate<out String>.InInner<Char> = InOuter<Int>().OutIntermediate<String>().InInner()
|
||||
|
||||
fun test15(): InOuter<Int>.OutIntermediate<String>.InInner<in Char> = InOuter<Int>().OutIntermediate<String>().InInner()
|
||||
fun test16(): <!CONFLICTING_PROJECTION!>InOuter<Int>.OutIntermediate<String>.InInner<out Char><!> = InOuter<Int>().OutIntermediate<String>().InInner()
|
||||
|
||||
fun test17(): InOuter<in Int>.OutIntermediate<out String>.InInner<Char> = InOuter<Int>().OutIntermediate<String>().InInner()
|
||||
fun test18(): <!CONFLICTING_PROJECTION!>InOuter<Int>.OutIntermediate<in String>.InInner<out Char><!> = InOuter<Int>().OutIntermediate<String>().InInner()
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
FILE: conflictingProjection.kt
|
||||
public final class None<T> : R|kotlin/Any| {
|
||||
public constructor<T>(): R|None<T>| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
public final class In<in T> : R|kotlin/Any| {
|
||||
public constructor<in T>(): R|In<T>| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
public final class Out<out T> : R|kotlin/Any| {
|
||||
public constructor<out T>(): R|Out<T>| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
public final fun a1(value: R|None<kotlin/Int>|): R|kotlin/Unit| {
|
||||
}
|
||||
public final fun a2(value: R|None<in kotlin/Int>|): R|kotlin/Unit| {
|
||||
}
|
||||
public final fun a3(value: R|None<out kotlin/Int>|): R|kotlin/Unit| {
|
||||
}
|
||||
public final fun a4(value: R|In<kotlin/Int>|): R|kotlin/Unit| {
|
||||
}
|
||||
public final fun a5(value: R|In<in kotlin/Int>|): R|kotlin/Unit| {
|
||||
}
|
||||
public final fun a6(value: R|In<out kotlin/Int>|): R|kotlin/Unit| {
|
||||
}
|
||||
public final fun a7(value: R|Out<kotlin/Int>|): R|kotlin/Unit| {
|
||||
}
|
||||
public final fun a8(value: R|Out<in kotlin/Int>|): R|kotlin/Unit| {
|
||||
}
|
||||
public final fun a9(value: R|Out<out kotlin/Int>|): R|kotlin/Unit| {
|
||||
}
|
||||
public final typealias A1<K> = R|None<K>|
|
||||
public final typealias A2<K> = R|None<in K>|
|
||||
public final typealias A3<K> = R|None<out K>|
|
||||
public final typealias A4<in K> = R|None<K>|
|
||||
public final typealias A5<in K> = R|None<in K>|
|
||||
public final typealias A6<in K> = R|None<out K>|
|
||||
public final typealias A7<out K> = R|None<K>|
|
||||
public final typealias A8<out K> = R|None<in K>|
|
||||
public final typealias A9<out K> = R|None<out K>|
|
||||
public final typealias A10<K> = R|In<K>|
|
||||
public final typealias A11<K> = R|In<in K>|
|
||||
public final typealias A12<K> = R|In<out K>|
|
||||
public final typealias A13<in K> = R|In<K>|
|
||||
public final typealias A14<in K> = R|In<in K>|
|
||||
public final typealias A15<in K> = R|In<out K>|
|
||||
public final typealias A16<out K> = R|In<K>|
|
||||
public final typealias A17<out K> = R|In<in K>|
|
||||
public final typealias A18<out K> = R|In<out K>|
|
||||
public final typealias A19<K> = R|Out<K>|
|
||||
public final typealias A20<K> = R|Out<in K>|
|
||||
public final typealias A21<K> = R|Out<out K>|
|
||||
public final typealias A22<in K> = R|Out<K>|
|
||||
public final typealias A23<in K> = R|Out<in K>|
|
||||
public final typealias A24<in K> = R|Out<out K>|
|
||||
public final typealias A25<out K> = R|Out<K>|
|
||||
public final typealias A26<out K> = R|Out<in K>|
|
||||
public final typealias A27<out K> = R|Out<out K>|
|
||||
public final class Outer<T> : R|kotlin/Any| {
|
||||
public constructor<T>(): R|Outer<T>| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final inner class Intermediate<K, T> : R|kotlin/Any| {
|
||||
public constructor<K>(): R|Outer.Intermediate<K, T>| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final inner class Inner<G, K, T> : R|kotlin/Any| {
|
||||
public constructor<G>(): R|Outer.Intermediate.Inner<G, K, T>| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
public final fun test1(): R|Outer.Intermediate.Inner<kotlin/Char, kotlin/String, kotlin/Int>| {
|
||||
^test1 R|/Outer.Outer|<R|kotlin/Int|>().R|/Outer.Intermediate.Intermediate|<R|kotlin/String|>().R|/Outer.Intermediate.Inner.Inner|<R|kotlin/Char|>()
|
||||
}
|
||||
public final fun test2(): R|Outer.Intermediate.Inner<kotlin/Char, kotlin/String, in kotlin/Int>| {
|
||||
^test2 R|/Outer.Outer|<R|kotlin/Int|>().R|/Outer.Intermediate.Intermediate|<R|kotlin/String|>().R|/Outer.Intermediate.Inner.Inner|<R|kotlin/Char|>()
|
||||
}
|
||||
public final fun test3(): R|Outer.Intermediate.Inner<kotlin/Char, kotlin/String, out kotlin/Int>| {
|
||||
^test3 R|/Outer.Outer|<R|kotlin/Int|>().R|/Outer.Intermediate.Intermediate|<R|kotlin/String|>().R|/Outer.Intermediate.Inner.Inner|<R|kotlin/Char|>()
|
||||
}
|
||||
public final fun test4(): R|Outer.Intermediate.Inner<kotlin/Char, in kotlin/String, kotlin/Int>| {
|
||||
^test4 R|/Outer.Outer|<R|kotlin/Int|>().R|/Outer.Intermediate.Intermediate|<R|kotlin/String|>().R|/Outer.Intermediate.Inner.Inner|<R|kotlin/Char|>()
|
||||
}
|
||||
public final fun test5(): R|Outer.Intermediate.Inner<kotlin/Char, out kotlin/String, kotlin/Int>| {
|
||||
^test5 R|/Outer.Outer|<R|kotlin/Int|>().R|/Outer.Intermediate.Intermediate|<R|kotlin/String|>().R|/Outer.Intermediate.Inner.Inner|<R|kotlin/Char|>()
|
||||
}
|
||||
public final fun test6(): R|Outer.Intermediate.Inner<in kotlin/Char, kotlin/String, kotlin/Int>| {
|
||||
^test6 R|/Outer.Outer|<R|kotlin/Int|>().R|/Outer.Intermediate.Intermediate|<R|kotlin/String|>().R|/Outer.Intermediate.Inner.Inner|<R|kotlin/Char|>()
|
||||
}
|
||||
public final fun test7(): R|Outer.Intermediate.Inner<out kotlin/Char, kotlin/String, kotlin/Int>| {
|
||||
^test7 R|/Outer.Outer|<R|kotlin/Int|>().R|/Outer.Intermediate.Intermediate|<R|kotlin/String|>().R|/Outer.Intermediate.Inner.Inner|<R|kotlin/Char|>()
|
||||
}
|
||||
public final fun test8(): R|Outer.Intermediate.Inner<kotlin/Char, out kotlin/String, in kotlin/Int>| {
|
||||
^test8 R|/Outer.Outer|<R|kotlin/Int|>().R|/Outer.Intermediate.Intermediate|<R|kotlin/String|>().R|/Outer.Intermediate.Inner.Inner|<R|kotlin/Char|>()
|
||||
}
|
||||
public final fun test9(): R|Outer.Intermediate.Inner<out kotlin/Char, in kotlin/String, kotlin/Int>| {
|
||||
^test9 R|/Outer.Outer|<R|kotlin/Int|>().R|/Outer.Intermediate.Intermediate|<R|kotlin/String|>().R|/Outer.Intermediate.Inner.Inner|<R|kotlin/Char|>()
|
||||
}
|
||||
public final class InOuter<in T> : R|kotlin/Any| {
|
||||
public constructor<in T>(): R|InOuter<T>| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final inner class OutIntermediate<out K, in T> : R|kotlin/Any| {
|
||||
public constructor<out K>(): R|InOuter.OutIntermediate<K, T>| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final inner class InInner<in G, out K, in T> : R|kotlin/Any| {
|
||||
public constructor<in G>(): R|InOuter.OutIntermediate.InInner<G, K, T>| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
public final fun test10(): R|InOuter.OutIntermediate.InInner<kotlin/Char, kotlin/String, kotlin/Int>| {
|
||||
^test10 R|/InOuter.InOuter|<R|kotlin/Int|>().R|/InOuter.OutIntermediate.OutIntermediate|<R|kotlin/String|>().R|/InOuter.OutIntermediate.InInner.InInner|<R|kotlin/Char|>()
|
||||
}
|
||||
public final fun test11(): R|InOuter.OutIntermediate.InInner<kotlin/Char, kotlin/String, in kotlin/Int>| {
|
||||
^test11 R|/InOuter.InOuter|<R|kotlin/Int|>().R|/InOuter.OutIntermediate.OutIntermediate|<R|kotlin/String|>().R|/InOuter.OutIntermediate.InInner.InInner|<R|kotlin/Char|>()
|
||||
}
|
||||
public final fun test12(): R|InOuter.OutIntermediate.InInner<kotlin/Char, kotlin/String, out kotlin/Int>| {
|
||||
^test12 R|/InOuter.InOuter|<R|kotlin/Int|>().R|/InOuter.OutIntermediate.OutIntermediate|<R|kotlin/String|>().R|/InOuter.OutIntermediate.InInner.InInner|<R|kotlin/Char|>()
|
||||
}
|
||||
public final fun test13(): R|InOuter.OutIntermediate.InInner<kotlin/Char, in kotlin/String, kotlin/Int>| {
|
||||
^test13 R|/InOuter.InOuter|<R|kotlin/Int|>().R|/InOuter.OutIntermediate.OutIntermediate|<R|kotlin/String|>().R|/InOuter.OutIntermediate.InInner.InInner|<R|kotlin/Char|>()
|
||||
}
|
||||
public final fun test14(): R|InOuter.OutIntermediate.InInner<kotlin/Char, out kotlin/String, kotlin/Int>| {
|
||||
^test14 R|/InOuter.InOuter|<R|kotlin/Int|>().R|/InOuter.OutIntermediate.OutIntermediate|<R|kotlin/String|>().R|/InOuter.OutIntermediate.InInner.InInner|<R|kotlin/Char|>()
|
||||
}
|
||||
public final fun test15(): R|InOuter.OutIntermediate.InInner<in kotlin/Char, kotlin/String, kotlin/Int>| {
|
||||
^test15 R|/InOuter.InOuter|<R|kotlin/Int|>().R|/InOuter.OutIntermediate.OutIntermediate|<R|kotlin/String|>().R|/InOuter.OutIntermediate.InInner.InInner|<R|kotlin/Char|>()
|
||||
}
|
||||
public final fun test16(): R|InOuter.OutIntermediate.InInner<out kotlin/Char, kotlin/String, kotlin/Int>| {
|
||||
^test16 R|/InOuter.InOuter|<R|kotlin/Int|>().R|/InOuter.OutIntermediate.OutIntermediate|<R|kotlin/String|>().R|/InOuter.OutIntermediate.InInner.InInner|<R|kotlin/Any?|>()
|
||||
}
|
||||
public final fun test17(): R|InOuter.OutIntermediate.InInner<kotlin/Char, out kotlin/String, in kotlin/Int>| {
|
||||
^test17 R|/InOuter.InOuter|<R|kotlin/Int|>().R|/InOuter.OutIntermediate.OutIntermediate|<R|kotlin/String|>().R|/InOuter.OutIntermediate.InInner.InInner|<R|kotlin/Char|>()
|
||||
}
|
||||
public final fun test18(): R|InOuter.OutIntermediate.InInner<out kotlin/Char, in kotlin/String, kotlin/Int>| {
|
||||
^test18 R|/InOuter.InOuter|<R|kotlin/Int|>().R|/InOuter.OutIntermediate.OutIntermediate|<R|kotlin/String|>().R|/InOuter.OutIntermediate.InInner.InInner|<R|kotlin/Any?|>()
|
||||
}
|
||||
Generated
+5
@@ -931,6 +931,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/conflictingOverloads.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("conflictingProjection.kt")
|
||||
public void testConflictingProjection() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/conflictingProjection.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("constructorInInterface.kt")
|
||||
public void testConstructorInInterface() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/constructorInInterface.kt");
|
||||
|
||||
+5
@@ -931,6 +931,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/conflictingOverloads.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("conflictingProjection.kt")
|
||||
public void testConflictingProjection() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/conflictingProjection.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("constructorInInterface.kt")
|
||||
public void testConstructorInInterface() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/constructorInInterface.kt");
|
||||
|
||||
+1
@@ -23,6 +23,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
|
||||
FirTypeParametersInObjectChecker,
|
||||
FirConflictsChecker,
|
||||
FirConstructorInInterfaceChecker,
|
||||
FirConflictingProjectionChecker,
|
||||
)
|
||||
|
||||
override val memberDeclarationCheckers: List<FirMemberDeclarationChecker> = listOf(
|
||||
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.declaration
|
||||
|
||||
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.FirErrors
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
object FirConflictingProjectionChecker : FirBasicDeclarationChecker() {
|
||||
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
// we can't just check for FirTypedDeclaration
|
||||
// because it leads to duplicate reports for
|
||||
// some cases. Maybe we should fix this via not
|
||||
// visiting the same firs twice instead.
|
||||
when (declaration) {
|
||||
is FirPropertyAccessor -> {}
|
||||
is FirProperty -> {
|
||||
checkTypeRef(declaration.returnTypeRef, context, reporter)
|
||||
}
|
||||
is FirFunction<*> -> {
|
||||
for (it in declaration.valueParameters) {
|
||||
checkTypeRef(it.returnTypeRef, context, reporter)
|
||||
}
|
||||
checkTypeRef(declaration.returnTypeRef, context, reporter)
|
||||
}
|
||||
is FirClass<*> -> {
|
||||
for (it in declaration.superTypeRefs) {
|
||||
checkTypeRef(it, context, reporter)
|
||||
}
|
||||
}
|
||||
is FirTypeAlias -> {
|
||||
for (it in declaration.typeParameters) {
|
||||
if (it.variance != Variance.INVARIANT) {
|
||||
reporter.reportVarianceNotAllowed(it.source)
|
||||
}
|
||||
}
|
||||
checkTypeRef(declaration.expandedTypeRef, context, reporter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkTypeRef(typeRef: FirTypeRef, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val declaration = typeRef.safeAs<FirResolvedTypeRef>()
|
||||
?.coneTypeSafe<ConeClassLikeType>()
|
||||
?.lookupTag
|
||||
?.toSymbol(context.session)
|
||||
?.fir.safeAs<FirRegularClass>()
|
||||
?: return
|
||||
|
||||
declaration.typeParameters.zip(typeRef.coneType.typeArguments).forEach { (proto, actual) ->
|
||||
val protoVariance = proto.safeAs<FirTypeParameterRef>()
|
||||
?.symbol?.fir
|
||||
?.variance
|
||||
?: return@forEach
|
||||
|
||||
if (protoVariance == Variance.INVARIANT) {
|
||||
return@forEach
|
||||
}
|
||||
|
||||
if (
|
||||
actual is ConeKotlinTypeProjectionIn && protoVariance == Variance.OUT_VARIANCE ||
|
||||
actual is ConeKotlinTypeProjectionOut && protoVariance == Variance.IN_VARIANCE
|
||||
) {
|
||||
reporter.reportConflictingProjections(typeRef.source, typeRef.coneType.toString())
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun DiagnosticReporter.reportConflictingProjections(source: FirSourceElement?, desiredProjection: String) {
|
||||
source?.let { report(FirErrors.CONFLICTING_PROJECTION.on(it, desiredProjection)) }
|
||||
}
|
||||
|
||||
private fun DiagnosticReporter.reportVarianceNotAllowed(source: FirSourceElement?) {
|
||||
source?.let { report(FirErrors.VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED.on(it)) }
|
||||
}
|
||||
}
|
||||
+11
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CLASS_IN_SUPERTYP
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONFLICTING_OVERLOADS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CAN_BE_VAL
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONFLICTING_PROJECTION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONSTRUCTOR_IN_INTERFACE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONSTRUCTOR_IN_OBJECT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CYCLIC_CONSTRUCTOR_DELEGATION_CALL
|
||||
@@ -104,6 +105,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNRESOLVED_LABEL
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNRESOLVED_REFERENCE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UPPER_BOUND_VIOLATED
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VARIABLE_EXPECTED
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAR_ANNOTATION_PARAMETER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_INVOCATION_KIND
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_NUMBER_OF_TYPE_ARGUMENTS
|
||||
@@ -254,6 +256,15 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
|
||||
map.put(TYPE_PARAMETERS_IN_OBJECT, "Type parameters are not allowed for objects")
|
||||
// map.put(ILLEGAL_PROJECTION_USAGE, ...) // &
|
||||
map.put(TYPE_PARAMETERS_IN_ENUM, "Enum class cannot have type parameters")
|
||||
map.put(
|
||||
CONFLICTING_PROJECTION,
|
||||
"Projection is conflicting with variance of the corresponding type parameter of {0}. Remove the projection or replace it with ''*''",
|
||||
TO_STRING
|
||||
)
|
||||
map.put(
|
||||
VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED,
|
||||
"Variance annotations are only allowed for type parameters of classes and interfaces"
|
||||
)
|
||||
|
||||
// Redeclarations
|
||||
map.put(MANY_COMPANION_OBJECTS, "Only one companion object is allowed per class")
|
||||
|
||||
@@ -125,6 +125,8 @@ object FirErrors {
|
||||
val TYPE_PARAMETERS_IN_OBJECT by error0<FirSourceElement, PsiElement>()
|
||||
val ILLEGAL_PROJECTION_USAGE by error0<FirSourceElement, PsiElement>()
|
||||
val TYPE_PARAMETERS_IN_ENUM by error0<FirSourceElement, PsiElement>()
|
||||
val CONFLICTING_PROJECTION by error1<FirSourceElement, PsiElement, String>()
|
||||
val VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED by error0<FirSourceElement, PsiElement>()
|
||||
|
||||
// Redeclarations
|
||||
val MANY_COMPANION_OBJECTS by error0<FirSourceElement, PsiElement>()
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
$TESTDATA_DIR$/conflictingProjection.kt
|
||||
-Xuse-fir
|
||||
-d
|
||||
$TEMP_DIR$
|
||||
@@ -0,0 +1,19 @@
|
||||
class None<T>
|
||||
class In<in T>
|
||||
class Out<out T>
|
||||
|
||||
fun a1(value: None<Int>) {}
|
||||
fun a2(value: None<in Int>) {}
|
||||
fun a3(value: None<out Int>) {}
|
||||
|
||||
fun a7(value: Out<Int>) {}
|
||||
fun a8(value: Out<in Int>) {}
|
||||
fun a9(value: Out<out Int>) {}
|
||||
|
||||
typealias A1<K> = None<K>
|
||||
typealias A2<K> = None<in K>
|
||||
typealias A3<K> = None<out K>
|
||||
|
||||
typealias A13<in K> = In<K>
|
||||
typealias A14<in K> = In<in K>
|
||||
typealias A15<in K> = In<out K>
|
||||
@@ -0,0 +1,16 @@
|
||||
compiler/testData/cli/jvm/conflictingProjection.kt:10:15: error: projection is conflicting with variance of the corresponding type parameter of Out<in kotlin/Int>. Remove the projection or replace it with '*'
|
||||
fun a8(value: Out<in Int>) {}
|
||||
^
|
||||
compiler/testData/cli/jvm/conflictingProjection.kt:17:15: error: variance annotations are only allowed for type parameters of classes and interfaces
|
||||
typealias A13<in K> = In<K>
|
||||
^
|
||||
compiler/testData/cli/jvm/conflictingProjection.kt:18:15: error: variance annotations are only allowed for type parameters of classes and interfaces
|
||||
typealias A14<in K> = In<in K>
|
||||
^
|
||||
compiler/testData/cli/jvm/conflictingProjection.kt:19:15: error: variance annotations are only allowed for type parameters of classes and interfaces
|
||||
typealias A15<in K> = In<out K>
|
||||
^
|
||||
compiler/testData/cli/jvm/conflictingProjection.kt:19:23: error: projection is conflicting with variance of the corresponding type parameter of In<out K>. Remove the projection or replace it with '*'
|
||||
typealias A15<in K> = In<out K>
|
||||
^
|
||||
COMPILATION_ERROR
|
||||
Vendored
+2
-2
@@ -4,11 +4,11 @@ class Inv<T>
|
||||
class X
|
||||
|
||||
fun f1(p: In<in X>) {}
|
||||
fun f2(p: In<out X>) {}
|
||||
fun f2(p: <!CONFLICTING_PROJECTION!>In<out X><!>) {}
|
||||
fun f3(p: In<X>) {}
|
||||
|
||||
fun f4(p: Out<out X>) {}
|
||||
fun f5(p: Out<in X>) {}
|
||||
fun f5(p: <!CONFLICTING_PROJECTION!>Out<in X><!>) {}
|
||||
fun f6(p: Out<X>) {}
|
||||
|
||||
fun f6(p: Inv<X>) {}
|
||||
|
||||
@@ -51,7 +51,7 @@ val String.x1 get() = ""
|
||||
|
||||
fun <K> bar1(f: KFunction2<K, String, String>) {}
|
||||
|
||||
fun <K> bar2(f: KFunction2<out K, String, String>) {}
|
||||
fun <K> bar2(f: <!CONFLICTING_PROJECTION!>KFunction2<out K, String, String><!>) {}
|
||||
|
||||
fun <K> bar3(f: Any?) {}
|
||||
|
||||
|
||||
+1
-1
@@ -7,5 +7,5 @@ class In<in T>() {
|
||||
|
||||
fun test1(x: In<String>): Unit = x.f("1")
|
||||
fun test2(x: In<in String>): Unit = x.f("1")
|
||||
fun test3(x: In<out String>): Unit = x.f("1")
|
||||
fun test3(x: <!CONFLICTING_PROJECTION!>In<out String><!>): Unit = x.f("1")
|
||||
fun test4(x: In<*>): Unit = x.f("1")
|
||||
+2
-2
@@ -6,8 +6,8 @@ interface Out<out T>
|
||||
typealias InAlias<T> = In<T>
|
||||
typealias OutAlias<T> = Out<T>
|
||||
|
||||
typealias TestOutForIn<T> = In<out T>
|
||||
typealias TestInForOut<T> = Out<in T>
|
||||
typealias TestOutForIn<T> = <!CONFLICTING_PROJECTION!>In<out T><!>
|
||||
typealias TestInForOut<T> = <!CONFLICTING_PROJECTION!>Out<in T><!>
|
||||
|
||||
typealias TestOutForInWithinAlias<T> = InAlias<out T>
|
||||
typealias TestInForOutWithinAlias<T> = OutAlias<in T>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// !DIAGNOSTICS: -UNUSED_TYPEALIAS_PARAMETER
|
||||
|
||||
typealias WithVariance<in X, out Y> = Int
|
||||
typealias WithVariance<<!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>in X<!>, <!VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED!>out Y<!>> = Int
|
||||
typealias WithBounds1<T : T> = Int
|
||||
typealias WithBounds2<X : Y, Y : X> = Int
|
||||
|
||||
|
||||
@@ -6,11 +6,11 @@ class Inv<T>
|
||||
|
||||
typealias In1<T> = In<T>
|
||||
typealias In2<T> = In<in T>
|
||||
typealias In3<T> = In<out T>
|
||||
typealias In3<T> = <!CONFLICTING_PROJECTION!>In<out T><!>
|
||||
typealias In4<T> = In<*>
|
||||
|
||||
typealias Out1<T> = Out<T>
|
||||
typealias Out2<T> = Out<in T>
|
||||
typealias Out2<T> = <!CONFLICTING_PROJECTION!>Out<in T><!>
|
||||
typealias Out3<T> = Out<out T>
|
||||
typealias Out4<T> = Out<*>
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ interface Test<in I, out O, P> {
|
||||
fun neOk6(i: In<In<O>>)
|
||||
fun neOk7(i: Pair<In<I>, O>)
|
||||
fun neOk8(i: Inv<out O>)
|
||||
fun neOk9(i: In<out P>)
|
||||
fun neOk9(i: <!CONFLICTING_PROJECTION!>In<out P><!>)
|
||||
fun neOk10(i: Out<O>)
|
||||
|
||||
fun neOk11(i: Inv<in I>)
|
||||
|
||||
@@ -23,7 +23,7 @@ interface Test<in I, out O, P> {
|
||||
var neOk7: Pair<In<I>, O>
|
||||
var neOk8: Inv<in O>
|
||||
var neOk9: Inv<in I>
|
||||
var neOk10: In<out I>
|
||||
var neOk10: <!CONFLICTING_PROJECTION!>In<out I><!>
|
||||
|
||||
var neOk11: I
|
||||
var neOk12: In<O>
|
||||
|
||||
@@ -28,7 +28,7 @@ interface Test<in I, out O, P> {
|
||||
fun neOk5(): Inv<O>
|
||||
fun neOk6(): Pair<In<O>, I>
|
||||
fun neOk7(): Inv<in O>
|
||||
fun neOk8(): Out<in I>
|
||||
fun neOk8(): <!CONFLICTING_PROJECTION!>Out<in I><!>
|
||||
|
||||
fun neOk10(): Inv<in O>
|
||||
fun neOk11(): Inv<out I>
|
||||
|
||||
@@ -140,6 +140,11 @@ public class CliTestGenerated extends AbstractCliTest {
|
||||
runTest("compiler/testData/cli/jvm/conflictingOverloads.args");
|
||||
}
|
||||
|
||||
@TestMetadata("conflictingProjection.args")
|
||||
public void testConflictingProjection() throws Exception {
|
||||
runTest("compiler/testData/cli/jvm/conflictingProjection.args");
|
||||
}
|
||||
|
||||
@TestMetadata("coroutinesEnable.args")
|
||||
public void testCoroutinesEnable() throws Exception {
|
||||
runTest("compiler/testData/cli/jvm/coroutinesEnable.args");
|
||||
|
||||
Reference in New Issue
Block a user