Report warnings or errors for violated type parameter's upper bounds from Java annotated with nullability annotations
^KT-43262 Fixed
This commit is contained in:
+6
@@ -34327,6 +34327,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
|||||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/testsWithStdLib/java"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/testsWithStdLib/java"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("checkEnhancedUpperBounds.kt")
|
||||||
|
public void testCheckEnhancedUpperBounds() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/java/checkEnhancedUpperBounds.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("concurrentHashMapContains.kt")
|
@TestMetadata("concurrentHashMapContains.kt")
|
||||||
public void testConcurrentHashMapContains() throws Exception {
|
public void testConcurrentHashMapContains() throws Exception {
|
||||||
|
|||||||
+46
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* 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.resolve.jvm.checkers
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
|
import org.jetbrains.kotlin.psi.KtTypeReference
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||||
|
import org.jetbrains.kotlin.resolve.UpperBoundChecker
|
||||||
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
|
||||||
|
import org.jetbrains.kotlin.types.*
|
||||||
|
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||||
|
|
||||||
|
class EnhancedUpperBoundChecker(override val languageVersionSettings: LanguageVersionSettings) : UpperBoundChecker {
|
||||||
|
override fun checkBound(
|
||||||
|
bound: KotlinType,
|
||||||
|
substitutor: TypeSubstitutor,
|
||||||
|
trace: BindingTrace,
|
||||||
|
jetTypeArgument: KtTypeReference,
|
||||||
|
typeArgument: KotlinType
|
||||||
|
): Boolean {
|
||||||
|
val isCheckPassed = super.checkBound(bound, substitutor, trace, jetTypeArgument, typeArgument)
|
||||||
|
|
||||||
|
// The error is already reported, it's unnecessary to do more checks
|
||||||
|
if (!isCheckPassed) return false
|
||||||
|
|
||||||
|
val enhancedBound = bound.getEnhancement() ?: return false
|
||||||
|
|
||||||
|
val isTypeEnhancementImprovementsEnabled =
|
||||||
|
languageVersionSettings.supportsFeature(LanguageFeature.ImprovementsAroundTypeEnhancement)
|
||||||
|
val substitutedBound = substitutor.safeSubstitute(enhancedBound, Variance.INVARIANT)
|
||||||
|
if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(typeArgument, substitutedBound)) {
|
||||||
|
if (isTypeEnhancementImprovementsEnabled) {
|
||||||
|
trace.report(Errors.UPPER_BOUND_VIOLATED.on(jetTypeArgument, substitutedBound, typeArgument))
|
||||||
|
} else {
|
||||||
|
trace.report(ErrorsJvm.UPPER_BOUND_VIOLATED_BASED_ON_JAVA_ANNOTATIONS.on(jetTypeArgument, substitutedBound, typeArgument))
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
@@ -85,6 +85,7 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension {
|
|||||||
MAP.put(SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC, "Using non-JVM static members protected in the superclass companion is unsupported yet");
|
MAP.put(SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC, "Using non-JVM static members protected in the superclass companion is unsupported yet");
|
||||||
|
|
||||||
MAP.put(NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS, "Type mismatch: inferred type is {1} but {0} was expected", RENDER_TYPE, RENDER_TYPE);
|
MAP.put(NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS, "Type mismatch: inferred type is {1} but {0} was expected", RENDER_TYPE, RENDER_TYPE);
|
||||||
|
MAP.put(UPPER_BOUND_VIOLATED_BASED_ON_JAVA_ANNOTATIONS, "Type argument is not within its bounds: should be subtype of ''{0}''", RENDER_TYPE, RENDER_TYPE);
|
||||||
MAP.put(NULLABLE_TYPE_PARAMETER_AGAINST_NOT_NULL_TYPE_PARAMETER,
|
MAP.put(NULLABLE_TYPE_PARAMETER_AGAINST_NOT_NULL_TYPE_PARAMETER,
|
||||||
"Type mismatch: value of a nullable type {0} is used where non-nullable type is expected. " +
|
"Type mismatch: value of a nullable type {0} is used where non-nullable type is expected. " +
|
||||||
"This warning will become an error soon. " +
|
"This warning will become an error soon. " +
|
||||||
|
|||||||
@@ -137,6 +137,9 @@ public interface ErrorsJvm {
|
|||||||
DiagnosticFactory2<KtElement, KotlinType, KotlinType> NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS
|
DiagnosticFactory2<KtElement, KotlinType, KotlinType> NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS
|
||||||
= DiagnosticFactory2.create(WARNING);
|
= DiagnosticFactory2.create(WARNING);
|
||||||
|
|
||||||
|
DiagnosticFactory2<KtTypeReference, KotlinType, KotlinType> UPPER_BOUND_VIOLATED_BASED_ON_JAVA_ANNOTATIONS
|
||||||
|
= DiagnosticFactory2.create(WARNING);
|
||||||
|
|
||||||
DiagnosticFactory1<KtElement, KotlinType> NULLABLE_TYPE_PARAMETER_AGAINST_NOT_NULL_TYPE_PARAMETER
|
DiagnosticFactory1<KtElement, KotlinType> NULLABLE_TYPE_PARAMETER_AGAINST_NOT_NULL_TYPE_PARAMETER
|
||||||
= DiagnosticFactory1.create(WARNING);
|
= DiagnosticFactory1.create(WARNING);
|
||||||
|
|
||||||
|
|||||||
+1
@@ -97,6 +97,7 @@ object JvmPlatformConfigurator : PlatformConfiguratorBase(
|
|||||||
) {
|
) {
|
||||||
override fun configureModuleComponents(container: StorageComponentContainer) {
|
override fun configureModuleComponents(container: StorageComponentContainer) {
|
||||||
container.useImpl<JvmStaticChecker>()
|
container.useImpl<JvmStaticChecker>()
|
||||||
|
container.useImpl<EnhancedUpperBoundChecker>()
|
||||||
container.useImpl<JvmReflectionAPICallChecker>()
|
container.useImpl<JvmReflectionAPICallChecker>()
|
||||||
container.useImpl<JavaSyntheticScopes>()
|
container.useImpl<JavaSyntheticScopes>()
|
||||||
container.useImpl<SamConversionResolverImpl>()
|
container.useImpl<SamConversionResolverImpl>()
|
||||||
|
|||||||
@@ -56,11 +56,12 @@ internal class DeclarationsCheckerBuilder(
|
|||||||
private val identifierChecker: IdentifierChecker,
|
private val identifierChecker: IdentifierChecker,
|
||||||
private val languageVersionSettings: LanguageVersionSettings,
|
private val languageVersionSettings: LanguageVersionSettings,
|
||||||
private val typeSpecificityComparator: TypeSpecificityComparator,
|
private val typeSpecificityComparator: TypeSpecificityComparator,
|
||||||
private val diagnosticSuppressor: PlatformDiagnosticSuppressor
|
private val diagnosticSuppressor: PlatformDiagnosticSuppressor,
|
||||||
|
private val upperBoundChecker: UpperBoundChecker
|
||||||
) {
|
) {
|
||||||
fun withTrace(trace: BindingTrace) = DeclarationsChecker(
|
fun withTrace(trace: BindingTrace) = DeclarationsChecker(
|
||||||
descriptorResolver, originalModifiersChecker, annotationChecker, identifierChecker, trace, languageVersionSettings,
|
descriptorResolver, originalModifiersChecker, annotationChecker, identifierChecker, trace, languageVersionSettings,
|
||||||
typeSpecificityComparator, diagnosticSuppressor
|
typeSpecificityComparator, diagnosticSuppressor, upperBoundChecker
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,7 +73,8 @@ class DeclarationsChecker(
|
|||||||
private val trace: BindingTrace,
|
private val trace: BindingTrace,
|
||||||
private val languageVersionSettings: LanguageVersionSettings,
|
private val languageVersionSettings: LanguageVersionSettings,
|
||||||
typeSpecificityComparator: TypeSpecificityComparator,
|
typeSpecificityComparator: TypeSpecificityComparator,
|
||||||
private val diagnosticSuppressor: PlatformDiagnosticSuppressor
|
private val diagnosticSuppressor: PlatformDiagnosticSuppressor,
|
||||||
|
private val upperBoundChecker: UpperBoundChecker
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val modifiersChecker = modifiersChecker.withTrace(trace)
|
private val modifiersChecker = modifiersChecker.withTrace(trace)
|
||||||
@@ -360,7 +362,7 @@ class DeclarationsChecker(
|
|||||||
|
|
||||||
for (delegationSpecifier in classOrObject.superTypeListEntries) {
|
for (delegationSpecifier in classOrObject.superTypeListEntries) {
|
||||||
val typeReference = delegationSpecifier.typeReference ?: continue
|
val typeReference = delegationSpecifier.typeReference ?: continue
|
||||||
typeReference.type()?.let { DescriptorResolver.checkBounds(typeReference, it, trace) }
|
typeReference.type()?.let { upperBoundChecker.checkBounds(typeReference, it, trace) }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (classOrObject !is KtClass) return
|
if (classOrObject !is KtClass) return
|
||||||
@@ -383,7 +385,7 @@ class DeclarationsChecker(
|
|||||||
DescriptorResolver.checkUpperBoundTypes(trace, upperBoundCheckRequests, false)
|
DescriptorResolver.checkUpperBoundTypes(trace, upperBoundCheckRequests, false)
|
||||||
|
|
||||||
for (request in upperBoundCheckRequests) {
|
for (request in upperBoundCheckRequests) {
|
||||||
DescriptorResolver.checkBounds(request.upperBound, request.upperBoundType, trace)
|
upperBoundChecker.checkBounds(request.upperBound, request.upperBoundType, trace)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1312,61 +1312,6 @@ public class DescriptorResolver {
|
|||||||
return propertyDescriptor;
|
return propertyDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void checkBounds(@NotNull KtTypeReference typeReference, @NotNull KotlinType type, @NotNull BindingTrace trace) {
|
|
||||||
if (KotlinTypeKt.isError(type)) return;
|
|
||||||
|
|
||||||
KtTypeElement typeElement = typeReference.getTypeElement();
|
|
||||||
if (typeElement == null) return;
|
|
||||||
|
|
||||||
List<TypeParameterDescriptor> parameters = type.getConstructor().getParameters();
|
|
||||||
List<TypeProjection> arguments = type.getArguments();
|
|
||||||
assert parameters.size() == arguments.size();
|
|
||||||
|
|
||||||
List<KtTypeReference> ktTypeArguments = typeElement.getTypeArgumentsAsTypes();
|
|
||||||
|
|
||||||
// A type reference from Kotlin code can yield a flexible type only if it's `ft<T1, T2>`, whose bounds should not be checked
|
|
||||||
if (FlexibleTypesKt.isFlexible(type) && !DynamicTypesKt.isDynamic(type)) {
|
|
||||||
assert ktTypeArguments.size() == 2
|
|
||||||
: "Flexible type cannot be denoted in Kotlin otherwise than as ft<T1, T2>, but was: "
|
|
||||||
+ PsiUtilsKt.getElementTextWithContext(typeReference);
|
|
||||||
// it's really ft<Foo, Bar>
|
|
||||||
FlexibleType flexibleType = FlexibleTypesKt.asFlexibleType(type);
|
|
||||||
checkBounds(ktTypeArguments.get(0), flexibleType.getLowerBound(), trace);
|
|
||||||
checkBounds(ktTypeArguments.get(1), flexibleType.getUpperBound(), trace);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the numbers of type arguments do not match, the error has been already reported in TypeResolver
|
|
||||||
if (ktTypeArguments.size() != arguments.size()) return;
|
|
||||||
|
|
||||||
TypeSubstitutor substitutor = TypeSubstitutor.create(type);
|
|
||||||
for (int i = 0; i < ktTypeArguments.size(); i++) {
|
|
||||||
KtTypeReference ktTypeArgument = ktTypeArguments.get(i);
|
|
||||||
if (ktTypeArgument == null) continue;
|
|
||||||
|
|
||||||
KotlinType typeArgument = arguments.get(i).getType();
|
|
||||||
checkBounds(ktTypeArgument, typeArgument, trace);
|
|
||||||
|
|
||||||
TypeParameterDescriptor typeParameterDescriptor = parameters.get(i);
|
|
||||||
checkBounds(ktTypeArgument, typeArgument, typeParameterDescriptor, substitutor, trace);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void checkBounds(
|
|
||||||
@NotNull KtTypeReference jetTypeArgument,
|
|
||||||
@NotNull KotlinType typeArgument,
|
|
||||||
@NotNull TypeParameterDescriptor typeParameterDescriptor,
|
|
||||||
@NotNull TypeSubstitutor substitutor,
|
|
||||||
@NotNull BindingTrace trace
|
|
||||||
) {
|
|
||||||
for (KotlinType bound : typeParameterDescriptor.getUpperBounds()) {
|
|
||||||
KotlinType substitutedBound = substitutor.safeSubstitute(bound, Variance.INVARIANT);
|
|
||||||
if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(typeArgument, substitutedBound)) {
|
|
||||||
trace.report(UPPER_BOUND_VIOLATED.on(jetTypeArgument, substitutedBound, typeArgument));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean checkHasOuterClassInstance(
|
public static boolean checkHasOuterClassInstance(
|
||||||
@NotNull LexicalScope scope,
|
@NotNull LexicalScope scope,
|
||||||
@NotNull BindingTrace trace,
|
@NotNull BindingTrace trace,
|
||||||
|
|||||||
@@ -70,7 +70,8 @@ class TypeResolver(
|
|||||||
private val dynamicCallableDescriptors: DynamicCallableDescriptors,
|
private val dynamicCallableDescriptors: DynamicCallableDescriptors,
|
||||||
private val identifierChecker: IdentifierChecker,
|
private val identifierChecker: IdentifierChecker,
|
||||||
private val platformToKotlinClassMapper: PlatformToKotlinClassMapper,
|
private val platformToKotlinClassMapper: PlatformToKotlinClassMapper,
|
||||||
private val languageVersionSettings: LanguageVersionSettings
|
private val languageVersionSettings: LanguageVersionSettings,
|
||||||
|
private val upperBoundChecker: UpperBoundChecker
|
||||||
) {
|
) {
|
||||||
private val isNonParenthesizedAnnotationsOnFunctionalTypesEnabled =
|
private val isNonParenthesizedAnnotationsOnFunctionalTypesEnabled =
|
||||||
languageVersionSettings.getFeatureSupport(LanguageFeature.NonParenthesizedAnnotationsOnFunctionalTypes) == LanguageFeature.State.ENABLED
|
languageVersionSettings.getFeatureSupport(LanguageFeature.NonParenthesizedAnnotationsOnFunctionalTypes) == LanguageFeature.State.ENABLED
|
||||||
@@ -524,7 +525,7 @@ class TypeResolver(
|
|||||||
val typeReference = collectedArgumentAsTypeProjections.getOrNull(i)?.typeReference
|
val typeReference = collectedArgumentAsTypeProjections.getOrNull(i)?.typeReference
|
||||||
|
|
||||||
if (typeReference != null) {
|
if (typeReference != null) {
|
||||||
DescriptorResolver.checkBounds(typeReference, argument, parameter, substitutor, c.trace)
|
upperBoundChecker.checkBounds(typeReference, argument, parameter, substitutor, c.trace)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* 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.resolve
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
|
import org.jetbrains.kotlin.container.DefaultImplementation
|
||||||
|
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||||
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
|
import org.jetbrains.kotlin.psi.KtTypeReference
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
|
||||||
|
import org.jetbrains.kotlin.types.*
|
||||||
|
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||||
|
|
||||||
|
@DefaultImplementation(impl = UpperBoundChecker::class)
|
||||||
|
interface UpperBoundChecker {
|
||||||
|
val languageVersionSettings: LanguageVersionSettings
|
||||||
|
|
||||||
|
fun checkBounds(typeReference: KtTypeReference, type: KotlinType, trace: BindingTrace) {
|
||||||
|
if (type.isError) return
|
||||||
|
|
||||||
|
val typeElement = typeReference.typeElement ?: return
|
||||||
|
val parameters = type.constructor.parameters
|
||||||
|
val arguments = type.arguments
|
||||||
|
|
||||||
|
assert(parameters.size == arguments.size)
|
||||||
|
|
||||||
|
val ktTypeArguments = typeElement.typeArgumentsAsTypes
|
||||||
|
|
||||||
|
// A type reference from Kotlin code can yield a flexible type only if it's `ft<T1, T2>`, whose bounds should not be checked
|
||||||
|
if (type.isFlexible() && !type.isDynamic()) {
|
||||||
|
assert(ktTypeArguments.size == 2) {
|
||||||
|
("Flexible type cannot be denoted in Kotlin otherwise than as ft<T1, T2>, but was: "
|
||||||
|
+ typeReference.getElementTextWithContext())
|
||||||
|
}
|
||||||
|
// it's really ft<Foo, Bar>
|
||||||
|
val flexibleType = type.asFlexibleType()
|
||||||
|
checkBounds(ktTypeArguments[0], flexibleType.lowerBound, trace)
|
||||||
|
checkBounds(ktTypeArguments[1], flexibleType.upperBound, trace)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the numbers of type arguments do not match, the error has been already reported in TypeResolver
|
||||||
|
if (ktTypeArguments.size != arguments.size) return
|
||||||
|
|
||||||
|
val substitutor = TypeSubstitutor.create(type)
|
||||||
|
|
||||||
|
for (i in ktTypeArguments.indices) {
|
||||||
|
val ktTypeArgument = ktTypeArguments[i] ?: continue
|
||||||
|
checkBounds(ktTypeArgument, arguments[i].type, trace)
|
||||||
|
checkBounds(ktTypeArgument, arguments[i].type, parameters[i], substitutor, trace)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun checkBounds(
|
||||||
|
jetTypeArgument: KtTypeReference,
|
||||||
|
typeArgument: KotlinType,
|
||||||
|
typeParameterDescriptor: TypeParameterDescriptor,
|
||||||
|
substitutor: TypeSubstitutor,
|
||||||
|
trace: BindingTrace
|
||||||
|
) {
|
||||||
|
for (bound in typeParameterDescriptor.upperBounds) {
|
||||||
|
checkBound(bound, substitutor, trace, jetTypeArgument, typeArgument)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun checkBound(
|
||||||
|
bound: KotlinType,
|
||||||
|
substitutor: TypeSubstitutor,
|
||||||
|
trace: BindingTrace,
|
||||||
|
jetTypeArgument: KtTypeReference,
|
||||||
|
typeArgument: KotlinType
|
||||||
|
): Boolean {
|
||||||
|
val substitutedBound = substitutor.safeSubstitute(bound, Variance.INVARIANT)
|
||||||
|
if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(typeArgument, substitutedBound)) {
|
||||||
|
trace.report(Errors.UPPER_BOUND_VIOLATED.on(jetTypeArgument, substitutedBound, typeArgument))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -53,7 +53,8 @@ class CandidateResolver(
|
|||||||
private val reflectionTypes: ReflectionTypes,
|
private val reflectionTypes: ReflectionTypes,
|
||||||
private val additionalTypeCheckers: Iterable<AdditionalTypeChecker>,
|
private val additionalTypeCheckers: Iterable<AdditionalTypeChecker>,
|
||||||
private val smartCastManager: SmartCastManager,
|
private val smartCastManager: SmartCastManager,
|
||||||
private val dataFlowValueFactory: DataFlowValueFactory
|
private val dataFlowValueFactory: DataFlowValueFactory,
|
||||||
|
private val upperBoundChecker: UpperBoundChecker
|
||||||
) {
|
) {
|
||||||
fun <D : CallableDescriptor> performResolutionForCandidateCall(
|
fun <D : CallableDescriptor> performResolutionForCandidateCall(
|
||||||
context: CallCandidateResolutionContext<D>,
|
context: CallCandidateResolutionContext<D>,
|
||||||
@@ -596,7 +597,7 @@ class CandidateResolver(
|
|||||||
val typeArgument = typeArguments[i]
|
val typeArgument = typeArguments[i]
|
||||||
val typeReference = ktTypeArguments[i].typeReference
|
val typeReference = ktTypeArguments[i].typeReference
|
||||||
if (typeReference != null) {
|
if (typeReference != null) {
|
||||||
DescriptorResolver.checkBounds(typeReference, typeArgument, typeParameterDescriptor, substitutor, trace)
|
upperBoundChecker.checkBounds(typeReference, typeArgument, typeParameterDescriptor, substitutor, trace)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
// FULL_JDK
|
||||||
|
|
||||||
|
// FILE: MapLike.java
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public interface MapLike<@org.jetbrains.annotations.NotNull K, V> {
|
||||||
|
void putAll(Map<K, V> map);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: main.kt
|
||||||
|
fun test(map : MapLike<Int?, Int>) {}
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
// !LANGUAGE: +ProhibitUsingNullableTypeParameterAgainstNotNullAnnotated
|
||||||
|
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
|
// FULL_JDK
|
||||||
|
|
||||||
|
// FILE: MapLike.java
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public interface MapLike<@org.jetbrains.annotations.NotNull K, V> {
|
||||||
|
void putAll(Map<K, V> map);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: main.kt
|
||||||
|
fun test0(map : MapLike<<!UPPER_BOUND_VIOLATED_BASED_ON_JAVA_ANNOTATIONS!>Int?<!>, Int>) {}
|
||||||
|
fun <K> test11(map : MapLike<<!UPPER_BOUND_VIOLATED_BASED_ON_JAVA_ANNOTATIONS!>K<!>, K>) {}
|
||||||
|
fun <K> test12(map : MapLike<<!UPPER_BOUND_VIOLATED_BASED_ON_JAVA_ANNOTATIONS!>K?<!>, K>) {}
|
||||||
|
fun <K : Any> test13(map : MapLike<K, K>) {}
|
||||||
|
fun <K : Any> test14(map : MapLike<<!UPPER_BOUND_VIOLATED_BASED_ON_JAVA_ANNOTATIONS!>K?<!>, K>) {}
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun test0(/*0*/ map: MapLike<kotlin.Int?, kotlin.Int>): kotlin.Unit
|
||||||
|
public fun </*0*/ K> test11(/*0*/ map: MapLike<K, K>): kotlin.Unit
|
||||||
|
public fun </*0*/ K> test12(/*0*/ map: MapLike<K?, K>): kotlin.Unit
|
||||||
|
public fun </*0*/ K : kotlin.Any> test13(/*0*/ map: MapLike<K, K>): kotlin.Unit
|
||||||
|
public fun </*0*/ K : kotlin.Any> test14(/*0*/ map: MapLike<K?, K>): kotlin.Unit
|
||||||
|
public fun test2(/*0*/ map: MapLike<kotlin.Int, kotlin.Int>): kotlin.Unit
|
||||||
|
|
||||||
|
public interface MapLike</*0*/ @org.jetbrains.annotations.NotNull K : kotlin.Any!, /*1*/ V : kotlin.Any!> {
|
||||||
|
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 putAll(/*0*/ map: kotlin.collections.(Mutable)Map<K!, V!>!): kotlin.Unit
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
Generated
+6
@@ -34423,6 +34423,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
|||||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/testsWithStdLib/java"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/testsWithStdLib/java"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("checkEnhancedUpperBounds.kt")
|
||||||
|
public void testCheckEnhancedUpperBounds() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/java/checkEnhancedUpperBounds.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("concurrentHashMapContains.kt")
|
@TestMetadata("concurrentHashMapContains.kt")
|
||||||
public void testConcurrentHashMapContains() throws Exception {
|
public void testConcurrentHashMapContains() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user