From 8ec63bd4ddc59e1b822ac7dae4138c8ae14e1bea Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Mon, 25 Jan 2016 18:09:51 +0300 Subject: [PATCH] Use type arguments from supertype when resolving constructor delegation call #KT-3357 Fixed --- .../kotlin/resolve/calls/CallResolver.java | 33 +++++++++++-------- .../resolve/calls/tasks/TaskPrioritizer.kt | 32 ++++++++++-------- .../generics/innerClasses/bareTypesComplex.kt | 14 ++++++++ .../innerClasses/bareTypesComplex.txt | 31 +++++++++++++++++ .../generics/innerClasses/innerSuperCall.kt | 9 +++++ .../generics/innerClasses/innerSuperCall.txt | 29 ++++++++++++++++ .../innerClasses/innerSuperCallSecondary.kt | 12 +++++++ .../innerClasses/innerSuperCallSecondary.txt | 30 +++++++++++++++++ .../tests/generics/innerClasses/kt3357.kt | 18 ++++++++++ .../tests/generics/innerClasses/kt3357.txt | 31 +++++++++++++++++ .../checkers/DiagnosticsTestGenerated.java | 24 ++++++++++++++ 11 files changed, 236 insertions(+), 27 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/generics/innerClasses/bareTypesComplex.kt create mode 100644 compiler/testData/diagnostics/tests/generics/innerClasses/bareTypesComplex.txt create mode 100644 compiler/testData/diagnostics/tests/generics/innerClasses/innerSuperCall.kt create mode 100644 compiler/testData/diagnostics/tests/generics/innerClasses/innerSuperCall.txt create mode 100644 compiler/testData/diagnostics/tests/generics/innerClasses/innerSuperCallSecondary.kt create mode 100644 compiler/testData/diagnostics/tests/generics/innerClasses/innerSuperCallSecondary.txt create mode 100644 compiler/testData/diagnostics/tests/generics/innerClasses/kt3357.kt create mode 100644 compiler/testData/diagnostics/tests/generics/innerClasses/kt3357.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolver.java index 2ae05411e81..8942c979995 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolver.java @@ -18,6 +18,7 @@ package org.jetbrains.kotlin.resolve.calls; import com.google.common.collect.Lists; import com.intellij.openapi.util.Condition; +import com.intellij.psi.PsiElement; import com.intellij.util.containers.ContainerUtil; import kotlin.Unit; import kotlin.jvm.functions.Function0; @@ -372,14 +373,18 @@ public class CallResolver { context.trace.report(NOT_A_CLASS.on(expression)); return checkArgumentTypesAndFail(context); } + ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor; + Collection constructors = classDescriptor.getConstructors(); if (constructors.isEmpty()) { context.trace.report(NO_CONSTRUCTOR.on(CallUtilKt.getValueArgumentListOrElement(context.call))); return checkArgumentTypesAndFail(context); } + TypeSubstitutor knownSubstitutor = TypeSubstitutor.create(constructedType); Collection> candidates = - taskPrioritizer.convertWithImpliedThisAndNoReceiver(context.scope, constructors, context.call); + taskPrioritizer.convertWithImpliedThisAndNoReceiver( + context.scope, constructors, context.call, knownSubstitutor); return computeTasksFromCandidatesAndResolvedCall(context, functionReference, candidates, CallTransformer.FUNCTION_CALL_TRANSFORMER); } @@ -450,27 +455,29 @@ public class CallResolver { return checkArgumentTypesAndFail(context); } - List> candidates = Lists.newArrayList(); - ReceiverValue constructorDispatchReceiver = !delegateClassDescriptor.isInner() ? null : - ((ClassDescriptor) delegateClassDescriptor.getContainingDeclaration()). - getThisAsReceiverParameter().getValue(); - KotlinType expectedType = isThisCall ? + KotlinType superType = isThisCall ? calleeConstructor.getContainingDeclaration().getDefaultType() : DescriptorUtils.getSuperClassType(currentClassDescriptor); - TypeSubstitutor knownTypeParametersSubstitutor = TypeSubstitutor.create(expectedType); - for (CallableDescriptor descriptor : constructors) { - candidates.add(ResolutionCandidate.create( - context.call, descriptor, constructorDispatchReceiver, null, - ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, - knownTypeParametersSubstitutor)); - } + TypeSubstitutor knownTypeParametersSubstitutor = TypeSubstitutor.create(superType); + + Collection> candidates = + taskPrioritizer.convertWithImpliedThisAndNoReceiver( + context.scope, constructors, context.call, knownTypeParametersSubstitutor); TracingStrategy tracing = call.isImplicit() ? new TracingStrategyForImplicitConstructorDelegationCall(call, context.call) : TracingStrategyImpl.create(calleeExpression, context.call); + PsiElement reportOn = call.isImplicit() ? call : calleeExpression; + + if (delegateClassDescriptor.isInner() + && !DescriptorResolver.checkHasOuterClassInstance(context.scope, context.trace, reportOn, + (ClassDescriptor) delegateClassDescriptor.getContainingDeclaration())) { + return checkArgumentTypesAndFail(context); + } + return computeTasksFromCandidatesAndResolvedCall(context, candidates, CallTransformer.FUNCTION_CALL_TRANSFORMER, tracing); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TaskPrioritizer.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TaskPrioritizer.kt index c4502075439..22c79c2b926 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TaskPrioritizer.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/TaskPrioritizer.kt @@ -46,6 +46,7 @@ import org.jetbrains.kotlin.resolve.selectMostSpecificInEachOverridableGroup import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.TypeSubstitutor import org.jetbrains.kotlin.types.checker.KotlinTypeChecker import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils import org.jetbrains.kotlin.types.isDynamic @@ -427,24 +428,24 @@ class TaskPrioritizer( fun convertWithImpliedThisAndNoReceiver( scope: LexicalScope, descriptors: Collection, - call: Call + call: Call, + knownSubstitutor: TypeSubstitutor? = null ): Collection> { - return convertWithImpliedThis(scope, null, descriptors, NO_EXPLICIT_RECEIVER, call) + return convertWithImpliedThis(scope, null, descriptors, NO_EXPLICIT_RECEIVER, call, knownSubstitutor) } fun convertWithImpliedThis( scope: LexicalScope, - receiverParameter: ReceiverValue?, + receiverValue: ReceiverValue?, descriptors: Collection, receiverKind: ExplicitReceiverKind, - call: Call + call: Call, + knownSubstitutor: TypeSubstitutor? = null ): Collection> { val result = Lists.newArrayList>() for (descriptor in descriptors) { - val candidate = ResolutionCandidate.create(call, descriptor) - candidate.setReceiverArgument(receiverParameter) - candidate.explicitReceiverKind = receiverKind - if (setImpliedThis(scope, candidate)) { + val candidate = ResolutionCandidate.create(call, descriptor, null, receiverValue, receiverKind, knownSubstitutor) + if (setImpliedThis(scope, candidate, knownSubstitutor)) { result.add(candidate) } } @@ -453,15 +454,18 @@ class TaskPrioritizer( private fun setImpliedThis( scope: LexicalScope, - candidate: ResolutionCandidate + candidate: ResolutionCandidate, + knownSubstitutor: TypeSubstitutor? ): Boolean { - val dispatchReceiver = candidate.descriptor.dispatchReceiverParameter - if (dispatchReceiver == null) return true + val dispatchReceiver = candidate.descriptor.dispatchReceiverParameter ?: return true + val substitutedDispatchReceiver = knownSubstitutor?.let { + dispatchReceiver.substitute(it) ?: return false + } ?: dispatchReceiver + val receivers = scope.getImplicitReceiversHierarchy() for (receiver in receivers) { - if (KotlinTypeChecker.DEFAULT.isSubtypeOf(receiver.type, dispatchReceiver.type)) { - // TODO : Smartcasts & nullability - candidate.dispatchReceiver = dispatchReceiver.value + if (KotlinTypeChecker.DEFAULT.isSubtypeOf(receiver.type, substitutedDispatchReceiver.type)) { + candidate.dispatchReceiver = substitutedDispatchReceiver.value return true } } diff --git a/compiler/testData/diagnostics/tests/generics/innerClasses/bareTypesComplex.kt b/compiler/testData/diagnostics/tests/generics/innerClasses/bareTypesComplex.kt new file mode 100644 index 00000000000..6659a53794c --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/innerClasses/bareTypesComplex.kt @@ -0,0 +1,14 @@ +open class SuperOuter { + inner open class SuperInner +} + +class DerivedOuter : SuperOuter() { + inner class DerivedInner : SuperOuter.SuperInner() +} + +fun bare(x: SuperOuter<*>.SuperInner<*>, y: Any?) { + if (x is SuperOuter.SuperInner) return + if (y is SuperOuter.SuperInner) { + return + } +} diff --git a/compiler/testData/diagnostics/tests/generics/innerClasses/bareTypesComplex.txt b/compiler/testData/diagnostics/tests/generics/innerClasses/bareTypesComplex.txt new file mode 100644 index 00000000000..9b03bfbbe34 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/innerClasses/bareTypesComplex.txt @@ -0,0 +1,31 @@ +package + +public fun bare(/*0*/ x: SuperOuter<*>.SuperInner<*>, /*1*/ y: kotlin.Any?): kotlin.Unit + +public final class DerivedOuter : SuperOuter { + public constructor DerivedOuter() + 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 inner class DerivedInner /*captured type parameters: /*1*/ G*/ : SuperOuter.SuperInner { + public constructor DerivedInner() + 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 open class SuperOuter { + public constructor SuperOuter() + 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 open inner class SuperInner /*captured type parameters: /*1*/ E*/ { + public constructor SuperInner() + 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 + } +} diff --git a/compiler/testData/diagnostics/tests/generics/innerClasses/innerSuperCall.kt b/compiler/testData/diagnostics/tests/generics/innerClasses/innerSuperCall.kt new file mode 100644 index 00000000000..64d4139d014 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/innerClasses/innerSuperCall.kt @@ -0,0 +1,9 @@ +open class Super { + inner open class Inner { + } +} + +class Sub : Super() { + // TODO: it would be nice to have a possibility to omit explicit type argument in supertype + inner class SubInner : Super.Inner() {} +} diff --git a/compiler/testData/diagnostics/tests/generics/innerClasses/innerSuperCall.txt b/compiler/testData/diagnostics/tests/generics/innerClasses/innerSuperCall.txt new file mode 100644 index 00000000000..9e018d21172 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/innerClasses/innerSuperCall.txt @@ -0,0 +1,29 @@ +package + +public final class Sub : Super { + public constructor Sub() + 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 inner class SubInner : Super.Inner { + public constructor SubInner() + 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 open class Super { + public constructor Super() + 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 open inner class Inner /*captured type parameters: /*0*/ T*/ { + public constructor Inner() + 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 + } +} diff --git a/compiler/testData/diagnostics/tests/generics/innerClasses/innerSuperCallSecondary.kt b/compiler/testData/diagnostics/tests/generics/innerClasses/innerSuperCallSecondary.kt new file mode 100644 index 00000000000..9d96d736e46 --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/innerClasses/innerSuperCallSecondary.kt @@ -0,0 +1,12 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +open class Super { + inner open class Inner { + } +} + +class Sub : Super() { + inner class SubInner : Super.Inner { + constructor() + constructor(x: Int) : super() {} + } +} diff --git a/compiler/testData/diagnostics/tests/generics/innerClasses/innerSuperCallSecondary.txt b/compiler/testData/diagnostics/tests/generics/innerClasses/innerSuperCallSecondary.txt new file mode 100644 index 00000000000..dfdcf7a1eca --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/innerClasses/innerSuperCallSecondary.txt @@ -0,0 +1,30 @@ +package + +public final class Sub : Super { + public constructor Sub() + 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 inner class SubInner : Super.Inner { + public constructor SubInner() + public constructor SubInner(/*0*/ x: kotlin.Int) + 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 open class Super { + public constructor Super() + 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 open inner class Inner /*captured type parameters: /*0*/ T*/ { + public constructor Inner() + 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 + } +} diff --git a/compiler/testData/diagnostics/tests/generics/innerClasses/kt3357.kt b/compiler/testData/diagnostics/tests/generics/innerClasses/kt3357.kt new file mode 100644 index 00000000000..795e8235a6c --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/innerClasses/kt3357.kt @@ -0,0 +1,18 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE + +open class Super { + inner open class Inner { + open fun getOuter(): Super = throw UnsupportedOperationException() + } +} + +class Sub(): Super() { + inner class SubInner : Super.Inner() { // 'Inner' is unresolved + // Also, T1 is not resolved to anything, and not marked as resolved + init { + val x: Super.Inner = this // T1 is not resolved to anything + } + + override fun getOuter(): Sub = throw UnsupportedOperationException() + } +} diff --git a/compiler/testData/diagnostics/tests/generics/innerClasses/kt3357.txt b/compiler/testData/diagnostics/tests/generics/innerClasses/kt3357.txt new file mode 100644 index 00000000000..6671f6e2f2a --- /dev/null +++ b/compiler/testData/diagnostics/tests/generics/innerClasses/kt3357.txt @@ -0,0 +1,31 @@ +package + +public final class Sub : Super { + public constructor Sub() + 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 inner class SubInner /*captured type parameters: /*0*/ T1*/ : Super.Inner { + public constructor SubInner() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ fun getOuter(): Sub + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} + +public open class Super { + public constructor Super() + 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 open inner class Inner /*captured type parameters: /*0*/ T*/ { + public constructor Inner() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun getOuter(): Super + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index fe40568e141..09391e7d63d 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -6947,6 +6947,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("bareTypesComplex.kt") + public void testBareTypesComplex() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/innerClasses/bareTypesComplex.kt"); + doTest(fileName); + } + @TestMetadata("checkBoundsOuter.kt") public void testCheckBoundsOuter() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/innerClasses/checkBoundsOuter.kt"); @@ -6959,6 +6965,18 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("innerSuperCall.kt") + public void testInnerSuperCall() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/innerClasses/innerSuperCall.kt"); + doTest(fileName); + } + + @TestMetadata("innerSuperCallSecondary.kt") + public void testInnerSuperCallSecondary() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/innerClasses/innerSuperCallSecondary.kt"); + doTest(fileName); + } + @TestMetadata("innerTP.kt") public void testInnerTP() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/innerClasses/innerTP.kt"); @@ -6995,6 +7013,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("kt3357.kt") + public void testKt3357() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/innerClasses/kt3357.kt"); + doTest(fileName); + } + @TestMetadata("kt408.kt") public void testKt408() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/generics/innerClasses/kt408.kt");