K1: implement warning for upper bound violated in type alias constructors
Partially implements KT-47473
This commit is contained in:
+6
@@ -39187,6 +39187,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
|
|||||||
public void testUpperBoundViolated() throws Exception {
|
public void testUpperBoundViolated() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/typealias/upperBoundViolated.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/typealias/upperBoundViolated.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("upperBoundViolated2.kt")
|
||||||
|
public void testUpperBoundViolated2() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/typealias/upperBoundViolated2.kt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
|
|||||||
+6
@@ -39251,6 +39251,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
|||||||
public void testUpperBoundViolated() throws Exception {
|
public void testUpperBoundViolated() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/typealias/upperBoundViolated.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/typealias/upperBoundViolated.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("upperBoundViolated2.kt")
|
||||||
|
public void testUpperBoundViolated2() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/typealias/upperBoundViolated2.kt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
|
|||||||
+6
@@ -39251,6 +39251,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
|||||||
public void testUpperBoundViolated() throws Exception {
|
public void testUpperBoundViolated() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/typealias/upperBoundViolated.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/typealias/upperBoundViolated.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("upperBoundViolated2.kt")
|
||||||
|
public void testUpperBoundViolated2() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/typealias/upperBoundViolated2.kt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
|
|||||||
+53
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2022 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.resolve.jvm.checkers
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
|
||||||
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
|
import org.jetbrains.kotlin.psi.KtCallExpression
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutorByConstructorMap
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
|
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||||
|
import org.jetbrains.kotlin.types.checker.ClassicTypeCheckerState
|
||||||
|
import org.jetbrains.kotlin.types.checker.ClassicTypeCheckerStateInternals
|
||||||
|
|
||||||
|
object UpperBoundViolatedInTypealiasConstructorChecker : CallChecker {
|
||||||
|
@OptIn(ClassicTypeCheckerStateInternals::class)
|
||||||
|
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
|
||||||
|
val resultingDescriptor = resolvedCall.resultingDescriptor as? TypeAliasConstructorDescriptor ?: return
|
||||||
|
val callExpression = reportOn.getStrictParentOfType<KtCallExpression>() ?: return
|
||||||
|
val underlyingConstructedType = resultingDescriptor.underlyingConstructorDescriptor.returnType
|
||||||
|
val underlyingTypeArguments = underlyingConstructedType.arguments
|
||||||
|
val underlyingTypeParameters = resultingDescriptor.underlyingConstructorDescriptor.returnType.constructor.parameters
|
||||||
|
val state = ClassicTypeCheckerState(isErrorTypeEqualsToAnything = false)
|
||||||
|
val substitutor = NewTypeSubstitutorByConstructorMap(
|
||||||
|
underlyingTypeParameters.withIndex().associate {
|
||||||
|
Pair(it.value.typeConstructor, underlyingTypeArguments[it.index].type.unwrap())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
// Note: necessary only for diagnostic duplication check
|
||||||
|
val aliasTypeParameters = resolvedCall.candidateDescriptor.typeParameters
|
||||||
|
val originalTypes = resultingDescriptor.typeAliasDescriptor.underlyingType.arguments.map { it.type }
|
||||||
|
for ((index, argumentAndParameter) in underlyingTypeArguments.zip(underlyingTypeParameters).withIndex()) {
|
||||||
|
val (argument, parameter) = argumentAndParameter
|
||||||
|
// To remove duplication of UPPER_BOUND_VIOLATED
|
||||||
|
// See createToFreshVariableSubstitutorAndAddInitialConstraints in ResolutionParts.kt, citing:
|
||||||
|
// ... if (kotlinType == typeParameter.defaultType) i else null ...
|
||||||
|
if (aliasTypeParameters.getOrNull(index)?.defaultType == originalTypes.getOrNull(index)) continue
|
||||||
|
|
||||||
|
for (upperBound in parameter.upperBounds) {
|
||||||
|
if (!AbstractTypeChecker.isSubtypeOf(state, argument.type, substitutor.safeSubstitute(upperBound.unwrap()))) {
|
||||||
|
val typeReference = callExpression.typeArguments.getOrNull(index)?.typeReference ?: continue
|
||||||
|
context.trace.report(Errors.UPPER_BOUND_VIOLATED_WARNING.on(typeReference, upperBound, argument.type))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
@@ -61,6 +61,7 @@ object JvmPlatformConfigurator : PlatformConfiguratorBase(
|
|||||||
PolymorphicSignatureCallChecker,
|
PolymorphicSignatureCallChecker,
|
||||||
SamInterfaceConstructorReferenceCallChecker,
|
SamInterfaceConstructorReferenceCallChecker,
|
||||||
EnumDeclaringClassDeprecationChecker,
|
EnumDeclaringClassDeprecationChecker,
|
||||||
|
UpperBoundViolatedInTypealiasConstructorChecker,
|
||||||
),
|
),
|
||||||
|
|
||||||
additionalTypeCheckers = listOf(
|
additionalTypeCheckers = listOf(
|
||||||
|
|||||||
+1
-1
@@ -594,7 +594,7 @@ public class DefaultErrorMessages {
|
|||||||
});
|
});
|
||||||
|
|
||||||
MAP.put(UPPER_BOUND_VIOLATED, "Type argument is not within its bounds: should be subtype of ''{0}''", RENDER_TYPE, RENDER_TYPE);
|
MAP.put(UPPER_BOUND_VIOLATED, "Type argument is not within its bounds: should be subtype of ''{0}''", RENDER_TYPE, RENDER_TYPE);
|
||||||
MAP.put(UPPER_BOUND_VIOLATED_WARNING, "Type argument is not within its bounds: should be subtype of ''{0}''", RENDER_TYPE, RENDER_TYPE);
|
MAP.put(UPPER_BOUND_VIOLATED_WARNING, "Type argument is not within its bounds: ''{1}'' should be subtype of ''{0}''. This warning will become an error in K2", RENDER_TYPE, RENDER_TYPE);
|
||||||
MAP.put(FINAL_UPPER_BOUND, "''{0}'' is a final type, and thus a value of the type parameter is predetermined", RENDER_TYPE);
|
MAP.put(FINAL_UPPER_BOUND, "''{0}'' is a final type, and thus a value of the type parameter is predetermined", RENDER_TYPE);
|
||||||
MAP.put(UPPER_BOUND_IS_EXTENSION_FUNCTION_TYPE, "Extension function type can not be used as an upper bound");
|
MAP.put(UPPER_BOUND_IS_EXTENSION_FUNCTION_TYPE, "Extension function type can not be used as an upper bound");
|
||||||
MAP.put(ONLY_ONE_CLASS_BOUND_ALLOWED, "Only one of the upper bounds can be a class");
|
MAP.put(ONLY_ONE_CLASS_BOUND_ALLOWED, "Only one of the upper bounds can be a class");
|
||||||
|
|||||||
+1
-1
@@ -18,7 +18,7 @@ val test5 = NA<Int>()
|
|||||||
val test6 = NA<<!UPPER_BOUND_VIOLATED!>Any<!>>()
|
val test6 = NA<<!UPPER_BOUND_VIOLATED!>Any<!>>()
|
||||||
val test7 = NL<Int>()
|
val test7 = NL<Int>()
|
||||||
val test8 = MMMM<<!UPPER_BOUND_VIOLATED!>Int<!>>()
|
val test8 = MMMM<<!UPPER_BOUND_VIOLATED!>Int<!>>()
|
||||||
val test9dwd = NL<Any>()
|
val test9dwd = NL<<!UPPER_BOUND_VIOLATED_WARNING!>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>>) {}
|
||||||
|
|||||||
+1
-1
@@ -31,7 +31,7 @@ fun main1(x: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>A<Int?><!>) {}
|
|||||||
fun main2(x: A2<Int?>) {}
|
fun main2(x: A2<Int?>) {}
|
||||||
fun main3(x: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>A3<Int?><!>) {}
|
fun main3(x: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>A3<Int?><!>) {}
|
||||||
fun main3() {
|
fun main3() {
|
||||||
val x = <!UPPER_BOUND_VIOLATED!>A3<Int?>()<!> // TODO: support reporting errors on typealias constructor calls
|
val x = <!UPPER_BOUND_VIOLATED!>A3<Int?>()<!>
|
||||||
val x2 = <!UPPER_BOUND_VIOLATED!>A<Int?>()<!>
|
val x2 = <!UPPER_BOUND_VIOLATED!>A<Int?>()<!>
|
||||||
val y: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>A3<Int?><!> = <!UPPER_BOUND_VIOLATED!>A3<Int?>()<!>
|
val y: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>A3<Int?><!> = <!UPPER_BOUND_VIOLATED!>A3<Int?>()<!>
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -31,7 +31,7 @@ fun main1(x: A<<!UPPER_BOUND_VIOLATED!>Int?<!>>) {}
|
|||||||
fun main2(x: A2<<!UPPER_BOUND_VIOLATED!>Int?<!>>) {}
|
fun main2(x: A2<<!UPPER_BOUND_VIOLATED!>Int?<!>>) {}
|
||||||
fun main3(x: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>A3<Int?><!>) {}
|
fun main3(x: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>A3<Int?><!>) {}
|
||||||
fun main3() {
|
fun main3() {
|
||||||
val x = A3<Int?>() // TODO: support reporting errors on typealias constructor calls
|
val x = A3<<!UPPER_BOUND_VIOLATED_WARNING!>Int?<!>>()
|
||||||
val x2 = A<<!UPPER_BOUND_VIOLATED!>Int?<!>>()
|
val x2 = A<<!UPPER_BOUND_VIOLATED!>Int?<!>>()
|
||||||
val y: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>A3<Int?><!> = A3<Int?>()
|
val y: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>A3<Int?><!> = A3<<!UPPER_BOUND_VIOLATED_WARNING!>Int?<!>>()
|
||||||
}
|
}
|
||||||
|
|||||||
-4
@@ -4,7 +4,3 @@ typealias AliasOfNumList<A3> = NumList<A3>
|
|||||||
|
|
||||||
val falseUpperBoundViolation = AliasOfNumList<Int>() // Shouldn't be error
|
val falseUpperBoundViolation = AliasOfNumList<Int>() // Shouldn't be error
|
||||||
val missedUpperBoundViolation = <!UPPER_BOUND_VIOLATED!>NumList<Any>()<!> // Should be error
|
val missedUpperBoundViolation = <!UPPER_BOUND_VIOLATED!>NumList<Any>()<!> // Should be error
|
||||||
|
|
||||||
class Base<T : List<CharSequence>>
|
|
||||||
typealias Alias<T> = Base<List<T>>
|
|
||||||
val a = <!UPPER_BOUND_VIOLATED!>Alias<Any>()<!> // Also should be error
|
|
||||||
|
|||||||
+2
-6
@@ -2,9 +2,5 @@ class NumColl<T : Collection<Number>>
|
|||||||
typealias NumList<T2> = NumColl<List<T2>>
|
typealias NumList<T2> = NumColl<List<T2>>
|
||||||
typealias AliasOfNumList<A3> = NumList<A3>
|
typealias AliasOfNumList<A3> = NumList<A3>
|
||||||
|
|
||||||
val falseUpperBoundViolation = AliasOfNumList<<!UPPER_BOUND_VIOLATED!>Int<!>>() // Shouldn't be error
|
val falseUpperBoundViolation = AliasOfNumList<<!UPPER_BOUND_VIOLATED("Collection<Number>; Int")!>Int<!>>() // Shouldn't be error
|
||||||
val missedUpperBoundViolation = NumList<Any>() // Should be error
|
val missedUpperBoundViolation = NumList<<!UPPER_BOUND_VIOLATED_WARNING("Collection<Number>; List<Any>")!>Any<!>>() // Should be error
|
||||||
|
|
||||||
class Base<T : List<CharSequence>>
|
|
||||||
typealias Alias<T> = Base<List<T>>
|
|
||||||
val a = Alias<Any>() // Also should be error
|
|
||||||
|
|||||||
+1
-9
@@ -1,22 +1,14 @@
|
|||||||
package
|
package
|
||||||
|
|
||||||
public val a: Alias<kotlin.Any> /* = Base<kotlin.collections.List<kotlin.Any>> */
|
|
||||||
public val falseUpperBoundViolation: AliasOfNumList<kotlin.Int> /* = NumColl<kotlin.collections.List<kotlin.Int>> */
|
public val falseUpperBoundViolation: AliasOfNumList<kotlin.Int> /* = NumColl<kotlin.collections.List<kotlin.Int>> */
|
||||||
public val missedUpperBoundViolation: NumList<kotlin.Any> /* = NumColl<kotlin.collections.List<kotlin.Any>> */
|
public val missedUpperBoundViolation: NumList<kotlin.Any> /* = NumColl<kotlin.collections.List<kotlin.Any>> */
|
||||||
|
|
||||||
public final class Base</*0*/ T : kotlin.collections.List<kotlin.CharSequence>> {
|
|
||||||
public constructor Base</*0*/ T : kotlin.collections.List<kotlin.CharSequence>>()
|
|
||||||
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 class NumColl</*0*/ T : kotlin.collections.Collection<kotlin.Number>> {
|
public final class NumColl</*0*/ T : kotlin.collections.Collection<kotlin.Number>> {
|
||||||
public constructor NumColl</*0*/ T : kotlin.collections.Collection<kotlin.Number>>()
|
public constructor NumColl</*0*/ T : kotlin.collections.Collection<kotlin.Number>>()
|
||||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
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 hashCode(): kotlin.Int
|
||||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
}
|
}
|
||||||
public typealias Alias</*0*/ T> = Base<kotlin.collections.List<T>>
|
|
||||||
public typealias AliasOfNumList</*0*/ A3> = NumList<A3>
|
public typealias AliasOfNumList</*0*/ A3> = NumList<A3>
|
||||||
public typealias NumList</*0*/ T2> = NumColl<kotlin.collections.List<T2>>
|
public typealias NumList</*0*/ T2> = NumColl<kotlin.collections.List<T2>>
|
||||||
|
|
||||||
|
|||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
/upperBoundViolated2.kt:4:15: warning: type argument is not within its bounds: 'List<Any>' should be subtype of 'List<CharSequence>'. This warning will become an error in K2
|
||||||
|
val a = Alias<Any>() // Also should be error
|
||||||
|
^
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
// !RENDER_DIAGNOSTICS_FULL_TEXT
|
||||||
|
class Base<T : List<CharSequence>>
|
||||||
|
typealias Alias<T> = Base<List<T>>
|
||||||
|
val a = <!UPPER_BOUND_VIOLATED!>Alias<Any>()<!> // Also should be error
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
// !RENDER_DIAGNOSTICS_FULL_TEXT
|
||||||
|
class Base<T : List<CharSequence>>
|
||||||
|
typealias Alias<T> = Base<List<T>>
|
||||||
|
val a = Alias<<!UPPER_BOUND_VIOLATED_WARNING("List<CharSequence>; List<Any>")!>Any<!>>() // Also should be error
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public val a: Alias<kotlin.Any> /* = Base<kotlin.collections.List<kotlin.Any>> */
|
||||||
|
|
||||||
|
public final class Base</*0*/ T : kotlin.collections.List<kotlin.CharSequence>> {
|
||||||
|
public constructor Base</*0*/ T : kotlin.collections.List<kotlin.CharSequence>>()
|
||||||
|
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 typealias Alias</*0*/ T> = Base<kotlin.collections.List<T>>
|
||||||
Generated
+6
@@ -39341,6 +39341,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
|||||||
public void testUpperBoundViolated() throws Exception {
|
public void testUpperBoundViolated() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/typealias/upperBoundViolated.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/typealias/upperBoundViolated.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("upperBoundViolated2.kt")
|
||||||
|
public void testUpperBoundViolated2() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/typealias/upperBoundViolated2.kt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
|
|||||||
Reference in New Issue
Block a user