[NI] Support callable references on qualified types with generics
#KT-32154 Fixed
This commit is contained in:
+5
@@ -1719,6 +1719,11 @@ public class FirDiagnosticsSmokeTestGenerated extends AbstractFirDiagnosticsSmok
|
|||||||
runTest("compiler/testData/diagnostics/tests/callableReference/parsingPriorityOfGenericArgumentsVsLess.kt");
|
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")
|
@TestMetadata("rewriteAtSliceOnGetOperator.kt")
|
||||||
public void testRewriteAtSliceOnGetOperator() throws Exception {
|
public void testRewriteAtSliceOnGetOperator() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/callableReference/rewriteAtSliceOnGetOperator.kt");
|
runTest("compiler/testData/diagnostics/tests/callableReference/rewriteAtSliceOnGetOperator.kt");
|
||||||
|
|||||||
@@ -683,10 +683,7 @@ class PSICallResolver(
|
|||||||
is DoubleColonLHS.Type -> {
|
is DoubleColonLHS.Type -> {
|
||||||
val qualifiedExpression = ktExpression.receiverExpression!!.let { it.referenceExpression() ?: it }
|
val qualifiedExpression = ktExpression.receiverExpression!!.let { it.referenceExpression() ?: it }
|
||||||
val qualifier = expressionTypingContext.trace.get(BindingContext.QUALIFIER, qualifiedExpression)
|
val qualifier = expressionTypingContext.trace.get(BindingContext.QUALIFIER, qualifiedExpression)
|
||||||
when (qualifier) {
|
LHSResult.Type(qualifier, lhsResult.type.unwrap())
|
||||||
is ClassQualifier, is TypeAliasQualifier -> LHSResult.Type(qualifier, lhsResult.type.unwrap())
|
|
||||||
else -> LHSResult.Error
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
-14
@@ -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.calls.tower.*
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.DetailedReceiver
|
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.ReceiverValue
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo
|
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.checker.captureFromExpression
|
||||||
import org.jetbrains.kotlin.types.expressions.CoercionStrategy
|
import org.jetbrains.kotlin.types.expressions.CoercionStrategy
|
||||||
import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes
|
import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes
|
||||||
@@ -32,11 +33,10 @@ import org.jetbrains.kotlin.utils.SmartList
|
|||||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
|
|
||||||
sealed class CallableReceiver(val receiver: ReceiverValueWithSmartCastInfo) {
|
sealed class CallableReceiver(val receiver: ReceiverValueWithSmartCastInfo) {
|
||||||
class UnboundReference(val qualifier: QualifierReceiver, receiver: ReceiverValueWithSmartCastInfo) : CallableReceiver(receiver)
|
class UnboundReference(receiver: ReceiverValueWithSmartCastInfo) : CallableReceiver(receiver)
|
||||||
class BoundValueReference(val qualifier: QualifierReceiver, receiver: ReceiverValueWithSmartCastInfo) : CallableReceiver(receiver)
|
class BoundValueReference(receiver: ReceiverValueWithSmartCastInfo) : CallableReceiver(receiver)
|
||||||
class ScopeReceiver(receiver: ReceiverValueWithSmartCastInfo) : CallableReceiver(receiver)
|
class ScopeReceiver(receiver: ReceiverValueWithSmartCastInfo) : CallableReceiver(receiver)
|
||||||
class ExplicitValueReceiver(val lhsArgument: SimpleKotlinCallArgument, receiver: ReceiverValueWithSmartCastInfo) :
|
class ExplicitValueReceiver(receiver: ReceiverValueWithSmartCastInfo) : CallableReceiver(receiver)
|
||||||
CallableReceiver(receiver)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo investigate similar code in CheckVisibility
|
// 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
|
// note that if we use PrioritizedCompositeScopeTowerProcessor then static will win over unbound members
|
||||||
val staticOrUnbound = SamePriorityCompositeScopeTowerProcessor(static, unbound)
|
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))
|
return PrioritizedCompositeScopeTowerProcessor(staticOrUnbound, factory.createCallableProcessor(asValue))
|
||||||
}
|
}
|
||||||
is LHSResult.Object -> {
|
is LHSResult.Object -> {
|
||||||
@@ -329,17 +329,16 @@ class CallableReferencesCandidateFactory(
|
|||||||
private fun toCallableReceiver(receiver: ReceiverValueWithSmartCastInfo, isExplicit: Boolean): CallableReceiver {
|
private fun toCallableReceiver(receiver: ReceiverValueWithSmartCastInfo, isExplicit: Boolean): CallableReceiver {
|
||||||
if (!isExplicit) return CallableReceiver.ScopeReceiver(receiver)
|
if (!isExplicit) return CallableReceiver.ScopeReceiver(receiver)
|
||||||
|
|
||||||
val lhsResult = argument.lhsResult
|
return when (val lhsResult = argument.lhsResult) {
|
||||||
return when (lhsResult) {
|
is LHSResult.Expression -> CallableReceiver.ExplicitValueReceiver(receiver)
|
||||||
is LHSResult.Expression -> CallableReceiver.ExplicitValueReceiver(lhsResult.lshCallArgument, receiver)
|
|
||||||
is LHSResult.Type -> {
|
is LHSResult.Type -> {
|
||||||
if (lhsResult.qualifier.classValueReceiver?.type == receiver.receiverValue.type) {
|
if (lhsResult.qualifier?.classValueReceiver?.type == receiver.receiverValue.type) {
|
||||||
CallableReceiver.BoundValueReference(lhsResult.qualifier, receiver)
|
CallableReceiver.BoundValueReference(receiver)
|
||||||
} else {
|
} 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")
|
else -> throw IllegalStateException("Unsupported kind of lhsResult: $lhsResult")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-1
@@ -167,7 +167,11 @@ private fun preprocessCallableReference(
|
|||||||
val lhsType = it.unboundDetailedReceiver.stableType
|
val lhsType = it.unboundDetailedReceiver.stableType
|
||||||
if (ReflectionTypes.isNumberedTypeWithOneOrMoreNumber(expectedType)) {
|
if (ReflectionTypes.isNumberedTypeWithOneOrMoreNumber(expectedType)) {
|
||||||
val lhsTypeVariable = expectedType.arguments.first().type.unwrap()
|
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) {
|
if (notCallableTypeConstructor != null) {
|
||||||
|
|||||||
+2
-3
@@ -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
|
||||||
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability.INAPPLICABLE
|
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.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.KotlinType
|
||||||
import org.jetbrains.kotlin.types.UnwrappedType
|
|
||||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||||
import org.jetbrains.kotlin.types.model.TypeVariableMarker
|
import org.jetbrains.kotlin.types.model.TypeVariableMarker
|
||||||
|
|
||||||
@@ -58,7 +57,7 @@ class KnownTypeParameterConstraintPosition(val typeArgument: KotlinType) : Const
|
|||||||
override fun toString() = "TypeArgument $typeArgument"
|
override fun toString() = "TypeArgument $typeArgument"
|
||||||
}
|
}
|
||||||
|
|
||||||
class LHSArgumentConstraintPosition(val receiver: QualifierReceiver) : ConstraintPosition() {
|
class LHSArgumentConstraintPosition(val receiver: DetailedReceiver) : ConstraintPosition() {
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "LHS receiver $receiver"
|
return "LHS receiver $receiver"
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-3
@@ -78,12 +78,14 @@ interface FunctionExpression : LambdaKotlinCallArgument {
|
|||||||
* D.E::foo <-> Expression
|
* D.E::foo <-> Expression
|
||||||
*/
|
*/
|
||||||
sealed class LHSResult {
|
sealed class LHSResult {
|
||||||
class Type(val qualifier: QualifierReceiver, resolvedType: UnwrappedType) : LHSResult() {
|
class Type(val qualifier: QualifierReceiver?, resolvedType: UnwrappedType) : LHSResult() {
|
||||||
val unboundDetailedReceiver: ReceiverValueWithSmartCastInfo
|
val unboundDetailedReceiver: ReceiverValueWithSmartCastInfo
|
||||||
|
|
||||||
init {
|
init {
|
||||||
assert(qualifier.descriptor is ClassDescriptor || qualifier.descriptor is TypeAliasDescriptor) {
|
if (qualifier != null) {
|
||||||
"Should be ClassDescriptor: ${qualifier.descriptor}"
|
assert(qualifier.descriptor is ClassDescriptor || qualifier.descriptor is TypeAliasDescriptor) {
|
||||||
|
"Should be ClassDescriptor: ${qualifier.descriptor}"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val unboundReceiver = TransientReceiver(resolvedType)
|
val unboundReceiver = TransientReceiver(resolvedType)
|
||||||
|
|||||||
+43
@@ -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
|
||||||
|
}
|
||||||
+22
@@ -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");
|
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")
|
@TestMetadata("rewriteAtSliceOnGetOperator.kt")
|
||||||
public void testRewriteAtSliceOnGetOperator() throws Exception {
|
public void testRewriteAtSliceOnGetOperator() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/callableReference/rewriteAtSliceOnGetOperator.kt");
|
runTest("compiler/testData/diagnostics/tests/callableReference/rewriteAtSliceOnGetOperator.kt");
|
||||||
|
|||||||
Generated
+5
@@ -1721,6 +1721,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
|
|||||||
runTest("compiler/testData/diagnostics/tests/callableReference/parsingPriorityOfGenericArgumentsVsLess.kt");
|
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")
|
@TestMetadata("rewriteAtSliceOnGetOperator.kt")
|
||||||
public void testRewriteAtSliceOnGetOperator() throws Exception {
|
public void testRewriteAtSliceOnGetOperator() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/callableReference/rewriteAtSliceOnGetOperator.kt");
|
runTest("compiler/testData/diagnostics/tests/callableReference/rewriteAtSliceOnGetOperator.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user