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<in T!>! after substitution becomes MutableList<in T!>..List<*>?.

But it's not wrong because List<in T> behaves exactly as List<*>, and the same happens when substituing Java class scope:
public class A<E> {
    <T> void foo(List<? super T> x) {}
}

Kotlin:
A.foo(), type of first value parameter --- (Mutable)List<in T!>
A<String>().foo(), type of first value parameter --- MutableList<in T!>..List<*>?
This commit is contained in:
Denis Zharkov
2015-07-08 10:51:36 +03:00
parent f6c4ec1533
commit c01c59d562
6 changed files with 56 additions and 18 deletions
@@ -2,5 +2,5 @@ package test
public open class MethodWithMappedClasses {
public constructor MethodWithMappedClasses()
public open fun </*0*/ T> copy(/*0*/ dest: kotlin.(Mutable)List<in T!>!, /*1*/ src: kotlin.(Mutable)List<T!>!): kotlin.Unit
public open fun </*0*/ T> copy(/*0*/ dest: (kotlin.MutableList<in T!>..kotlin.List<*>?), /*1*/ src: kotlin.(Mutable)List<T!>!): kotlin.Unit
}
@@ -2,5 +2,5 @@ package test
public open class MethodWithTypeParameters {
public constructor MethodWithTypeParameters()
public open fun </*0*/ A, /*1*/ B : java.lang.Runnable!> foo(/*0*/ a: A!, /*1*/ b: (kotlin.MutableList<out B!>..kotlin.List<B!>?), /*2*/ c: kotlin.(Mutable)List<in kotlin.String!>!): kotlin.Unit where B : kotlin.(Mutable)List<kotlin.Cloneable!>!
public open fun </*0*/ A, /*1*/ B : java.lang.Runnable!> foo(/*0*/ a: A!, /*1*/ b: (kotlin.MutableList<out B!>..kotlin.List<B!>?), /*2*/ c: (kotlin.MutableList<in kotlin.String!>..kotlin.List<*>?)): kotlin.Unit where B : kotlin.(Mutable)List<kotlin.Cloneable!>!
}
@@ -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(),
@@ -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<JetType> enhancedValueParametersTypes,
@NotNull JetType enhancedReturnType
) {
JavaMethodDescriptor enhancedMethod = createSubstitutedCopy(getContainingDeclaration(), getOriginal(), getKind());
enhancedMethod.initialize(
enhancedReceiverType,
getDispatchReceiverParameter(),
getTypeParameters(),
DescriptorsPackage.createEnhancedValueParameters(enhancedValueParametersTypes, getValueParameters(), enhancedMethod),
enhancedReturnType,
getModality(),
getVisibility()
List<ValueParameterDescriptor> 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);
}
@@ -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<ValueParameterDescriptor> 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<ValueParameterDescriptor> substitutedValueParameters = getSubstitutedValueParameters(substitutedDescriptor, this, substitutor);
List<ValueParameterDescriptor> 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<ValueParameterDescriptor> getSubstitutedValueParameters(FunctionDescriptor substitutedDescriptor, @NotNull FunctionDescriptor functionDescriptor, @NotNull TypeSubstitutor substitutor) {
public static List<ValueParameterDescriptor> getSubstitutedValueParameters(
FunctionDescriptor substitutedDescriptor,
@NotNull List<ValueParameterDescriptor> unsubstitutedValueParameters,
@NotNull TypeSubstitutor substitutor
) {
List<ValueParameterDescriptor> result = new ArrayList<ValueParameterDescriptor>();
List<ValueParameterDescriptor> unsubstitutedValueParameters = functionDescriptor.getValueParameters();
for (ValueParameterDescriptor unsubstitutedValueParameter : unsubstitutedValueParameters) {
// TODO : Lazy?
JetType substitutedType = substitutor.substitute(unsubstitutedValueParameter.getType(), Variance.IN_VARIANCE);
@@ -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<ValueParameterDescriptor> substitutedValueParameters = FunctionDescriptorImpl.getSubstitutedValueParameters(newSetter, setter, substitutor);
List<ValueParameterDescriptor> substitutedValueParameters = FunctionDescriptorImpl.getSubstitutedValueParameters(
newSetter, setter.getValueParameters(), substitutor
);
if (substitutedValueParameters == null) {
// The setter is projected out, e.g. in this case:
// trait Tr<T> { var v: T }