From f3e0470dcdb8312d6f87aeb8f5744c87d3fcb908 Mon Sep 17 00:00:00 2001 From: Stanislav Erokhin Date: Mon, 20 Aug 2018 11:03:52 +0300 Subject: [PATCH] Allow generic type parameter to have mixed constraints for @InlineOnly functions #KT-19323 Fixed --- .../kotlin/resolve/DeclarationsChecker.kt | 4 ++++ .../kotlin/resolve/calls/CallResolverUtil.kt | 13 ++++++++++++- .../jetbrains/kotlin/types/TypeIntersector.java | 5 ++++- .../upperBounds/typeParameterAsUpperBound.kt | 16 ++++++++++++++++ .../upperBounds/typeParameterAsUpperBound.txt | 5 +++++ .../checkers/DiagnosticsTestGenerated.java | 5 +++++ .../DiagnosticsUsingJavacTestGenerated.java | 5 +++++ 7 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/inference/upperBounds/typeParameterAsUpperBound.kt create mode 100644 compiler/testData/diagnostics/tests/inference/upperBounds/typeParameterAsUpperBound.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt index 36aa0ac2807..46bfa406572 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt @@ -25,6 +25,7 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.descriptors.annotations.isInlineOnly import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0 import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.Errors.* @@ -45,6 +46,7 @@ import org.jetbrains.kotlin.resolve.source.KotlinSourceElement import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.checker.KotlinTypeChecker import org.jetbrains.kotlin.types.typeUtil.* +import org.jetbrains.kotlin.utils.addToStdlib.safeAs import java.util.* internal class DeclarationsCheckerBuilder( @@ -405,6 +407,8 @@ class DeclarationsChecker( declaration } + if (descriptor.containingDeclaration.safeAs()?.isInlineOnly() == true) return + trace.report(BOUNDS_NOT_ALLOWED_IF_BOUNDED_BY_TYPE_PARAMETER.on(reportOn)) } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolverUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolverUtil.kt index 682bcc28ac5..7f5e72c9d1b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolverUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolverUtil.kt @@ -90,11 +90,22 @@ fun CallableDescriptor.hasInferredReturnType(constraintSystem: ConstraintSystem) return true } +private fun filterOutTypeParameters(upperBounds: List, candidateDescriptor: CallableDescriptor): List { + if (upperBounds.size < 2) return upperBounds + val result = upperBounds.filterNot { + val declarationDescriptor = it.constructor.declarationDescriptor + declarationDescriptor is TypeParameterDescriptor && declarationDescriptor.containingDeclaration == candidateDescriptor + } + if (result.isEmpty()) return upperBounds + return result +} + fun getErasedReceiverType(receiverParameterDescriptor: ReceiverParameterDescriptor, descriptor: CallableDescriptor): KotlinType { var receiverType = receiverParameterDescriptor.type for (typeParameter in descriptor.typeParameters) { if (typeParameter.typeConstructor == receiverType.constructor) { - receiverType = TypeIntersector.getUpperBoundsAsType(typeParameter) + val properUpperBounds = filterOutTypeParameters(typeParameter.upperBounds, descriptor) + receiverType = TypeIntersector.intersectUpperBounds(typeParameter, properUpperBounds) } } val fakeTypeArguments = ContainerUtil.newSmartList() diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/TypeIntersector.java b/compiler/frontend/src/org/jetbrains/kotlin/types/TypeIntersector.java index 1690cb4d125..18616c7901d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/TypeIntersector.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/TypeIntersector.java @@ -150,7 +150,10 @@ public class TypeIntersector { */ @NotNull public static KotlinType getUpperBoundsAsType(@NotNull TypeParameterDescriptor descriptor) { - List upperBounds = descriptor.getUpperBounds(); + return intersectUpperBounds(descriptor, descriptor.getUpperBounds()); + } + + public static KotlinType intersectUpperBounds(@NotNull TypeParameterDescriptor descriptor, @NotNull List upperBounds) { assert !upperBounds.isEmpty() : "Upper bound list is empty: " + descriptor; KotlinType upperBoundsAsType = intersectTypes(upperBounds); return upperBoundsAsType != null ? upperBoundsAsType : getBuiltIns(descriptor).getNothingType(); diff --git a/compiler/testData/diagnostics/tests/inference/upperBounds/typeParameterAsUpperBound.kt b/compiler/testData/diagnostics/tests/inference/upperBounds/typeParameterAsUpperBound.kt new file mode 100644 index 00000000000..4c57d990a7b --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/upperBounds/typeParameterAsUpperBound.kt @@ -0,0 +1,16 @@ +// !CHECK_TYPE + + +@kotlin.internal.InlineOnly +public inline fun C.ifEmpty(f: () -> R): R where C : Collection<*>, C : R = if (isEmpty()) f() else this + +public fun listOf(t: T): List = TODO() + + +fun usage(c: List) { + val cn = c.ifEmpty { null } + cn checkType { _?>() } + + val cs = c.ifEmpty { listOf("x") } + cs checkType { _>() } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inference/upperBounds/typeParameterAsUpperBound.txt b/compiler/testData/diagnostics/tests/inference/upperBounds/typeParameterAsUpperBound.txt new file mode 100644 index 00000000000..cb7b0c81214 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/upperBounds/typeParameterAsUpperBound.txt @@ -0,0 +1,5 @@ +package + +public fun listOf(/*0*/ t: T): kotlin.collections.List +public fun usage(/*0*/ c: kotlin.collections.List): kotlin.Unit +@kotlin.internal.InlineOnly public inline fun , /*1*/ R> C.ifEmpty(/*0*/ f: () -> R): R where C : R diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 2c2b6a34c41..6a34db13f7b 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -10289,6 +10289,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { runTest("compiler/testData/diagnostics/tests/inference/upperBounds/nonNullUpperBound.kt"); } + @TestMetadata("typeParameterAsUpperBound.kt") + public void testTypeParameterAsUpperBound() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/upperBounds/typeParameterAsUpperBound.kt"); + } + @TestMetadata("useBoundsIfUnknownParameters.kt") public void testUseBoundsIfUnknownParameters() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/upperBounds/useBoundsIfUnknownParameters.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index 3d5cf43a16c..08b23c05cb0 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -10289,6 +10289,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/inference/upperBounds/nonNullUpperBound.kt"); } + @TestMetadata("typeParameterAsUpperBound.kt") + public void testTypeParameterAsUpperBound() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/upperBounds/typeParameterAsUpperBound.kt"); + } + @TestMetadata("useBoundsIfUnknownParameters.kt") public void testUseBoundsIfUnknownParameters() throws Exception { runTest("compiler/testData/diagnostics/tests/inference/upperBounds/useBoundsIfUnknownParameters.kt");