Use type arguments from supertype when resolving constructor delegation call
#KT-3357 Fixed
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
+14
@@ -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
|
||||
}
|
||||
}
|
||||
+31
@@ -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
|
||||
}
|
||||
}
|
||||
+12
@@ -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() {}
|
||||
}
|
||||
}
|
||||
+30
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user