From c01c59d562b6051d6d1a6ba2eed1b7fd08fddbc9 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Wed, 8 Jul 2015 10:51:36 +0300 Subject: [PATCH] Use doSubstitute when enhacing types of Java method Before this commit old type parameters were inserted into new descriptor, and that broke a simple contract: desc.child.getContainingDeclaration() == desc. We use `doSubstitute` here because it does exactly what we need: 1. creates full copy of descriptor 2. copies method's type parameters (with new containing declaration) and properly substitute to them in value parameters, return type and etc. But we had to customize `doSubstitute`: add some parameters like `newReturnType` NOTE: Strange testData change. (Mutable)List! after substitution becomes MutableList..List<*>?. But it's not wrong because List behaves exactly as List<*>, and the same happens when substituing Java class scope: public class A { void foo(List x) {} } Kotlin: A.foo(), type of first value parameter --- (Mutable)List A().foo(), type of first value parameter --- MutableList..List<*>? --- .../MethodWithMappedClasses.txt | 2 +- .../MethodWithTypeParameters.txt | 2 +- .../JavaConstructorDescriptor.java | 1 + .../descriptors/JavaMethodDescriptor.java | 23 ++++++---- .../impl/FunctionDescriptorImpl.java | 42 ++++++++++++++++--- .../impl/PropertyDescriptorImpl.java | 4 +- 6 files changed, 56 insertions(+), 18 deletions(-) diff --git a/compiler/testData/loadJava/compiledJava/kotlinSignature/MethodWithMappedClasses.txt b/compiler/testData/loadJava/compiledJava/kotlinSignature/MethodWithMappedClasses.txt index af3fde71cba..ff5ea05cdd9 100644 --- a/compiler/testData/loadJava/compiledJava/kotlinSignature/MethodWithMappedClasses.txt +++ b/compiler/testData/loadJava/compiledJava/kotlinSignature/MethodWithMappedClasses.txt @@ -2,5 +2,5 @@ package test public open class MethodWithMappedClasses { public constructor MethodWithMappedClasses() - public open fun copy(/*0*/ dest: kotlin.(Mutable)List!, /*1*/ src: kotlin.(Mutable)List!): kotlin.Unit + public open fun copy(/*0*/ dest: (kotlin.MutableList..kotlin.List<*>?), /*1*/ src: kotlin.(Mutable)List!): kotlin.Unit } diff --git a/compiler/testData/loadJava/compiledJava/kotlinSignature/MethodWithTypeParameters.txt b/compiler/testData/loadJava/compiledJava/kotlinSignature/MethodWithTypeParameters.txt index 8a999647cfc..8c2a3a0006c 100644 --- a/compiler/testData/loadJava/compiledJava/kotlinSignature/MethodWithTypeParameters.txt +++ b/compiler/testData/loadJava/compiledJava/kotlinSignature/MethodWithTypeParameters.txt @@ -2,5 +2,5 @@ package test public open class MethodWithTypeParameters { public constructor MethodWithTypeParameters() - public open fun foo(/*0*/ a: A!, /*1*/ b: (kotlin.MutableList..kotlin.List?), /*2*/ c: kotlin.(Mutable)List!): kotlin.Unit where B : kotlin.(Mutable)List! + public open fun foo(/*0*/ a: A!, /*1*/ b: (kotlin.MutableList..kotlin.List?), /*2*/ c: (kotlin.MutableList..kotlin.List<*>?)): kotlin.Unit where B : kotlin.(Mutable)List! } diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/descriptors/JavaConstructorDescriptor.java b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/descriptors/JavaConstructorDescriptor.java index 44090e6b210..4343f749847 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/descriptors/JavaConstructorDescriptor.java +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/descriptors/JavaConstructorDescriptor.java @@ -101,6 +101,7 @@ public class JavaConstructorDescriptor extends ConstructorDescriptorImpl impleme @NotNull JetType enhancedReturnType ) { JavaConstructorDescriptor enhanced = createSubstitutedCopy(getContainingDeclaration(), getOriginal(), getKind()); + // We do not use doSubstitute here as in JavaMethodDescriptor.enhance because type parameters of constructor belongs to class enhanced.initialize( enhancedReceiverType, getDispatchReceiverParameter(), diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/descriptors/JavaMethodDescriptor.java b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/descriptors/JavaMethodDescriptor.java index e999b400cd5..e9f9b2aa4b8 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/descriptors/JavaMethodDescriptor.java +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/descriptors/JavaMethodDescriptor.java @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations; import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.types.JetType; +import org.jetbrains.kotlin.types.TypeSubstitutor; import java.util.List; @@ -100,16 +101,20 @@ public class JavaMethodDescriptor extends SimpleFunctionDescriptorImpl implement @NotNull List enhancedValueParametersTypes, @NotNull JetType enhancedReturnType ) { - JavaMethodDescriptor enhancedMethod = createSubstitutedCopy(getContainingDeclaration(), getOriginal(), getKind()); - enhancedMethod.initialize( - enhancedReceiverType, - getDispatchReceiverParameter(), - getTypeParameters(), - DescriptorsPackage.createEnhancedValueParameters(enhancedValueParametersTypes, getValueParameters(), enhancedMethod), - enhancedReturnType, - getModality(), - getVisibility() + List enhancedValueParameters = + DescriptorsPackage.createEnhancedValueParameters(enhancedValueParametersTypes, getValueParameters(), this); + + // We use `doSubstitute` here because it does exactly what we need: + // 1. creates full copy of descriptor + // 2. copies method's type parameters (with new containing declaration) and properly substitute to them in value parameters, return type and etc. + JavaMethodDescriptor enhancedMethod = (JavaMethodDescriptor) doSubstitute( + TypeSubstitutor.EMPTY, getContainingDeclaration(), getModality(), getVisibility(), getOriginal(), + /* copyOverrides = */ false, getKind(), + enhancedValueParameters, enhancedReceiverType, enhancedReturnType ); + + assert enhancedMethod != null : "null after substitution while enhancing " + toString(); + for (FunctionDescriptor overridden : getOverriddenDescriptors()) { enhancedMethod.addOverriddenDescriptor(overridden); } diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/FunctionDescriptorImpl.java b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/FunctionDescriptorImpl.java index 3ce0941e14b..dfb6b614f3e 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/FunctionDescriptorImpl.java +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/FunctionDescriptorImpl.java @@ -197,6 +197,31 @@ public abstract class FunctionDescriptorImpl extends DeclarationDescriptorNonRoo @Nullable FunctionDescriptor original, boolean copyOverrides, @NotNull Kind kind + ) { + return doSubstitute(originalSubstitutor, + newOwner, newModality, newVisibility, original, copyOverrides, kind, + getValueParameters(), getExtensionReceiverParameterType(), getReturnType() + ); + } + + @Nullable + protected JetType getExtensionReceiverParameterType() { + if (extensionReceiverParameter == null) return null; + return extensionReceiverParameter.getType(); + } + + + @Nullable + protected FunctionDescriptor doSubstitute(@NotNull TypeSubstitutor originalSubstitutor, + @NotNull DeclarationDescriptor newOwner, + @NotNull Modality newModality, + @NotNull Visibility newVisibility, + @Nullable FunctionDescriptor original, + boolean copyOverrides, + @NotNull Kind kind, + @NotNull List newValueParameterDescriptors, + @Nullable JetType newExtensionReceiverParameterType, + @NotNull JetType newReturnType ) { FunctionDescriptorImpl substitutedDescriptor = createSubstitutedCopy(newOwner, original, kind); @@ -207,8 +232,8 @@ public abstract class FunctionDescriptorImpl extends DeclarationDescriptorNonRoo ); JetType substitutedReceiverParameterType = null; - if (extensionReceiverParameter != null) { - substitutedReceiverParameterType = substitutor.substitute(getExtensionReceiverParameter().getType(), Variance.IN_VARIANCE); + if (newExtensionReceiverParameterType != null) { + substitutedReceiverParameterType = substitutor.substitute(newExtensionReceiverParameterType, Variance.IN_VARIANCE); if (substitutedReceiverParameterType == null) { return null; } @@ -232,12 +257,14 @@ public abstract class FunctionDescriptorImpl extends DeclarationDescriptorNonRoo } } - List substitutedValueParameters = getSubstitutedValueParameters(substitutedDescriptor, this, substitutor); + List substitutedValueParameters = getSubstitutedValueParameters( + substitutedDescriptor, newValueParameterDescriptors, substitutor + ); if (substitutedValueParameters == null) { return null; } - JetType substitutedReturnType = substitutor.substitute(getReturnType(), Variance.OUT_VARIANCE); + JetType substitutedReturnType = substitutor.substitute(newReturnType, Variance.OUT_VARIANCE); if (substitutedReturnType == null) { return null; } @@ -272,9 +299,12 @@ public abstract class FunctionDescriptorImpl extends DeclarationDescriptorNonRoo } @Nullable - public static List getSubstitutedValueParameters(FunctionDescriptor substitutedDescriptor, @NotNull FunctionDescriptor functionDescriptor, @NotNull TypeSubstitutor substitutor) { + public static List getSubstitutedValueParameters( + FunctionDescriptor substitutedDescriptor, + @NotNull List unsubstitutedValueParameters, + @NotNull TypeSubstitutor substitutor + ) { List result = new ArrayList(); - List unsubstitutedValueParameters = functionDescriptor.getValueParameters(); for (ValueParameterDescriptor unsubstitutedValueParameter : unsubstitutedValueParameters) { // TODO : Lazy? JetType substitutedType = substitutor.substitute(unsubstitutedValueParameter.getType(), Variance.IN_VARIANCE); diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/PropertyDescriptorImpl.java b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/PropertyDescriptorImpl.java index b03a1c84f8b..546b9a39ef7 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/PropertyDescriptorImpl.java +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/PropertyDescriptorImpl.java @@ -255,7 +255,9 @@ public class PropertyDescriptorImpl extends VariableDescriptorImpl implements Pr setter.hasBody(), setter.isDefault(), kind, original == null ? null : original.getSetter(), SourceElement.NO_SOURCE ); if (newSetter != null) { - List substitutedValueParameters = FunctionDescriptorImpl.getSubstitutedValueParameters(newSetter, setter, substitutor); + List substitutedValueParameters = FunctionDescriptorImpl.getSubstitutedValueParameters( + newSetter, setter.getValueParameters(), substitutor + ); if (substitutedValueParameters == null) { // The setter is projected out, e.g. in this case: // trait Tr { var v: T }