KT-3553 Problem with propagation for extension functions
#KT-3553 fixed
This commit is contained in:
+61
-27
@@ -20,7 +20,10 @@ import com.google.common.collect.*;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -154,47 +157,52 @@ public class SignaturesPropagationData {
|
||||
private JavaDescriptorResolver.ValueParameterDescriptors modifyValueParametersAccordingToSuperMethods(
|
||||
@NotNull JavaDescriptorResolver.ValueParameterDescriptors parameters // descriptors built by parameters resolver
|
||||
) {
|
||||
// we are not processing receiver type specifically:
|
||||
// if this function comes from Kotlin, then we don't need to do it, if it doesn't, then it can't have receiver
|
||||
assert parameters.getReceiverType() == null : "Parameters before propagation have receiver type," +
|
||||
" but propagation should be disabled for functions compiled from Kotlin in class: " +
|
||||
DescriptorUtils.getFQName(containingClass);
|
||||
|
||||
JetType receiverType = null;
|
||||
List<ValueParameterDescriptor> resultParameters = Lists.newArrayList();
|
||||
|
||||
boolean shouldBeExtension = checkIfShouldBeExtension();
|
||||
|
||||
for (ValueParameterDescriptor originalParam : parameters.getDescriptors()) {
|
||||
final int index = originalParam.getIndex();
|
||||
final int originalIndex = originalParam.getIndex();
|
||||
List<TypeAndVariance> typesFromSuperMethods = ContainerUtil.map(superFunctions,
|
||||
new Function<FunctionDescriptor, TypeAndVariance>() {
|
||||
@Override
|
||||
public TypeAndVariance fun(FunctionDescriptor superFunction) {
|
||||
ReceiverParameterDescriptor receiver = superFunction.getReceiverParameter();
|
||||
int index = receiver != null ? originalIndex - 1 : originalIndex;
|
||||
if (index == -1) {
|
||||
assert receiver != null : "can't happen: index is -1, while function is not extension";
|
||||
return new TypeAndVariance(receiver.getType(), INVARIANT);
|
||||
}
|
||||
return new TypeAndVariance(superFunction.getValueParameters().get(index).getType(), INVARIANT);
|
||||
}
|
||||
});
|
||||
|
||||
VarargCheckResult varargCheckResult =
|
||||
checkVarargInSuperFunctions(originalParam);
|
||||
VarargCheckResult varargCheckResult = checkVarargInSuperFunctions(originalParam);
|
||||
|
||||
JetType altType = modifyTypeAccordingToSuperMethods(varargCheckResult.parameterType, typesFromSuperMethods, MEMBER_SIGNATURE_CONTRAVARIANT);
|
||||
|
||||
resultParameters.add(new ValueParameterDescriptorImpl(
|
||||
originalParam.getContainingDeclaration(),
|
||||
index,
|
||||
originalParam.getAnnotations(),
|
||||
originalParam.getName(),
|
||||
altType,
|
||||
originalParam.declaresDefaultValue(),
|
||||
varargCheckResult.isVararg ? KotlinBuiltIns.getInstance().getArrayElementType(altType) : null
|
||||
));
|
||||
if (shouldBeExtension && originalIndex == 0) {
|
||||
receiverType = altType;
|
||||
}
|
||||
else {
|
||||
resultParameters.add(new ValueParameterDescriptorImpl(
|
||||
originalParam.getContainingDeclaration(),
|
||||
shouldBeExtension ? originalIndex - 1 : originalIndex,
|
||||
originalParam.getAnnotations(),
|
||||
originalParam.getName(),
|
||||
altType,
|
||||
originalParam.declaresDefaultValue(),
|
||||
varargCheckResult.isVararg ? KotlinBuiltIns.getInstance().getArrayElementType(altType) : null
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
JetType originalReceiverType = parameters.getReceiverType();
|
||||
if (originalReceiverType != null) {
|
||||
JetType substituted = SignaturesUtil.createSubstitutorForTypeParameters(autoTypeParameterToModified)
|
||||
.substitute(originalReceiverType, INVARIANT);
|
||||
assert substituted != null;
|
||||
return new JavaDescriptorResolver.ValueParameterDescriptors(substituted, resultParameters);
|
||||
}
|
||||
else {
|
||||
return new JavaDescriptorResolver.ValueParameterDescriptors(null, resultParameters);
|
||||
}
|
||||
return new JavaDescriptorResolver.ValueParameterDescriptors(receiverType, resultParameters);
|
||||
}
|
||||
|
||||
private static List<FunctionDescriptor> getSuperFunctionsForMethod(
|
||||
@@ -270,7 +278,7 @@ public class SignaturesPropagationData {
|
||||
for (FunctionDescriptor fun : klass.getDefaultType().getMemberScope().getFunctions(functionName)) {
|
||||
CallableMemberDescriptor.Kind kind = fun.getKind();
|
||||
if ((kind == CallableMemberDescriptor.Kind.DECLARATION || kind == CallableMemberDescriptor.Kind.DELEGATION) &&
|
||||
fun.getValueParameters().size() == parameterCount) {
|
||||
fun.getValueParameters().size() + (fun.getReceiverParameter() != null ? 1 : 0) == parameterCount) {
|
||||
PsiElement declaration = BindingContextUtils.descriptorToDeclaration(bindingContext, fun);
|
||||
if (declaration instanceof PsiMethod) {
|
||||
result.put(fqName, Pair.create(fun, (PsiMethod) declaration));
|
||||
@@ -295,12 +303,38 @@ public class SignaturesPropagationData {
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean checkIfShouldBeExtension() {
|
||||
boolean someSupersExtension = false;
|
||||
boolean someSupersNotExtension = false;
|
||||
|
||||
for (FunctionDescriptor superFunction : superFunctions) {
|
||||
if (superFunction.getReceiverParameter() != null) {
|
||||
someSupersExtension = true;
|
||||
}
|
||||
else {
|
||||
someSupersNotExtension = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (someSupersExtension) {
|
||||
if (someSupersNotExtension) {
|
||||
reportError("Incompatible super methods: some are extension functions, some are not");
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private VarargCheckResult checkVarargInSuperFunctions(@NotNull ValueParameterDescriptor originalParam) {
|
||||
boolean someSupersVararg = false;
|
||||
boolean someSupersNotVararg = false;
|
||||
for (FunctionDescriptor superFunction : superFunctions) {
|
||||
if (superFunction.getValueParameters().get(originalParam.getIndex()).getVarargElementType() != null) {
|
||||
int originalIndex = originalParam.getIndex();
|
||||
int index = superFunction.getReceiverParameter() != null ? originalIndex - 1 : originalIndex;
|
||||
if (index != -1 && superFunction.getValueParameters().get(index).getVarargElementType() != null) {
|
||||
someSupersVararg = true;
|
||||
}
|
||||
else {
|
||||
|
||||
+1
-1
@@ -151,7 +151,7 @@ public final class JavaFunctionResolver {
|
||||
List<String> signatureErrors = Lists.newArrayList();
|
||||
|
||||
List<FunctionDescriptor> superFunctions;
|
||||
if (ownerDescriptor instanceof ClassDescriptor) {
|
||||
if (ownerDescriptor instanceof ClassDescriptor && !method.getJetMethodAnnotation().isDefined()) { // don't propagate for Kotlin functions
|
||||
SignaturesPropagationData signaturesPropagationData = new SignaturesPropagationData(
|
||||
(ClassDescriptor) ownerDescriptor, returnType, valueParameterDescriptors, methodTypeParameters, method, trace);
|
||||
superFunctions = signaturesPropagationData.getSuperFunctions();
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package test
|
||||
|
||||
public trait Sub : test.Super1, test.Super2 {
|
||||
public abstract override /*1*/ fun bar(/*0*/ vararg p: jet.String /*jet.Array<jet.String>*/): jet.Unit
|
||||
public abstract override /*1*/ fun foo(/*0*/ p: jet.String): jet.Unit
|
||||
public abstract override /*1*/ /*fake_override*/ fun jet.Array<jet.String>.bar(): jet.Unit
|
||||
public abstract override /*1*/ /*fake_override*/ fun jet.String.foo(): jet.Unit
|
||||
}
|
||||
|
||||
public trait Super1 {
|
||||
public abstract fun jet.Array<jet.String>.bar(): jet.Unit
|
||||
public abstract fun jet.String.foo(): jet.Unit
|
||||
}
|
||||
|
||||
public trait Super2 {
|
||||
public abstract fun bar(/*0*/ vararg p: jet.String /*jet.Array<jet.String>*/): jet.Unit
|
||||
public abstract fun foo(/*0*/ p: jet.String): jet.Unit
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package test;
|
||||
|
||||
import org.jetbrains.jet.jvm.compiler.annotation.ExpectLoadError;
|
||||
|
||||
public interface Sub extends Super1, Super2 {
|
||||
@ExpectLoadError("Incompatible super methods: some are extension functions, some are not")
|
||||
void foo(String p);
|
||||
|
||||
@ExpectLoadError("Incompatible super methods: some are extension functions, some are not|Incompatible super methods: some have vararg parameter, some have not")
|
||||
void bar(String... p);
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package test
|
||||
|
||||
public trait Super1 {
|
||||
public fun String.foo()
|
||||
public fun Array<String>.bar()
|
||||
}
|
||||
|
||||
public trait Super2 {
|
||||
public fun foo(p: String)
|
||||
public fun bar(vararg p: String)
|
||||
}
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package test
|
||||
|
||||
public open class Sub : test.Super {
|
||||
public constructor Sub()
|
||||
public open override /*1*/ fun jet.String.bar(/*0*/ param: jet.String): jet.String
|
||||
public final override /*1*/ /*fake_override*/ fun jet.String.foo(): jet.Unit
|
||||
}
|
||||
|
||||
public open class Super {
|
||||
public constructor Super()
|
||||
public abstract fun jet.String.bar(/*0*/ p: jet.String): jet.Unit
|
||||
public final fun jet.String.foo(): jet.Unit
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
package test;
|
||||
|
||||
public class Sub extends Super {
|
||||
public String bar(String recv, String param) {
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
package test
|
||||
|
||||
public open class Super {
|
||||
public fun String.foo() = Unit.VALUE
|
||||
public abstract fun String.bar(p: String)
|
||||
}
|
||||
@@ -25,6 +25,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.ConfigurationKind;
|
||||
import org.jetbrains.jet.JetTestUtils;
|
||||
import org.jetbrains.jet.TestJdkKind;
|
||||
import org.jetbrains.jet.cli.jvm.JVMConfigurationKeys;
|
||||
import org.jetbrains.jet.cli.jvm.compiler.CliLightClassGenerationSupport;
|
||||
import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment;
|
||||
import org.jetbrains.jet.config.CommonConfigurationKeys;
|
||||
@@ -136,6 +137,7 @@ public abstract class AbstractLoadJavaTest extends TestCaseWithTmpdir {
|
||||
CompilerConfiguration configuration = JetTestUtils.compilerConfigurationForTests(
|
||||
ConfigurationKind.JDK_ONLY, TestJdkKind.MOCK_JDK, tmpdir);
|
||||
configuration.put(CommonConfigurationKeys.SOURCE_ROOTS_KEY, Arrays.asList(sourcesDir.getAbsolutePath()));
|
||||
configuration.add(JVMConfigurationKeys.CLASSPATH_KEY, new File("compiler/tests")); // for @ExpectLoadError annotation
|
||||
JetCoreEnvironment environment = new JetCoreEnvironment(getTestRootDisposable(), configuration);
|
||||
|
||||
ModuleDescriptorImpl moduleDescriptor = AnalyzerFacadeForJVM.createJavaModule("<test module>");
|
||||
|
||||
@@ -1367,6 +1367,16 @@ public class LoadJavaTestGenerated extends AbstractLoadJavaTest {
|
||||
doTestJavaAgainstKotlin("compiler/testData/loadJava/javaAgainstKotlin/signaturePropagation/DeepSubclassingKotlinInJava.txt");
|
||||
}
|
||||
|
||||
@TestMetadata("InheritExtensionAndNot.txt")
|
||||
public void testInheritExtensionAndNot() throws Exception {
|
||||
doTestJavaAgainstKotlin("compiler/testData/loadJava/javaAgainstKotlin/signaturePropagation/InheritExtensionAndNot.txt");
|
||||
}
|
||||
|
||||
@TestMetadata("InheritExtensionFunction.txt")
|
||||
public void testInheritExtensionFunction() throws Exception {
|
||||
doTestJavaAgainstKotlin("compiler/testData/loadJava/javaAgainstKotlin/signaturePropagation/InheritExtensionFunction.txt");
|
||||
}
|
||||
|
||||
@TestMetadata("SubclassFromTraitImplementation.txt")
|
||||
public void testSubclassFromTraitImplementation() throws Exception {
|
||||
doTestJavaAgainstKotlin("compiler/testData/loadJava/javaAgainstKotlin/signaturePropagation/SubclassFromTraitImplementation.txt");
|
||||
|
||||
Reference in New Issue
Block a user