diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index f587b0bc31a..feb52803e97 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1897,7 +1897,7 @@ public class ExpressionCodegen extends JetVisitor implem } SimpleFunctionDescriptor original = ((SimpleFunctionDescriptor) fun).getOriginal(); if (original.getKind() == CallableMemberDescriptor.Kind.SYNTHESIZED) { - return bindingContext.get(SAM_ADAPTER_FUNCTION_TO_ORIGINAL, original); + return (SimpleFunctionDescriptor) bindingContext.get(SAM_ADAPTER_FUNCTION_TO_ORIGINAL, original); // TODO support constructor } if (original.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) { for (FunctionDescriptor overridden : original.getOverriddenDescriptors()) { diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaConstructorResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaConstructorResolver.java index 812e92143cd..03943e0f754 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaConstructorResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaConstructorResolver.java @@ -18,6 +18,7 @@ package org.jetbrains.jet.lang.resolve.java.resolver; import com.google.common.collect.Lists; import com.intellij.psi.*; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; @@ -31,6 +32,7 @@ import org.jetbrains.jet.lang.resolve.java.*; import org.jetbrains.jet.lang.resolve.java.kotlinSignature.AlternativeMethodSignatureData; import org.jetbrains.jet.lang.resolve.java.kt.JetConstructorAnnotation; import org.jetbrains.jet.lang.resolve.java.provider.ClassPsiDeclarationProvider; +import org.jetbrains.jet.lang.resolve.java.sam.SingleAbstractMethodUtils; import org.jetbrains.jet.lang.resolve.java.wrapper.PsiMethodWrapper; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.types.JetType; @@ -149,6 +151,7 @@ public final class JavaConstructorResolver { ConstructorDescriptor constructor = resolveConstructor(psiClass, isStatic, psiConstructor, containingClass); if (constructor != null) { constructors.add(constructor); + ContainerUtil.addIfNotNull(constructors, resolveSamAdapter(constructor)); } } } @@ -218,4 +221,16 @@ public final class JavaConstructorResolver { trace.record(BindingContext.CONSTRUCTOR, psiConstructor, constructorDescriptor); return constructorDescriptor; } + + @Nullable + private ConstructorDescriptor resolveSamAdapter(@NotNull ConstructorDescriptor original) { + if (SingleAbstractMethodUtils.isSamAdapterNecessary(original)) { + ConstructorDescriptor adapterFunction = SingleAbstractMethodUtils.createSamAdapterConstructor(original); + + trace.record(BindingContext.SAM_ADAPTER_FUNCTION_TO_ORIGINAL, adapterFunction, original); + trace.record(BindingContext.SOURCE_DESCRIPTOR_FOR_SYNTHESIZED, adapterFunction, original); + return adapterFunction; + } + return null; + } } \ No newline at end of file diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/sam/SingleAbstractMethodUtils.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/sam/SingleAbstractMethodUtils.java index 791161d5abc..7134388ac38 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/sam/SingleAbstractMethodUtils.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/sam/SingleAbstractMethodUtils.java @@ -21,6 +21,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; +import org.jetbrains.jet.lang.descriptors.impl.ConstructorDescriptorImpl; import org.jetbrains.jet.lang.descriptors.impl.SimpleFunctionDescriptorImpl; import org.jetbrains.jet.lang.descriptors.impl.TypeParameterDescriptorImpl; import org.jetbrains.jet.lang.descriptors.impl.ValueParameterDescriptorImpl; @@ -174,7 +175,7 @@ public class SingleAbstractMethodUtils { return getFunctionTypeForSamType(type) != null; } - public static boolean isSamAdapterNecessary(@NotNull SimpleFunctionDescriptor fun) { + public static boolean isSamAdapterNecessary(@NotNull FunctionDescriptor fun) { for (ValueParameterDescriptor param : fun.getValueParameters()) { if (isSamType(param.getType())) { return true; @@ -184,20 +185,77 @@ public class SingleAbstractMethodUtils { } @NotNull - public static SimpleFunctionDescriptor createSamAdapterFunction(@NotNull SimpleFunctionDescriptor original) { - SimpleFunctionDescriptorImpl result = new SimpleFunctionDescriptorImpl( + public static SimpleFunctionDescriptor createSamAdapterFunction(@NotNull final SimpleFunctionDescriptor original) { + final SimpleFunctionDescriptorImpl result = new SimpleFunctionDescriptorImpl( original.getContainingDeclaration(), original.getAnnotations(), original.getName(), CallableMemberDescriptor.Kind.SYNTHESIZED ); + FunctionInitializer initializer = new FunctionInitializer() { + @Override + public void initialize( + @NotNull List typeParameters, + @NotNull List valueParameters, + @Nullable JetType returnType + ) { + result.initialize( + null, + original.getExpectedThisObject(), + typeParameters, + valueParameters, + returnType, + original.getModality(), + original.getVisibility(), + false + ); + } + }; + return initSamAdapter(original, result, initializer); + } - TypeParameters typeParameters = recreateAndInitializeTypeParameters(original.getTypeParameters(), result); + @NotNull + public static ConstructorDescriptor createSamAdapterConstructor(@NotNull final ConstructorDescriptor original) { + final ConstructorDescriptorImpl result = new ConstructorDescriptorImpl( + original.getContainingDeclaration(), + original.getAnnotations(), + original.isPrimary(), + CallableMemberDescriptor.Kind.SYNTHESIZED + ); + FunctionInitializer initializer = new FunctionInitializer() { + @Override + public void initialize( + @NotNull List typeParameters, + @NotNull List valueParameters, + @Nullable JetType returnType + ) { + result.initialize( + typeParameters, + valueParameters, + original.getVisibility(), + original.getExpectedThisObject() == ReceiverParameterDescriptor.NO_RECEIVER_PARAMETER + ); + } + }; + return initSamAdapter(original, result, initializer); + } + + private static F initSamAdapter( + @NotNull F original, + @NotNull F adapter, + @NotNull FunctionInitializer initializer + ) { + TypeParameters typeParameters = recreateAndInitializeTypeParameters(original.getTypeParameters(), adapter); JetType returnTypeUnsubstituted = original.getReturnType(); - assert returnTypeUnsubstituted != null : original; - JetType returnType = typeParameters.substitutor.substitute(returnTypeUnsubstituted, Variance.OUT_VARIANCE); - assert returnType != null : "couldn't substitute type: " + returnType + ", substitutor = " + typeParameters.substitutor; + JetType returnType; + if (returnTypeUnsubstituted == null) { // return type may be null for not yet initialized constructors + returnType = null; + } + else { + returnType = typeParameters.substitutor.substitute(returnTypeUnsubstituted, Variance.OUT_VARIANCE); + assert returnType != null : "couldn't substitute type: " + returnType + ", substitutor = " + typeParameters.substitutor; + } List valueParameters = Lists.newArrayList(); for (ValueParameterDescriptor originalParam : original.getValueParameters()) { @@ -208,22 +266,12 @@ public class SingleAbstractMethodUtils { assert newType != null : "couldn't substitute type: " + newTypeUnsubstituted + ", substitutor = " + typeParameters.substitutor; ValueParameterDescriptor newParam = new ValueParameterDescriptorImpl( - result, originalParam.getIndex(), originalParam.getAnnotations(), originalParam.getName(), newType, false, null); + adapter, originalParam.getIndex(), originalParam.getAnnotations(), originalParam.getName(), newType, false, null); valueParameters.add(newParam); } - result.initialize( - null, - original.getExpectedThisObject(), - typeParameters.descriptors, - valueParameters, - returnType, - original.getModality(), - original.getVisibility(), - false - ); - - return result; + initializer.initialize(typeParameters.descriptors, valueParameters, returnType); + return adapter; } @NotNull @@ -273,4 +321,12 @@ public class SingleAbstractMethodUtils { this.substitutor = substitutor; } } + + private static abstract class FunctionInitializer { + public abstract void initialize( + @NotNull List typeParameters, + @NotNull List valueParameters, + @Nullable JetType returnType + ); + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/impl/ConstructorDescriptorImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/impl/ConstructorDescriptorImpl.java index abe1d6f6d50..e0560aea197 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/impl/ConstructorDescriptorImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/impl/ConstructorDescriptorImpl.java @@ -22,6 +22,7 @@ import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.name.Name; +import org.jetbrains.jet.lang.types.JetType; import java.util.Collections; import java.util.List; @@ -36,7 +37,11 @@ public class ConstructorDescriptorImpl extends FunctionDescriptorImpl implements private static final Name NAME = Name.special(""); public ConstructorDescriptorImpl(@NotNull ClassDescriptor containingDeclaration, @NotNull List annotations, boolean isPrimary) { - super(containingDeclaration, annotations, NAME, Kind.DECLARATION); + this(containingDeclaration, annotations, isPrimary, Kind.DECLARATION); + } + + public ConstructorDescriptorImpl(@NotNull ClassDescriptor containingDeclaration, @NotNull List annotations, boolean isPrimary, Kind kind) { + super(containingDeclaration, annotations, NAME, kind); this.isPrimary = isPrimary; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java index b84fa9060f8..dbc1d85ee1d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java @@ -265,7 +265,7 @@ public interface BindingContext { WritableSlice IS_DECLARED_IN_JAVA = Slices.createSimpleSlice(); WritableSlice SAM_CONSTRUCTOR_TO_INTERFACE = Slices.createSimpleSlice(); - WritableSlice SAM_ADAPTER_FUNCTION_TO_ORIGINAL = Slices.createSimpleSlice(); + WritableSlice SAM_ADAPTER_FUNCTION_TO_ORIGINAL = Slices.createSimpleSlice(); WritableSlice SOURCE_DESCRIPTOR_FOR_SYNTHESIZED = Slices.createSimpleSlice(); @SuppressWarnings("UnusedDeclaration") diff --git a/compiler/testData/loadJava/compiledJava/singleAbstractMethod/adapter/Constructor.java b/compiler/testData/loadJava/compiledJava/singleAbstractMethod/adapter/Constructor.java new file mode 100644 index 00000000000..527ec3102bd --- /dev/null +++ b/compiler/testData/loadJava/compiledJava/singleAbstractMethod/adapter/Constructor.java @@ -0,0 +1,6 @@ +package test; + +public class Constructor { + public Constructor(Runnable r) { + } +} diff --git a/compiler/testData/loadJava/compiledJava/singleAbstractMethod/adapter/Constructor.txt b/compiler/testData/loadJava/compiledJava/singleAbstractMethod/adapter/Constructor.txt new file mode 100644 index 00000000000..a9b54f026fc --- /dev/null +++ b/compiler/testData/loadJava/compiledJava/singleAbstractMethod/adapter/Constructor.txt @@ -0,0 +1,6 @@ +package test + +public open class Constructor : java.lang.Object { + public /*synthesized*/ constructor Constructor(/*0*/ p0: (() -> jet.Unit)?) + public constructor Constructor(/*0*/ p0: java.lang.Runnable?) +} diff --git a/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java b/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java index 5d88070a54a..65c21f08fae 100644 --- a/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaTestGenerated.java @@ -1239,6 +1239,11 @@ public class LoadJavaTestGenerated extends AbstractLoadJavaTest { doTestCompiledJava("compiler/testData/loadJava/compiledJava/singleAbstractMethod/adapter/Basic.java"); } + @TestMetadata("Constructor.java") + public void testConstructor() throws Exception { + doTestCompiledJava("compiler/testData/loadJava/compiledJava/singleAbstractMethod/adapter/Constructor.java"); + } + @TestMetadata("DeepSamLoop.java") public void testDeepSamLoop() throws Exception { doTestCompiledJava("compiler/testData/loadJava/compiledJava/singleAbstractMethod/adapter/DeepSamLoop.java");