Use type arguments from supertype when resolving constructor delegation call

#KT-3357 Fixed
This commit is contained in:
Denis Zharkov
2016-01-25 18:09:51 +03:00
parent 8b828f1d9a
commit 8ec63bd4dd
11 changed files with 236 additions and 27 deletions
@@ -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<ConstructorDescriptor> 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<ResolutionCandidate<CallableDescriptor>> candidates =
taskPrioritizer.<CallableDescriptor>convertWithImpliedThisAndNoReceiver(context.scope, constructors, context.call);
taskPrioritizer.<CallableDescriptor>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<ResolutionCandidate<CallableDescriptor>> 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<ResolutionCandidate<CallableDescriptor>> candidates =
taskPrioritizer.<CallableDescriptor>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);
}
@@ -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 <D : CallableDescriptor> convertWithImpliedThisAndNoReceiver(
scope: LexicalScope,
descriptors: Collection<D>,
call: Call
call: Call,
knownSubstitutor: TypeSubstitutor? = null
): Collection<ResolutionCandidate<D>> {
return convertWithImpliedThis(scope, null, descriptors, NO_EXPLICIT_RECEIVER, call)
return convertWithImpliedThis(scope, null, descriptors, NO_EXPLICIT_RECEIVER, call, knownSubstitutor)
}
fun <D : CallableDescriptor> convertWithImpliedThis(
scope: LexicalScope,
receiverParameter: ReceiverValue?,
receiverValue: ReceiverValue?,
descriptors: Collection<D>,
receiverKind: ExplicitReceiverKind,
call: Call
call: Call,
knownSubstitutor: TypeSubstitutor? = null
): Collection<ResolutionCandidate<D>> {
val result = Lists.newArrayList<ResolutionCandidate<D>>()
for (descriptor in descriptors) {
val candidate = ResolutionCandidate.create<D>(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 <D : CallableDescriptor> setImpliedThis(
scope: LexicalScope,
candidate: ResolutionCandidate<D>
candidate: ResolutionCandidate<D>,
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
}
}
@@ -0,0 +1,14 @@
open class SuperOuter<E> {
inner open class SuperInner<F>
}
class DerivedOuter<G> : SuperOuter<G>() {
inner class DerivedInner<H> : SuperOuter<G>.SuperInner<H>()
}
fun bare(x: SuperOuter<*>.SuperInner<*>, y: Any?) {
if (x is SuperOuter.SuperInner) return
if (y is <!NO_TYPE_ARGUMENTS_ON_RHS!>SuperOuter.SuperInner<!>) {
return
}
}
@@ -0,0 +1,31 @@
package
public fun bare(/*0*/ x: SuperOuter<*>.SuperInner<*>, /*1*/ y: kotlin.Any?): kotlin.Unit
public final class DerivedOuter</*0*/ G> : SuperOuter<G> {
public constructor DerivedOuter</*0*/ G>()
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</*0*/ H> /*captured type parameters: /*1*/ G*/ : SuperOuter<G>.SuperInner<H> {
public constructor DerivedInner</*0*/ H>()
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</*0*/ E> {
public constructor SuperOuter</*0*/ E>()
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</*0*/ F> /*captured type parameters: /*1*/ E*/ {
public constructor SuperInner</*0*/ F>()
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
}
}
@@ -0,0 +1,9 @@
open class Super<T> {
inner open class Inner {
}
}
class Sub : Super<String>() {
// TODO: it would be nice to have a possibility to omit explicit type argument in supertype
inner class SubInner : Super<String>.Inner() {}
}
@@ -0,0 +1,29 @@
package
public final class Sub : Super<kotlin.String> {
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<kotlin.String>.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</*0*/ T> {
public constructor Super</*0*/ 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
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
}
}
@@ -0,0 +1,12 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
open class Super<T> {
inner open class Inner {
}
}
class Sub : Super<String>() {
inner class SubInner : Super<String>.Inner {
constructor()
constructor(x: Int) : super() {}
}
}
@@ -0,0 +1,30 @@
package
public final class Sub : Super<kotlin.String> {
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<kotlin.String>.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</*0*/ T> {
public constructor Super</*0*/ 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
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
}
}
@@ -0,0 +1,18 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE
open class Super<T> {
inner open class Inner {
open fun getOuter(): Super<T> = throw UnsupportedOperationException()
}
}
class Sub<T1>(): Super<T1>() {
inner class SubInner : Super<T1>.Inner() { // 'Inner' is unresolved
// Also, T1 is not resolved to anything, and not marked as resolved
init {
val x: Super<T1>.Inner = this // T1 is not resolved to anything
}
override fun getOuter(): Sub<T1> = throw UnsupportedOperationException()
}
}
@@ -0,0 +1,31 @@
package
public final class Sub</*0*/ T1> : Super<T1> {
public constructor Sub</*0*/ 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 inner class SubInner /*captured type parameters: /*0*/ T1*/ : Super<T1>.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<T1>
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
}
public open class Super</*0*/ T> {
public constructor Super</*0*/ 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
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<T>
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
}
@@ -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");