[NI] Support callable references on qualified types with generics

#KT-32154 Fixed
This commit is contained in:
Mikhail Zarechenskiy
2019-06-25 15:55:33 +03:00
parent b8ccd98a17
commit c77f18fbe6
10 changed files with 106 additions and 25 deletions
@@ -1719,6 +1719,11 @@ public class FirDiagnosticsSmokeTestGenerated extends AbstractFirDiagnosticsSmok
runTest("compiler/testData/diagnostics/tests/callableReference/parsingPriorityOfGenericArgumentsVsLess.kt");
}
@TestMetadata("propertyOfNestedGenericClass.kt")
public void testPropertyOfNestedGenericClass() throws Exception {
runTest("compiler/testData/diagnostics/tests/callableReference/propertyOfNestedGenericClass.kt");
}
@TestMetadata("rewriteAtSliceOnGetOperator.kt")
public void testRewriteAtSliceOnGetOperator() throws Exception {
runTest("compiler/testData/diagnostics/tests/callableReference/rewriteAtSliceOnGetOperator.kt");
@@ -683,10 +683,7 @@ class PSICallResolver(
is DoubleColonLHS.Type -> {
val qualifiedExpression = ktExpression.receiverExpression!!.let { it.referenceExpression() ?: it }
val qualifier = expressionTypingContext.trace.get(BindingContext.QUALIFIER, qualifiedExpression)
when (qualifier) {
is ClassQualifier, is TypeAliasQualifier -> LHSResult.Type(qualifier, lhsResult.type.unwrap())
else -> LHSResult.Error
}
LHSResult.Type(qualifier, lhsResult.type.unwrap())
}
}
@@ -19,10 +19,11 @@ import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.EXTENSION_R
import org.jetbrains.kotlin.resolve.calls.tower.*
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.scopes.receivers.DetailedReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.QualifierReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.checker.captureFromExpression
import org.jetbrains.kotlin.types.expressions.CoercionStrategy
import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes
@@ -32,11 +33,10 @@ import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.kotlin.utils.addIfNotNull
sealed class CallableReceiver(val receiver: ReceiverValueWithSmartCastInfo) {
class UnboundReference(val qualifier: QualifierReceiver, receiver: ReceiverValueWithSmartCastInfo) : CallableReceiver(receiver)
class BoundValueReference(val qualifier: QualifierReceiver, receiver: ReceiverValueWithSmartCastInfo) : CallableReceiver(receiver)
class UnboundReference(receiver: ReceiverValueWithSmartCastInfo) : CallableReceiver(receiver)
class BoundValueReference(receiver: ReceiverValueWithSmartCastInfo) : CallableReceiver(receiver)
class ScopeReceiver(receiver: ReceiverValueWithSmartCastInfo) : CallableReceiver(receiver)
class ExplicitValueReceiver(val lhsArgument: SimpleKotlinCallArgument, receiver: ReceiverValueWithSmartCastInfo) :
CallableReceiver(receiver)
class ExplicitValueReceiver(receiver: ReceiverValueWithSmartCastInfo) : CallableReceiver(receiver)
}
// todo investigate similar code in CheckVisibility
@@ -89,7 +89,7 @@ fun createCallableReferenceProcessor(factory: CallableReferencesCandidateFactory
// note that if we use PrioritizedCompositeScopeTowerProcessor then static will win over unbound members
val staticOrUnbound = SamePriorityCompositeScopeTowerProcessor(static, unbound)
val asValue = lhsResult.qualifier.classValueReceiverWithSmartCastInfo ?: return staticOrUnbound
val asValue = lhsResult.qualifier?.classValueReceiverWithSmartCastInfo ?: return staticOrUnbound
return PrioritizedCompositeScopeTowerProcessor(staticOrUnbound, factory.createCallableProcessor(asValue))
}
is LHSResult.Object -> {
@@ -329,17 +329,16 @@ class CallableReferencesCandidateFactory(
private fun toCallableReceiver(receiver: ReceiverValueWithSmartCastInfo, isExplicit: Boolean): CallableReceiver {
if (!isExplicit) return CallableReceiver.ScopeReceiver(receiver)
val lhsResult = argument.lhsResult
return when (lhsResult) {
is LHSResult.Expression -> CallableReceiver.ExplicitValueReceiver(lhsResult.lshCallArgument, receiver)
return when (val lhsResult = argument.lhsResult) {
is LHSResult.Expression -> CallableReceiver.ExplicitValueReceiver(receiver)
is LHSResult.Type -> {
if (lhsResult.qualifier.classValueReceiver?.type == receiver.receiverValue.type) {
CallableReceiver.BoundValueReference(lhsResult.qualifier, receiver)
if (lhsResult.qualifier?.classValueReceiver?.type == receiver.receiverValue.type) {
CallableReceiver.BoundValueReference(receiver)
} else {
CallableReceiver.UnboundReference(lhsResult.qualifier, receiver)
CallableReceiver.UnboundReference(receiver)
}
}
is LHSResult.Object -> CallableReceiver.BoundValueReference(lhsResult.qualifier, receiver)
is LHSResult.Object -> CallableReceiver.BoundValueReference(receiver)
else -> throw IllegalStateException("Unsupported kind of lhsResult: $lhsResult")
}
}
@@ -167,7 +167,11 @@ private fun preprocessCallableReference(
val lhsType = it.unboundDetailedReceiver.stableType
if (ReflectionTypes.isNumberedTypeWithOneOrMoreNumber(expectedType)) {
val lhsTypeVariable = expectedType.arguments.first().type.unwrap()
csBuilder.addSubtypeConstraint(lhsType, lhsTypeVariable, LHSArgumentConstraintPosition(it.qualifier))
csBuilder.addSubtypeConstraint(
lhsType,
lhsTypeVariable,
LHSArgumentConstraintPosition(it.qualifier ?: it.unboundDetailedReceiver)
)
}
}
if (notCallableTypeConstructor != null) {
@@ -21,9 +21,8 @@ import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability.INAPPLICABLE
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER
import org.jetbrains.kotlin.resolve.scopes.receivers.QualifierReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.DetailedReceiver
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.TypeVariableMarker
@@ -58,7 +57,7 @@ class KnownTypeParameterConstraintPosition(val typeArgument: KotlinType) : Const
override fun toString() = "TypeArgument $typeArgument"
}
class LHSArgumentConstraintPosition(val receiver: QualifierReceiver) : ConstraintPosition() {
class LHSArgumentConstraintPosition(val receiver: DetailedReceiver) : ConstraintPosition() {
override fun toString(): String {
return "LHS receiver $receiver"
}
@@ -78,12 +78,14 @@ interface FunctionExpression : LambdaKotlinCallArgument {
* D.E::foo <-> Expression
*/
sealed class LHSResult {
class Type(val qualifier: QualifierReceiver, resolvedType: UnwrappedType) : LHSResult() {
class Type(val qualifier: QualifierReceiver?, resolvedType: UnwrappedType) : LHSResult() {
val unboundDetailedReceiver: ReceiverValueWithSmartCastInfo
init {
assert(qualifier.descriptor is ClassDescriptor || qualifier.descriptor is TypeAliasDescriptor) {
"Should be ClassDescriptor: ${qualifier.descriptor}"
if (qualifier != null) {
assert(qualifier.descriptor is ClassDescriptor || qualifier.descriptor is TypeAliasDescriptor) {
"Should be ClassDescriptor: ${qualifier.descriptor}"
}
}
val unboundReceiver = TransientReceiver(resolvedType)
@@ -0,0 +1,43 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_EXPRESSION -UNUSED_VARIABLE
import kotlin.reflect.KProperty1
class Scope {
abstract class Nested<T> {
abstract val key: Int
abstract val keyT: T
}
}
fun simple(a: Any?) {}
fun <K> id(x: K): K = x
fun test() {
simple(Scope.Nested<String>::key)
val a = id(Scope.Nested<String>::keyT)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.reflect.KProperty1<Scope.Nested<kotlin.String>, kotlin.String>")!>a<!>
val b = id(Scope.Nested<*>::keyT)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.reflect.KProperty1<Scope.Nested<*>, kotlin.Any?>")!>b<!>
val c = id(Scope.Nested<out Number?>::keyT)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.reflect.KProperty1<Scope.Nested<out kotlin.Number?>, kotlin.Number?>")!>c<!>
val d = id(Scope.Nested<*>::keyT <!UNCHECKED_CAST!>as Scope.Nested<Number><!>)
<!DEBUG_INFO_EXPRESSION_TYPE("Scope.Nested<kotlin.Number>")!>d<!>
val g = id<KProperty1<Scope.Nested<*>, Any?>>(Scope.Nested<*>::keyT)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.reflect.KProperty1<Scope.Nested<*>, kotlin.Any?>")!>g<!>
}
fun justResolve() {
val a = Scope.Nested<String>::key
val b = Scope.Nested<String>::keyT
val c = Scope.Nested<*>::keyT
val d = Scope.Nested<out Number?>::keyT
}
@@ -0,0 +1,22 @@
package
public fun </*0*/ K> id(/*0*/ x: K): K
public fun justResolve(): kotlin.Unit
public fun simple(/*0*/ a: kotlin.Any?): kotlin.Unit
public fun test(): kotlin.Unit
public final class Scope {
public constructor Scope()
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 abstract class Nested</*0*/ T> {
public constructor Nested</*0*/ T>()
public abstract val key: kotlin.Int
public abstract val keyT: T
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
}
}
@@ -1726,6 +1726,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
runTest("compiler/testData/diagnostics/tests/callableReference/parsingPriorityOfGenericArgumentsVsLess.kt");
}
@TestMetadata("propertyOfNestedGenericClass.kt")
public void testPropertyOfNestedGenericClass() throws Exception {
runTest("compiler/testData/diagnostics/tests/callableReference/propertyOfNestedGenericClass.kt");
}
@TestMetadata("rewriteAtSliceOnGetOperator.kt")
public void testRewriteAtSliceOnGetOperator() throws Exception {
runTest("compiler/testData/diagnostics/tests/callableReference/rewriteAtSliceOnGetOperator.kt");
@@ -1721,6 +1721,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
runTest("compiler/testData/diagnostics/tests/callableReference/parsingPriorityOfGenericArgumentsVsLess.kt");
}
@TestMetadata("propertyOfNestedGenericClass.kt")
public void testPropertyOfNestedGenericClass() throws Exception {
runTest("compiler/testData/diagnostics/tests/callableReference/propertyOfNestedGenericClass.kt");
}
@TestMetadata("rewriteAtSliceOnGetOperator.kt")
public void testRewriteAtSliceOnGetOperator() throws Exception {
runTest("compiler/testData/diagnostics/tests/callableReference/rewriteAtSliceOnGetOperator.kt");