From 2c74796b0b6e97bb1804b46148ddacb87d2695fa Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Wed, 23 Jan 2019 11:12:58 +0300 Subject: [PATCH] Fix detecting upper bounds of generics of typealiases constructors in NI --- .../calls/components/ResolutionParts.kt | 36 +++++++++++++++++-- .../boundViolationInTypeAliasConstructor.kt | 8 ++--- ...boundsViolationInDeepTypeAliasExpansion.kt | 2 +- .../boundsViolationInTypeAliasExpansion.kt | 4 +-- ...ypeAliasConstructorCrazyProjections.ni.txt | 2 +- ...eAliasConstructorTypeArgumentsInference.kt | 2 +- ...orTypeArgumentsInferenceWithNestedCalls.kt | 2 +- ...NumberOfArgumentsInTypeAliasConstructor.kt | 11 ++++-- ...erOfArgumentsInTypeAliasConstructor.ni.txt | 13 +++++++ ...umberOfArgumentsInTypeAliasConstructor.txt | 13 +++++++ 10 files changed, 79 insertions(+), 14 deletions(-) diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt index f5b8b014a8a..171890ca82c 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.builtins.getReceiverTypeFromFunctionType import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor import org.jetbrains.kotlin.builtins.getFunctionalClassKind import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor import org.jetbrains.kotlin.resolve.calls.components.TypeArgumentsToParametersMapper.TypeArgumentsMapping.NoExplicitArguments import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation import org.jetbrains.kotlin.resolve.calls.inference.components.FreshVariableNewTypeSubstitutor @@ -21,6 +22,7 @@ import org.jetbrains.kotlin.resolve.calls.tower.InfixCallNoInfixModifier import org.jetbrains.kotlin.resolve.calls.tower.InvokeConventionCallNoOperatorModifier import org.jetbrains.kotlin.resolve.calls.tower.VisibilityError import org.jetbrains.kotlin.types.ErrorUtils +import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.typeUtil.contains import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.checker.anySuperTypeConstructor @@ -185,13 +187,42 @@ internal object CreateFreshVariablesSubstitutor : ResolutionPart() { csBuilder.registerVariable(freshVariable) } + fun TypeVariableFromCallableDescriptor.addSubtypeConstraint( + upperBound: KotlinType, + position: DeclaredUpperBoundConstraintPosition + ) { + csBuilder.addSubtypeConstraint(defaultType, toFreshVariables.safeSubstitute(upperBound.unwrap()), position) + } + for (index in typeParameters.indices) { val typeParameter = typeParameters[index] val freshVariable = freshTypeVariables[index] val position = DeclaredUpperBoundConstraintPosition(typeParameter) for (upperBound in typeParameter.upperBounds) { - csBuilder.addSubtypeConstraint(freshVariable.defaultType, toFreshVariables.safeSubstitute(upperBound.unwrap()), position) + freshVariable.addSubtypeConstraint(upperBound, position) + } + } + + if (candidateDescriptor is TypeAliasConstructorDescriptor) { + val typeAliasDescriptor = candidateDescriptor.typeAliasDescriptor + val originalTypes = typeAliasDescriptor.underlyingType.arguments.map { it.type } + val originalTypeParameters = candidateDescriptor.underlyingConstructorDescriptor.typeParameters + for (index in typeParameters.indices) { + val typeParameter = typeParameters[index] + val freshVariable = freshTypeVariables[index] + val typeMapping = originalTypes.mapIndexedNotNull { i: Int, kotlinType: KotlinType -> + if (kotlinType == typeParameter.defaultType) i else null + } + for (originalIndex in typeMapping) { + // there can be null in case we already captured type parameter in outer class (in case of inner classes) + // see test innerClassTypeAliasConstructor.kt + val originalTypeParameter = originalTypeParameters.getOrNull(originalIndex) ?: continue + val position = DeclaredUpperBoundConstraintPosition(originalTypeParameter) + for (upperBound in originalTypeParameter.upperBounds) { + freshVariable.addSubtypeConstraint(upperBound, position) + } + } } } return toFreshVariables @@ -270,7 +301,8 @@ private fun KotlinResolutionCandidate.getExpectedTypeWithSAMConversion( if (!argumentIsFunctional) return null val originalExpectedType = argument.getExpectedType(candidateParameter.original, callComponents.languageVersionSettings) - val convertedTypeByOriginal = callComponents.samConversionTransformer.getFunctionTypeForPossibleSamType(originalExpectedType) ?: return null + val convertedTypeByOriginal = + callComponents.samConversionTransformer.getFunctionTypeForPossibleSamType(originalExpectedType) ?: return null val candidateExpectedType = argument.getExpectedType(candidateParameter, callComponents.languageVersionSettings) val convertedTypeByCandidate = callComponents.samConversionTransformer.getFunctionTypeForPossibleSamType(candidateExpectedType) diff --git a/compiler/testData/diagnostics/tests/typealias/boundViolationInTypeAliasConstructor.kt b/compiler/testData/diagnostics/tests/typealias/boundViolationInTypeAliasConstructor.kt index e352d285a1a..2a4864084e6 100644 --- a/compiler/testData/diagnostics/tests/typealias/boundViolationInTypeAliasConstructor.kt +++ b/compiler/testData/diagnostics/tests/typealias/boundViolationInTypeAliasConstructor.kt @@ -5,8 +5,8 @@ typealias N = Num typealias N2 = N val x1 = Num<String>("") -val x2 = N<String>("") -val x3 = N2<String>("") +val x2 = N<String>("") +val x3 = N2<String>("") class TColl> @@ -14,5 +14,5 @@ typealias TC = TColl typealias TC2 = TC val y1 = TCollAny>() -val y2 = TCAny>() -val y3 = TC2Any>() +val y2 = TCAny>() +val y3 = TC2Any>() diff --git a/compiler/testData/diagnostics/tests/typealias/boundsViolationInDeepTypeAliasExpansion.kt b/compiler/testData/diagnostics/tests/typealias/boundsViolationInDeepTypeAliasExpansion.kt index 435a78514e2..d4592f5148e 100644 --- a/compiler/testData/diagnostics/tests/typealias/boundsViolationInDeepTypeAliasExpansion.kt +++ b/compiler/testData/diagnostics/tests/typealias/boundsViolationInDeepTypeAliasExpansion.kt @@ -14,4 +14,4 @@ fun test4(x: TC2>() val test6 = TC2>() val test7 = TC2>() -val test8 = TC2List>() +val test8 = TC2List>() diff --git a/compiler/testData/diagnostics/tests/typealias/boundsViolationInTypeAliasExpansion.kt b/compiler/testData/diagnostics/tests/typealias/boundsViolationInTypeAliasExpansion.kt index 0cf2b72f456..9526c950a20 100644 --- a/compiler/testData/diagnostics/tests/typealias/boundsViolationInTypeAliasExpansion.kt +++ b/compiler/testData/diagnostics/tests/typealias/boundsViolationInTypeAliasExpansion.kt @@ -15,7 +15,7 @@ fun test3(x: NL) {} fun test4(x: NL) {} val test5 = NA() -val test6 = NA<Any>() +val test6 = NA<Any>() val test7 = NL() val test8 = NL() @@ -27,4 +27,4 @@ fun test12(x: TCList>) {} val test13 = TC>() val test14 = TC>() val test15 = TC>() -val test16 = TCList>() +val test16 = TCList>() diff --git a/compiler/testData/diagnostics/tests/typealias/typeAliasConstructorCrazyProjections.ni.txt b/compiler/testData/diagnostics/tests/typealias/typeAliasConstructorCrazyProjections.ni.txt index 382d0c92914..4a42df4485d 100644 --- a/compiler/testData/diagnostics/tests/typealias/typeAliasConstructorCrazyProjections.ni.txt +++ b/compiler/testData/diagnostics/tests/typealias/typeAliasConstructorCrazyProjections.ni.txt @@ -1,7 +1,7 @@ package public val test1: [ERROR : Type for BOutIn(listOf(), null!!)] -public val test2: BInIn /* = Bound, in kotlin.Any?> */ +public val test2: BInIn>> /* = Bound>>, in kotlin.collections.List>> */ public fun listOf(): kotlin.collections.List public final class Bound { diff --git a/compiler/testData/diagnostics/tests/typealias/typeAliasConstructorTypeArgumentsInference.kt b/compiler/testData/diagnostics/tests/typealias/typeAliasConstructorTypeArgumentsInference.kt index 33c59d94497..268e740ef69 100644 --- a/compiler/testData/diagnostics/tests/typealias/typeAliasConstructorTypeArgumentsInference.kt +++ b/compiler/testData/diagnostics/tests/typealias/typeAliasConstructorTypeArgumentsInference.kt @@ -5,7 +5,7 @@ class Num(val x: Tn) typealias N = Num val test0 = N(1) -val test1 = N("1") +val test1 = N("1") class Cons(val head: T, val tail: Cons?) diff --git a/compiler/testData/diagnostics/tests/typealias/typeAliasConstructorTypeArgumentsInferenceWithNestedCalls.kt b/compiler/testData/diagnostics/tests/typealias/typeAliasConstructorTypeArgumentsInferenceWithNestedCalls.kt index 0edbeb9e1d1..376d408b644 100644 --- a/compiler/testData/diagnostics/tests/typealias/typeAliasConstructorTypeArgumentsInferenceWithNestedCalls.kt +++ b/compiler/testData/diagnostics/tests/typealias/typeAliasConstructorTypeArgumentsInferenceWithNestedCalls.kt @@ -5,4 +5,4 @@ class Cons(val head: T, val tail: Cons?) typealias C = Cons val test1 = C(1, C(2, null)) -val test2 = C(1, C("", null)) +val test2 = C(1, C("", null)) diff --git a/compiler/testData/diagnostics/tests/typealias/wrongNumberOfArgumentsInTypeAliasConstructor.kt b/compiler/testData/diagnostics/tests/typealias/wrongNumberOfArgumentsInTypeAliasConstructor.kt index c173c0f9b57..be6aff68aab 100644 --- a/compiler/testData/diagnostics/tests/typealias/wrongNumberOfArgumentsInTypeAliasConstructor.kt +++ b/compiler/testData/diagnostics/tests/typealias/wrongNumberOfArgumentsInTypeAliasConstructor.kt @@ -29,7 +29,14 @@ val test3pr = P2((val x: T) typealias N = Num -val testN0 = N("") +val testN0 = N("") val testN1 = N(1) -val testN1a = N<String>("") +val testN1a = N<String>("") val testN2 = N(1) + +class MyPair(val string: T1, val number: T2) +typealias MP = MyPair + +val testMP0 = MP("", 1) +val testMP1 = MP(1, "") +val testMP2 = MP<String>("", "") \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/typealias/wrongNumberOfArgumentsInTypeAliasConstructor.ni.txt b/compiler/testData/diagnostics/tests/typealias/wrongNumberOfArgumentsInTypeAliasConstructor.ni.txt index 4a4f090ea02..be9b0aa0ebb 100644 --- a/compiler/testData/diagnostics/tests/typealias/wrongNumberOfArgumentsInTypeAliasConstructor.ni.txt +++ b/compiler/testData/diagnostics/tests/typealias/wrongNumberOfArgumentsInTypeAliasConstructor.ni.txt @@ -14,11 +14,23 @@ public val test2pra: PR /* = Pair /* = Pair */ public val test3p2: P2 /* = Pair */ public val test3pr: Pair +public val testMP0: MP /* = MyPair */ +public val testMP1: MP /* = MyPair */ +public val testMP2: MP /* = MyPair */ public val testN0: N /* = Num */ public val testN1: N /* = Num */ public val testN1a: N /* = Num */ public val testN2: N /* = Num */ +public final class MyPair { + public constructor MyPair(/*0*/ string: T1, /*1*/ number: T2) + public final val number: T2 + public final val string: T1 + 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 Num { public constructor Num(/*0*/ x: T) public final val x: T @@ -35,6 +47,7 @@ public final class Pair { public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } +public typealias MP = MyPair public typealias N = Num public typealias P = Pair public typealias P2 = Pair diff --git a/compiler/testData/diagnostics/tests/typealias/wrongNumberOfArgumentsInTypeAliasConstructor.txt b/compiler/testData/diagnostics/tests/typealias/wrongNumberOfArgumentsInTypeAliasConstructor.txt index 5b150ff48b9..01ac4bdd81f 100644 --- a/compiler/testData/diagnostics/tests/typealias/wrongNumberOfArgumentsInTypeAliasConstructor.txt +++ b/compiler/testData/diagnostics/tests/typealias/wrongNumberOfArgumentsInTypeAliasConstructor.txt @@ -14,11 +14,23 @@ public val test2pra: PR /* = Pair /* = Pair */ public val test3p2: P2 /* = Pair */ public val test3pr: P2 /* = Pair */ +public val testMP0: MP /* = MyPair */ +public val testMP1: [ERROR : Type for MP(1, "")] +public val testMP2: MP /* = MyPair */ public val testN0: [ERROR : Type for N("")] public val testN1: N /* = Num */ public val testN1a: N /* = Num */ public val testN2: N /* = Num */ +public final class MyPair { + public constructor MyPair(/*0*/ string: T1, /*1*/ number: T2) + public final val number: T2 + public final val string: T1 + 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 Num { public constructor Num(/*0*/ x: T) public final val x: T @@ -35,6 +47,7 @@ public final class Pair { public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } +public typealias MP = MyPair public typealias N = Num public typealias P = Pair public typealias P2 = Pair