[FIR] Add diagnostic UPPER_BOUND_VIOLATED
This commit is contained in:
+41
@@ -0,0 +1,41 @@
|
|||||||
|
interface A
|
||||||
|
|
||||||
|
class B<T> where T : A
|
||||||
|
class C : A
|
||||||
|
typealias GGG = C
|
||||||
|
typealias HHH = GGG
|
||||||
|
typealias JJJ = B<C>
|
||||||
|
|
||||||
|
fun <T : A> fest() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
val b1 = B<<!UPPER_BOUND_VIOLATED!>Int<!>>()
|
||||||
|
val b2 = B<C>()
|
||||||
|
fest<<!UPPER_BOUND_VIOLATED!>Boolean<!>>()
|
||||||
|
fest<C>()
|
||||||
|
fest<HHH>()
|
||||||
|
fest<<!UPPER_BOUND_VIOLATED!>JJJ<!>>()
|
||||||
|
}
|
||||||
|
|
||||||
|
open class S<F, G : F>
|
||||||
|
class T<U, Y : U> : S<U, Y>()
|
||||||
|
|
||||||
|
fun <K, L : K> rest() {
|
||||||
|
val o1 = S<K, L>()
|
||||||
|
val o2 = S<K, K>()
|
||||||
|
val o3 = S<L, L>()
|
||||||
|
|
||||||
|
val o4 = S<S<K, L>, T<K, L>>()
|
||||||
|
val o5 = S<S<K, L>, <!UPPER_BOUND_VIOLATED!>T<K, K><!>>()
|
||||||
|
val o5 = S<S<L, L>, <!UPPER_BOUND_VIOLATED!>T<K, L><!>>()
|
||||||
|
|
||||||
|
val o6 = S<Any, <!UPPER_BOUND_VIOLATED!>T<S<K, L>, String><!>>()
|
||||||
|
val o7 = S<Any, T<S<K, L>, Nothing>>()
|
||||||
|
}
|
||||||
|
|
||||||
|
class NumColl<T : Collection<Number>>
|
||||||
|
typealias NL<K> = NumColl<List<K>>
|
||||||
|
val test7 = NL<Int>()
|
||||||
|
val test8 = <!UPPER_BOUND_VIOLATED!>NL<String>()<!>
|
||||||
+61
@@ -0,0 +1,61 @@
|
|||||||
|
FILE: upperBoundViolated.kt
|
||||||
|
public abstract interface A : R|kotlin/Any| {
|
||||||
|
}
|
||||||
|
public final class B<T : R|A|> : R|kotlin/Any| {
|
||||||
|
public constructor<T : R|A|>(): R|B<T>| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public final class C : R|A| {
|
||||||
|
public constructor(): R|C| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public final typealias GGG = R|C|
|
||||||
|
public final typealias HHH = R|GGG|
|
||||||
|
public final typealias JJJ = R|B<C>|
|
||||||
|
public final fun <T : R|A|> fest(): R|kotlin/Unit| {
|
||||||
|
}
|
||||||
|
public final fun test(): R|kotlin/Unit| {
|
||||||
|
lval b1: R|B<kotlin/Int>| = R|/B.B|<R|kotlin/Int|>()
|
||||||
|
lval b2: R|B<C>| = R|/B.B|<R|C|>()
|
||||||
|
R|/fest|<R|kotlin/Boolean|>()
|
||||||
|
R|/fest|<R|C|>()
|
||||||
|
R|/fest|<R|C|>()
|
||||||
|
R|/fest|<R|B<C>|>()
|
||||||
|
}
|
||||||
|
public open class S<F, G : R|F|> : R|kotlin/Any| {
|
||||||
|
public constructor<F, G : R|F|>(): R|S<F, G>| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public final class T<U, Y : R|U|> : R|S<U, Y>| {
|
||||||
|
public constructor<U, Y : R|U|>(): R|T<U, Y>| {
|
||||||
|
super<R|S<U, Y>|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public final fun <K, L : R|K|> rest(): R|kotlin/Unit| {
|
||||||
|
lval o1: R|S<K, L>| = R|/S.S|<R|K|, R|L|>()
|
||||||
|
lval o2: R|S<K, K>| = R|/S.S|<R|K|, R|K|>()
|
||||||
|
lval o3: R|S<L, L>| = R|/S.S|<R|L|, R|L|>()
|
||||||
|
lval o4: R|S<S<K, L>, T<K, L>>| = R|/S.S|<R|S<K, L>|, R|T<K, L>|>()
|
||||||
|
lval o5: R|S<S<K, L>, T<K, K>>| = R|/S.S|<R|S<K, L>|, R|T<K, K>|>()
|
||||||
|
lval o5: R|S<S<L, L>, T<K, L>>| = R|/S.S|<R|S<L, L>|, R|T<K, L>|>()
|
||||||
|
lval o6: R|S<kotlin/Any, T<S<K, L>, kotlin/String>>| = R|/S.S|<R|kotlin/Any|, R|T<S<K, L>, kotlin/String>|>()
|
||||||
|
lval o7: R|S<kotlin/Any, T<S<K, L>, kotlin/Nothing>>| = R|/S.S|<R|kotlin/Any|, R|T<S<K, L>, kotlin/Nothing>|>()
|
||||||
|
}
|
||||||
|
public final class NumColl<T : R|kotlin/collections/Collection<kotlin/Number>|> : R|kotlin/Any| {
|
||||||
|
public constructor<T : R|kotlin/collections/Collection<kotlin/Number>|>(): R|NumColl<T>| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public final typealias NL<K> = R|NumColl<kotlin/collections/List<K>>|
|
||||||
|
public final val test7: R|NumColl<kotlin/collections/List<kotlin/Int>>| = R|/NumColl.NumColl|<R|kotlin/Int|>()
|
||||||
|
public get(): R|NumColl<kotlin/collections/List<kotlin/Int>>|
|
||||||
|
public final val test8: R|NumColl<kotlin/collections/List<kotlin/String>>| = R|/NumColl.NumColl|<R|kotlin/String|>()
|
||||||
|
public get(): R|NumColl<kotlin/collections/List<kotlin/String>>|
|
||||||
Generated
+5
@@ -946,6 +946,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
|
|||||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/typeOfAnnotationMember.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/typeOfAnnotationMember.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("upperBoundViolated.kt")
|
||||||
|
public void testUpperBoundViolated() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/upperBoundViolated.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("valOnAnnotationParameter.kt")
|
@TestMetadata("valOnAnnotationParameter.kt")
|
||||||
public void testValOnAnnotationParameter() throws Exception {
|
public void testValOnAnnotationParameter() throws Exception {
|
||||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/valOnAnnotationParameter.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/valOnAnnotationParameter.kt");
|
||||||
|
|||||||
+5
@@ -946,6 +946,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
|||||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/typeOfAnnotationMember.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/typeOfAnnotationMember.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("upperBoundViolated.kt")
|
||||||
|
public void testUpperBoundViolated() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/upperBoundViolated.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("valOnAnnotationParameter.kt")
|
@TestMetadata("valOnAnnotationParameter.kt")
|
||||||
public void testValOnAnnotationParameter() throws Exception {
|
public void testValOnAnnotationParameter() throws Exception {
|
||||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/valOnAnnotationParameter.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/valOnAnnotationParameter.kt");
|
||||||
|
|||||||
+2
-1
@@ -13,7 +13,8 @@ object CommonExpressionCheckers : ExpressionCheckers() {
|
|||||||
FirSuperclassNotAccessibleFromInterfaceChecker,
|
FirSuperclassNotAccessibleFromInterfaceChecker,
|
||||||
FirAbstractSuperCallChecker,
|
FirAbstractSuperCallChecker,
|
||||||
FirQualifiedSupertypeExtendedByOtherSupertypeChecker,
|
FirQualifiedSupertypeExtendedByOtherSupertypeChecker,
|
||||||
FirProjectionsOnNonClassTypeArgumentChecker
|
FirProjectionsOnNonClassTypeArgumentChecker,
|
||||||
|
FirUpperBoundViolatedChecker,
|
||||||
)
|
)
|
||||||
override val functionCallCheckers: List<FirFunctionCallChecker> = listOf()
|
override val functionCallCheckers: List<FirFunctionCallChecker> = listOf()
|
||||||
}
|
}
|
||||||
+212
@@ -0,0 +1,212 @@
|
|||||||
|
/*
|
||||||
|
* 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.expression
|
||||||
|
|
||||||
|
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.expressions.FirQualifiedAccessExpression
|
||||||
|
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.typeContext
|
||||||
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
|
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||||
|
import org.jetbrains.kotlin.types.AbstractTypeCheckerContext
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
|
object FirUpperBoundViolatedChecker : FirQualifiedAccessChecker() {
|
||||||
|
override fun check(functionCall: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
|
// something that contains the type parameters
|
||||||
|
// declarations with their declared bounds.
|
||||||
|
// it may be the called function declaration
|
||||||
|
// or the class declaration
|
||||||
|
val calleeFir = functionCall.calleeReference.safeAs<FirResolvedNamedReference>()
|
||||||
|
?.resolvedSymbol
|
||||||
|
?.fir.safeAs<FirTypeParameterRefsOwner>()
|
||||||
|
?: return
|
||||||
|
|
||||||
|
val typeCheckerContext = context.session.typeContext.newBaseTypeCheckerContext(
|
||||||
|
errorTypesEqualToAnything = false,
|
||||||
|
stubTypesEqualToAnything = false
|
||||||
|
)
|
||||||
|
|
||||||
|
val parameterPairs = calleeFir.typeParameters.zip(functionCall.typeArguments)
|
||||||
|
.map { (proto, actual) ->
|
||||||
|
proto.symbol to actual.safeAs<FirTypeProjectionWithVariance>()
|
||||||
|
?.typeRef.safeAs<FirResolvedTypeRef>()
|
||||||
|
}
|
||||||
|
.toMapWithoutNulls()
|
||||||
|
|
||||||
|
// we substitute actual values to the
|
||||||
|
// type parameters from the declaration
|
||||||
|
val substitutor = substitutorByMap(
|
||||||
|
parameterPairs.mapValues { it.value.type }
|
||||||
|
)
|
||||||
|
|
||||||
|
parameterPairs.forEach { proto, actual ->
|
||||||
|
if (!satisfiesBounds(proto, actual.type, substitutor, typeCheckerContext)) {
|
||||||
|
reporter.report(actual.source)
|
||||||
|
return@forEach
|
||||||
|
}
|
||||||
|
|
||||||
|
// we must analyze nested things like
|
||||||
|
// S<S<K, L>, T<K, L>>()
|
||||||
|
actual.type.safeAs<ConeClassLikeType>()?.let {
|
||||||
|
analyzeTypeParameters(it, context, reporter, typeCheckerContext, actual.source)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we're dealing with a constructor
|
||||||
|
// resolved from a typealias we need to
|
||||||
|
// check if our actual parameters satisfy
|
||||||
|
// this constructor parameters.
|
||||||
|
// e.g.
|
||||||
|
// class B<T : Collection<Number>>
|
||||||
|
// typealias A<G> = B<List<G>>
|
||||||
|
// val a = A<Int>()
|
||||||
|
when (calleeFir) {
|
||||||
|
is FirConstructor -> analyzeConstructorCall(functionCall, substitutor, typeCheckerContext, reporter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun analyzeConstructorCall(
|
||||||
|
functionCall: FirQualifiedAccessExpression,
|
||||||
|
callSiteSubstitutor: ConeSubstitutor,
|
||||||
|
typeCheckerContext: AbstractTypeCheckerContext,
|
||||||
|
reporter: DiagnosticReporter,
|
||||||
|
) {
|
||||||
|
// holds Collection<Number> bound.
|
||||||
|
// note that if B used another type parameter here,
|
||||||
|
// we'd get Collection<K>. So we need to do one more
|
||||||
|
// substitution here
|
||||||
|
val protoConstructor = functionCall.calleeReference.safeAs<FirResolvedNamedReference>()
|
||||||
|
?.resolvedSymbol.safeAs<FirConstructorSymbol>()
|
||||||
|
?.overriddenSymbol
|
||||||
|
?.fir.safeAs<FirConstructor>()
|
||||||
|
?: return
|
||||||
|
|
||||||
|
// holds Collection<G> bound.
|
||||||
|
// we need to do substitution here to get
|
||||||
|
// Collection<Int>
|
||||||
|
val actualConstructor = functionCall.calleeReference.safeAs<FirResolvedNamedReference>()
|
||||||
|
?.resolvedSymbol.safeAs<FirConstructorSymbol>()
|
||||||
|
?.fir.safeAs<FirConstructor>()
|
||||||
|
?.returnTypeRef.safeAs<FirResolvedTypeRef>()
|
||||||
|
?.type.safeAs<ConeClassLikeType>()
|
||||||
|
?: return
|
||||||
|
|
||||||
|
val constructorsParameterPairs = protoConstructor.typeParameters
|
||||||
|
.zip(actualConstructor.typeArguments)
|
||||||
|
.map { (proto, actual) ->
|
||||||
|
proto.symbol to actual.safeAs<ConeSimpleKotlinType>()
|
||||||
|
}
|
||||||
|
.toMapWithoutNulls()
|
||||||
|
|
||||||
|
// we substitute typealias declaration
|
||||||
|
// parameters to the ones used in the
|
||||||
|
// typealias target
|
||||||
|
val declarationSiteSubstitutor = substitutorByMap(
|
||||||
|
constructorsParameterPairs.mapValues { it.value.type }
|
||||||
|
)
|
||||||
|
|
||||||
|
constructorsParameterPairs.forEach { proto, actual ->
|
||||||
|
// just in case
|
||||||
|
var intersection = typeCheckerContext.intersectTypes(
|
||||||
|
proto.fir.bounds.filterIsInstance<FirResolvedTypeRef>().map { it.type }
|
||||||
|
).safeAs<ConeKotlinType>() ?: return@forEach
|
||||||
|
|
||||||
|
intersection = declarationSiteSubstitutor.substituteOrSelf(intersection)
|
||||||
|
intersection = callSiteSubstitutor.substituteOrSelf(intersection)
|
||||||
|
|
||||||
|
// substitute Int for G from
|
||||||
|
// the example above
|
||||||
|
val target = callSiteSubstitutor.substituteOrSelf(actual)
|
||||||
|
val satisfiesBounds = AbstractTypeChecker.isSubtypeOf(typeCheckerContext, target, intersection)
|
||||||
|
|
||||||
|
if (!satisfiesBounds) {
|
||||||
|
reporter.report(functionCall.source)
|
||||||
|
return@forEach
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively analyzes type parameters
|
||||||
|
* and reports the diagnostic on the given
|
||||||
|
* reportTarget (because we can't report them
|
||||||
|
* on type parameters themselves now).
|
||||||
|
*/
|
||||||
|
private fun analyzeTypeParameters(
|
||||||
|
type: ConeClassLikeType,
|
||||||
|
context: CheckerContext,
|
||||||
|
reporter: DiagnosticReporter,
|
||||||
|
typeCheckerContext: AbstractTypeCheckerContext,
|
||||||
|
reportTarget: FirSourceElement?
|
||||||
|
) {
|
||||||
|
val prototypeClass = type.lookupTag.toSymbol(context.session)
|
||||||
|
?.fir.safeAs<FirRegularClass>()
|
||||||
|
?: return
|
||||||
|
|
||||||
|
val parameterPairs = prototypeClass.typeParameters.zip(type.typeArguments)
|
||||||
|
.map { (proto, actual) ->
|
||||||
|
proto.symbol to actual.safeAs<ConeClassLikeType>()
|
||||||
|
}
|
||||||
|
.toMapWithoutNulls()
|
||||||
|
|
||||||
|
val substitutor = substitutorByMap(
|
||||||
|
parameterPairs.mapValues { it.value.type }
|
||||||
|
)
|
||||||
|
|
||||||
|
parameterPairs.forEach { proto, actual ->
|
||||||
|
if (!satisfiesBounds(proto, actual.type, substitutor, typeCheckerContext)) {
|
||||||
|
// should report on the parameter instead!
|
||||||
|
reporter.report(reportTarget)
|
||||||
|
return@forEach
|
||||||
|
}
|
||||||
|
|
||||||
|
analyzeTypeParameters(actual, context, reporter, typeCheckerContext, reportTarget)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if target satisfies the
|
||||||
|
* bounds of the prototypeSymbol.
|
||||||
|
*/
|
||||||
|
private fun satisfiesBounds(
|
||||||
|
prototypeSymbol: FirTypeParameterSymbol,
|
||||||
|
target: ConeKotlinType,
|
||||||
|
substitutor: ConeSubstitutor,
|
||||||
|
typeCheckerContext: AbstractTypeCheckerContext
|
||||||
|
): Boolean {
|
||||||
|
var intersection = typeCheckerContext.intersectTypes(
|
||||||
|
prototypeSymbol.fir.bounds.filterIsInstance<FirResolvedTypeRef>().map { it.type }
|
||||||
|
).safeAs<ConeKotlinType>() ?: return true
|
||||||
|
|
||||||
|
intersection = substitutor.substituteOrSelf(intersection)
|
||||||
|
return AbstractTypeChecker.isSubtypeOf(typeCheckerContext, target, intersection)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the entries where either A? or B?
|
||||||
|
* is null and constructs a Map<A, B>.
|
||||||
|
*/
|
||||||
|
private fun <A, B> List<Pair<A?, B?>>.toMapWithoutNulls() = this
|
||||||
|
.filter { it.first != null && it.second != null }
|
||||||
|
.map { it.first!! to it.second!! }
|
||||||
|
.toMap()
|
||||||
|
|
||||||
|
private fun DiagnosticReporter.report(source: FirSourceElement?) {
|
||||||
|
source?.let {
|
||||||
|
report(FirErrors.UPPER_BOUND_VIOLATED.on(it))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -76,8 +76,8 @@ object FirErrors {
|
|||||||
val DEPRECATED_MODIFIER_PAIR by error2<FirSourceElement, PsiElement, KtModifierKeywordToken, KtModifierKeywordToken>()
|
val DEPRECATED_MODIFIER_PAIR by error2<FirSourceElement, PsiElement, KtModifierKeywordToken, KtModifierKeywordToken>()
|
||||||
val INCOMPATIBLE_MODIFIERS by error2<FirSourceElement, PsiElement, KtModifierKeywordToken, KtModifierKeywordToken>()
|
val INCOMPATIBLE_MODIFIERS by error2<FirSourceElement, PsiElement, KtModifierKeywordToken, KtModifierKeywordToken>()
|
||||||
|
|
||||||
// projection
|
|
||||||
val PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT by error0<FirSourceElement, PsiElement>()
|
val PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT by error0<FirSourceElement, PsiElement>()
|
||||||
|
val UPPER_BOUND_VIOLATED by error0<FirSourceElement, PsiElement>()
|
||||||
|
|
||||||
// Control flow diagnostics
|
// Control flow diagnostics
|
||||||
val UNINITIALIZED_VARIABLE by error1<FirSourceElement, PsiElement, FirPropertySymbol>()
|
val UNINITIALIZED_VARIABLE by error1<FirSourceElement, PsiElement, FirPropertySymbol>()
|
||||||
|
|||||||
+7
-7
@@ -7,13 +7,13 @@ package boundsWithSubstitutors
|
|||||||
class C : A<C>()
|
class C : A<C>()
|
||||||
|
|
||||||
val a = B<C>()
|
val a = B<C>()
|
||||||
val a1 = B<Int>()
|
val a1 = B<<!UPPER_BOUND_VIOLATED!>Int<!>>()
|
||||||
|
|
||||||
class X<A, B : A>()
|
class X<A, B : A>()
|
||||||
|
|
||||||
val b = X<Any, X<A<C>, C>>()
|
val b = X<Any, X<A<C>, C>>()
|
||||||
val b0 = X<Any, Any?>()
|
val b0 = X<Any, <!UPPER_BOUND_VIOLATED!>Any?<!>>()
|
||||||
val b1 = X<Any, X<A<C>, String>>()
|
val b1 = X<Any, <!UPPER_BOUND_VIOLATED!>X<A<C>, String><!>>()
|
||||||
|
|
||||||
// FILE: b.kt
|
// FILE: b.kt
|
||||||
open class A {}
|
open class A {}
|
||||||
@@ -22,19 +22,19 @@ package boundsWithSubstitutors
|
|||||||
class Pair<A, B>
|
class Pair<A, B>
|
||||||
|
|
||||||
abstract class C<T : B<Int>, X : (B<Char>) -> Pair<B<Any>, B<A>>>() : B<Any>() { // 2 errors
|
abstract class C<T : B<Int>, X : (B<Char>) -> Pair<B<Any>, B<A>>>() : B<Any>() { // 2 errors
|
||||||
val a = B<Char>() // error
|
val a = B<<!UPPER_BOUND_VIOLATED!>Char<!>>() // error
|
||||||
|
|
||||||
abstract val x : (B<Char>) -> B<Any>
|
abstract val x : (B<Char>) -> B<Any>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun test() {
|
fun test() {
|
||||||
foo<Int?>()
|
foo<<!UPPER_BOUND_VIOLATED!>Int?<!>>()
|
||||||
foo<Int>()
|
foo<Int>()
|
||||||
bar<Int?>()
|
bar<Int?>()
|
||||||
bar<Int>()
|
bar<Int>()
|
||||||
bar<Double?>()
|
bar<<!UPPER_BOUND_VIOLATED!>Double?<!>>()
|
||||||
bar<Double>()
|
bar<<!UPPER_BOUND_VIOLATED!>Double<!>>()
|
||||||
1.<!INAPPLICABLE_CANDIDATE!>buzz<!><Double>()
|
1.<!INAPPLICABLE_CANDIDATE!>buzz<!><Double>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,8 +36,8 @@ class Test1<T>()
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun test() {
|
fun test() {
|
||||||
Test1<B>()
|
Test1<<!UPPER_BOUND_VIOLATED!>B<!>>()
|
||||||
Test1<A>()
|
Test1<<!UPPER_BOUND_VIOLATED!>A<!>>()
|
||||||
Test1<C>()
|
Test1<C>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -9,13 +9,13 @@ fun <T> materialize() = null as T
|
|||||||
|
|
||||||
fun test() {
|
fun test() {
|
||||||
consume(
|
consume(
|
||||||
materialize<Foo<Bar<ErrorType>>>(),
|
materialize<<!UPPER_BOUND_VIOLATED!>Foo<Bar<ErrorType>><!>>(),
|
||||||
materialize<Foo<Bar<ErrorType>>>()
|
materialize<<!UPPER_BOUND_VIOLATED!>Foo<Bar<ErrorType>><!>>()
|
||||||
)
|
)
|
||||||
|
|
||||||
<!INAPPLICABLE_CANDIDATE!>consume<!>(
|
<!INAPPLICABLE_CANDIDATE!>consume<!>(
|
||||||
materialize<Foo<Bar<ErrorType>>>(),
|
materialize<<!UPPER_BOUND_VIOLATED!>Foo<Bar<ErrorType>><!>>(),
|
||||||
materialize<Foo<ErrorType>>()
|
materialize<<!UPPER_BOUND_VIOLATED!>Foo<ErrorType><!>>()
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -31,8 +31,8 @@ class Bar<T, K: Any> {
|
|||||||
val foos14 = ArrayList<A<T>?>()
|
val foos14 = ArrayList<A<T>?>()
|
||||||
val foos15 = ArrayList<A<T?>>()
|
val foos15 = ArrayList<A<T?>>()
|
||||||
|
|
||||||
val foos16 = J<Foo>()
|
val foos16 = J<<!UPPER_BOUND_VIOLATED!>Foo<!>>()
|
||||||
val foos17 = J<Foo?>()
|
val foos17 = J<<!UPPER_BOUND_VIOLATED!>Foo?<!>>()
|
||||||
val foos18 = J<T>()
|
val foos18 = J<<!UPPER_BOUND_VIOLATED!>T<!>>()
|
||||||
val foos19 = J<T?>()
|
val foos19 = J<<!UPPER_BOUND_VIOLATED!>T?<!>>()
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-5
@@ -5,14 +5,14 @@ typealias N<T> = Num<T>
|
|||||||
typealias N2<T> = N<T>
|
typealias N2<T> = N<T>
|
||||||
|
|
||||||
val x1 = <!INAPPLICABLE_CANDIDATE!>Num<!><String>("")
|
val x1 = <!INAPPLICABLE_CANDIDATE!>Num<!><String>("")
|
||||||
val x2 = N<String>("")
|
val x2 = <!UPPER_BOUND_VIOLATED!>N<String>("")<!>
|
||||||
val x3 = N2<String>("")
|
val x3 = <!UPPER_BOUND_VIOLATED!>N2<String>("")<!>
|
||||||
|
|
||||||
class TColl<T, C : Collection<T>>
|
class TColl<T, C : Collection<T>>
|
||||||
|
|
||||||
typealias TC<T, C> = TColl<T, C>
|
typealias TC<T, C> = TColl<T, C>
|
||||||
typealias TC2<T, C> = TC<T, C>
|
typealias TC2<T, C> = TC<T, C>
|
||||||
|
|
||||||
val y1 = TColl<Any, Any>()
|
val y1 = TColl<Any, <!UPPER_BOUND_VIOLATED!>Any<!>>()
|
||||||
val y2 = TC<Any, Any>()
|
val y2 = <!UPPER_BOUND_VIOLATED!>TC<Any, Any>()<!>
|
||||||
val y3 = TC2<Any, Any>()
|
val y3 = <!UPPER_BOUND_VIOLATED!>TC2<Any, Any>()<!>
|
||||||
|
|||||||
Vendored
+1
-1
@@ -14,4 +14,4 @@ fun test4(x: TC2<Number, List<Any>>) {}
|
|||||||
val test5 = TC2<Number, Collection<Number>>()
|
val test5 = TC2<Number, Collection<Number>>()
|
||||||
val test6 = TC2<Number, Collection<Int>>()
|
val test6 = TC2<Number, Collection<Int>>()
|
||||||
val test7 = TC2<Number, List<Int>>()
|
val test7 = TC2<Number, List<Int>>()
|
||||||
val test8 = TC2<Number, List<Any>>()
|
val test8 = <!UPPER_BOUND_VIOLATED!>TC2<Number, List<Any>>()<!>
|
||||||
|
|||||||
+6
-4
@@ -6,7 +6,8 @@ class NumColl<T : Collection<Number>>
|
|||||||
class TColl<T, C : Collection<T>>
|
class TColl<T, C : Collection<T>>
|
||||||
|
|
||||||
typealias NA<T> = Num<T>
|
typealias NA<T> = Num<T>
|
||||||
typealias NL<T> = NumColl<List<T>>
|
typealias NL<T2> = NumColl<List<T2>>
|
||||||
|
typealias MMMM<A3> = NL<A3>
|
||||||
typealias TC<T1, T2> = TColl<T1, T2>
|
typealias TC<T1, T2> = TColl<T1, T2>
|
||||||
|
|
||||||
fun test1(x: NA<Int>) {}
|
fun test1(x: NA<Int>) {}
|
||||||
@@ -15,9 +16,10 @@ fun test3(x: NL<Int>) {}
|
|||||||
fun test4(x: NL<Any>) {}
|
fun test4(x: NL<Any>) {}
|
||||||
|
|
||||||
val test5 = NA<Int>()
|
val test5 = NA<Int>()
|
||||||
val test6 = NA<Any>()
|
val test6 = <!UPPER_BOUND_VIOLATED!>NA<Any>()<!>
|
||||||
val test7 = NL<Int>()
|
val test7 = NL<Int>()
|
||||||
val test8 = NL<Any>()
|
val test8 = MMMM<Int>()
|
||||||
|
val test9dwd = <!UPPER_BOUND_VIOLATED!>NL<Any>()<!>
|
||||||
|
|
||||||
fun test9(x: TC<Number, Collection<Number>>) {}
|
fun test9(x: TC<Number, Collection<Number>>) {}
|
||||||
fun test10(x: TC<Number, Collection<Int>>) {}
|
fun test10(x: TC<Number, Collection<Int>>) {}
|
||||||
@@ -27,4 +29,4 @@ fun test12(x: TC<Number, List<Any>>) {}
|
|||||||
val test13 = TC<Number, Collection<Number>>()
|
val test13 = TC<Number, Collection<Number>>()
|
||||||
val test14 = TC<Number, Collection<Int>>()
|
val test14 = TC<Number, Collection<Int>>()
|
||||||
val test15 = TC<Number, List<Int>>()
|
val test15 = TC<Number, List<Int>>()
|
||||||
val test16 = TC<Number, List<Any>>()
|
val test16 = <!UPPER_BOUND_VIOLATED!>TC<Number, List<Any>>()<!>
|
||||||
|
|||||||
Vendored
+1
-1
@@ -5,7 +5,7 @@ class Num<Tn : Number>(val x: Tn)
|
|||||||
typealias N<T> = Num<T>
|
typealias N<T> = Num<T>
|
||||||
|
|
||||||
val test0 = N(1)
|
val test0 = N(1)
|
||||||
val test1 = N("1")
|
val test1 = <!UPPER_BOUND_VIOLATED!>N("1")<!>
|
||||||
|
|
||||||
|
|
||||||
class Cons<T>(val head: T, val tail: Cons<T>?)
|
class Cons<T>(val head: T, val tail: Cons<T>?)
|
||||||
|
|||||||
+1
-1
@@ -5,4 +5,4 @@ class Cons<T : Number>(val head: T, val tail: Cons<T>?)
|
|||||||
typealias C<T> = Cons<T>
|
typealias C<T> = Cons<T>
|
||||||
|
|
||||||
val test1 = C(1, C(2, null))
|
val test1 = C(1, C(2, null))
|
||||||
val test2 = C(1, C("", null))
|
val test2 = <!UPPER_BOUND_VIOLATED!>C(1, <!UPPER_BOUND_VIOLATED!>C("", null)<!>)<!>
|
||||||
|
|||||||
Vendored
+3
-3
@@ -29,9 +29,9 @@ val test3pr = <!INAPPLICABLE_CANDIDATE!>P2<!><String, Int, Int>(1, "")
|
|||||||
class Num<T : Number>(val x: T)
|
class Num<T : Number>(val x: T)
|
||||||
typealias N<T> = Num<T>
|
typealias N<T> = Num<T>
|
||||||
|
|
||||||
val testN0 = N("")
|
val testN0 = <!UPPER_BOUND_VIOLATED!>N("")<!>
|
||||||
val testN1 = N<Int>(1)
|
val testN1 = N<Int>(1)
|
||||||
val testN1a = N<String>("")
|
val testN1a = <!UPPER_BOUND_VIOLATED!>N<String>("")<!>
|
||||||
val testN2 = <!INAPPLICABLE_CANDIDATE!>N<!><Int, Int>(1)
|
val testN2 = <!INAPPLICABLE_CANDIDATE!>N<!><Int, Int>(1)
|
||||||
|
|
||||||
class MyPair<T1 : CharSequence, T2 : Number>(val string: T1, val number: T2)
|
class MyPair<T1 : CharSequence, T2 : Number>(val string: T1, val number: T2)
|
||||||
@@ -39,4 +39,4 @@ typealias MP<T1> = MyPair<String, T1>
|
|||||||
|
|
||||||
val testMP0 = MP<Int>("", 1)
|
val testMP0 = MP<Int>("", 1)
|
||||||
val testMP1 = <!INAPPLICABLE_CANDIDATE!>MP<!>(1, "")
|
val testMP1 = <!INAPPLICABLE_CANDIDATE!>MP<!>(1, "")
|
||||||
val testMP2 = MP<String>("", "")
|
val testMP2 = <!UPPER_BOUND_VIOLATED!>MP<String>("", "")<!>
|
||||||
Reference in New Issue
Block a user