Allow generic type parameter to have mixed constraints for @InlineOnly functions

#KT-19323 Fixed
This commit is contained in:
Stanislav Erokhin
2018-08-20 11:03:52 +03:00
parent 7d4dfc87b1
commit f3e0470dcd
7 changed files with 51 additions and 2 deletions
@@ -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<MemberDescriptor>()?.isInlineOnly() == true) return
trace.report(BOUNDS_NOT_ALLOWED_IF_BOUNDED_BY_TYPE_PARAMETER.on(reportOn))
}
}
@@ -90,11 +90,22 @@ fun CallableDescriptor.hasInferredReturnType(constraintSystem: ConstraintSystem)
return true
}
private fun filterOutTypeParameters(upperBounds: List<KotlinType>, candidateDescriptor: CallableDescriptor): List<KotlinType> {
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<TypeProjection>()
@@ -150,7 +150,10 @@ public class TypeIntersector {
*/
@NotNull
public static KotlinType getUpperBoundsAsType(@NotNull TypeParameterDescriptor descriptor) {
List<KotlinType> upperBounds = descriptor.getUpperBounds();
return intersectUpperBounds(descriptor, descriptor.getUpperBounds());
}
public static KotlinType intersectUpperBounds(@NotNull TypeParameterDescriptor descriptor, @NotNull List<KotlinType> upperBounds) {
assert !upperBounds.isEmpty() : "Upper bound list is empty: " + descriptor;
KotlinType upperBoundsAsType = intersectTypes(upperBounds);
return upperBoundsAsType != null ? upperBoundsAsType : getBuiltIns(descriptor).getNothingType();
@@ -0,0 +1,16 @@
// !CHECK_TYPE
@<!INVISIBLE_MEMBER!>kotlin.internal.<!INVISIBLE_REFERENCE!>InlineOnly<!><!>
public inline fun <C, R> C.ifEmpty(f: () -> R): R where C : Collection<*>, C : R = if (isEmpty()) f() else this
public fun <T> listOf(<!UNUSED_PARAMETER!>t<!>: T): List<T> = TODO()
fun usage(c: List<String>) {
val cn = c.ifEmpty { null }
cn checkType { _<List<String>?>() }
val cs = c.ifEmpty { listOf("x") }
cs checkType { _<List<String>>() }
}
@@ -0,0 +1,5 @@
package
public fun </*0*/ T> listOf(/*0*/ t: T): kotlin.collections.List<T>
public fun usage(/*0*/ c: kotlin.collections.List<kotlin.String>): kotlin.Unit
@kotlin.internal.InlineOnly public inline fun </*0*/ C : kotlin.collections.Collection<*>, /*1*/ R> C.ifEmpty(/*0*/ f: () -> R): R where C : R
@@ -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");
@@ -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");